架构师公众号文章

输出结果不等于完成任务:Agent 最容易忽略的一环

Agent 不只要产出内容,还要留下可回读证据;输出、工具返回和业务完成之间,需要清楚的完成条件。

架构师

公众号 · 37 篇文章

架构师(JiaGouX)

我们都是架构师!
架构未来,你来不来?


很多 AI Agent 架构图,末端都会画一个方框:输出结果。

用户提出目标,Planner 拆任务,模型推理,Tool 和 MCP 连接外部系统,Memory 留住过程,Reflection 做检查。箭头一路走到最后,交出一段回答、一个文件,或者一次外部操作。

图画到这里,任务看上去结束了。

放到业务系统里,这一格不够。

假设用户交给 Agent 一个任务:

整理三家竞品最近的产品变化,写成一份简报,发到项目 Slack 群里。

Agent 搜索资料,整理内容,生成简报,然后调用 Slack 接口。发送消息时,请求超时。

这时还不能判定成功或失败。消息可能没有发出去,也可能已经发出,只是响应没有回来。

如果 Agent 回复“任务已完成”,用户可能在群里看不到任何东西;如果 Agent 把超时当成失败,马上重发,群里又可能出现两份简报。

模型有了输出,工具也被调用过。但任务是否完成,系统没有证据。

这里少了一个判断:Agent 不只要产出内容,还要知道哪些事实足以支持自己停下来。

输出到完成的边界
输出到完成的边界

完成不止一层

前面几篇文章里,我们拆过 Planner、Tool、MCP、Memory、Harness 和 Handoff。它们分别处理目标理解、动作选择、系统连接和下一轮调度。

把这些能力接起来,仍然不等于“任务完成”。在工程里,完成至少有几层。

层次
它能说明什么
它还不能说明什么
模型有输出
这一轮生成结束了
用户目标已经实现
工具调用结束
外部能力返回了结果
返回结果真实、可用
产物已经生成
文件、报告或记录存在
内容符合要求、别人能访问
外部动作已生效
消息、订单或配置可以被回读
业务对象和结果完全正确
目标通过验收
成功条件已有对应证据
这时才适合宣布完成

OpenAI Agents SDK 的运行循环能说明这个边界:模型产出符合要求的文本,并且不再发起工具调用时,Runner 会把它判断为 final_output,agent loop 结束。

这是一条运行结束条件,不是业务完成条件。

从一些 Coding Agent 的源码实现看,这条边界也很清楚:assistant、tool_result、result、status 和 task_notification 往往是不同消息;Stop、TaskCompleted 这类事件记录的是运行生命周期。框架能记下工具返回了什么、这一轮怎么结束,但不会替业务判断交付物是否已经被正确接收。

final_output 只能说明这次 run 已经收口。它不能回答:简报是不是发到了正确的群,链接有没有权限,内容是否覆盖了指定的三家竞品。

框架没有做错。它只是不知道每个业务认为什么叫交付。完成条件只能由应用自己补上。

反思不是观察

在一些 Agent 架构里,Reflection 放在动作之后:执行、观察、反思,再决定是否继续。这个环节是否有效,取决于 Reflection 拿到了什么。

如果工具只返回一句:

message sent successfully

模型最多只能判断“工具说发送成功”。它看不到目标频道里是否真的出现了消息,也不知道消息里的报告链接能不能打开。

让模型再反思一遍,不会让缺失的事实出现。它很可能只是把工具的说法换一种语气复述出来。

所以要看观察。一次外部动作之后,系统有没有重新读取真实状态。

发送消息,要拿到频道和消息 ID,再按这个 ID 回读。写入文件,要检查文件是否存在、可读,必要章节是否齐全。修改配置,要确认运行中的系统已经加载新值。创建订单,要核对订单状态、金额和对象。

这些检查不一定要交给模型。确定性代码更适合做这类事:按消息 ID 查询、比较内容摘要、校验字段、检查状态转换。

kimi-code 的工具说明里有一条规则适合放在这里:一次 Edit 或 Write 成功后,不必为了证明写入已经发生而重读文件;但如果任务依赖某个精确的文件、API 或输出形态,结束前要检查最终外部契约。

放到 Agent 系统里也是同一件事。不必每一步都验证,但任务终点要验证。越靠近终点,判断依据越应该来自可回读证据,而不是模型的自我确认。

终点先写清

如果最后才问“这算完成了吗”,Agent 只能拿已有输出替自己作证。

规划阶段可以直接写下完成条件。它不需要变成一套流程,只要说清三件事:要得到什么结果,结果落在哪里,用什么事实证明。

回到 Slack 简报的例子,完成条件可以写得很直接。

简报不是“生成一段文字”,而是一份包含三家竞品、指定时间范围和来源的文档。最终对象不是 Agent 工作目录里的临时文件,而是项目 Slack 群里的消息。能证明它完成的事实,是稳定文档链接、目标成员可访问、Slack 返回消息 ID,并且按这个 ID 回读时,频道、正文和链接都对得上。

Planner 拆出的任务就会从“搜索、写作、发送”,变成一条能收口的链路:

