db-gpt — 本课题摘录
读了哪几篇: 01-agent-loop(单个 agent 的五步循环)。
其余几篇本轮没读。
这一家把"验证"提升成了循环的一等公民,而且验证的手段是真去执行。
它对本课题回答了什么
决定四(形状):比标准三步多出评审与验证两步
标准的循环是"想 → 做 → 看结果"。它是五步:
┌──────────────────────────────────────────┐
▼ │ 不通过:把失败原因
① 想 ──► ② 自审 ──► ③ 真执行 ──► ④ 对答案 ──┤ 当新「观察」塞回
问模型 合规吗 跑 SQL/代码 成功?有数据? │
通过 ──► 写记忆 → 返回
(依据:Agent 库 · DB-GPT · 单个 Agent 的五步循环 —— generate_reply 是 think→review→act→verify→自我纠错 五步循环,比标准三步多出评审与验证两步,失败时把失败原因当成新的 observation 塞回下一轮,最多重试 max_retry_count 次)
它的动机说得很直白:大模型会写数据库查询,但它不知道自己写的跑不跑得通。
答案:别信模型,去执行,用执行结果当裁判。
决定四最值钱的一条:验证是"真执行后对答案",不是问模型
具体的验证长这样:不是问模型"你这条对吗",而是真去连库执行。查不到数据、抛异常,都返回(失败, 具体原因)。
这个原因就变成下一轮的输入,模型读着"字段 xxx 不存在"去改。 (依据:Agent 库 · DB-GPT · 单个 Agent 的五步循环 —— DataScientistAgent.correctness_check 不问模型而是真去 database.query 执行 SQL,查不到数据或抛异常都返回 (False, 具体原因),该原因沿回边变成下一轮的 observation)
这一条是本课题第四个决定的一个重要分支: "什么时候停"的前提是"怎么知道做对了"。 绝大多数实现的答案是"模型说做完了就是做完了"——db-gpt 说不行,要有一个外部裁判。
它选的裁判是"真执行"。这是最硬的一种。
对我们的最小原型有直接用处: 如果我们的工具里有一个"跑一段代码"或"查一次数据", 那"跑成功了吗、有结果吗"就是天然的验证信号,不用额外造。
验证的基类做三层检查:自审没批准 → 失败;执行标记为不成功 → 失败;执行结果为空 → 失败。最后才落到子类做语义校验。
"执行结果为空也算失败"这一条容易漏。 命令跑通了但什么也没返回,在很多场景里就是错了。
决定三:失败原因原样回填,而且失败本 身也写进记忆
失败时不仅把原因设为新的输入,还把失败写进记忆——这样模型重试时能从记忆里看到"我上次错在哪",而不是干净地从头再来。
下一轮开始前,上一版回复也会作为一条消息回发,让历史里留下"我试过、失败了"的痕迹。
这一条区分了两种重试:
- 干净重试:抹掉失败,重新问一遍(模型可能犯同样的错);
- 带记录重试:失败留在历史里(模型看得见自己踩过的坑)。
db-gpt 选后者,而且是显式的两处写入(记忆 + 历史)。 mirothinker 的"把失败压成结构化复盘喂回下一次"是同一条路的更强版本。
三个护栏
| 护栏 | 说的是 |
|---|---|
| 不可重试标记 | 动作可以声明"这类失败重试也没用",命中就立刻跳出,不再重试——避免空转 |
| 终止信号 | 动作可以声明"任务彻底完成",强行结束循环 |
| 单 agent 超时 | 每轮结束检查累计耗时,防止单个 agent 把整条会话拖死 |
(依据:Agent 库 · DB-GPT · 单个 Agent 的五步循环 —— ActionOutput.have_retry 为假时即使没通过也立刻 break 不再重试,ActionOutput.terminate 为真强行结束循环,每轮结束检查 time_cost > max_timeout 做超时兜底)
"这类失败重试也没用"这个标记很实用。 权限不足、字段不存在于表结构——重试十次也是同样的错。 前面 cowagent 的"同参连败分档"是从外部检测,db-gpt 这条是让动作自己声明。
还有两条工程性的:
- 整个循环包在异常捕获里,出异常返回一条标记失败的消息而非崩溃——保证一个 agent 炸了不会拖垮整体。
- 每一步都有独立的追踪段(想/自审/做/验证各一个),调试一次失败的纠错链路时,这些追踪是眼睛。
"每一步一个追踪段"这条对我们值得早做。 本课题的原型一旦开始转好几轮,没有分步追踪就没法看清它在哪一步跑偏。
问模型那一步自带三次网络重试,抗限流和抖动。
注意这是两层重试:网络层的重试(同一个请求再发一次)和循环层的重试(带着失败原因重来一轮)。 两者性质完全不同,不能混成一个计数器。
它没回答什么
- 怎么认出模型要调工具——它用"动作解析",从模型文本里解析成结构化动作,但这一篇没细讲格式。
- 历史怎么压——不在这一篇。
- 并发——它是串行的。
坑与代价
- 五步里的"自审"在基类默认放行,等于大多数场景其实是四步。这一步是留给子类的钩子,不是默认能力。
- 验证靠真执行,意味着执行必须是可重复且无害的。 查询可以随便重跑,但"发一封邮件"这种验证不了——重跑就是发两封。
判断(无锚): "执行驱动的验证"只适用于只读或幂等的动作。有副作用的动作需要另一种验证。 如果错,会错在: 如果动作本身带回滚(事务、临时目录),那有副作用也能验证——先跑再回滚。
- 重试次数是按场景调的经验值(容易出错的那类调到 5)。
- 失败写进记忆也写进历史,重试几次后历史里会堆一串失败版本。 这既是资产也是负担——长任务里要有人清理。