为什么许多智能体系统在生产中失效,以及如何通过状态机、明确的工具契约、重试策略和深度可观测性来设计可靠的智能体。

智能体系统是指那种 LLM 不仅回答提示,而是决定下一步要做什么的应用:调用哪个工具、获取哪些数据、执行哪些步骤,以及何时“完成”。它们将模型、一组工具(API、数据库、服务)、一个规划/执行循环和把各部分连接起来的基础设施组合在一起。
在演示中,这看起来很神奇:智能体制定计划、调用几个工具,然后返回完美结果。快乐路径短、延迟低,并且没有多个环节同时失败。
在真实负载下,同样的智能体会遭遇演示从未暴露的压力:
结果是:难以复现的间歇性行为、静默的数据损坏以及偶尔挂起或无限循环的用户流。
间歇性智能体不仅影响“用户体验”。它们:
本文讲述的是工程模式,而不是“更好的提示”。我们将探讨状态机、显式工具契约、重试与失败处理策略、内存与并发控制,以及让智能体在高负载下变得可预测而不仅是舞台上令人惊叹的可观测性模式。
大多数智能体系统在单次快乐路径演示中看起来没问题。但当流量、工具与边缘情况一同到来时,它们就会失败。
天真的编排假设模型会在一两次调用中“做对事”。在真实使用下,你会看到反复出现的模式:
没有显式状态与结束条件,这些行为几乎不可避免。
LLM 采样、延迟变化与工具时序带来隐含的非确定性。相同输入可能走不同分支、调用不同工具或对工具结果有不同解读。
在规模化时,工具问题占主导:
每一个都会演变成多余的循环、重试或错误的最终答案。
在 10 RPS 很少出问题的场景,在 1000 RPS 下会频繁失败。并发揭示了:
产品团队通常期望确定的工作流、清晰 SLA 与可审计性。未经约束的智能体提供的是概率性、尽力而为的行为,保证很弱。
当架构忽视这种不匹配——把智能体当传统服务而不是随机规划器来对待——系统在可靠性最重要时段会变得不可预测。
面向生产的智能体更依赖严谨的系统设计,而非“聪明的提示”。一种有用的思路是:把智能体看作偶尔调用 LLM 的小型、可预测的机器,而不是偶尔触碰你系统的神秘 LLM 大块头。
四个属性最关键:
这些属性不是靠提示获得,而是靠结构获得。
许多团队默认模式是:"while not done, call the model, let it think, maybe call a tool, repeat"。这方便原型开发但难以运维。
更安全的模式是将智能体表示为显式工作流:
COLLECTING_INPUT, PLANNING, EXECUTING_STEP, WAITING_ON_HUMAN, DONE)。这将智能体变为一个状态机,每一步都可检查、测试和重放。自由形式的循环看起来灵活,但显式工作流才是让事故可调试、行为可审计的关键。
一体化的万能智能体虽然诱人,但会把无关职责紧耦合:规划、检索、业务逻辑、UI 协调等。
相反,组合小而明确职责的智能体或技能:
每个技能可以有自己的状态机、工具与安全规则。组合逻辑成了更高层的工作流,而不是单个智能体内不断膨胀的提示。
这种模块化让每个智能体足够简单以便推理,并允许你在不破坏其他部分的情况下进化单个能力。
一个有用的思想模型是把智能体拆成三层:
决策策略(LLM 提示 + 模型)
封装智能体如何选择下一步行动,并在严格约束下解释。你应能在不改系统连线的情况下替换模型、调整温度或细化提示。
状态机 / 工作流引擎
负责当前处于流程何处、哪些转移可行以及如何持久化进度。策略提出动作;状态机验证并应用它。
工具层
实现现实世界中能发生的操作:API、数据库、队列、外部服务。工具暴露窄且类型化的契约,并执行授权、速率限制与输入校验。
通过强制这些分层,你就避免把业务逻辑藏在提示或工具描述里。LLM 成为清晰确定性外壳内的一个决策组件,而不是整个外壳本身。
最可靠的智能体并不是最令人惊艳的演示,而是那些你能在白板上解释其行为的系统。
具体做法:
这种偏向小、可组合、结构良好的智能体设计,能使系统在范围扩大时不被自身复杂性压垮。
大多数智能体实现开始于一个“思考—行动—观察”的循环,围绕 LLM 调用。这对演示可以,但很快变得不透明且脆弱。更好的方法是把智能体当作显式状态机:一组有限状态,以及由事件触发的明确定义的转移。
不要让模型隐式决定下一步做什么,而是定义一个小型状态图:
这些状态之间的转移由类型化事件触发,例如 UserRequestReceived, ToolCallSucceeded, ToolValidationFailed, TimeoutExceeded 或 HumanOverride。每个事件加上当前状态决定下一状态与动作。
这让重试与超时变得直接:你可以把策略附加到单个状态(例如 CALL_TOOL 可重试 3 次并使用指数退避,PLAN 则可能不重试),而不是把重试逻辑散落在代码库各处。
将当前状态与最小上下文持久化到外部存储(数据库、队列或工作流引擎)。这样智能体就成了纯函数:
next_state, actions = transition(current_state, event, context)
这带来好处:
有了状态机,智能体行为的每一步都是显式的:它处于哪个状态、发生了哪一事件、哪个转移触发、产生了哪些副作用。这样的清晰度让调试更快,简化事故调查,并为合规审查创建自然的审计轨迹。你可以从日志与状态历史中证明:某些高风险操作仅在特定状态且满足既定条件时才被执行。
当工具更像“有明确保证的接口”而不是“埋在散文里的 API”时,智能体的行为会更可预测。
每个工具应包含契约,涵盖:
InvalidInput, NotFound, RateLimited, TransientFailure)并赋予明确定义。把这些契约以结构化文档的形式暴露给模型,而不是一墙文字。智能体规划器应该知道哪些错误可重试、哪些需要人工干预、哪些应终止工作流。
把工具的输入输出当作生产 API:
这能让提示更简短:与其用冗长指令,不如依赖 schema 驱动的引导。清晰的约束能减少幻觉式的参数和荒谬的工具序列。
工具会演进;智能体不应在每次演进时都崩溃。
v1, v1.1, v2),并把智能体锁定到某一版本。规划逻辑随后可以安全地混合不同成熟度的智能体与工具。
在设计契约时就考虑部分失败:
智能体据此可适应:用受限功能继续工作、向用户确认或切换到回退工具。
工具契约是编码安全限制的天然位置:
confirm: true)。并在服务端做校验;不要仅仅依赖模型“自觉守规矩”。
当工具拥有清晰、已校验、版本化的契约时,提示可更短,编排逻辑更简单,调试更容易。你把复杂性从脆弱的自然语言说明迁移到确定性的 schema 与策略,从而减少幻觉式工具调用与意外副作用。
可靠的智能体系统假定“万物终将失败”:模型、工具、网络,甚至你自己的协调层都会失败。目标不是避免失败,而是让失败代价低且安全。
幂等性意味着:重复同一请求的对外可见效果应与只执行一次相同。这对经常在部分失败或不确定响应后重新发起工具调用的 LLM 智能体至关重要。
通过设计让工具具备幂等性:
request_id。工具记录该 ID,并在再次看到时返回相同结果。对瞬时错误(超时、速率限制、5xx)使用结构化重试:指数退避、抖动以避免群体效应,并设定严格的最大尝试次数。用相关 ID 记录每次尝试以便追踪智能体行为。
对于永久性失败(4xx、校验错误、业务规则违背)不要重试。将结构化错误暴露给智能体策略,让其重规划、询问用户或选择其他工具。
在智能体与工具层实现断路器:在连续失败后暂时阻止对该工具的调用并快速失败。配合明确定义的回退策略:降级模式、缓存数据或替代工具。
避免在智能体循环中盲目重试。没有幂等工具与清晰失败分类,你只会放大副作用、延迟与成本。
可靠的智能体始于对“什么是状态”与“它在哪里”这两个问题的清晰思考。
把智能体当作处理请求的服务看待:
混用会导致混乱与缺陷。例如,把短期工具结果放进“记忆”会让智能体在未来会话中重复使用过时上下文。
你有三种主要选择:
一个好的规则:把 LLM 当作对显式状态对象的无状态函数。把该对象持久化到模型外,并从它重生成提示。
一个常见失败模式是把对话日志、追踪或原始提示当做事实记忆。
问题包括:
相反,定义结构化记忆 schema:user_profile、project、task_history 等。从日志派生记录,而不是反过来。
当多个工具或智能体更新同一实体(例如 CRM 记录或任务状态)时,需要基础一致性控制:
对于高价值操作,记录一份与会话日志分离的决策日志:记录是什么被改变、为什么、基于哪些输入。
为了在崩溃、部署与速率限制下存活,工作流应可恢复:
这也支持时间旅行调试:你可以检查并重放导致错误决策的确切状态。
记忆既是资产也是负担。生产智能体应:
把记忆当作一个产品面:被设计、版本化与治理——而不是附着在智能体上的不断增长的文本堆栈。
智能体在白板上看似顺序,但在真实负载下表现为分布式系统。只要有大量并发用户、工具与后台作业,你就要处理竞态条件、重复工作与顺序问题。
常见失败模式:
这些问题通过幂等工具契约、显式工作流状态和数据层的乐观/悲观锁来缓解。
同步的请求—响应流程简单但脆弱:每个依赖都必须在线、在速率限制内且快速。一旦智能体扇出到多个工具或并行子任务,就应把长时间运行或有副作用的步骤移到队列之后。
基于队列的编排让你:
智能体通常会触及三类限额:
需要显式的速率限制层,包含按用户、按租户与全局的节流策略。使用令牌桶或漏桶算法执行策略,并返回明确错误类型(例如 RATE_LIMIT_SOFT, RATE_LIMIT_HARD),以便智能体优雅退避。
背压是系统在压力下保护自身的方式。策略包括:
监控饱和信号:队列深度、工作进程利用率、模型/工具错误率与延迟分位数。当队列深度上升且延迟或 429/503 错误增加时,是智能体超载环境的早期预警。
如果你不能快速回答两个问题:“它做了什么?”与“为什么这么做?”,就无法让智能体可靠。智能体的可观测性就是让这些答案便宜且精确。
设计可观测性,使单个任务有一条追踪,串联起:
在追踪中,附加关键决策的结构化日志(路由选择、计划修正、护栏触发)和用于容量与健康的指标。
一个有用的追踪通常包含:
以结构化形式记录提示、工具输入与输出,但先通过脱敏层:
在低环境中可以开放未脱敏的原始内容;生产默认应展示脱敏视图。
至少要跟踪:
发生事故时,良好的追踪与指标能把“智能体看起来不稳定”转为精准的陈述,例如:“P95 任务在 ToolSelection 状态在 2 次重试后失败,原因是 billing_service 的新 schema”,把排查时间从小时缩短到分钟,并给出可操作的调优手段。
测试智能体意味着既要测试工具,也要测试把一切串在一起的流程。把它当作分布式系统测试,而不仅仅是提示微调。
从工具边界的单元测试开始:
这些测试不依赖 LLM。直接调用工具并用合成输入断言精确输出或错误契约。
集成测试应端到端地检验智能体工作流:LLM + 工具 + 编排。
将它们建模为基于场景的测试:
这些测试断言状态转移与工具调用,而不是 LLM 每个令牌的措辞。检查:调用了哪些工具、传入了哪些参数、顺序如何、以及智能体最终达到的状态/结果。
为保持测试可重复性,要对 LLM 响应与工具输出做夹具(fixture):
典型模式:
with mocked_llm(fixtures_dir="fixtures/llm"), mocked_tools():
result = run_agent_scenario(input_case)
assert result.state == "COMPLETED"
每次提示或 schema 变更都应触发不可妥协的回归运行:
schema 演进(新增字段、收紧类型)应有专门回归用例,以捕捉仍假定旧契约的智能体或工具。
切勿把新模型、策略或路由策略直接推到生产流量中。
相反:
只有在通过离线门禁后,新变体才应进入生产,且最好在功能开关与逐步发布下进行。
智能体日志常包含敏感用户数据。测试必须尊重这一点:
把这些规则写入 CI 流程,确保没有未经匿名化检查的测试工件被生成或存储。
在生产中运行智能体更像是在运维分布式系统,而不是发布静态模型。你需要发布控制、明确的可靠性目标与严格的变更管理。
逐步引入新智能体或行为:
所有这些应由功能开关与配置驱动策略支持:路由规则、启用的工具、温度、安全设置。变更应以配置可下发、而非必须改代码,并能即时回滚。
定义反映系统健康与用户价值的 SLO:
把这些接入告警系统,按常规服务处理事故:明确归属、排查运行手册与标准缓解步骤(回滚标志、抽流、进入安全模式)。
用日志、追踪与会话记录来改进提示、工具与策略。把每次变更视为版本化工件并通过审核、批准与回滚机制管理。
避免无声的提示或工具更改。没有变更控制,你无法把回归与具体编辑关联起来,事故响应会变成猜测而非工程化的过程。
生产就绪的智能体系统受益于清晰的关注点分离。目标是让智能体在决策上智能,但在基础设施上“愚笨”。
1. 网关 / API 边缘
客户端(应用、服务、UI)的单一入口。负责:
2. 编排器
编排器是“脑干”,而非大脑。它负责协调:
LLM 位于编排器后面,被规划器与需要语言理解的特定工具使用。
3. 工具与存储层
业务逻辑保留在现有微服务、队列与数据系统中。工具是对这些资源的薄封装:
编排器通过严格契约调用工具,而存储系统保持事实源头。
在网关处强制执行认证与配额;在编排器处强制执行安全、数据访问与策略。所有调用(LLM 与工具)向结构化遥测管道发出数据,供:
更简单的架构(网关 → 单一编排器 → 工具)更易运维;增加独立的规划器、策略引擎与模型网关能提升灵活性,但成本是更多的协调、延迟与运维复杂性。
现在你已有让智能体在真实负载下可预测的核心要素:显式状态机、清晰的工具契约、纪律化的重试与深度可观测性。最后一步是把这些理念变成团队可复用的实践。
把每个智能体想象成一个有状态的工作流:
当这些部分协同工作时,系统会优雅降级,而不是在边缘情况下崩溃。
在把原型智能体发布给真实用户之前,请确认:
如果任何项缺失,你仍处于原型阶段。
可持续的设置通常分离职责:
这样既能让产品团队快速迭代,又能让平台团队强制保证可靠性、安全与成本控制。
在打好基础后,你可以探索:
在此方向上应采取渐进式引入:把新学习组件置于功能开关后面,进行离线评估并加上强力护栏。
贯穿始终的主题是:为失败而设计,偏好清晰而非聪明,并在可观测且可回滚的前提下迭代。在这些约束就位后,智能体不再是可怕的原型,而是组织可依赖的基础设施。
智能体系统是一类应用,LLM 不只是回答单次提示,而是决定下一步做什么:调用哪个工具、检索哪些数据、执行工作流中的哪一步以及何时结束。
与简单的对话补全不同,智能体系统由以下部分组成:
在生产环境中,LLM 成为更大确定性外壳内的一个决策组件——而非整个系统的全部。
演示通常只覆盖“快乐路径”:单个用户、理想的工具行为、没有超时、没有模式漂移、对话很短。生产环境下,智能体会遇到:
如果没有显式的工作流、契约和故障处理,这些因素会引发循环、阻塞、部分完成和沉默错误,而这些在演示环境中往往看不到。
让 LLM 在一个清晰结构内运行,而不是自由循环:
这让你能逐步解释、测试和调试行为,而不是追着不透明的“智能体思路”跑。
把智能体建模为带名称状态和类型化事件的工作流,而不是 while not done: call LLM。
典型状态可能包括:
把工具设计成真正的生产 API,而不是埋在提示里的散文说明。每个工具应包含:
假设所有外部调用都会在某个时刻失败,并据此设计:
关键模式:
request_id 或业务键,重复调用应返回相同结果。把短期状态和长期记忆分离,并让 LLM 本身保持无状态。
避免用原始日志或完整会话历史作为“记忆”;应从中派生简洁的结构化记录并制定明确的保留与隐私规则。
把你的智能体系统当作在负载下运行的分布式系统来设计,即使每个流程在白板上看起来是顺序的。
要保持可靠:
监控队列深度、延迟分位数与 错误率,以便在过载成为故障前检测到问题。
你需要能回答“该智能体做了什么?”和“为什么这么做?”两个问题。
实用需求:
有了这些,事件响应就能从“智能体很不稳定”变为定位具体状态、工具或变更的精确陈述。
把智能体当作不断演进的服务来管理,而不是静态的提示,采用与其他生产系统同样严谨的管理方式。
建议做法:
这样既能让产品团队快速迭代,又能保证故障被限制、可诊断且可回滚。
PLAN — 解析请求并生成逐步计划CALL_TOOL — 调用具体工具或一组工具VERIFY — 根据简单不变式或附加模型检查输出RECOVER — 通过重试、回退或升级处理错误DONE / FAILED — 终态事件(例如 ToolCallSucceeded, TimeoutExceeded)加上当前状态决定下一步状态。这使得重试、超时和错误处理变得显式,而不是隐藏在提示或胶水代码中。
InvalidInput、NotFound、RateLimited、TransientFailure在调用前验证输入,调用后验证输出。对工具契约进行版本化,并将智能体固定到具体版本,以免模式变动悄然破坏流程。
这样能在不产生失控循环、重复副作用或成本暴涨的前提下保持高可用性。
429/503