系统篇

09|Agent一次任务的完整循环:谁在思考,谁在执行

系统篇约 6.1 千字1 组分步图解
本章目录

本章预备知识

Agent是外围程序驱动的一串模型调用。请求、响应、工具结果与任务状态各有自己的生命周期;“模型说完成”和“环境真的达到目标”需要分开验证。

本章各题列出所需基础。可先完成相应基础课,也可通过自检确认掌握程度。

进入深读前的小检查:画一次“请求读文件→校验调用→读取→返回文件→再次调用模型”的环路,标出哪个箭头由程序执行,哪个判断由模型输出。

术语带虚线时可点击速查。公式中的字母先看定义;不要用猜缩写替代推导。

以下使用“修复仓库里exclude不生效”的原创教学任务。它不代表对用户真实仓库做了修改。读这一章时始终分清模型建议、Harness执行和环境真实状态。

沿着对象与状态理解本章

把模型、宿主、工具画成不同泳道后,问“谁真正改变了文件”就有明确答案。跟踪每条返回消息,再判断需要继续调用模型、执行工具还是结束;不要把模型说完成当成环境已经完成。

下方图解的固定输入在“输入与适用条件”中声明。它用于解释本章机制,不与本章其他独立例子的数值暗中接续。

动态图解 · F22

把一个Agent任务拆成真正发生的几轮

同一句用户任务,为什么可能调用模型不止一次?

LLM生成下一步提议,宿主执行获准的动作,把结果再交给LLM。这是外层任务循环;每次模型调用内部还要经历逐Token生成。外层的一轮工具行动不等于内部生成一个Token,两种“循环”不能混用。

调用标识把某次工具请求与其结果连接的ID。
工具结果程序实际执行后返回的内容。
上下文本轮明确交给模型的信息,而非整个电脑状态。

输入与适用条件:构造的只读教学任务:文件config.txt含timeout=30。泳道展示职责边界,不声称调用了真实商业API;数据和动作顺序固定。

1 / 8 · 1. 用户任务:读config.txt中的timeout

第1步,共8步

窄屏可左右滑动图形,或点击“放大图形”。文字解释紧随图后。

把一个Agent任务拆成真正发生的几轮:1. 用户任务:读config.txt中的timeout用户宿主LLM文件工具用户任务:读config.txt中的timeout模型请求:任务+read_file工具定义模型输出:call_id=c1,path=config.txt宿主校验后读取文件工具结果:timeout=30下一轮输入:原任务+调用+结果模型回答:配置的timeout为30宿主显示回答;任务结束

模型尚未看到磁盘文件。先区分用户给的任务与环境真实内容。

未读取

默认静止。用“下一步”看完解释再继续;播放到最后一步自动停止。键盘聚焦播放器后,可用左右键逐步查看、空格播放/暂停。图中颜色辅助区分,含义同时用文字注明。

为什么需要

模型可以借助工具获得新证据,而不把一切都塞入参数。

怎样实现

按请求、校验、执行、结果回填、继续决策组织循环。

可能的代价与误解

忘记回填工具结果会让模型重复请求;把输出文本当执行证明会误报完成。

如何判断是否做对

对照每轮模型输入和工具日志,确认结果与call_id匹配。

Q033|用户输入一句话后,Agent怎样经过多轮模型调用完成任务?

核心回答

Agent把目标、规则、工具定义和当前证据组装成模型输入;模型返回普通文本或工具调用;Harness检查并执行调用,把结果作为新的上下文;模型依据观察继续决定下一步。循环以可验证完成、需要用户决策、失败或预算耗尽等条件结束。ReAct描述推理—行动—观察的结合,产品Harness负责把它落地为真实执行系统。[REACT][CODEX]

走完六轮,而不是只画一个循环箭头

轮次 模型此刻看到了什么 模型输出 Harness/环境发生什么
1 用户目标、仓库规则、搜索工具描述 搜索exclude入口 搜索返回路径和行号
2 前述内容+搜索结果 读取实现与测试 返回带版本的代码片段
3 条件分支、失败案例 运行目标测试 进程退出1,输出断言失败
4 实际失败与相关代码 应用局部补丁 校验旧内容后修改文件
5 补丁结果与新版本 运行回归测试 记录命令、版本、退出码
6 当前diff和测试证据 完成说明 Harness结束本任务

