cline — 本课题摘录
读了哪几篇: 01-agent-loop(内核:无状态的工具调用循环)、03-orchestration-safety(会话编排与安全护栏)。
其余四篇(工具集、LLM 网关、检查点与多 agent)本轮没读——它们属工具层、换厂商与多 agent 课题。
它对本课题回答了什么
决定一:循环放在哪一层
循环本身不记事,记事的是包在外面的那一层;每一轮都新造一个循环实例。 (依据:Agent 库 · Cline · 内核:无状态的工具调用循环 —— AgentRuntime 无状态,不负责持久化也不负责跨会话记忆,给它一组消息和一组工具、跑到收尾就完事)
外层每次开跑,把整个历史当作初始消息塞进新建的循环里,跑完再存回。 (依据:Agent 库 · Cline · 会话编排与安全护栏 —— 所有跨轮状态活在 SessionRuntime 里,每一轮新造一个一次性的 AgentRuntime,把完整历史当 initialMessages 喂进去,跑完丢弃)
为什么要这么切: 它自己给的理由是——内核不持有状态,重跑一遍就是干净的,于是登录失效后重试、把一次运行重放一遍都变得可行。 (依据:Agent 库 · Cline · 会话编排与安全护栏 —— 注释点明每轮新建是为了让 OAuth 重试与 run 重放可行,会话级状态活得比任何一个 AgentRuntime 都久)
决定二:怎么认出模型要调工具
模型是流式吐字的,工具调用的参数也是一段段碎着回来。所以"认出来"分两件事:
- 归并碎片——同一个调用 id 的多段参数文本拼到一起;
- 保住顺序——用一个序列数组按到达顺序记"这段是文本"还是"这里有个工具调用的占位",等流结束再回填,文本与工具调用的相对顺序不会乱。 (依据:Agent 库 · Cline · 内核:无状态的工具调用循环 —— 用 sequence 数组按到达顺序记录文本段与工具占位、用 Map 按 toolCallId 归并参数碎片,流结束后回填以保住相对顺序)
决定三:结果怎么回填
「错误即消息」是它最要紧的一条。 工具抛错、参数是非法 JSON,都不中断循环,而是包成一条带"这是错误"标记的结果喂回模型。 (依据: shelf=agent/cline#01-agent-loop @1de61b178aec 事实=executePreparedTool 用 try/catch 包住,工具抛错被包成 {output:{error}, isError:true} 当消息喂回模型,循环不终止)
参数解析失败时,它当场拼一句明确的纠错文本("你给的参数不是合法 JSON,错在……")一起喂回去。 (依据:Agent 库 · Cline · 内核:无状态的工具调用循环 —— parseToolInput 在 JSON.parse 失败时就地拼出 "emitted invalid JSON arguments: ${error}" 的纠错文本喂回模型,而不是直接崩)
决定四:什么时候停
三个退出口,外加两道护栏。
| 退出口 | 触发 |
|---|---|
| 自然收尾 | 模型这一轮不再要工具 |
| 显式收尾 | 模型调用了一个被标成"完成工具"的工具且成功 |
| 兜底 | 超过轮数上限,抛错 |
(依据:Agent 库 · Cline · 内核:无状态的工具调用循环 —— execute 的三个退出口是 toolCalls.length===0、findCompletingToolMessage 命中、iteration 超过 maxIterations)