乐于分享
好东西不私藏

九十天生产考验:AI智能体架构模式与检查清单

九十天生产考验:AI智能体架构模式与检查清单

标题我修改了一下。

一份面向实战的智能体拓扑、状态设计及失效模式指南——帮你分清演示原型与能撑过九十天生产考验的系统之间的区别。

架构师之道

 AI · LLM · Agents | Enterprise Architecture | Digital Transformation

1 引言

半年前,一家物流公司请我去看他们的“客户运营自动化”试点项目。供应商的演示令人惊艳:智能体能报交货时间、修正地址偏差、标记高风险货件转人工处理。在受控演示环境下,它不需要人工介入就能解决94%的测试用例。

我问他们要生产环境的实际数据。对方沉默了一下。CTO调出仪表盘——面对每天约四千张工单、混乱的地址、滞后的追踪信息、愤怒的客户,同样的智能体只解决了11%的案例,其余至少十几个案例里它还凭空捏造了送货承诺。其中一些承诺让公司赔了不少钱——退款、补发,真金白银地往外掏。

演示不是假的,模型本身也没问题。问题出在:没有人真正设计过系统的架构。他们只是把一个好用的模型塞进提示词,外面套个循环,就管它叫智能体。

本文要讲的就是我当时希望那个供应商能拿出来的模式语言——包括拓扑结构、状态设计、工具契约,以及决定一个智能体能否在生产环境活下去的那些失效模式。读完本文,你就能一眼看穿任何一个智能体项目用的是哪种模式,更重要的是,能判断它选得对不对。

2 忘掉“智能体”这个词,先说“拓扑”

“智能体”是营销词汇,“拓扑”才是工程词汇。拓扑就是你的系统结构:有多少个推理循环,它们之间怎么通信,状态归谁管,下一步由谁来决定。生产环境里的智能体崩掉,十有八九不是模型的错,而是拓扑跟任务不匹配——或者更准确地说,是拓扑、任务、状态和工具契约没有对齐。

不管演示文档画得多漂亮,绝大多数智能体架构都可以归结为以下六种基础模式。它们很少单独出现,实际系统常常是几种模式的嵌套或组合。学会辨认它们,因为每一种都有各自的成本、失效模式,以及真正擅长的任务范围。

2.1 单循环(Single Loop)

一个模型、一个上下文窗口、一套工具、一个while循环。这是默认配置,也是主力干将。系统提示词里放着目标,上下文窗口里存着当前工作状态,工具提供操作能力,预算计数器防止它无限跑下去。

  • 成本:最低。
  • 延迟:最低。
  • 擅长:范围狭窄、边界清晰的任务——比如查余额、提取表单字段、基于工具的单一领域问答。

2.2 路由器(Router)

用一个轻量级、速度快的小模型对请求做分类,然后分发给对应的专业处理模块。比如工单分类路由器:支付纠纷走退款流程,物流问题走追踪工具,其他走通用智能体。路由器本身没有自主推理循环,但它分发的下游处理器可能有循环。

  • 成本:低。
  • 延迟:多一次轻量级调用。
  • 擅长:高流量场景,且大多数请求属于有限的几种已知类型。这是生产环境中最被低估的模式,也是我本人会优先采用的模式。

2.3 编排器–工作器(Orchestrator–Worker)

一个编排器把大任务拆成子任务,交给工作器智能体(也可以是普通函数或搜索任务)处理。工作器返回结果,编排器综合汇总。这是人们说“多智能体”时真正指的东西——大多数情况下就是一个编排器加几个专业工作器。

  • 成本:中等。
  • 延迟:中等。
  • 擅长:报告生成、调研、代码审查——这类任务天然可拆解。

2.4 分层式(Hierarchical)