每轮输入可以包含历史,也可以通过服务端状态引用衔接,但逻辑上必须让模型知道与当前决策有关的结果。工具调用不是模型“想象自己已经读了文件”;必须真实执行,拿回真实输出。模型第3轮说“测试应该失败”不能代替运行结果。

模型可一次请求多个互不依赖工具,Harness也可能确定性地执行预设检查,因此真实流程不必每轮恰好一个动作。重要的是输入—决策—执行—反馈有明确对应关系。阅读文件、修改文件和测试结果之间的版本要能连接,否则会把旧证据用到新状态。

运行示例 · Q033

一个修复任务,为什么产生三次模型调用

输入与条件。任务是把 config.json 的超时从3改成5,工具有read、write、test。下面是确定的教学轨迹,而非真实模型自主运行。

步骤与对象内部动作中间结果 / 新状态
1调用1输入用户任务+可用工具说明模型提出read,尚未承诺文件已修改。
2工具1结果读取版本v7,timeout=3结果连同调用ID进入历史。
3调用2输入任务+read调用+结果模型提出在v7基础上写timeout=5。
4工具2结果写入成功,得到v8宿主仍未证明功能测试通过。
5调用3输入新版本和测试返回pass模型归纳变更与验证;如果模型还需自行提出test,则还要增加一轮。
6计数区别用户看见一个任务后端可能有多次模型请求和多次工具操作。

把过程连起来。一轮模型调用的输出不是任务的全部生命周期;哪些工具由模型决策、哪些由宿主自动触发必须说清。

边界与反例。本例test由宿主固定触发,因此三次调用成立;不要与“每一步工具都须另一次模型提议”的配置混计。

依据与适用范围:[TOOLS]。示例输入和场景由本书明确设定。

追问:为什么不一次把所有文件读完,再让模型直接给补丁?

小仓库有时可以,但大仓库成本高且无关信息多。更重要的是下一步证据需求常由前一步发现决定。先发现入口才能知道该查哪条调用链;先跑测试才能知道真实失败。按需读取是在用环境反馈减少猜测,不是为了人为增加调用轮数。

追问:Agent是不是一定由LLM自由决定所有步骤?

不是。预设workflow可以固定检索、验证、审批等关键步骤;LLM在不确定部分做判断。动态Agent允许模型选择路径,灵活但更难预测成本和行为。实际系统常混合两者,应按任务的不确定性分配控制,而不是把确定性程序也全部改成Prompt。[AGENTS]

追问:如何判断某次失败是模型问题还是Harness问题?

先保存本轮可见输入、可调用工具与实际结果。若正确文件未返回,是检索/工具链问题;返回了但被裁掉,是上下文问题;模型生成合法调用而执行器找不到工具,是注册/路由问题;所有必要证据都可见却推断错误,才更接近模型推理问题。最终错误文本本身不能定位责任层。

Q034|Agent有哪些状态?为什么对话摘要不能替代任务数据库?

核心回答

至少分三类:模型可见的认知上下文、Harness的控制状态、外部环境的实际状态。它们可能暂时不一致。摘要表达“认为发生了什么”,任务记录表达“系统追踪到什么”,文件/数据库/远程服务才是副作用实际发生的位置。

以一次提交为例拆状态

模型说“准备修改filter.py”,这是计划。Harness生成调用c17并记录pending,这是控制状态。工具完成磁盘写入,文件内容变了,这是环境状态。随后进程在把成功写回任务数据库之前崩溃:环境已成功,控制状态仍pending,模型还未看到结果。

恢复时若只读对话摘要“修改未完成”,会重复写;若只读pending就当失败,也可能重复副作用。应查动作身份、预期旧版本、写后内容或远端幂等结果,把状态恢复为已成功或仍未知。不能让模型凭语气决定。

教学上可用以下对象分工:

Task: 目标、约束、完成条件、总体状态
Turn: 一次用户推进或运行阶段
ModelCall: 本轮输入版本、输出项、使用量
ToolCall: 调用ID、参数、授权、执行状态
Artifact: 文件/结果对象及版本
Evidence: 哪个版本被哪条命令验证

这不是要求所有项目新增六张表。简单本地Agent可以用日志和文件实现;核心是别把这些语义混成一句“已完成”。

