代理循环
代理循环是 Rusty 的核心调度器。它管理着用户、LLM 与工具三者之间的对话。
-
用户消息——用户的输入被加入消息历史。
-
自动压缩检查——若上下文占用较高,旧消息会通过三级压缩系统进行管理(见下文)。
-
发送给 LLM——完整的消息历史、系统提示词与工具定义通过 SSE 流式发送给 LLM 提供方。
-
流式响应——响应逐事件流式返回:文本增量、思考增量与工具调用增量在到达时被累积。
-
处理工具调用——若响应包含工具调用,所有调用会通过
JoinSet并发执行。每个工具调用作为独立派生任务运行,全部完成后按调用顺序收集并返回结果。 -
循环或结束——若存在工具调用,循环回到第 2 步并带上新消息。若没有工具调用,则将响应文本作为最终答案返回。
长对话通过三级压缩系统进行管理,以保持在上下文窗口以内:
| 层级 | 上下文阈值 | 动作 |
|---|---|---|
| 第一级 | 25% | 微压缩:用简短占位符替换旧的工具结果 |
| 第二级 | 50% | 通过一次 LLM 调用将结构化检查点提取到 checkpoint.md |
| 第三级 | 75% | 通过一次 LLM 调用总结旧消息,保留最近 10 条 |
每级在一次对话中最多触发一次。笔记暂存区的内容(来自 note 工具)会被纳入检查点与总结,然后清空。
使用 /compact 可手动触发压缩。
并发工具执行
Section titled “并发工具执行”当 LLM 在单次响应中发起多个工具调用时,它们通过 tokio::JoinSet 并发执行。这意味着:
- 互不依赖的工具(例如两次
file_read调用)并行运行。 - 所有工具完成后统一收集结果。
- 相比串行执行,实际耗时大幅缩短。
在 TUI 模式下可随时通过 Ctrl+C 取消代理循环。取消会设置一个原子标志,循环在各步骤之间检查它。取消时:
- 当前的 LLM 流被终止
- 部分文本被丢弃
- 会话状态被保留(不会丢失任何消息)
--max-turns 参数限制代理循环的迭代次数。每次执行工具调用的迭代算作一轮。这可以防止代理无限调用工具造成的失控循环。
rusty --max-turns 10 --prompt "分析这个代码库"系统提示词由多个来源组装而成:
- 工具描述:所有可用工具的名称、说明与输入 schema
- 权限模式:当前权限模式与允许的工具
- 平台信息:操作系统、架构、工作目录
- Git 状态:当前分支、近期提交、工作区状态
- 沙箱提示:提醒文件操作被限制在工作目录内
- 上下文文件:项目中找到的 AGENTS.md、CLAUDE.md 或 RUSTY.md 文件内容
- 当前日期:用于对时间敏感的操作
- 任务规划说明:用于结构化任务跟踪的可选说明
所有与 LLM 的通信都以流式为先。提供方产出一串事件流:
| 事件 | 说明 |
|---|---|
TextDelta | 一段响应文本 |
ThinkingDelta | 一段推理/思考内容 |
ToolCallDelta | 一段工具调用(名称或参数) |
Usage | Token 用量信息 |
Done | 流已完成 |
Error | 发生错误 |
事件由代理循环逐个消费,并通过回调转发给 UI。
代理接受可选的回调,用于实时更新 UI:
| 回调 | 用途 |
|---|---|
TextCallback | 每次文本增量时调用 |
ThinkingCallback | 每次思考增量时调用 |
ToolCallback | 工具调用开始或完成时调用 |
PermissionCallback | 工具需要权限时调用 |
正是这些回调驱动了 TUI 的流式显示与权限提示浮层。
子代理作为独立的 Tokio 任务派生,拥有各自的代理循环实例。它们以 BypassPermissions 运行,可访问除 agent 工具以外的所有工具(以防止递归派生)。父代理会将子代理的最终响应作为单个文本块接收。