智能体管智能体。主编排器生成子编排器,每个子编排器再管自己的工作器。这是把编排器–工作器模式扩展到超大规模任务的方式,但也正是复杂度和成本开始滚雪球的地方。

  • 成本:高。
  • 延迟:高。
  • 擅长:涉及数千份文档的企业级研究流水线。但凡模式3能搞定的,用分层式通常都是过度设计。

2.5 对等团队(Peer Team)

多个地位平等的智能体通过对话或并行协作,共同达成一个目标——这就是CrewAI和AutoGen的经典画面:研究员、写手、评论家为了一份文档来回争论,直到达成共识。

  • 成本:高——每一次同伴对话都是一次完整模型调用,协调开销不可小视。
  • 延迟:高。
  • 擅长:创意起草、辩论式任务。
  • 不擅长:有严格截止日期和预算限制的事情。

2.6 状态机 / 预定义工作流(State Machine / Predefined Workflow)

控制流在部署前已经确定:查询、校验、扣款、确认——每一步要么是确定性的,要么借助模型辅助。它没有模型自主决定的开放式推理循环,但可以有预定义的有限重试、条件分支或循环边。LangGraph的图模型和n8n的节点模型,就是这种模式套上了工程化的外衣。

  • 成本:每步最低。
  • 延迟:可预测。
  • 擅长:那些80%是已知流程、只有少数模糊决策点的事情。大多数所谓的“智能体”用例,本质上都是这个。这也是清单里最诚实的模式。

2.7 速查表

我给客户看的版本:

模式
有自主推理循环?
成本
失效模式
最适合
单循环
上下文膨胀
边界清晰的小任务
路由器
取决于下游处理器
分类器不准
高流量分拣
编排器–工作器
交接过程丢失上下文
调研、报告
分层式
成本指数级增长
超大规模拆解
对等团队
协调对话过多
起草、辩论
状态机 / 预定义工作流
无自主循环,可能有预定义循环边
对异常情况过于死板
已知流程

这些模式不是互斥的。真实的系统可能是“路由器 → 状态机”,或者“编排器 → 多个状态机”的组合方式。写代码之前,我最常问的一个问题:这个任务是一个带几个判断点的流程,还是一个目标开放、步骤未知的探索型任务? 流程 → 状态机;开放探索 → 单循环或编排器–工作器。几乎不要第一天就上对等团队。

3 在选拓扑之前:先定义任务模型和工具语义

拓扑是骨,领域模型是肉。如果这一步没做好,即使拓扑选对了,也可能因为领域模型混乱而失败。动手画图之前,先回答:

  • 任务有哪些类型?每种任务的关键实体是什么?
  • 工具能力如何形式化?每个工具的前提条件、副作用、失败模式是什么?
  • 状态机有哪些合法状态和迁移?哪些决策可以自动化,哪些必须人工?
  • 哪些步骤是确定性的,哪些步骤需要模型判断?

花半天时间把这些问题写下来,往往比之后花两周修架构更划算。

4 状态:那个所有人都忘了的部分

选对拓扑还不够——真正让生产环境智能体翻车的,是状态。

一个智能体的状态,就是它在每一步之间携带的所有信息:任务目标、已经尝试过什么、排除了什么、工具调用的结果、还剩多少预算。如果状态只放在模型的上下文窗口里,你就有了内存问题——上下文窗口有大小限制、容易塞满噪声、还容易被污染。如果状态放在数据库里,你就有工程问题——每一步都需要保存、加载、版本管理。

我现在给客户立下的规矩是:工作状态(模型当前桌面上正在处理的东西)放在上下文窗口里,但必须狠心裁剪;持久状态(任务已经完成的事项,包括重试和重启后的进展)放在存储里。每一步都封装成可重放的状态转换函数:输入是持久状态加上模型的决策,输出是新状态和待执行动作。不要叫它纯函数——模型调用和工具调用都有非确定性和副作用。重点是可重放、可审计、可恢复。

仅靠一张任务表和step_count字段是远远不够的。要可靠恢复,你需要更细粒度的状态记录。至少拆成三张表:

