Skip to main content

代理循环

Copilot CLI 如何端到端处理用户消息:从提示到 session.idle

Architecture

图示:显示所述过程的图示。

SDK 是一个传输层,它通过 JSON-RPC 将提示发送到 Copilot CLI,并将事件呈现回应用。 CLI 是运行智能体工具调用循环的编排器,会持续发起一次或多次 LLM API 调用,直到任务完成。

工具使用循环

调用 session.send({ prompt })时,CLI 将进入循环:

图示:显示所述过程的流程图。

该模型查看每个呼叫 的完整对话历史记录 -系统提示、用户消息以及所有以前的工具调用和结果。

关键见解: 此循环的每个迭代都是一个 LLM API 调用,在事件日志中显示为一 assistant.turn_start / assistant.turn_end 对。 没有隐藏调用。

轮次 - 它们是什么

轮次是一次 LLM API 调用及其产生的后果:

  1. CLI 将会话历史记录发送到 LLM
  2. LLM 作出响应(可能包含工具请求)
  3. 如果请求了工具,CLI 会执行它们
  4. assistant.turn_end 被发出

单个用户消息通常会导致 多个轮次。 例如,像“X 在这个代码库中是如何工作的?”这样的问题。 可能会生成:

转动模型的作用toolRequests?
1调用 grepglob 搜索代码库
✅ 是的
2基于搜索结果读取特定文件
✅ 是的
3阅读更多文件以获取更深入的上下文
✅ 是的
4生成最终文本答案
❌ 否→循环结束

模型决定每个轮次是请求更多工具还是生成最终答案。 每个调用都会看到 完整的累积上下文 (所有以前的工具调用和结果),因此它可以就它是否有足够的信息做出明智的决定。

多轮交互的事件流

图示:显示所述过程的流程图。

每一轮由谁触发?

Actor责任
你的应用通过 session.send() 发送初始提示
Copilot CLI运行工具使用循环 - 执行工具和将结果馈送回 LLM 以供下一轮使用
LLM决定是否请求工具(继续循环)或生成最终响应(停止)
SDK传递事件;不控制循环

CLI 纯粹是机械性的:“模型要求工具→再次执行→调用模型。 模型是何时停止的决策者。

session.idlesession.task_complete

这些是两个不同的完成信号,有非常不同的保证:

session.idle

  • 始终发出,当工具使用循环结束时
  • 临时:未保存到磁盘,在会话恢复时不重播
  • 表示:“代理已停止处理,并已准备好接收下一条消息”
  • 将此 用作可靠的“完成”信号

SDK sendAndWait() 的方法等待此事件:

// Blocks until session.idle fires
const response = await session.sendAndWait({ prompt: "Fix the bug" });

session.task_complete

  • 可选输出:要求模型明确标示这一点
  • 已持久化:已保存到磁盘上的会话事件日志中
  • 表示:“代理认为整体任务已完成”
  • 包含一个可选的 summary 字段
session.on("session.task_complete", (event) => {
    console.log("Task done:", event.data.summary);
});

Autopilot 模式:CLI 提示 task_complete

Autopilot 模式 (无外设/自主操作)中,CLI 会主动跟踪模型是否已调用 task_complete。 如果工具使用循环在没有它的情况下结束,CLI 会注入一条合成的用户消息来提示模型:

“你尚未使用 task_complete 工具将该任务标记为完成。如果你还在规划,就停止规划,开始执行。在你彻底完成该任务之前,都不能算完成。”

这实际上会重启工具调用循环——模型会将这一提示视为一条新的用户消息,并继续执行。 该提示还指示模型不要过早调用task_complete

  • 如果你还有未解决的问题,就不要调用它——先做出决定,继续推进工作
  • 如果遇到错误,请不要调用它 - 尝试解决它
  • 如果还有剩余步骤,请不要调用它——请先完成这些步骤

这将在 Autopilot 中创建两级完成机制

  1. 模型使用摘要调用 task_complete → CLI 输出 session.task_complete → 完成
  2. 模型停止而未调用它 → CLI 提示一下 → 模型继续或调用 task_complete

为什么 task_complete 可能未出现

交互模式(普通聊天)中,CLI 不会提示 task_complete。 模型可能完全跳过它。 常见原因:

  • 对话问答:模型回答问题,只是停止 - 没有离散的“任务”来完成
  • 模型自由裁量权:模型在不调用任务完成信号的情况下生成最终文本响应
  • 中断的会话:会话在模型到达完成点之前结束

不管怎样,CLI 都会发出 session.idle ,因为它是一个机械信号(循环结束),而不是语义信号(模型认为它已完成)。

你应使用哪一种?

用例信号
“等待代理完成处理”
session.idle
“了解编码任务何时完成”
session.task_complete (尽力而为)
“超时/错误处理”
session.idle

session.error ✅ |

统计 LLM 调用

事件日志中的对数 assistant.turn_start / assistant.turn_end 等于进行 LLM API 调用的总数。 没有用于规划、评估或完成检查的隐藏调用。

要查看会话的轮次计数:

# Count turns in a session's event log
grep -c "assistant.turn_start" ~/.copilot/session-state/<sessionId>/events.jsonl

延伸阅读