A·Agent Guide 从经典智能体到前沿工程 ← 返回主博客
AGENT GUIDE / READING NOTES

第 2 章 LLM Agent 的最小执行循环

运行真实修改与测试,逐步分析正常、超时和假完成轨迹

2.1 先拆开模型输出与工具执行

本章目标:读懂并运行一个具备工具白名单、调用记录、错误反馈、预算和完成验收的闭环;能解释怎样把确定性策略替换为模型适配器。

模型生成的是 token。所谓工具调用,是运行时把某类输出识别为结构化动作请求,例如 name=read_file、arguments={"path":"pricing.py"}。文件不会因为模型写出这段 JSON 自动被读取,运行时必须明确执行它,再把返回值送回策略。

带预算、校验和终止条件的工具调用循环

一个最小系统可以拆成四个接口:policy.next(history) 提出决策;tools.execute(name,args) 执行允许的动作;trace.append(...) 保存关联关系;accept_final(...) 根据证据判断能否结束。真实模型适配器还要处理消息格式、工具 schema、流式结果及调用 ID。

2.2 消息和状态为什么必须分开

模型决策通常是 tool 或 final,但工具结果还有成功、业务失败、超时、权限拒绝等情况。这些状态不是同一层。

{
  "step": 1,
  "call_id": "call-1",
  "decision": {"kind": "tool", "name": "run_tests", "arguments": {}},
  "result": {"status": "ok", "passed": false, "source_hash": "..."}
}

status=ok 表示测试工具成功运行,passed=false 表示被测代码不合格。如果把它统一标成“工具失败”,策略可能反复重启测试,而不修代码。相反,工具超时无法说明代码一定不合格,因为此次执行没有取得足够证据。

每条结果要关联唯一调用 ID。并行工具可能以不同顺序返回,仅靠“上一条消息”匹配会串结果。教学脚本顺序执行,因此用步数构造 ID;产品通常需要在请求生命周期中维护更完整的标识与状态。

2.3 逐步读正常修复轨迹

下载 repair_lab.py,或在仓库根目录运行:

python3 agent/examples/repair_lab.py --scenario happy
决策步 执行动作 新增证据 下一步为何合理
1 run_tests 边界、会员、负数不合格 需要查看对应实现
2 read_file 初始代码仅检查 > 100 能指出三个缺失规则
3 replace_file 当前源码哈希变化 写入成功仍不等于正确
4 run_tests 当前版本五项检查通过 取得本次完成依据
5 final 验收器核对当前哈希 接受结束并返回轨迹

重点读 Tools.execute 和 run,最后再读 DemoPolicy。策略中已预置正确补丁,目的是让你专注执行机制。把预置答案的成功率当成真实 LLM 修复率,会得出完全没有意义的结论。

原来的更小例子 mini_agent.py 只演示搜索与观察回填,适合先熟悉接口;它没有这里的修改、测试与版本验收链路。

2.4 为什么结束判断要核对当前版本

实验中的测试记录保存通过时的源码哈希。每次写入先清空 last_verified;最终回答到来时,运行时再次比较记录与当前文件。这样能拒绝“测试后又改代码,再引用旧成功”的路径。

# 核心机制摘录;完整上下文见 repair_lab.py。
verified = tools.last_verified == digest(root / "pricing.py")
status = "success" if verified else "rejected"

真实项目不能只哈希一个文件。测试结果还依赖其他源码、测试文件、依赖、配置和环境。因此需要绑定更完整的 revision 或工作区快照,并确认验收器本身未被 Agent 篡改。教学中的单文件哈希只展示“证据应绑定被测状态”这条原则。

2.5 错误返回之后,策略应怎样继续

python3 agent/examples/repair_lab.py --scenario timeout
python3 agent/examples/repair_lab.py --scenario invalid
python3 agent/examples/repair_lab.py --scenario stale
python3 agent/examples/repair_lab.py --scenario budget

timeout 在首次测试注入一次模拟超时,策略重试固定的只读检查,随后正常完成,共六步。invalid 请求读取 ../secret.txt,运行时拒绝越界路径并结束。stale 在测试通过后把错误代码写回,最终验收拒绝旧证据。budget 只给三步,代码虽已修改,但尚未测试,所以返回 budget_exhausted。

可恢复错误不必立即结束;持续权限拒绝也不值得无限重试。应定义每种错误能做的下一步,以及总次数或总时间上限。重试是否安全还取决于副作用,第 4 章会专门讨论。

2.6 ReAct 与模型适配器放在哪里

ReAct [导读] 的关键是行动和观察交替:新反馈改变下一步,而不只是生成更长的计划。一次 run_tests 给出三种缺陷,策略下一轮读取实现;测试通过后又有写入,就需要再次测试。这才是反馈进入决策。

接入模型时,适配器把目标、约束、工具描述和已取得证据转成模型输入,再把输出标准化为内部决策对象。不要直接把模型文本传给任意 eval 或 shell。未知工具、缺字段、错误类型应作为受控错误处理;不能为了让模型输出“顺利运行”绕过校验。

工具结果保留可信来源、状态和关键内容即可,不需要向用户公开模型的全部内部推理。用于调试的决策记录也应避免记录密钥或不必要的私人数据。

2.7 动手修改与参考检查

给脚本增加 empty_read 场景,模拟读取到空内容。你需要决定这是合法空文件、路径错误还是输出截断,给出明确状态,并使策略避免无证据写补丁。只新增一句提示而不修改状态处理,不能算完成练习。

参考检查:运行正常路径仍成功;空内容路径没有误报完成;新增结果关联正确调用 ID;预算耗尽仍能返回已有轨迹。再把终止判断改成“只要 policy 返回 final 就成功”,运行 false_final 与 stale,观察保护如何失效,然后恢复实现。

本章交付物:一条正常轨迹、四种异常路径、一次修改后的验收结果。应该能逐条回答:哪一层发现了错误,哪一层决定下一步,最终结束由谁接受。


Agent Guide · 从反馈闭环走向可靠系统基于 Markdown 构建