让 AI Coding Agent 证明它的工作:Keel 门控框架完全指南
AI Coding Agent 正在快速进化——Claude Code、Codex、Copilot 和 Kiro 都能独立完成从需求到代码的全流程。但一个核心问题始终悬而未决:如何确认 Agent 声称的”完成”是真的?
当 Agent 告诉你”测试全部通过,功能已实现”时,你要么信任它,要么自己跑一遍验证。对于生产级项目来说,这种”信任但需复核”的模式成本太高。
keel(GitHub: daneb/keel)是一个 Rust 编写的门控框架(gated harness),它的核心理念是:让 AI Coding Agent 证明它的工作。keel 不实现模型适配器、工具注册表或推理循环——这些留给 Claude Code、Codex 等工具去做。keel 站在它们之上,负责两件事:可审计的停止条件和跨工具的持久记忆。
安装与基本概念
keel 在 crates.io 上以 keel-harness 包名发布(因为 keel 和 keel-cli 已被其他无关项目占用),安装后二进制文件名为 keel:
cargo install keel-harness # 安装后得到一个名为 keel 的二进制文件
当前版本为 v0.10.1,基于 Rust 编写,支持 macOS 和 Linux,采用 MIT OR Apache-2.0 双许可证。项目状态显示已完成所有五个阶段(PLAN.md),包含证据链、bundle 验证、PR 检查和 GitHub Actions runtime。
keel 的核心设计哲学可以概括为一句话:keel 是指挥者,不是 Agent 循环。 它不重复造轮子,而是站在现有 Agent 之上提供治理层。
核心概念:Gates 与证据链
Gates(门控)
keel 定义了六个门控阶段,每个阶段都有明确的通过/失败标准:
| 门控 | 职责 | 失败条件 |
|---|---|---|
| G0 | Spec 校验:EARS 格式?有 oracle?无占位符?store 是否最新? | 任何标准不可证伪 |
| G1 | Plan 校验:影响范围已追踪?预算合理?有回滚方案?影响集是否最新? | 未追踪、超预算、无回滚 |
| G2 | 执行校验:构建、测试、lint、所有 oracle、scope、budget、ratchet | 任何检查失败 |
| G2.5 | 质量审查:是否新增 mock?测试是否被篡改?findings 分级(HIGH 阻止) | HIGH findings 存在 |
| G3 | 人工审批:前序门控全绿、diff 可审阅、人工判定 | 人工否决 |
| G4 | 学习闭环:分类失败、提出 lessons | — |
关键设计细节:
blocked是一个真实的判定结果,有自己的退出码(3)。它意味着检查无法运行(缺少工具、无索引、无凭据),永远不会静默通过,也不会归咎于 Agent。- Approvals 绑定到 hash:如果在签认后修改了 spec,G1 会以
spec changed after approval失败。否则”approved”就成了一枚永远有效的印章。 - Budgets 是不变式:每个生成物都拟合到硬行数预算内,截断通知消耗的是预算的一部分。被裁剪的内容不会删除,而是携带指向全文的指针。
证据链(Evidence Chain)
keel 将所有审批、门控判定和运行记录链接成一条 hash 链。每条记录引用前一条的 hash,形成防篡改结构。
keel chain verify # 验证整条链 keel chain head # 查看链头 keel chain verify --head# 验证指定哈希之后的部分
如果有人在链中插入、删除或重排记录,keel chain verify 会精确指出哪一步出了问题。
完整工作流:从 Spec 到 Evidence Bundle
Step 1:初始化项目
keel init # 脚手架、种子数据、构建第一个符号索引
keel init 会扫描代码库,使用 tree-sitter 构建符号索引(支持 Rust、Python、JavaScript、TypeScript/TSX、Go、Java、C#),并生成 .keel/store 目录作为单一事实来源。
Step 2:创建 Spec(定义”完成”的含义)
keel spec new rate-limit # 脚手架化 spec,然后自动运行 G0
Spec 是你对”完成”的精确定义,采用 EARS 格式(Every time / When / Then / And / So),每条标准必须附带一个可运行的 oracle(自动化检查)。G0 会拒绝任何包含占位符或不可证伪标准的 spec。
Step 3:审批 Spec
keel approve rate-limit --stage spec
审批会将你的签名绑定到当前 spec 的 hash。之后修改 spec 会导致后续 G1 失败。
Step 4:生成 Plan(计算影响范围)
keel plan rate-limit # 计算 blast radius,生成 plan.md + tasks.md keel tasks # 将 plan 按依赖波次展示
keel 利用符号索引计算影响范围(blast radius),生成按依赖关系分波次的任务列表。G1 会验证:影响集是否已追踪、预算是否合理、是否有回滚方案。
Step 5:驱动 Agent 执行
keel run rate-limit # 驱动 Agent,捕获证据,进行门控 keel run rate-limit --waves # 每个任务一个 worktree,逐波执行 keel run rate-limit --no-driver # 不驱动 Agent,直接门控当前工作树
执行过程中,keel 会:
- 从 Store 组装上下文(约定、技术栈、地图、lessons、spec、task)
- 通过
keel.drivertask/1JSON 协议向 Agent 发送任务 - Agent 返回
keel.driverresult/1+ diff - keel 运行 G2/G2.5/G3 门控
Step 6:导出证据 Bundle
keel export rate-limit # → keel-rate-limit.tar.gz keel bundle verify keel-rate-limit.tar.gz # 离线验证每条链接
Bundle 包含:轨迹(trajectory.jsonl)、门控判定、证据和 manifest。任何人可以在没有访问仓库的情况下离线验证整个运行过程。
Step 7:CI 集成
模式 A:PR 覆盖检查(keel-cover)
在 .github/workflows/keel-cover.yml 中添加一行,即可阻止没有任何 keel bundle 的 PR:
on: pull_request
jobs:
keel-cover:
runs-on: ubuntu-latest
steps:
- uses: daneb/keel@v0.10.1
只有携带了恰好匹配其内容的通过运行的 bundle 的 PR 才能通过。维护者可以通过添加 keel:exempt label 来豁免特定 PR。
模式 B:CI Runtime(keel-runtime)
在 GitHub Actions 中,keel 可以直接在 gVisor 容器内门控 PR,并将 bundle 提交回 PR:
- uses: daneb/keel/runtime@v0.10.1
with:
spec: rate-limit
image: rust:1-bookworm # 你的工具链
此模式下,GitHub runner 持有证据链并从外部对容器进行 attestation,keel 在 gVisor 容器内门控 PR,最后将 bundle 提交回去。
检索命令:Retrieve, Don’t Read
keel 的核心理念之一是 “Retrieve, don’t read”——不要读整个文件,而是精准检索所需信息。以下命令都基于符号索引:
keel outline# 文件的结构大纲 keel symbol # 查找符号 keel source # 获取源码片段 keel refs # 查找引用 keel importers # 查找谁导入了这个模块 keel blast 'src/api/**' # 这个变更会影响什么? keel slice T-1 # 获取一个任务所需的全部上下文(预算适配) keel bench # 测量 token 节省量(vs 读取整个文件) keel mcp # 通过 MCP 协议暴露相同查询(stdio)
关键设计:索引是加速器而非依赖项。如果索引缺失、过期或语法不支持,所有查询会自动降级到 ripgrep,并明确告知。这防止了 Agent 在降级时自信地给出错误答案。
证据与学习系统
重放与运行管理
keel replay# 重放一次运行 keel runs # 列出所有运行 keel runs --prune # 清理旧运行 keel report [slug] # 查看一个 feature 的完整生命周期 keel serve # 浏览器只读视图(loopback)
学习闭环
keel learn # 从运行中学习 keel failures # 查看失败分类 keel lessons # 查看所有 lessons keel lesson promote# 提升 lesson keel lesson reject # 拒绝 lesson keel lesson demote # 降级 lesson
当同一个失败模式在不同运行中出现两次时,可以将其提升为一个 lesson。一旦 lesson 拥有 oracle,它会编译为 G2 检查(携带 from: L-nnnn),不再注入上下文——因为如果一个规则不能被违反,就不需要每次提醒。
指标与 Ratchet
keel metrics # 通过率、失败分类、token 用量、gate theatre keel ratchet # 只能改善不能退化的指标
扩展机制
keel 通过三个 JSON 子进程契约扩展,所有语言无关:
| 扩展类型 | 输入/输出 | 添加方式 |
|---|---|---|
| Gate Check | stdout 打印 Check | [[gate.G2.check]] in keel.toml |
| Agent Driver | keel.drivertask/1 in → keel.driverresult/1 out | ~40 行适配器 + [[driver]] |
| Reviewer | keel.reviewrequest/1 in → keel.reviewresult/1 out | [[review]] 条目 |
| Shared Store | 另一个 repo 的 .keel/store | [[shared]] 路径或 submodule |
keel driver check 会在一个 scratch repository 中运行任意 driver 的 conformance probes,绝不在你的主工作树上执行。
keel 与 moor:协作关系
keel 有一个配套工具 moor,用于在本地机器上运行 Agent:
- keel 决定什么被允许、检查工作、保持记录
- moor 决定 Agent 在哪里运行:密封的 Docker 沙箱,无 host mounts,egress allowlist
moor 从沙箱外部写入 keel 的记录,因此 Agent 无法篡改记录。两者独立工作,但设计上为协作而构建。
适用场景与注意事项
适合的场景:
- 生产级项目中需要严格的质量门控
- 多 Agent 协作场景(不同 Agent 共享同一 store)
- 需要审计跟踪的团队环境
- 对 AI 生成的代码有合规要求的项目
注意事项:
- keel 不替代 Agent,而是治理 Agent。你需要同时运行 Claude Code/Codex 等工具
- 首次
keel init需要几分钟构建索引(取决于代码库大小) - CI 集成需要配置
contents: write权限(runtime 模式) - 当前仅支持 macOS 和 Linux,Windows 支持尚未实现