运行示例 · Q034

对话说“写好了”,但磁盘与任务状态都不同意

输入与条件。同一时刻有三份内容:assistant文本“已更新”;执行日志 call-7=timeout;磁盘版本仍为v7。

步骤与对象内部动作中间结果 / 新状态
1列出对象自然语言、调用记录、外部文件它们不是同一份状态的三个可靠副本。
2核对事实读取磁盘仍timeout=3不能把assistant表述当作写入证据。
3记录状态工具请求可能尚未完成先写unknown或pending,不能靠一句话强行改成succeeded。
4检查点内容目标、当前版本、调用ID、状态、下一步核查恢复进程据此继续。
5新会话反例只把“已更新”摘要交给后继Agent它可能跳过真正的写入和验证。

把过程连起来。执行状态以系统证据为准;对话提供计划和解释,却不能替代外部结果。

边界与反例。unknown的后续处理依工具能否查询、是否具有副作用而定。这里只描述可诊断的状态模型。

依据与适用范围:[DERIVE]。示例输入和场景由本书明确设定。

追问:LLM的KV缓存属于哪一类?

它是推理服务内部计算状态,支持模型连续生成,不是业务完成状态。KV丢失可能需要重新Prefill,但文件修改仍然存在;数据库丢失也不会自动从KV恢复出可靠操作日志。这两种故障需要不同恢复手段。

追问:Plan文件、Checkpoint和长期记忆分别保存什么?

Plan保存希望完成的步骤,Checkpoint保存可恢复的执行位置和状态,长期记忆保存未来可复用事实或经验。计划“测试”不证明测试运行过;Checkpoint中一次通过不代表跨版本永远通过;长期经验“此类接口要幂等”也不能替代当前调用的状态。

追问:为什么每个状态都持久化可能过度工程化?

不是所有中间推测都值得落库。可重做的只读搜索和临时推理可以轻量处理;不可逆操作、长期任务恢复点、关键证据更值得持久化。按丢失后果决定存储强度,而不是为所有Token做复杂审计。

Q035|无状态API与有状态会话各怎样构建下一轮输入?会话ID是不是长期记忆?

核心回答

无状态调用通常由客户端传入需要的历史;有状态接口可以引用服务端已有会话或响应状态,减少客户端搬运。两者都要遵守模型上下文与产品状态规则。有会话ID不等于永久可用、不等于跨任务知识治理,也不保证计算缓存命中。[CODEX][COMPACT]

两条等价目标、不同实现的链

在无状态风格中,第二轮输入可能是[规则,用户任务,助手调用c1,工具结果c1]。第三轮再附加新调用及结果。若客户端漏掉工具调用只发工具结果,协议可能无法正确配对;若只把工具结果粘成用户文本,还可能丢失来源和可信边界。

有状态风格可能发送previous_response_id + 新工具结果,服务端恢复必要上下文。它降低的是显式传输与状态管理负担,不意味着全部旧历史无限进入模型。服务仍可能截断、压缩、要求传递特定状态项,具体依接口而定。

跨会话记忆还需要选择保存内容、身份隔离、版本、更新与失效。一个能续接十分钟前响应的ID,没有自动完成这些治理。相反,即使所有模型调用无状态,也可以通过自己的知识库与任务Checkpoint实现良好长期能力。

运行示例 · Q035

同一个session_id不代表相同的模型输入

输入与条件。第1轮用户说“变量a=7”,第2轮问“a是多少”。用两种API风格对比。

步骤与对象内部动作中间结果 / 新状态
1无状态调用第2轮只发送问题模型没有收到a=7,session_id只是业务字段时不会自动补历史。
2显式历史第2轮发送两条用户消息及必要中间回复此时a=7进入本次上下文。
3服务端会话用受支持的conversation或previous-response机制服务端按接口约定恢复相关项目,但仍受上下文、权限和生命周期约束。
4宿主检查记录实际请求中的消息或服务端历史引用不能仅凭本地界面显示了旧消息就认定模型看见。
5失效反例服务端状态已删除,但本地沿用同一字符串会话键不再对应可恢复内容。

把过程连起来。状态的所有者可能是应用、API服务或文件系统,必须明确谁负责保存和重新提供。

边界与反例。字段名只是概念举例,具体跨请求行为应按所用API文档验证,不为所有SDK作统一保证。

