循环
runAgentLoop()runAgentLoopContinue()runLoop()
03 · Agent loop
这一章深入 packages/agent/src/agent-loop.ts:看 runLoop()
如何把 assistant、tool call、tool result、steering 和 follow-up 串成一个可持续推进的状态机。
目标是能解释 agent loop 如何把一次用户输入扩展成多轮模型调用和工具执行。
runAgentLoop()runAgentLoopContinue()runLoop()executeToolCalls()prepareToolCall()finalizeExecutedToolCall()terminateprepareNextTurnshouldStopAfterTurnsteer/followUptoolResult 放回上下文;然后模型基于新上下文继续,直到没有工具、没有队列消息、没有 follow-up。
真实源码很长,但新手先把 agent loop 理解成一个“模型 - 工具 - 回填”的循环。
while (true) {
const assistant = await model(context);
context.messages.push(assistant);
if (!assistant.toolCalls.length) break;
const results = await executeTools(assistant.toolCalls);
context.messages.push(...results);
}
新 prompt 和 continuation 是两种不同入口。
内层处理当前工作链,外层处理 agent 准备停下后的 follow-up。
while (true) {
let hasMoreToolCalls = true;
while (hasMoreToolCalls || pendingMessages.length > 0) {
// pending/steering
// assistant response
// tool calls
// tool results
}
const followUpMessages = await getFollowUpMessages();
if (followUpMessages.length > 0) {
pendingMessages = followUpMessages;
continue;
}
break;
}
toolcall_delta 就执行,而是等完整 assistant message 出来后再执行。
一批 tool calls 先决定串行或并行,再进入 prepare/execute/finalize。
toolcall_delta 只是片段,参数可能还没闭合,也还不能做 schema validation。
等 streamAssistantResponse() 产出完整 message 后,loop 才知道这一批 tool calls 的最终顺序、名称和参数。
hook 的位置体现了安全和扩展边界。
{ block: true } 阻止执行。content、details。isError。terminate。它不是停止某个工具,而是停止工具结果回填后的下一次模型请求。
return finalizedCalls.length > 0 &&
finalizedCalls.every(
(finalized) => finalized.result.terminate === true
);
这一段决定下一轮是否继续、是否换上下文、是否吸收队列消息。
turn_endprepareNextTurnshouldStopAfterTurngetSteeringMessagesgetFollowUpMessagessteer 插入下一次 assistant response 前。steer 不会中断正在执行的工具。followUp 等 agent 本来准备停止时再继续。shouldStopAfterTurn 在 steering 前,避免消费后又停止。这几处最容易把 agent loop 看成普通聊天或普通日志流水线。
它只是 assistant message 里的意图。只有 loop 取出完整 toolCall、校验参数、跑 hook 后,工具才会被执行。
它会被追加进 context,下一次模型请求会看到它。模型能继续推理,靠的是这一步回填。
steer 会尽快插入下一次 assistant 前,但不会中断已经开始的工具执行。要中止运行,需要外部 abort signal。
工具可以并发执行,但 toolResult message 仍按 assistant 原始 toolCall 顺序回填。
terminate 的含义是工具结果已经回填后,不再发起下一次模型请求。
能答出这些问题,才算真正理解 03 章主线。
核心循环已经读完,下一节进入默认工具实现。
read 工具。write/edit 文件修改。bash 执行边界。