目标 -> 行动 -> 观察 -> 验证 -> 完成
                   `-> 继续 / 等待 / 请人处理

验证不需要追求绝对完美。查天气,工具返回有效结果就够了;生成草稿,可以检查文件存在和结构完整;涉及付款、权限、发布或删除,证据要具体到可回读、可比对,必要时交给人确认。

失败代价越高,“完成”越不能只靠一句成功返回。

超时先置未知

一些系统只给 Agent 两个选择:成功或者失败。外部动作一多,这个二选一就不够。

还是 Slack 消息的例子。请求超时只说明调用方没有及时收到响应,它不能证明动作没有发生。此时应该进入第三种状态:未知。

未知不是失败。它表示系统缺少证据,不能宣布完成,也不能直接重试。

幂等设计解决的就是这类问题。AWS 在讨论安全重试时用了一个典型场景:创建资源的请求遇到网络超时,调用方无法确定资源是否已经创建;直接重试,可能产生多个资源。

AWS 的做法是让调用方提供唯一请求标识。服务端用这个标识识别同一次意图,并在重试时给出语义一致的结果。Stripe 的幂等键也是同一类思路。

放到 Agent 系统里,这个请求标识可以来自 task_id、步骤 ID 和动作序号。第一次调用和重试使用同一个幂等键;超时之后先按键查询,能找到已生效结果就继续验证,确认没有执行再重试。

超时后的状态分支
超时后的状态分支

如果外部工具不支持幂等键,也没有可靠的查询接口,Agent 就不该装作知道答案。保留 unknown,把现有证据和风险交给人,比假装确定更可信。

可靠的 Agent 除了会重试,还要知道哪些动作不能随便再来一次。

验收不是新 Agent

有的架构图会再放一个 Verifier Agent。但多一个角色,不等于完成判断已经解决。

我对这种做法会谨慎。

如果验收只是检查文件是否存在、查询消息 ID、比对数据库字段,再放一个模型进去,只会多一层不确定性。完成条件清楚时,代码、规则和状态机更直接,也更容易测试。

只有当结果本身需要语义判断时,模型验收才有价值。比如检查一份竞品简报是否遗漏重要产品变化,不同来源有没有互相矛盾,结论是否超出了证据。

这时模型可以参与评估,但它引用的材料、评分口径和最终证据要留下。

要补的是验收能力,不一定是验收 Agent。它可以是 Runtime 里的一段闭环。

验收职责分工
验收职责分工
责任
适合放在哪里
理解目标、处理模糊要求
模型
执行动作、记录请求身份
Runtime / Tool
回读外部状态、校验精确字段
确定性程序
评估内容质量和语义差异
模型或人工
保存证据、决定结束或继续
Runtime

这样分工能避开一个误区:让模型执行、自评,再自己宣布通过。

模型可能做对。但出了问题,很难知道错在动作、观察,还是那句过早的“已完成”。

记录要小

一个可用的完成记录不需要复杂。它至少留下任务状态、成功条件、外部结果标识、验证结果,以及下一步要做什么。

{
  "status": "completed | failed | unknown | needs_human",
  "success_criteria": ["report_created", "message_visible"],
  "result_ref": "slack:channel/message_id",
  "idempotency_key": "task_id/step_id/action_index",
  "verification": "matched",
  "evidence": ["report_url", "message_id"],
  "next_action": null
}

这些字段看起来不如 Planner、Reasoning、Memory 吸引人,却决定了 Agent 的产出能不能进入下一段业务流程。

后续系统不用再解析一大段自然语言来猜任务是否结束。监控可以分清完成、明确失败和结果未知。人工接手时,看到的是已经核对过的事实,而不是一句笼统的错误提示。

如果重画那张 Agent 架构图,我会在“输出结果”下面多留一点位置。

输出只是模型结束表达,工具返回只是一次调用结束。只有当结果被观察、被核对,并且能对应用户最初的目标,这项任务才有资格收口。

一个可以放心交事的 Agent,不该只会说“任务已完成”。证据不足时,它应该停在 unknown。能够恢复的任务继续往下走;完成条件满足后再结束。终点要写清楚,证据要留下来。

往期相关推文

  • 《AI Agent 架构全链路拆解:从 Planner、Tool、MCP 到 Memory 和 Reflection》
  • 《Codex Harness 源码拆解:Agent 控制面如何嵌进业务系统》
  • 《从 Claude Code 到 Codex:Coding Agent 的 Harness》
  • 《四大多 Agent 架构详解(四):Handoff 之后,下一轮到底由谁负责》

参考资料

  • OpenAI Agents SDK,Running agents(https://openai.github.io/openai-agents-python/running_agents/)
  • Malcolm Featonby,Making retries safe with idempotent APIs(https://aws.amazon.com/builders-library/making-retries-safe-with-idempotent-APIs/)
  • Stripe,Idempotent requests(https://docs.stripe.com/api/idempotent_requests)

如喜欢本文,请点击右上角,把文章分享到朋友圈

如有想了解学习的技术点,请留言给若飞安排分享

因公众号更改推送规则,请点“在看”并加“星标”第一时间获取精彩技术分享

·END·

相关阅读:

  • Loop Engineering,应该赞成还是反对?
  • Claude 做方案,Codex 写代码:多模型协作怎么交接才稳
  • 架构排熵:Loop Engineering 的持续清理系统
  • CLAUDE.md 拆解:Agent 进仓库前的上下文入口
  • Harness工程还没唱罢,Environment工程已然登场
  • 设计 Self-Harness 架构:会自我改进的Harness

版权申明:内容来源网络,仅供学习研究,版权归原创者所有。如有侵权烦请告知,我们会立即删除并表示歉意。谢谢!

架构师

我们都是架构师!

关注架构师(JiaGouX),添加“星标”

获取每天技术干货,一起成为牛逼架构师

技术群请加若飞:1321113940 进架构师群

投稿、合作、版权等邮箱:[email protected]

前往微信阅读全文

内容来自公众号,可前往微信查看原文。

查看作者的更多文章 →订阅更新、RSS 与阅读指南 →