SQL
-- =============================================================-- 任务主表:一个智能体任务的整体信息-- =============================================================CREATETABLE tasks (  id             uuid PRIMARYKEY,                     -- 任务唯一ID  pattern        text NOTNULL,                        -- 使用的拓扑模式:如 single_loop / router / orchestrator_worker / state_machine  goal           text NOTNULL,                        -- 任务目标描述,作为模型的核心输入  status         text NOTNULLDEFAULT'queued',       -- 任务状态:queued / running / completed / failed / plan_failed / cancelledresult         jsonb,                                -- 任务最终结果(结构化JSON),可包含摘要、输出、错误信息等  created_at     timestamptz NOTNULLDEFAULT now(),   -- 任务创建时间  updated_at     timestamptz NOTNULLDEFAULT now()    -- 任务最后更新时间);-- =============================================================-- 子任务表:编排器拆解出的可独立执行的子任务-- =============================================================CREATETABLE subtasks (  id             uuid PRIMARYKEY,                     -- 子任务唯一ID  task_id        uuid NOTNULLREFERENCES tasks(id),   -- 所属主任务ID  seq            int  NOTNULL,                        -- 子任务序号,用于排序和展示  description    text NOTNULL,                        -- 子任务描述,模型拆分出的具体指令  tool_name      text,                                 -- 需要调用的工具名称,若无需工具可为空  tool_args      jsonb,                                -- 调用工具的参数,JSON格式,由模型生成  status         text NOTNULLDEFAULT'pending',      -- 子任务状态:pending / running / completed / failedresult         jsonb,                                -- 子任务执行结果,JSON格式  attempt_count  int  NOTNULLDEFAULT0,              -- 已尝试次数,用于重试控制  created_at     timestamptz NOTNULLDEFAULT now(),   -- 子任务创建时间  updated_at     timestamptz NOTNULLDEFAULT now()    -- 子任务最后更新时间);-- =============================================================-- 工具调用事件表:记录每一次工具调用的完整信息,用于审计和恢复-- =============================================================CREATETABLE tool_calls (  id              uuid PRIMARYKEY,                    -- 工具调用唯一ID  task_id         uuid NOTNULLREFERENCES tasks(id),  -- 所属任务ID  subtask_id      uuid REFERENCES subtasks(id),        -- 所属子任务ID,可选  tool_name       text NOTNULL,                       -- 调用的工具名称input           jsonb NOTNULL,                      -- 工具调用输入参数,完整记录output          jsonb,                               -- 工具调用输出结果,完整记录  status          text NOTNULLDEFAULT'pending',     -- 调用状态:pending / running / success / failed  idempotency_key text NOTNULL,                       -- 幂等键,用于防止重复执行有副作用的工具  created_at      timestamptz NOTNULLDEFAULT now(),  -- 调用创建时间  updated_at      timestamptz NOTNULLDEFAULT now()   -- 调用最后更新时间);

每个工具调用都记录在tool_calls表里,并带有一个幂等键。如果进程崩溃,新起的工人读取任务和子任务状态,从第一个未完成的子任务继续,对于已经执行过的非幂等工具,要么确认结果,要么进入人工补偿流程。这就是“可靠智能体”的全部秘密——它们其实就是可以断点续跑、可审计的任务。

5 工具设计:描述即契约

我总说工具是智能体的双手,但大家真正搞砸的是工具描述。模型读你的工具描述,然后决定用不用它。描述写得敷衍,生产环境里模型一定会用错,百试百灵。

把工具描述当作一份三方契约,至少包含:

  1. 做什么:
     例如“获取已认证账户的当前可用余额”。
  2. 何时用:
     例如“客户问自己有多少钱或欠多少钱时调用。查交易记录请用 get_transactions,别用这个。”
  3. 输入 schema:
     明确参数类型、约束、默认值。
  4. 返回 schema:
     例如“返回 {balance: number}。若账户未认证,返回错误对象。”
  5. 副作用与幂等性:
     只读?可逆写?不可逆写?重复调用是否安全?
  6. 权限要求:
     调用该工具需要什么角色或审批。

