你已经会 harness engineering —— 给模型准备 prompt、上下文、工具调用协议。下一步是把"一次调用"变成"一个能自我纠正的闭环"。这一页用最短路径把差异讲清楚,配一个可点的 loop 模拟器让你看清 state → action → observation → termination 的实际流转。
state feedback termination observability retry policy
Harness engineering 关心的是单次调用的质量:system prompt、tools schema、structured output、上下文注入、token 预算。产出是一个"能被调用好"的 LLM 端点。
Loop engineering 关心的是把这个端点放进反馈回路里:每一步调用之后,环境(真实世界 / 工具 / 判官 / 用户)会返回一个观察,你要用它更新 state 并决定"继续、修正、还是停"。产出是一个能自己走完一个多步任务的 agent。
| 维度 | Harness engineering | Loop engineering |
|---|---|---|
| 时间跨度 | 1 次调用 | N 次调用组成一个 episode |
| 核心数据 | prompt + tools schema | state + history + observations |
| 失败模式 | 格式错、幻觉、越界 | 震荡、死循环、幻觉累积、goal drift |
| 调优对象 | system prompt、few-shot、schema | step function、终止条件、retry、reflection |
| 评估 | 输出对不对 | 能不能收敛到目标、代价、鲁棒性 |
| 常用工具 | OpenAI SDK、function calling | DSPy / LangGraph / 手写 while + verifier |
忘掉框架,先记住这 5 个部件。任何 agent loop 都是它们的组合:
此刻你知道什么。goal、已尝试的动作、错误历史、预算、外部环境快照。
坑: 只把 history 全塞回 LLM 不是 state 管理,是 context 堆积。真正的 state 应该被压缩/结构化:goal / facts_learned / open_hypotheses / budget_left。
给定 state,产出下一步 action。这里就是你之前的 harness——一次 LLM 调用。
坑: 不要让 policy 自己决定"我完成了"。让外部 verifier 判断,policy 只负责下动作。
执行 action 的地方:shell、HTTP、数据库、另一个 LLM (judge)、用户回复。
坑: 环境返回值要确定性——同样输入尽量同样输出。否则 loop 无法调试。
拿到环境返回,抽取信号写回 state。不是 "print 出来就完事",要形成下一轮能用的结构化条目。
坑: 最容易错的一步。把 stderr 原封不动塞回 prompt = 模型在噪声里工作。
什么时候停? 至少三个终止器一起用:success(目标达成)、budget(步数/token/钱到上限)、no-progress(连续 N 步 state 无变化)。
坑: 只有 success 一个终止器 = 死循环烧钱。三个都得有。
不属于 loop 内部,但等价重要:每一步的 trace 落盘。没有 trace 的 loop 无法调优,只能靠感觉。
做法: 每步记录 {step, state_before, action, observation, state_after, tokens, latency}。
下面这个 loop 要解决一个假想任务:"修复一个 CI 挂掉的 Python 项目"。你可以看到 state 怎么积累、什么时候触发不同的终止条件。挑一个策略,然后一步步 step,或者 run 让它跑完。
{goal, facts, hypotheses, budget}。 history 只在 debug 时看。{state,action,obs} 记下来,再谈"要不要加 reflection / rerank / self-consistency"。没有 trace 就是在猜。模型每步都自信地说"再试一次",但 state 没变化。你没有 no-progress 终止器。
治: 加 stall 检测——连续 N 步 state hash 相同就 abort。
第 10 轮的时候 context 有 40k tokens,全是老工具输出。模型开始忽略新信息。
治: 每轮显式 compress,只留最近一次 raw output + 累积 facts。
policy 自己说"任务完成",然后停了。跑完发现根本没修好。
治: success 判断要用可执行信号(跑测试、看 exit code、抓一次目标 URL)。
没有 max_steps / max_tokens,凌晨三点 API bill 告警。
治: 硬编码 budget 是最便宜的保险。step ≤ 20,tokens ≤ 200k,超了直接 raise。
工具吐 10KB 日志,你原样塞回 prompt。3 步后 context 爆炸。
治: observation 层做投影:只取 last error / diff / status,其他落盘存 trace。
开始要"修 CI",第 8 步在讨论要不要重构模块系统。
治: state 里 goal 字段 read-only;每步都把它重新拼进 prompt 头部。
while 循环,最多 10 步,里面调用你现有的 policy 函数。success、step >= 10、stall >= 3。facts_learned,raw observation 只保留最近一次。(step, state, action, obs) 落到 trace.jsonl。