ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

从 Demo 到生产:Agent 长任务执行的关键工程与可靠性设计

从 Demo 到生产:Agent 长任务执行的关键工程与可靠性设计 我做了快两年的 Agent 工程有个现象印象特别深几乎每个团队在第一个 Agent Demo 跑通的时候都会产生一种“这事已经成了”的错觉。Demo 里让模型搜个资料、写个周报、生成一段代码单次调用效果惊艳。可一旦把任务从“回答一个问题”变成“在真实系统里完成一件事情”——比如让它自己调研竞品、分析数据、再汇总成一份报告——崩盘往往就发生在这个节点。于是大家开始拼命调 prompt、换更大的模型结果发现还是不解决问题。干到后来我才慢慢想明白一件事当 AI Agent 从单次回答走向长任务执行真正发生变化的不只是模型的复杂程度而是整个系统的性质。单次提问解决的是“聪明不聪明”的问题长任务执行解决的是“可不可靠”的问题。“可靠”从来不是模型单方面能给的它需要外面那一圈系统工程来兜底。这篇东西我想系统聊一聊长任务执行里的工程工作到底发生在哪里哪些环节是决定成败的关键以及我在真实项目里踩过的坑和最后沉淀下来的做法。适合正在搭 Agent 系统、或者刚把 Demo 跑通正准备往生产方向推的工程师看。1. 被 Demo 掩盖的真相短任务与长任务的本质差异1.1 短任务的成功本质上是一种“一次性成功”先别急着上架构我们得先搞清楚一件事为什么单次问答的 Demo 总是给人很大的信心单轮问答的本质是“给定一段上下文生成下一段文本”。模型在这一步里只需要对当前输入做局部回应它不需要对前面说过的话负责不需要维护任何跨步骤的状态更不需要在多种外部反馈之间做协调。你在 Demo 里让它写周报它会写让它翻译一段话它会翻让它总结一篇文章它总结得比实习生还快。这种“局部正确性”极大程度地掩盖了系统性的问题。而长任务执行是另一回事。同样一个模型放到一个需要调研三个竞品、阅读二十篇资料、交叉验证数据、最后输出分析报告的任务里它会在某个中间步骤突然“忘了”最初的目标或者把第一步的错误结论当成事实带进后面的推理或者在某个工具返回异常之后开始原地打转。你让同一个模型跑十次十次的结果和路径可能都不一样但你很难定位是哪一环出了问题。1.2 长任务真正改变的维度从“生成”到“行动”长任务执行把问题的性质从“生成”变成了“在环境中行动”。模型需要在多个步骤之间保持目标一致性需要调用外部工具获取真实世界反馈需要接受中间结果来不断修正后续决策还需要在信息不完整的情况下做出下一步的取舍。这时模型的单步能力只是基础条件系统能不能把步骤串起来、把状态留住、把错误拦下来才是决定成败的关键。我在项目里看到的最典型的现象是同样的任务、同样的任务描述换成不同模型来跑成功率差得很多但哪怕是同一个模型在不同工程实现下跑稳定性也能差出一大截。这说明什么说明长任务的瓶颈往往不在模型本身而在工程侧的配合。下面这张表是我在不同项目里总结的短任务与长任务的差异它是我判断该不该用 Agent 的一个起点维度短任务单次问答长任务多步执行上下文静态、完整、一次性动态、有衰减、需要逐级维护错误影响单点失败不影响其他错误累积越到后面越不可控调试方式改 prompt 再跑一次需要轨迹回放、状态恢复成功标准输出内容质量任务完成度 过程可控性 成本工程复杂度低主要靠模型能力高需要系统架构配合2. 记忆与上下文长任务 Agent 的第一块基石2.1 上下文窗口不是记忆很多人在设计长任务 Agent 时第一个犯的错误就是“把上下文窗口当成记忆”。上下文窗口是一个物理上限模型只能看到窗口内的 token超过的部分会随着长度增加而产生注意力衰减严重的甚至直接被截断。长任务执行里每调一次外部工具返回一堆文本立刻就会挤占上下文空间。几十步下来最初的任务目标可能已经被挤到模型的注意力之外了。我实际做项目时发现“模型跑偏”很多时候不是模型不行而是任务目标从上下文里被挤出去了。比如让 Agent 先调研市场、再写方案它可能做到第 15 步的时候开始纠结某个竞品的细节完全忘了自己最终要交的是一份“可以执行的市场进入策略”。这不是模型能力问题这是上下文管理的问题。2.2 一个可落地的记忆分层设计既然上下文窗口不是记忆那我们就得自己搭一套记忆系统。我的做法是分四层每层解决不同的问题目标层固定放在系统提示词里包含任务目标、约束条件、验收标准。这层信息不可压缩、不能被挤掉我通常会写一段“目标锚定”文本每次请求都注入。轨迹层保留最近 N 步的完整记录超过 N 步之后的内容做摘要压缩。这层解决的是“模型需要知道它刚才做了什么”的问题。事实层任务过程中积累的结构化事实比如调研到的竞品价格、用户反馈、关键时间点统一整理成结构化对象需要的时候再注入而不是全部堆在上下文里。外部记忆存在向量库或数据库里跨会话复用比如用户的长期偏好、历史任务结果需要时检索出来。下面是一个简化但能落地的记忆结构示例dataclass class AgentMemory: goal: str # 目标层不可压缩 trajectory: deque[StepRecord] # 轨迹层保留最近 N 步 facts: dict[str, Any] # 事实层结构化事实 external_db: VectorStore # 外部记忆 def build_context(self, max_tokens: int) - str: # 组合目标 最近轨迹 需要的事实 检索的外部信息 context_parts [self.goal] for record in list(self.trajectory)[-self.recent_steps:]: context_parts.append(record.summarized()) # 动态注入与当前子任务相关的事实 relevant_facts self.get_relevant_facts() context_parts.append(relevant_facts) return truncate_to_limit(\n.join(context_parts), max_tokens)这套结构的关键是目标层永远在轨迹层保留最近几步的完整细节事实层按需注入外部记忆靠检索。这样处理下来长任务里最常出现的“任务目标丢失”问题基本被遏制住了。2.3 摘要压缩的取舍逻辑长任务的 token 管理不能靠简单截断因为截断会丢失关键信息。我的做法是分层摘要每个子任务完成后立即让模型生成一段摘要原始内容归档到外部存储摘要留在轨迹层。下个子任务开始时模型能看到前一个任务的摘要但不必看全部过程细节。团队里常说一个比喻Agent 不能当金鱼只有三秒记忆但也不能背着一座图书馆跑路。记忆管理的本质是在信息完整性和上下文容量之间做取舍。摘要压缩就是把最近的过程信息压成“够用”的状态既不丢失任务脉络又不把上下文塞爆。3. 从临场发挥到状态机规划与执行的工程化拆解3.1 两种主流范式的取舍在讨论 Agent 的执行架构时绕不开两种范式先规划再执行Plan-and-Execute和边执行边规划ReAct 风格。先规划再执行的好处是全局可控、成本可预估。模型先输出完整步骤然后按步执行工程侧可以提前看到整个执行路径也方便做预算和监控。坏处是任务越复杂中间遇到意外就越容易让整个计划作废重新规划的成本很高。边执行边规划则相反每走一步观察结果再决定下一步灵活性很强能在不确定性高的场景里随机应变。但代价是容易钻牛角尖模型可能会因为某个工具返回了不预期结果而反复重试同一个动作也容易在分支任务里越走越偏token 消耗不可控。3.2 工程侧最大的心得显式状态机这两种范式我都在项目里试过最后的结论是都不应该让模型“自由发挥”。工程落地最好的方式是把整个 Agent 执行过程建模成显式的任务状态机模型只是状态机里的决策者而不是流程本身。我会把任务状态定义成一组有限的、明确的状态并在每个状态之间定义清晰的转移条件from enum import Enum class AgentState(str, Enum): PENDING pending # 待执行 RUNNING running # 执行中 TOOL_CALLING tool_calling # 调用工具 VERIFYING verifying # 验证中间结果 COMPLETED completed # 任务完成 FAILED failed # 任务失败每一步执行流程是状态从 PENDING 进入 RUNNING模型决定要不要调用工具调用时进入 TOOL_CALLING等工具返回结果后进入 VERIFYING 做一致性检查检查通过则继续下一步不通过则回退全部步骤完成进入 COMPLETED出错且无法恢复则进入 FAILED。为什么非要用显式状态机因为状态机带来三个直接收益可恢复任务状态可以被持久化崩溃后能从最近状态继续跑可观测每一步处于什么状态一目了然排查问题方便可控可以对不同状态施加不同的重试策略和 token 预算技术上能拦住模型在某个分支里无限循环。3.3 状态流转与兜底规则实际操作里我会给状态流转配一套兜底规则。比如 TOOL_CALLING 状态下如果工具连续返回错误我允许模型在同一子任务里重试两次但超过两次就必须进入 VERIFYING 重新评估方案而不是继续硬试。再比如 RUNNING 状态下一旦发现上下文占用率超过 70%就强制触发摘要压缩把旧的轨迹层信息归档。状态进入条件可能的出口PENDING任务创建进入 RUNNINGRUNNING开始当前子任务调用工具进入 TOOL_CALLING或直接产出结果进 VERIFYINGTOOL_CALLING需要外部信息成功后进入 VERIFYING失败可重试或回 RUNNINGVERIFYING拿到中间结果验证通过继续 RUNNING不通过回退或 FAILEDCOMPLETED所有步骤完成无FAILED错误无法恢复无这套设计相当于给 Agent 套上了一个“轨道”它可以在轨道里自由加速、减速、换道但不能冲出轨道。长任务执行最怕的不是模型笨而是模型在一个错误路径上越走越远状态机是防止这个问题的最直接的工程手段。4. 工具调用的可靠性工程函数调用之外的一半工作量4.1 工具层的“最后一公里”问题把工具调用交给 Agent 之后真正的麻烦才开始。模型输出参数格式不稳定、工具返回值与模型预期不一致、外部服务超时限流、API 字段变动、同一操作被重复执行导致幂等性问题……这些才是最消耗长任务工程精力的事情。举一个我在项目里遇到的真实例子让 Agent 调用一个用户信息查询接口模型在生成参数时把可选的查询条件当成了必填项还把一个枚举值拼错结果工具直接报错。更糟的是模型拿到报错信息后没有重新审视参数而是重复提交了三次一模一样的请求。这个场景说明工具层不能只做“把参数传进去、把结果返回来”这种薄封装它需要一层完整的可靠性防护。4.2 一个工具执行循环应该有的处理顺序我在项目里沉淀了一套工具调用循环的处理顺序每一步都很直接第一步参数解析与校验。模型生成的参数是文本不能直接信任。在传给真实接口之前先用 JSON Schema 校验格式、检查必填项、规范枚举值。校验不通过就把明确的错误信息返回给模型让它重写参数而不是让真实接口去背锅。第二步执行与超时控制。每个工具都必须配独立的超时时间。我之前吃过亏某个外部服务在高峰期响应特别慢Agent 等不到结果就一直挂起整个任务卡死。后来给每个工具设了明确的 timeout宁可返回超时错误也不能让任务无限阻塞。第三步结果归一化。外部接口的返回五花八门有的返回 JSON有的返回 HTML有的直接在 message 里写一串错误码。我会把所有工具返回统一包一层结构让模型不用猜ToolResult { ok: True, # 是否执行成功 data: {...}, # 执行结果如果 ok error: None, # 错误信息如果不 ok truncated: False # 结果是否被截断 }第四步错误分类与重试决策。这里的关键是区分“可重试错误”和“不可重试错误”不能一刀切。4.3 重试语义的三种判断可重试瞬时错误比如网络抖动、超时、限流。策略是退避重试重试两到三次每次加重退避。不可重试的确定性错误参数错误、用户权限不足、资源不存在。这种重试多少次都一样正确做法是让模型修改行动方案而不是继续重复调用。需人工接管外部服务长时间不可用、涉及跨团队权限审批、存在资金或安全影响的操作。这种直接标记为需要人工介入不要在 Agent 内部死循环。把这个分类内置到工具协议之后长任务的成功率会有一个非常明显的提升。原因很简单模型在有明确错误分类的情况下更容易做出“换参数”“换工具”“终止任务”这些理性决策而不是在同一个坑里反复横跳。5. 让长任务自己兜底错误恢复与检查点设计5.1 高发故障与恢复策略长任务在执行过程中一定会遇到各种故障。我梳理过项目里出现频率最高的几类错误以及对应的恢复策略故障类型典型表现恢复策略工具超时外部服务响应慢或挂起重试 降级超过阈值则跳过该步骤参数错误模型把必填参数理解错回传结构化错误让模型修正参数步骤遗漏跳过某关键步骤直接输出结果用验证节点兜底发现遗漏就回退模型幻觉模型“凭记忆”断言未经验证的事实关键结论必须经由工具验证上下文溢出长度超过窗口导致关键信息丢失触发摘要压缩归档旧轨迹5.2 检查点长任务不再“一崩全崩”长任务执行的另一个关键设计是检查点。一个跑 30 分钟的任务如果中途因为某个工具临时故障崩溃然后从头开始跑这在工程上完全不可接受。所以我把任务状态做了持久化每一步执行完都写一次检查点包含当前状态、已完成步骤、已收集的事实、还有多步的轨迹摘要。{ task_id: task_001, state: VERIFYING, current_step: 12, completed_steps: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11], facts: { competitor_a_price: 99, competitor_b_launch_date: 2025-03-15 }, trajectory_summary: ... 前序步骤的摘要 ... }有了检查点Agent 崩溃或者上下文耗尽之后可以从最近的位置恢复而不是回到起点。恢复策略我倾向用“最后有效步回退”检查点记录的是上一步验证过的状态恢复时从那个状态重跑当前子任务而不是直接跳到下一步。5.3 允许模型说“我不行”这个看起来很简单但很多团队在设计 prompt 时都漏掉了给模型一条体面的退出路径。我在系统提示词里明确加了这样一条规则“如果当前信息不足或已多次尝试仍无法修正错误请输出 TASK_FAILED并附上已完成部分和无法继续完成的原因。”刚开始我担心加了这条会让模型轻易放弃实际用下来发现恰恰相反给了退出路径之后模型反而不怎么硬编了。因为它在逻辑上“知道”自己可以不完成就不需要用幻觉来凑一个假结果。对长任务工程来说承认失败不是坏事。一个诚实的 TASK_FAILED配合已完成的中间成果和失败原因比一份包装得光鲜但内容全错的报告有价值得多。失败信息让后续的人工接管有了清晰的交接点。6. 长任务的可观测性追踪、评估与成本6.1 缺少可观测性会让长任务变成黑盒长任务执行一旦跑起来如果看不见中间过程排查问题会变得非常痛苦。我之前经历过一次惨痛教训任务失败了模型给的结果看起来“写得挺好”但整体都是基于一个错误的中间数据展开的。当时系统没有任何轨迹记录我根本不知道哪一步开始出错只能重新跑一遍碰运气。这个教训之后我定了一个原则长任务系统里每个决策点都必须可见。模型做了什么判断、调用了什么工具、输入和输出是什么、花了多少 token、用了多长时间全部要留痕。6.2 全链路日志字段设计我给日志设计了一套统一结构每次模型调用和工具调用都按这个格式记录{ task_id: task_001, step: 12, state: TOOL_CALLING, input_summary: 查询竞品A的最新定价, model_output: 调用get_product_price(product_idA), tool_name: get_product_price, tool_args: {product_id: A}, tool_result_ok: true, tool_result_truncated: false, error_info: null, token_usage: 1536, latency_ms: 2340 }这份日志既是我调试 Agent 的排障工具也是后续评估 Agent 行为的重要依据。没有这些结构化的记录所谓“优化 Agent”可能只是凭感觉调 prompt有了日志你才能定位到具体是哪一步出了问题、哪个工具最不稳定、哪类错误最常发生。6.3 分阶段评估不要只看最终结果长任务是开放式的过程它不像机器翻译或文本分类那样有一个参考答案可以比对。所以我的建议是把长任务拆成多个验收点每个阶段先做“步级验收”通过之后再进入下一阶段。步级验收的意思是每个子任务完成时先拿这个子任务的预期结果做一次检查。比如“调研竞品价格”这个子任务验收标准是“拿到三个竞品的价格数据并且来源可追溯”。如果步级验收不通过就地重试或调整而不是等到整个任务跑完才发现问题。除了步级通过率我还会盯这几个过程指标指标含义我的建议目标任务完成率成功跑完的任务占比按任务类型分别统计步级通过率单步验收通过的比例越高越好低于 80% 说明子任务拆分有问题工具调用成功率工具成功返回的比例低于 90% 需要检查工具可靠性平均重试次数每步平均重试几轮超过 2 次说明模型在某个环节反复出错上下文使用率每步 token 占用趋势长期接近上限会增大失败风险6.4 成本是长任务工程里最现实的约束长任务跑起来很容易让人忽略一个事实token 消耗是线性累积甚至是指数累积的。一个 50 步的任务每步平均消耗几千 token跑 5 次迭代就是几十万 token。如果都用大模型来跑成本会让你怀疑人生。我的做法是分级低成本的小任务和中间步骤用轻量模型只在关键判断点和复杂决策时切换到更强的模型。同时给任务设置 token 预算预算用尽就先停下来评估进度。另外对重复的工具调用结果做缓存同样的查询在任务周期内直接复用结果能省掉很大一部分 token 开销。7. 边界判断什么任务值得做成 Agent什么不值得7.1 不适合做长任务 Agent 的典型画像老实说不是所有任务都适合做成 Agent。我见过不少人把简单问题复杂化最后的系统又贵又难维护。不适合的典型画像有几类。一种是本来一次 API 调用就能解决的问题硬写成几十步的 Agent 流程纯粹增加失败概率。另一种是需要人类审美判断、战略权衡的高价值决策场景Agent 可以做材料收集和初步分析但让它拍板就非常危险。还有一种是外部依赖很脆的场景工具动不动就挂又没有兜底机制这种情况下 Agent 跑得越久出错的概率就越大。7.2 适合长任务 Agent 的特征反之适合长任务 Agent 的任务通常具备这几个特征多步骤、需要外部信息、中间结果会影响后续方向、流程相对标准化、有明确的完成标准、可以容忍一定失败率并且有人工兜底。我常用的判断方法是把任务拆成三段看信息获取段、决策段、动作段。如果三段里只有一段需要模型判断别做长任务 Agent用一个流程编排脚本就够了。如果三段都需要模型的推理能力才值得投入做 Agent。我最真实的建议是为 Agent 而 Agent 是最烧钱的坑。先判断任务复杂度再决定要不要上长任务架构。最后分享一点我在实际项目里的体会。很多团队在 Agent 上踩坑最深的坑不是模型不够强而是把模型当成了整个世界觉得换一个更聪明的模型就万事大吉把系统工程当成了可有可无的部分。但长任务执行这件事模型只是发动机底盘、刹车、仪表盘以及副驾驶的判断逻辑全都要工程来搭。如果你正准备把一个 Demo 推成生产级 Agent我建议你先别急着调 prompt先把状态机、检查点、日志追踪这三件事搭起来。这三件事做扎实之后你会发现后面所有的迭代调整都有了可以依靠的抓手。
返回列表