再加几条铁律:执行之前,服务端必须校验输入参数和输出结果。模型的传参本质上也是模型输出——它们可能出错,恶意输入下甚至可能被注入攻击。通过工具参数夹带SQL注入字符串不是玩笑,这是家常便饭。工具返回的内容进入上下文前也要过滤或标记,防止提示注入。

6 一个可投产的最小编排器–工作器骨架

下面是一个遵循上述纪律的编排器–工作器实现骨架。它不是一个可运行的完整系统,但展示了关键的控制流和持久化点。依赖PostgreSQL和一个任务队列,每个子任务一次模型调用。

import json, uuidfrom typing import Anyfrom db import get_task, create_subtasks, get_next_pending_subtask, update_subtask, record_tool_callfrom queue import dequeue_taskdef run_task(task_id: uuid.UUID):    task = get_task(task_id)    plan = llm_call(        "你是一位研究主管。请把以下任务拆解为3~5个可独立执行的子任务,以JSON格式返回:"        '{"subtasks": [{"description": "...", "tool": "...", "args": {...}}]}',        task["goal"],    )    # 校验规划输出    try:        subtasks = json.loads(plan)["subtasks"]        assert 1 <= len(subtasks) <= 8        for s in subtasks:            assert isinstance(s["description"], str)            assert isinstance(s.get("tool"), str)            assert isinstance(s.get("args", {}), dict)    except Exception:        # 记录失败,可重试或转人工        update_task_status(task_id, "plan_failed")        return    create_subtasks(task_id, subtasks)    while True:        sub = get_next_pending_subtask(task_id)        if sub is None:            break        try:            update_subtask(sub["id"], status="running")            # 工作器:可以在这里加入模型调用,决定是否真的调用工具            result = run_tool(sub["tool_name"], sub["tool_args"])            # 记录工具调用事件            record_tool_call(task_id, sub["id"], sub["tool_name"], sub["tool_args"], result, status="success")            update_subtask(sub["id"], status="completed", result=result)        except Exception as e:            record_tool_call(task_id, sub["id"], sub["tool_name"], sub["tool_args"], {"error"str(e)}, status="failed")            update_subtask(sub["id"], status="failed", result={"error"str(e)})            # 根据策略重试或转人工            break    # 汇总所有已完成的子任务    results = get_completed_subtask_results(task_id)    final = llm_call(        "你是一位编辑,负责整合。请把各子任务结果合并成一份连贯的答案,回应当初的大任务。",        json.dumps({"goal": task["goal"], "results": results}),    )    update_task_status(task_id, "completed", result=final)

这个骨架体现了几个关键点:

  • 规划输出经过schema校验,不合法时任务标记失败而非继续。
  • 每个子任务有独立状态,可单独重试。
  • 每次工具调用都有事件记录和幂等键。
  • 失败后从下一个未完成子任务继续,而不是从步数猜测。

拿真实流量跑一遍,你会精准找到那些交接点——上下文丢失、任务卡住的地方。这恰恰是好事:你希望失败发生在交接层,因为交接层容易埋点、容易修。相比之下,如果子任务拆解本身就开始胡编,那就很难发现,也很难补救。

7 生产现实:真正让你疼的失效模式

