Files
zk-data-agent/docs/agent-loop.zh-CN.md
2026-07-26 21:32:12 +08:00

179 lines
8.0 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Agent 循环实现
中文 · [English](agent-loop.md)
## 目标
K1412 循环把模型补全 API 转变为一个可追责的编码 Agent。它最核心的规则很简单:文字声明不能证明工作真的发生过。文件、命令、报告和测试都必须由本次运行中成功的工具事件提供证据。
当前事件元数据使用以下标识:
- 策略:`agent-loop-v3`
- 调度器:`safe-parallel-v1`
- 上下文策略:`recent-visible-v1`
这些标识是实验契约的一部分,不是营销版本号。只要行为变化可能影响评测结果,就应更新对应标识。
## 运行状态机
```mermaid
stateDiagram-v2
[*] --> BuildContext
BuildContext --> RequestModel
RequestModel --> ValidateCalls: 存在工具调用
RequestModel --> CheckCompletion: 没有工具调用
ValidateCalls --> Schedule
Schedule --> Execute
Execute --> RecordEvidence
RecordEvidence --> RequestModel
CheckCompletion --> RequestModel: 证据不足且仍有预算
CheckCompletion --> Completed: 证据充分
CheckCompletion --> Unverified: 证据不足且重试预算耗尽
Completed --> [*]
Unverified --> [*]
```
每次顶层运行都有唯一的 `run_id`。所有事件都包含用户、对话、单调递增序号、时间戳、事件类型和净化后的载荷。
## 上下文策略
`ContextPolicy.prepare` 会:
1. 只接受 system、developer、user 和 assistant 消息;
2. 从旧的助手消息中移除已渲染的 `<details type="tool_calls">` 块,避免把 UI 标记再次送入模型上下文;
3. 前置 K1412 系统契约;
4. 最多附加八条持久用户记忆作为上下文,并明确说明它们不是更高优先级的指令;
5. 从新到旧遍历可见消息,直到达到该模型的字符预算;
6. 记录被丢弃的旧消息数量。
这一策略有意保持简单且可检查。它目前不会总结旧的对话分支、检索语义化工作区上下文,也不会估算不同提供方的具体 token 切分方式。这些都是未来可以实验的方向。
## 模型契约
`ModelSpec` 是以下配置在服务端的唯一事实来源:
- 公开模型 ID 和提供方模型 ID;
- 提供方选择;
- 是否支持思考以及显示标签;
- 提供方支持时所使用的 reasoning effort
- 最大输出 token 数;
- 最大循环迭代次数;
- 上下文字符预算。
Luna、Terra 和 Sol 是三个不同的本地模型,各自以布尔值表示是否支持思考;它们不是同一模型的三档推理强度。DeepSeek V4 Pro 使用 DeepSeek 提供方,启用思考,并设置 `reasoning_effort=max`
如果提供方协议要求,Runtime 会在多轮工具调用之间保留 `reasoning_content`,但不会把隐藏推理发布为用户可见内容。
## 工具目录
工作区工具:
- 获取状态,列出、读取、搜索、写入和补丁修改文件;
- 执行前台命令;
- 检查 Git 状态与 diff
- 启动、轮询和取消后台进程。
Runtime 状态工具:
- 更新每个对话的计划;
- 记住、回忆和遗忘持久用户记忆。
委派工具:
- 使用角色、任务和明确的写入策略启动一个有边界的子 Agent。
工具 schema 使用 `additionalProperties: false`,让格式错误的模型参数尽早失败。参数会在策略检查前完成规范化。内容正文和补丁正文不会写入公开运行事件的载荷。
## 基于意图的工具选择
根循环并不总是发送全部工具。轻量级请求分类器会判断任务是否涉及产物、执行、源码、报告、比较、进程、Git、记忆或委派。筛选后的工具目录可以降低模型进行工具决策的难度,同时保留核心工作区工具。
这只是启发式路由,不是权限控制。Gateway 仍然是实际的强制执行边界。
## 调度器
每次模型响应最多请求八个工具调用。调用按原始顺序解析,并划分为连续的组:
- 标为 `parallel_safe` 的工具并发执行;
- 写操作和其他非并行工具串行执行;
- 只读子 Agent 可以并行运行;
- 拥有写权限的子 Agent 串行执行;
- 子 Agent 不能再次委派。
Gateway 还会按用户串行化工作区写操作。第二层锁非常重要,因为多个 Runtime 请求或浏览器操作可能同时访问同一个工作区。
即使并行组中的任务完成顺序不同,调度器仍会保持结果的原始顺序。
## 防御性规范化与重试保护
循环会修复少量常见的模型格式错误,然后应用策略:
- 拒绝 `python3``bash``node` 这类没有参数的交互式命令;
- 拒绝把文档或数据文件当作可执行源码运行;
- 在写入完整 Python 文件之前拒绝语法无效的内容;
- 解码弱模型生成的、重复转义的源码布局换行;
- 跳过内容完全相同且此前成功的写入;
- 在内容变化前阻止重复执行完全相同的失败写入;
- 在发生写操作或实质不同的诊断前,阻止重复执行没有变化的失败命令;
- 对同一批次里的重复命令去重;
- 限制生成长度、迭代次数和工具批次大小。
在执行层,Bash 启用 `pipefail` 并返回真实退出码。前台工具默认最长运行 900 秒;后台进程具有明确的启动、轮询和取消生命周期。
## 基于证据的完成门禁
循环会从用户请求中推导所需证据。
| 请求类型 | 最低证据要求 |
| --- | --- |
| 具体产物 | 一次成功的文件写操作,以及之后一次成功的验证 |
| 执行/测试/分析 | 至少一次成功的执行或检查 |
| 源码请求 | 单独的可执行源文件 |
| 报告请求 | 在执行之后单独写入的报告 |
| 基准测试/比较报告 | 从成功执行输出中复制的精确数值测量 |
验证可以是之后的文件读取、Git diff/status、命令执行或后台进程轮询。失败的命令会一直保持未解决状态,直到后续执行成功。
如果模型过早尝试完成任务,Runtime 会发出 `completion.rejected`,向模型返回聚焦的恢复指令,并继续循环。经过多次被拒绝的完成检查或迭代次数耗尽后,Runtime 会返回明确的未完成结果,而不是把未经验证的声明包装成成功。
## 委派
根 Agent 可以委派一个边界明确的独立任务。子 Agent 会获得:
- 一个角色和精确任务;
- 最多八次迭代的缩减预算;
- 不包含委派工具;
- 默认仅有只读工具,除非明确请求了写权限。
子 Agent 事件与根运行共用同一事件流,但 `depth` 会增加。当前实现是在单个 Runtime 进程内递归执行,不是分布式队列,也不是持久自治 worker。
## 记忆与计划
持久记忆按用户 ID 隔离。当前优先返回最近记忆,并支持可选的、不区分大小写的子字符串过滤。计划按用户和对话隔离,并且最多只允许一个 `in_progress` 项。
记忆很有价值,但系统有意保持保守:不会从每次对话自动提取事实,也暂未实现向量检索、置信度评分、过期和冲突解决。
## 运行事件模型
重要事件类型包括:
- `run.created``context.built``run.completed``run.failed``run.cancelled`
- `model.requested``model.responded`
- `tool.started``tool.completed``tool.batch_limited`
- `completion.rejected``completion.unverified`
- `agent.spawned``agent.completed`
事件流目前用于驱动 UI 工具详情块,也是未来实现回放、评测、成本分析和 A/B 分组的基础。事件仅存储公开参数和简短摘要,不存储凭据、完整写入正文或隐藏推理。
## 已知限制
- 上下文压缩会直接丢弃旧消息,而不是总结。
- 记忆检索基于文本而不是语义。
- 工具意图分类器基于正则表达式。
- 调度器只并行连续的安全调用,且没有资源成本模型。
- Runtime 重启后,子 Agent 不会持久存在。
- 尚未实现实验分组和聚合仪表盘。
- 提供方返回的 token 统计会被保留,但尚未转换成统一成本模型。
这些都是有意保留的实验方向,记录在[实验方法](experiments.zh-CN.md)中。