dexmaddy/ai-agent-harness
GitHub: dexmaddy/ai-agent-harness
基于 hook 的 AI 编码 agent 会话管控框架,通过结构性拦截机制强制执行启动加载、漂移检测、信息整合与自我验证,解决 agent 会话中的规则漂移和上下文浪费问题。
Stars: 1 | Forks: 1
# AI Agent 框架
一个基于 hook 的框架,让 AI 编码 agent 的会话更加可靠——
从启动、工作到关闭。通过拦截机制进行结构性强制执行,
而不是靠提醒式的建议。
## 问题所在
如果没有框架,AI agent 的会通常会面临六个问题:
1. **上下文浪费** —— 每次会话都加载所有内容,会在当前任务不需要的规则上消耗大量 token。
2. **规则漂移** —— 事实、计数和引用会在不知不觉中失效。
直到违反了某项规则才会被发现。
3. **启动混乱** —— 指令写着“阅读这些文件”,但没有任何
强制措施。agent 会跳过文件,或者在规则加载完成前就开始工作。
4. **信息分散** —— 学到的知识和决策累积在
对话和随机文件中。会话结束后,它们就丢失了。
5. **会话失忆** —— 每个新会话都从零开始。agent 不
知道上次做了什么,或者下一步该做什么。
6. **未经证实的完成** —— agent 说“完成了”,但修复未经测试,
代码未提交,或者配置未经验证。
AI Agent 框架解决了所有这六个问题:
- **分层加载** —— 按需加载,其余延迟加载 (1, 2)
- **结构性拦截** —— 在上下文加载完成前阻止工具调用 (3)
- **漂移检测** —— 捕获过时的引用,自动修复安全项 (2)
- **Rule Zero** —— 在编辑时将分散的信息路由到整合的文件中 (4)
- **会话连续性** —— 持久的待办列表和会话交接 (5)
- **自我验证** —— 在工作得到验证(而不仅仅是口头叙述)前阻止退出 (6)
## 架构概述
五个 hook 点协同工作:
```
graph TD
A[SessionStart] -->|generates| B[manifest.json + sentinel.json]
B --> C{UserPromptSubmit}
C -->|tier1 incomplete| D[Inject 'read files first']
C -->|tier1 complete| E[Track prompt count + warn at thresholds]
F{PreToolUse} -->|tool = Read| G[Track file read + allow]
F -->|tier1 incomplete| H[BLOCK tool]
F -->|tier1 complete| I{Tier 2 keyword?}
I -->|yes| J[BLOCK: read tier2 file first]
I -->|no| K[ALLOW tool]
K --> O{PostToolUse}
O --> O1[Rule Zero enforcement]
O --> O2[Edit tracking]
O --> O3[Save reminders]
L{Stop} -->|repos dirty| M[Exit 2 = retry]
L -->|all clean| N[Exit 0 = allow]
style A fill:#4a90d9,color:#fff
style H fill:#d9534f,color:#fff
style J fill:#f0ad4e,color:#fff
style K fill:#5cb85c,color:#fff
style N fill:#5cb85c,color:#fff
```
**Manifest** (`manifest.json`) —— 列出所有 tier1/tier2 文件及其路径、大小
和触发关键字。每次会话都会重新生成。
**Sentinel** (`startup-complete-{session}.json`) —— 追踪 agent 已经
阅读了哪些文件,tier1 是否完成,以及是否运行了交叉检查。基于会话范围
防止并发或恢复的会话之间发生冲突。
## 快速开始 (Level 1)
最简单且有用的版本 —— manifest + tier1 加载,无拦截。
### 1. 安装
```
# 复制 hooks 到你的项目
mkdir -p .agent/hooks
cp hooks/on_session_start.py .agent/hooks/
cp hooks/validators.py .agent/hooks/
# 安装 dependency
pip install pyyaml
```
### 2. 创建你的配置
将 `config.example.yaml` 复制到你的项目根目录,并命名为 `startup-config.yaml`:
```
tiers:
tier1:
- name: project-rules
source: docs/rules.md
description: "Core project rules and conventions"
- name: infra-report
type: checks
description: "Infrastructure health"
checks:
- name: git-clean
command: "git status --porcelain"
validator: empty_output
- name: tests-pass
command: "npm test --silent 2>&1 | tail -1"
validator: "contains:passing"
optional: true
gates:
block_until_tier1: false # Level 1: no blocking
```
### 3. 添加 hook
添加到你的 `.agent/settings.json`(或从 `examples/level-1-minimal/` 复制):
```
{
"hooks": {
"SessionStart": [{
"matcher": "",
"hooks": [{
"type": "command",
"command": "python3 .agent/hooks/on_session_start.py",
"timeout": 60000
}]
}]
}
}
```
### 4. 开启会话
agent 会在会话开始时看到此输出:
```
STARTUP: 2 OK, 0 FAIL
Manifest: /tmp/manifest-abc123.json
Tier 1: 2 files (45 lines)
ACTION REQUIRED: Read manifest, then read all Tier 1 files.
- /tmp/tier1-project-rules-abc123.md (30 lines, project-rules)
- /tmp/tier1-infra-report-abc123.md (15 lines, infra-report)
```
添加到你的项目指令中:
```
## 启动
Read the manifest from SessionStart hook output, then read all Tier 1 files
before responding to any user message.
```
## Level 2:添加拦截
Level 1 依赖于 agent 自愿阅读文件。Level 2 **强制执行** 此操作——
在所有 tier1 文件加载完成之前,agent 不能使用除 Read 之外的任何工具。
### 变更内容
1. **PreToolUse 拦截** —— 阻止 Bash、Write、Edit、Agent 等,直到 tier1
完成。只允许使用 Read(以便 agent 可以加载文件)。
2. **UserPromptSubmit 拦截** —— 如果 tier1 未完成,则向 agent 的上下文中
注入“先读文件”的提示。同时追踪 prompt 数量并在达到阈值时发出警告。
### 安装
```
cp hooks/gate_check.py .agent/hooks/
cp hooks/on_prompt_submit.py .agent/hooks/
```
更新 `startup-config.yaml`:
```
gates:
block_until_tier1: true # NOW ENFORCED
prompt_health_warnings: [40, 60, 80]
```
从 `examples/level-2-gated/settings.json` 复制设置,或者将
PreToolUse 和 UserPromptSubmit hooks 添加到你现有的设置中。
### 工作原理
1. SessionStart 生成 tier1 文件 + 写入带有 `stage: "tier1_pending"` 的 sentinel
2. agent 尝试使用 Bash → PreToolUse 拦截读取 sentinel → tier1 未完成 → **DENIED**
3. agent 阅读 tier1 文件 → gate_check 在 sentinel 中追踪每一次 Read
4. 所有 tier1 文件已读 → sentinel 更新为 `stage: "complete"`
5. agent 再次尝试 Bash → 拦截检查 sentinel → tier1 完成 → **ALLOWED**
**Git commit 直通:** `git commit` 和 `git push` 在 `tier1_pending` 状态下也会被
自动允许,因此版本控制永远不会被阻断。
UserPromptSubmit hook 增加了第二层防护:如果 agent 以某种方式忽略了
PreToolUse 的拒绝,prompt 拦截会注入一条消息“先读文件”,
agent 在编写回复之前会看到这条消息。
## Level 3:按需加载 Tier 2
并非每次会话都需要所有规则。Tier 2 文件**仅在 agent 的工具调用中出现相关
关键字时**才会加载。
### 变更内容
在你的配置中添加带有触发关键字的 tier2 定义:
```
tiers:
tier2:
- name: api-rules
triggers: ["api", "endpoint", "REST", "swagger"]
source: docs/api-rules.md
- name: deploy-guide
triggers: ["deploy", "CI", "pipeline", "release"]
source: docs/deploy-guide.md
```
### 工作原理
1. agent 运行 `Bash("curl api.example.com/...")`
2. PreToolUse 拦截扫描命令文本以查找 tier2 触发器
3. 发现 "api" 匹配 `api-rules` 触发器 → **DENIES** 并附带消息:
"Tier 2 files triggered — read before proceeding: api-rules"
4. agent 阅读该文件 → 拦截对其进行追踪 → 允许下一次工具调用
**关键字扫描具有限制**,以防止误报:
- 仅扫描特定的 JSON 字段(command、file_path、prompt、description)
- 仅扫描每个字段的前 N 个字符(默认:120)
- 不区分大小写的匹配
### 交叉检查漂移检测
在 tier1 加载后,运行一次漂移检查,比较预期与实际状态。
这能在过时的引用引发问题之前捕获它们。
添加一个检查项目不变量的脚本:
```
# 示例:验证 docs 中的 rule 数量与实际数量匹配
expected = manifest["expected_counts"]["rules"]
actual = len(list(Path("rules/").glob("*.md")))
if expected != actual:
print(f"DRIFT: rules count {expected} in manifest vs {actual} on disk")
```
交叉检查每次会话运行一次(由 sentinel 中的 `cross_check_done` 追踪)。
## Level 4:完整架构
### 停止 Hook
在清理完成前阻止会话退出:
```
cp hooks/on_stop.py .agent/hooks/
```
```
stop:
require_clean_repos: true
require_transcript: false
max_retries: 8
shutdown_steps: # configurable checks before exit
- name: lint-clean
command: "npm run lint 2>&1 | tail -1"
validator: "contains:no errors"
fail_message: "Linter has errors"
```
当检查失败时,stop hook 返回退出代码 2(重试)。agent 会看到
失败消息并可以修复问题(例如,提交未提交的文件)。在达到最大
重试次数后,它会正常退出,以避免困住用户。
`shutdown_steps` 是可配置的 —— 使用与启动检查相同的验证器注册表
定义任意数量的自定义检查。每个失败的步骤都会触发
重试,让 agent 在退出前有机会修复问题。
### 基于输出的验证器
Shell 退出代码会骗人。像 `git status | grep -v node_modules` 这样的管道命令
即使有未提交的文件也会返回 0(因为 grep 执行成功了)。
验证器注册表会解析 stdout 作为替代方案:
| Validator | 通过条件 |
|-----------|-------------|
| `empty_output` | stdout 为空(仅包含空白字符) |
| `not_empty` | stdout 有内容 |
| `contains:text` | stdout 包含文本(不区分大小写) |
| `equals:text` | stdout 完全等于文本(去除首尾空白) |
| `regex:pattern` | regex 在 stdout 的任意位置匹配 |
通过扩展 `validators.py` 添加自定义验证器:
```
VALIDATORS["my_check"] = lambda stdout: (
int(stdout.strip()) > 0,
stdout.strip()
)
```
### 会话范围隔离
所有临时文件都包含会话 ID 后缀(`-{SESSION_ID}`)。这可以防止:
- 并发会话互相覆盖状态
- 恢复的会话读取上一次运行的陈旧 sentinel
- 多个 AI 编码 agent 实例之间的竞态条件
## 自定义检查清单
在将其适配到你的项目时:
- [ ] **Tier 1 文件** —— agent 必须始终遵守哪些规则/上下文?总数控制在约 1500 行以内
- [ ] **Tier 2 文件** —— 哪些内容仅偶尔需要?选择足够具体的触发关键字以避免误报
- [ ] **基础设施检查** —— 在启动时应验证什么?(DB 健康、git clean、测试通过、服务运行)
- [ ] **验证器** —— 是否有任何检查需要自定义 stdout 解析?
- [ ] **Prompt 阈值** —— 在什么 prompt 数量下,agent 应该警告上下文健康状况?
- [ ] **Stop 检查** —— 会话退出前必须做什么?(提交、保存记录、同步文件)
- [ ] **文件路径** —— 更新 `startup-config.yaml` 源以指向你的实际文件
## 经验教训
这些见解是在数十次会话中构建和迭代该系统时得出的:
1. **记录不等于执行。** 在 CLAUDE.md 中写下“agent 在启动时必须阅读 X”并不能保证它会执行。结构性强制执行(拦截工具调用的 hooks)是唯一可靠的机制。如果没有强制执行,它就是可选的。
2. **退出代码会骗人。** 带有管道、`||`、子shell 和错误掩码的 Shell 命令在不应返回 0 的时候返回了 0。使用验证器解析 stdout,而不是信任 `$?`。
3. **一切皆需会话范围。** 没有会话 ID 的临时文件在会话恢复或并发运行时会导致神秘的失败。始终添加会话 ID 作为后缀。
4. **明智地分层。** tier1 和 tier2 的划分应基于*使用频率*,而不是*重要性*。仅在处理 API 工作时才起作用的关键 API 规则属于带有 "api" 触发器的 tier2 —— 而不是放在 tier1 中浪费每次会话的 token。
5. **限制你的循环。** 交叉检查漂移检测必须是有边界的(最多 2 遍,然后继续)。无限制的自我修复循环在修复产生新漂移时可能会陷入死循环。修复安全的部分,记录其余部分,继续前进。
6. **要拦截,不要唠叨。** 写着“请先阅读 X”的书面指令只是一种建议。返回 `permissionDecision: "deny"` 的 PreToolUse hook 才是拦截。拦截有效。建议无效。
7. **追踪读取,而不是意图。** sentinel 追踪 agent *实际阅读了*哪些文件(通过 Read 工具路径匹配),而不是*被告知*要阅读哪些文件。这缩小了“我加载了规则”与“规则在我的上下文中”之间的差距。
8. **推理越多 = 忠实度越低。** 给予 LLM 更多的思考时间会使摘要对信息源的忠实度*降低* (r = -0.685)。将推理用于验证,永远不要用于生成。参见 `docs/rules/anti-hallucination-rules.md`。
## 反幻觉规则
`docs/rules/` 目录包含一个经过研究支持的、由 14 项认知
规则组成的框架,用于减少 LLM 生成摘要中的幻觉。这些规则是
通用的 —— 它们适用于任何摘要任务,而不仅仅是某个特定领域。
这些规则被组织成 5 个阶段(READ → WRITE → VERIFY PASS 1 →
VERIFY PASS 2 → SIGN-OFF),因为 LLM 会跳过平面
列表中间的规则(U 型注意力偏差)。每条规则都引用了经过同行评审的研究。
要使用它们,请将 `docs/rules/anti-hallucination-rules.md` 作为 Tier 1 文件包含在你的
配置中:
```
tiers:
tier1:
- name: ah-rules
source: docs/rules/anti-hallucination-rules.md
description: "Anti-hallucination rules for faithful summaries"
```
或者在生成摘要时在你的 LLM prompt 中直接引用它们。
## 幻灯片
下载配套的可视化幻灯片,一目了然地了解架构:
- **[PDF](slides/Structural_AI_Agent_Enforcement.pdf)** —— 10 页幻灯片,涵盖问题、5-hook 引擎、分层策略和全部 4 个等级
将这些幻灯片与课程结合使用,或作为团队的独立概述。
## 入门指南
### 快速设置(2 分钟)
克隆代码库并运行交互式向导:
```
git clone https://github.com/dexmaddy/ai-agent-harness.git
cd ai-agent-harness
python3 setup.py
```
向导将引导你完成:
1. **平台** —— Claude Code、Cursor、Windsurf、Aider 或自定义 agent
2. **数据存储** —— YAML/JSON 文件、SQLite 或 PostgreSQL
3. **等级** —— 你想要多少强制执行力 (1-4)
4. **项目详情** —— 反幻觉规则、持久化待办列表
它会生成所有配置文件,复制正确的 hook 脚本,创建
示例规则,并将所有内容为你选择的平台连接好。
### 学习概念
**参加[课程](docs/course/README.md)** —— 8 个模块,约 2.5 小时,
逐步为你的项目构建一个完整的工作系统。
**参考文档:**
1. **[引导指南](docs/reference/bootstrapping-guide.md)** —— 在 15 分钟内创建你的前 5 条规则,
包含用于 Web 应用、数据管道和基础设施的入门套件
2. **[规则演进模板](docs/reference/rule-evolution-template.md)** —— 将失败转化为结构性强制的模式:
失败 → 学习 → 规则 → 审计 → hook
3. **[冒烟测试](tests/smoke_test.py)** —— 验证你的设置是否能够端到端运行:
`python3/smoke_test.py --verbose`
## 文件结构
```
ai-agent-harness/
├── setup.py # Interactive setup wizard
├── README.md # This guide
├── mkdocs.yml # Website config (MkDocs Material)
├── config.example.yaml # Template config
├── settings.example.json # Hook configuration template
├── hooks/ # Hook scripts (copy to your project)
│ ├── on_session_start.py # Method A: YAML → manifest
│ ├── on_session_start_db.py # Method B: SQLite → manifest
│ ├── gate_check.py # PreToolUse gate
│ ├── on_prompt_submit.py # UserPromptSubmit gate
│ ├── on_stop.py # Stop hook with retries
│ ├── on_edit.py # PostToolUse actions
│ ├── cross_check.py # Drift detection
│ ├── audit.py # Standalone audit runner
│ └── validators.py # Output-based validators
├── checks/ # Sample audit check library
│ └── audit-checks.yaml # 10 generic checks
├── docs/ # Website content
│ ├── index.md # Home page
│ ├── course/ # 8-module course
│ │ ├── README.md # Course overview
│ │ └── module-1 through module-8 # Course modules
│ ├── reference/ # Guides, templates, patterns
│ │ ├── setup-wizard.md # Wizard docs
│ │ ├── bootstrapping-guide.md # First 5 rules
│ │ ├── rule-evolution-template.md # Failure → rule → hook
│ │ ├── rule-zero.md # Every edit triggers categorization
│ │ ├── self-healing-loop.md # Bidirectional rule-audit feedback
│ │ ├── self-verification.md # 4-point completion check
│ │ ├── audit-runner.md # On-demand audit checks
│ │ └── session-continuity.md # Persistent backlog
│ └── rules/ # Reusable rule frameworks
│ └── anti-hallucination-rules.md # 14 research-backed rules
├── slides/ # Visual companion
│ └── Structural_AI_Agent_Enforcement.pdf
├── tests/
│ └── smoke_test.py # 18-check verification
├── examples/
│ ├── level-1-minimal/settings.json # Just SessionStart
│ ├── level-2-gated/settings.json # + PreToolUse + UserPromptSubmit
│ └── level-4-full/settings.json # All 4 hooks
└── LICENSE # MIT
```
## 数据源:优先使用文件,进阶时使用数据库
本项目默认使用 **YAML 配置 + markdown 规则文件**。无需数据库
即可开始使用。这是刻意为之 —— 对于大多数用户来说,平面文件是
正确的选择。
**当文件适用时(约 50 条规则以内):**
- 可使用任何文本编辑器进行编辑,无需 CLI
- 免费获得完整的 git 历史
- 易于阅读、审查和新团队成员入职
- 除了 PyYAML 之外没有其他依赖项
**何时进阶到数据库(约 50 条规则以上):**
| 痛点信号 | 发生了什么 | 数据库解决方案 |
|-------------|-----------------|-------------|
| "哪些规则引用了事实 X?" | 交叉引用需要扫描每个文件 | 一次 JOIN 查询 |
| 漂移检测很脆弱 | `find + wc -l` 管道在边缘情况会失效 | `SELECT COUNT(*)` 是原子操作 |
| 并发的 agent 会话破坏状态 | 两个 agent 同时编辑同一个 YAML | SQLite WAL 模式处理并发写入 |
| 规则搜索缓慢 | Grep 20 多个文件才能找到一个类别 | 按 category/trigger 进行索引查询 |
| 无法追踪规则何时添加/更改 | Git log 有效但粒度太粗 | `created_at`、`updated_at` 列 |
**推荐的进阶路径:**
1. 从 YAML 开始(本项目的默认设置)
2. 注意上述痛点信号
3. 当它们出现时,迁移到 SQLite(单文件,无需服务器,Python 标准库)
4. 构建一个轻量级的 CLI 包装器,这样你就不需要直接编写原始 SQL
推荐使用 SQLite 而不是 Postgres/MySQL,因为它是嵌入式的(无需服务器),
数据库是一个可移植的单文件(与 YAML 相同),并且它随 Python 一起提供。
LangChain 和 CrewAI 都使用 SQLite 来实现持久的 agent 状态。
## 平台兼容性
**概念**(分层加载、拦截、漂移检测、反幻觉
规则)适用于任何 AI agent 系统。**参考实现**使用
Claude Code 的 hooks API,但这些模式可以适配任何具有生命周期事件的平台。
| 平台 | 如何适配 |
|----------|-------------|
| **Claude Code** | 直接使用 —— hooks 直接映射到 SessionStart、PreToolUse 等。 |
| **Cursor** | 使用 `.cursor/rules/` 作为 tier1 规则,`@rules` 作为 tier2。通过自定义命令进行拦截。 |
| **Windsurf** | 使用 `.windsurfrules` 作为规则,使用 Cascade memories 追踪 tier 状态。 |
| **Aider** | 使用 `.aider.conf.yml` 约定 + `--read` 标志在启动时加载 tier1。 |
| **Continue.dev** | 使用 `.continuerc.json` 上下文提供程序进行分层规则加载。 |
| **自定义 agent** | 在你的 agent 循环中将 hook 模式实现为中间件 —— 在工具执行前检查状态。 |
| **LangChain/CrewAI** | 添加一个加载规则的启动节点/任务,以及一个在工具使用前检查 sentinel 的 gate 回调。 |
**核心模式与框架无关:**
1. **会话工作前:** 加载必要的上下文 (tier1)
2. **每次工具调用前:** 验证上下文已加载,触发按需加载 (tier2)
3. **每次修改后:** 同步状态,检查是否存在漂移
4. **会话结束前:** 验证清理工作
## 两种部署方式
| | 方式 A:YAML 配置 | 方式 B:SQLite 数据库 |
|---|---|---|
| **脚本** | `on_session_start.py` | `on_session_start_db.py` |
| **规则存储于** | 磁盘上的 Markdown 文件 | SQLite 中的 `rules` 表 |
| **Backlog** | `backlog.json` | `backlog` 表 |
| **会话交接** | JSON 文件 | `session_summaries` 表 |
| **配置** | `startup-config.yaml` | `config` 表 |
| **依赖项** | PyYAML | 无(sqlite3 是 Python 标准库) |
| **最适合** | 约 50 条规则以内,单用户 | 50 条以上规则,交叉引用,并发会话 |
| **设置** | 复制配置,编写 markdown 文件 | `python3 hooks/on_session_start_db.py --init-db project.db` |
### 数据库模式特性
设置 `AGENT_DB_PATH` 后,方式 B(SQLite/PostgreSQL)可启用额外功能:
- **编辑日志** —— 每次 Write/Edit 都记录在 `rule_log` 表中 (`on_edit.py`)
- **会话摘要强制执行** —— `on_stop.py` 要求在退出前有 `session_summaries` 行
- **陈旧事实检测** —— 当 `system_facts` 或 `fact_references` 陈旧时,`gate_check.py` 会发出警告
这些使用了三个额外的表:`rule_log`、`system_facts`、`fact_references`。
从方式 A 开始。当你遇到数据源指南中描述的
[痛点信号](docs/session-continuity.md#why-sqlite-over-json)时,
进阶到方式 B。
## 环境要求
- Python 3.10+
- 方式 A:PyYAML (`pip install pyyaml`)
- 方式 B:无额外依赖(sqlite3 在 Python 标准库中)
- 支持 hook/中间件的 AI 编码 agent(Claude Code、Cursor、Windsurf、Aider 或自定义 agent)
## 许可证
MIT —— 随意使用、改编并分享。
标签:AI代理, Homebrew安装, 人工智能, 可靠性工程, 工作流自动化, 开发框架, 用户模式Hook绕过, 逆向工具, 防幻觉