经过一年多在制造AI、企业经营管理AI、物流、客服领域的实战交付,我按伤害程度排了个序,以下是最常见的翻车点:

  1. 静默越权。
     智能体自信满满地做了你从未授权的事——发邮件、打折、关工单,一气呵成。对策:加权限层——只读工具随便用,会改数据的工具必须审批或有硬性策略约束。更进一步,引入工具风险分级、运行时策略引擎、细粒度RBAC和审计日志。高危操作需要人工确认或限流。
  2. 上下文膨胀。
     每走一步就往提示词里追加内容,到第9步时模型面对的是自己吐出来的一堆噪声。对策:狠心裁剪,对旧步骤做摘要,或者把状态挪到存储里。
  3. 交接丢失。
     编排器–工作器模式下,编排器把工作器已经花词元生成过的内容又重新总结一遍。对策:让工作器返回结构化JSON,不要返回散文,编排器只负责组装。
  4. 非幂等操作重复执行。
     重试机制可能让同一个扣款、发信操作执行多次。对策:所有写操作工具必须携带幂等键,服务端做去重;非幂等工具进入人工确认队列。
  5. 模型输出格式错误。
     规划或工具参数不是合法JSON,导致整个流程中断。对策:所有模型输出经过schema校验,失败自动重试或转人工。
  6. 成本爆炸。
     对等团队和分层模式烧词元的速度是单循环的5到10倍。要注意计算每个已解决任务的成本,而不是单次运行成本。我曾测得某调研任务:单循环$0.18,编排器–工作器$0.61,对等团队$2.90(具体数字依赖模型和任务,仅供参考)。
  7. 无声劣化。
     模型慢慢不再调用工具,而是靠训练数据瞎猜。对策:监控每种模式的工具调用率、工具调用错误率、循环步数分布、任务完成率,一旦低于阈值就报警。
  8. 提示注入。
     用户输入或工具返回内容里夹带指令,诱导智能体执行非预期操作。对策:对输入和工具输出做过滤、标记,限制模型对工具结果的信任程度。

还有最大的一条,与技术无关:演示和实测的鸿沟。你的测试集是系统开发者自己挑的。从上线第一周开始,就必须拿留出的真实生产流量做评估,否则你迟早会在客户会议上发现自己的“11%版本”——就像那家物流公司一样。

8 什么时候不该用某种模式

  • 单循环?但你的任务其实是个已知流程?——请用状态机。你花的是开放式推理的钱,但你根本不需要开放式推理。
  • 编排器–工作器?但子任务之间无法独立运行?——那你只是在做一个更慢的单循环。每个工作器都在等前一个完成,编排器就多了一跳。
  • 对等团队?但各角色之间没有真正的分歧或互补性?——你是在为“表演”买单。
  • 任何模式?但一段确定性脚本就能搞定?——那就该用脚本。今年我劝一个客户停下:他们的“智能体”是用来解析一个从不变化的发票格式的,其实写个四十行解析器就够了。解析器每次运行成本不到一分钱,而那个智能体每次四美分,还有3%的失败率。我帮他们省下了一笔重复账单——靠的是不建那个架构。

9 我上线任何智能体之前必做的检查清单

    10 真正能在生产环境活下来的样子

    回到那家物流公司。我们把试点项目重构成了“路由器 + 状态机”:一个便宜的分类器把工单分到五种确定性流程之一,只有真正模糊的案例才交给单循环智能体,同时加上严格的预算、权限控制和状态持久化。第一个月,解决率就从11%爬到了78%——不是因为模型变好了,而是因为系统的形状终于跟工作的形状对上了,状态和工具契约也终于支撑得起真实流量。

    模型只是拼图的一块,架构、状态、工具和评估共同决定了系统能不能活下来。所以,动工之前先说出你正在构建的模式名称。如果你叫不出名字,那你没有架构——你只有一个挂着成本的提示词。画出拓扑图,定义好任务模型,把状态存进库,写好工具契约,把上面那份检查清单当作上线前的最后一道工序。

    有任何不同的看法,评论区我们可以继续聊~ 😊


    架构师之道

    架构之道,在于化繁为简,以设计思维驱动技术决策

    AILLM智能体企业架构数字化转型云原生

    > 关注作者并添加星标,与‘架构师之道’同行