跳转到主要内容

代理循环

说明 Copilot CLI 如何端到端地处理用户消息(从发送 prompt 到 session.idle)。

架构

SDK 是传输层。它通过 JSON-RPC 将 prompt 发送到 Copilot CLI,并把事件转发给应用。执行代理式工具使用循环、编排一次或多次 LLM API 调用直到任务完成的,是 CLI 侧。

工具使用循环

当你调用 session.send({ prompt }) 时,CLI 会进入以下循环。 模型在每次调用时会参考 整个对话历史(system prompt / user message / 到那时为止的所有工具调用与结果)。 重要: 该循环的一次迭代与一次 LLM API 调用完全对应,在事件日志中体现为一对 assistant.turn_start / assistant.turn_end。没有隐藏的调用。

什么是 Turn(轮次)

Turn 是指一次 LLM API 调用及其结果。
  1. CLI 将对话历史发送给 LLM
  2. LLM 响应(可能包含工具请求)
  3. 如果有工具请求,CLI 会执行它们
  4. 发出 assistant.turn_end
一条用户消息通常会产生 多个 turn。例如对于「在这个代码库中 X 是如何工作的?」这样的问题:
Turn模型的动作toolRequests?
1使用 grepglob 搜索代码库✅ Yes
2根据搜索结果读取特定文件✅ Yes
3为了更深入的上下文继续读取✅ Yes
4生成最终的文本回答❌ No → loop ends
模型在每一轮判断「是否继续使用工具」或「进入最终回答」。由于每次调用都能看到 累积的完整上下文(包括过去的工具调用与结果),因此可以判断信息是否足够。

多轮次时的事件流

谁来启动每一轮

ActorResponsibility
Your app通过 session.send() 发送最初的 prompt
Copilot CLI执行工具使用循环,将工具执行结果作为下一轮输入返回给 LLM
LLM决定是请求工具继续,还是返回最终响应并结束
SDK仅中继事件。不做循环控制
CLI 的行为是机械式的(「模型请求工具 → 执行 → 再次调用模型」)。做出停止判断的决策者是 模型

session.idlesession.task_complete 的区别

两者都是完成信号,但保证内容差别很大。

session.idle

  • 在工具使用循环结束时 一定会发出
  • 短暂性(ephemeral)。不会持久化到磁盘,也不会在会话恢复时重放
  • 含义:「代理已停止处理,可以接受下一条消息」
  • 作为可靠的「完成」信号请使用这个
SDK 的 sendAndWait() 会等待该事件。
// 等待直到发出 session.idle
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 mode(headless / autonomous)下,CLI 会跟踪模型是否调用了 task_complete。如果工具使用循环在没有 task_complete 的情况下结束,CLI 会插入以下合成用户消息以催促模型。
“You have not yet marked the task as complete using the task_complete tool. If you were planning, stop planning and start implementing. You aren’t done until you have fully completed the task.”
这实际上会重新启动工具使用循环。模型会把该催促当作新的用户消息接收并继续工作。催促中还包括「不要过早调用 task_complete」的内容。
  • 如果有未解决的疑问不要调用。做出判断并继续工作
  • 如果只是遇到了错误不要调用。尝试解决
  • 如果还有剩余任务不要调用。先完成它们
在 autopilot 中形成了以下 两阶段完成机制
  1. 模型带着 summary 调用 task_complete → CLI 发出 session.task_complete → 完成
  2. 模型没有调用就停止 → CLI 催促 → 模型继续或调用 task_complete

task_complete 不出现的原因

interactive mode(普通聊天)下,CLI 不会催促 task_complete。模型有时会省略它。主要原因如下。
  • 对话式 Q&A:回答问题后结束,没有离散的「已完成任务」
  • 模型判断:不调用 task_complete 就返回最终文本
  • 中断的会话:模型未到达完成点,会话就结束了
另一方面,CLI 总是会发出 session.idle。因为它不是语义化的信号(模型判断完成),而是机械式的信号(循环结束)。

该用哪一个

Use caseSignal
「等待代理处理结束」session.idle
「知道编码任务已完成」session.task_complete(best-effort)
「超时 / 错误处理」session.idle + session.error

计算 LLM 调用次数

事件日志中的 assistant.turn_start / assistant.turn_end 对数与 LLM API 调用总数一致。不存在计划、评估、完成确认等隐藏调用。 确认某个会话的轮次数示例:
# 计算会话事件日志中的 turn 数量
grep -c "assistant.turn_start" ~/.copilot/session-state/<sessionId>/events.jsonl

相关文档

最后修改于 2026年7月13日