依据与适用范围:[TOOLS] [COMPACT]。示例输入和场景由本书明确设定。

追问:能否把某个厂商的压缩块复制给另一个模型?

不应假定可以。压缩块可能是该服务专用的opaque状态,格式与解释依赖模型/接口。跨模型交接通常需要可读的事实、约束和证据引用,或双方明确支持的协议。加密状态不是通用Markdown摘要。[COMPACT]

追问:重试一次相同模型请求是否会得到同一个工具调用ID?

不能普遍假定。传输重连、请求重试与重新生成是不同操作。重新生成可能产生新的调用项;业务去重不能仅依赖模型随机给出的ID。执行器应维护自己的稳定动作身份,并结合接口提供的幂等或响应恢复机制。

追问:为什么切换模型后长任务可能退化?

不同模型对工具格式、上下文、推理状态和指令的支持不同;能力、Tokenizer和压缩表示也可能变化。安全切换需要重新构建兼容上下文,保留关键事实和未完成副作用,不能仅改模型名称继续塞原始状态。

Q036|Agent何时应该停?为什么“继续直到完成”容易变成死循环?

核心回答

停止需要结合模型判断和可验证条件。模型可以提出已完成、受阻或需要澄清,Harness还要检查结果证据、未决动作和预算。没有明确完成定义,循环可能反复搜索、改写计划或运行同一失败操作。

用完成谓词代替情绪判断

教学任务可定义:目标测试通过;新增边界测试通过;当前diff只包含授权范围;验证对应当前代码版本;没有unknown写操作。满足这些并不证明软件绝对无缺陷,但清楚定义了本任务的交付依据。

循环还应区分“没有新证据”与“任务仍有进展”。连续三轮读取同一文件而没有新假设、相同参数反复失败、补丁反复在两种写法间切换,都提示进展停滞。可以降低动作自由度,要求明确下一次操作预期检验什么,或者输出受阻原因。

预算至少包括墙钟时间、调用次数、Token、工具费用和风险。达到预算不应伪装完成;应保存已完成/未完成内容和准确证据。在长任务中,局部完成可交付,剩余问题明确分离,比无限“再审一遍”更可靠。

运行示例 · Q036

同一搜索重做五次,何时应该停止

输入与条件。任务需要找函数foo,工具连续返回not_found。前5次查询字符串、搜索目录和仓库版本完全相同。

步骤与对象内部动作中间结果 / 新状态
1标记进展定义“新路径、新证据或新状态”才算新增信息重复not_found不算进展。
2第2次失败检查大小写、目录和符号可能更名允许有理由地改变一次搜索策略。
3第3次同结果识别查询指纹相同、无新证据停止盲目重复,转到目录或调用者定位。
4终止条件预算用尽且关键证据仍缺报告缺口,不把找不到变成“函数不存在”的无条件结论。
5成功条件已修复、当前版本验证通过、原目标满足达到后不因还能继续反思就再开无意义循环。

把过程连起来。停止规则同时需要预算、进展和验收条件;只有最大轮数会过早停或长期空转。

边界与反例。指纹可用简单元组,不要求为所有文本引入哈希体系;示例轮数不是产品推荐阈值。

依据与适用范围:[DERIVE]。示例输入和场景由本书明确设定。

追问:停止条件是否必须写成很多硬规则?

不必。简单任务可由直接结果核验结束。高风险、长周期或曾反复失败的环节才值得增加明确条件。规则是为阻止具体失败模式,不是替代模型所有判断。

追问:模型说缺信息时,应立即问用户吗?

先看可用工具是否能解决。文件路径、测试命令、现有配置可以从仓库读取,不应把本可自行检索的问题交给用户。真正涉及业务意图、不可恢复操作选择或权限边界时,用户决策才不可替代。

追问:为什么不能用“所有测试都绿”作为唯一完成条件?

测试可能没覆盖目标、没有实际运行、被跳过、对旧版本执行,甚至被Agent删掉。还需要检查运行清单、退出状态、版本、测试有效性及改动范围。完整验证链在第22章展开。

记录保存在本机浏览器。

输入关键词即可检索。

↑ ↓ 选择 Enter 打开Esc 关闭 · 仅本地搜索

阅读设置

阅读设置仅保存在本机浏览器,不上传任何数据。