【免费下载链接】learn-harness-engineering
Harness engineering beginner tutorial, from 0 to 1
导读:本讲聚焦 AI Agent 工程化中最常见的反模式——「巨型指令文件」(giant instruction file)。当
AGENTS.md从 50 行膨胀到 600 行,Agent 的上下文预算被无关指令吞噬、关键安全约束被埋在文件中部而失效。你将掌握指令信噪比(SNR)、Lost in the Middle 效应、渐进式披露(Reveal on Demand)等核心概念,并学会用「50–200 行入口文件 + 按主题拆分的话题文档」架构重构指令体系。文中全部方案均在 learn-harness-engineering 仓库中有可直接运行或直接对照的示例代码与真实项目文件。
一、问题场景:你的指令文件正在“膨胀式失败”
假设你已经认真对待了 Harness 工程——创建了AGENTS.md,并把能想到的每一条规则、约束、经验教训都塞了进去。一个月后文件膨胀到 300 行,两个月 450 行,三个月 600 行。然后你发现 Agent 的表现反而在变差:
- 修一个简单的 bug,Agent 却烧掉大量上下文去处理无关的部署指令;
- 一条写在第 300 行的安全硬约束(例如「所有数据库查询必须使用参数化查询」)被直接无视;
- 三条互相矛盾的代码风格规则,导致 Agent 每次随机挑一条执行。
这就是「巨型指令文件陷阱」:每条指令单独看都有用,于是你全塞进去;结果为了找到某一条规则,Agent 必须翻遍整个文件。你写了 600 行,但对当前任务真正相关的可能只有三分之一。
根部的恶性循环
最常见的恶性循环是:
- Agent 犯了某个错误 → 你决定「加一条规则防止再犯」;
- 把规则加进
AGENTS.md,短期有效; - Agent 又犯了另一个错误 → 再加一条规则;
- 循环往复,直到文件失控膨胀。
「出问题就加规则」是再自然不过的反应,但累积效应是灾难性的。下面逐一拆解它到底错在哪里。
二、为什么单个大文件必然失败:五大失效机制
1. 上下文预算被吃光
Agent 的上下文窗口是有限的。以 200K token 窗口(Claude 的标准配置)为例:一份膨胀的指令文件可能就要消耗 10K–20K token,看似还剩很多余量,但一个复杂任务往往需要读取几十个源文件,工具执行输出同样占用上下文,对话历史还在不断累积。等到 Agent 真正需要理解代码时,预算早已耗尽。
2. Lost in the Middle:信息淹没在长文本中部
「Lost in the Middle」研究(Liu et al., 2023)已经明确证明:LLM 对长文本中部信息的利用效率,显著低于开头和结尾。你的AGENTS.md有 600 行,第 300 行写着「所有数据库查询必须使用参数化查询」——这是一条安全硬约束,但它埋在文件中部,Agent 几乎必然忽略它。
3. 优先级冲突:硬约束与软建议无法区分
文件把三类指令混在一起:
- 不可妥协的硬约束(如「永远不要使用
eval()」); - 重要的设计准则(如「优先使用函数式风格」);
- 具体的历史经验(如「上周修过一个 WebSocket 内存泄漏,注意类似模式」)。
这三类指令的重要性完全不同,但在文件里看起来一模一样。Agent 没有任何可靠信号去区分哪条是红线、哪条只是建议。
4. 维护衰退:文件只增不减
大文件天然难以维护。过时的指令很少被删除——因为删除的后果不确定(「也许别的规则依赖它?」),而新增指令感觉零成本。结果是文件只增长、不收缩,信噪比持续下降。这与软件中的技术债积累是同一个问题。
5. 矛盾累积
不同时期加入的指令开始互相冲突——一条说「使用 TypeScript strict mode」,另一条说「部分遗留文件允许使用any」。Agent 每次随机选一条执行。
三、核心概念速查
| 概念 | 定义与要点 |
|---|---|
| Instruction Bloat(指令膨胀) | 指令文件占上下文窗口 10–15% 时,开始挤占代码阅读与任务推理的预算。一份 600 行的AGENTS.md可能消耗 10,000–20,000 token——即 128K 窗口的 8–15%。 |
| Lost in the Middle | 长文本中部的信息容易被忽略。Liu et al. 2023 年的研究表明,LLM 对长文本中间信息的利用效率显著低于两端。600 行文件里埋在第 300 行的关键约束,被忽略的概率非常高。 |
| Instruction SNR(指令信噪比) | 文件中与当前任务相关的指令占比。修 bug 时被迫读 50 行部署指令——这就是低 SNR。 |
| Entry File(入口文件) | 一个简短入口文件,作用是引导 Agent 去读更详细的文档,而不是自己装下一切。50–200 行足够。 |
| Reveal on Demand(按需披露) | 先给概览信息,需要时再给详细信息。好的 Harness 设计就像好的 UI 设计——不要把全部选项一次性砸给用户。 |
| Can't Tell What Matters(无法判断轻重) | 当所有指令以相同的格式和位置出现时,Agent 无法区分不可妥协的硬约束与建议性的软准则。 |
四、指令架构对比:单体文件 vs 拆分布局
原讲义的架构图可用文字还原如下。
单体文件路线:
一个巨大的 AGENTS.md └─ 即使是小 bug 修复,也要读完全部部署规则和旧笔记 └─ 关键规则埋在文件中部,极易被漏掉拆分入口路线:
短小的 AGENTS.md(路由器) └─ 只有当本任务需要时,才读取 API / 数据库 / 测试文档 └─ 把更多上下文留给代码阅读与验证位置效应(针对 600 行单体文件):
- 顶部(quick start + 硬约束)→ 高召回概率;
- 中部(第 300 行的安全规则)→ 高概率被稀释或忽略;
- 底部(明确的收尾检查清单)→ 高召回概率。
五、如何拆分:入口文件 + 话题文档
核心原则
高频信息放在手边,低频信息收进抽屉,永远用不上的别带。
入口文件AGENTS.md:保持 50–200 行
只包含最必要的内容:
- 项目概览:一两句话讲清这是什么项目;
- 首次运行命令:如
make setup && make test; - 全局硬约束:不超过 15 条不可妥协的规则;
- 话题文档链接:一行描述 + 适用条件。
原讲义的示例模板:
# AGENTS.md ## Project Overview Python 3.11 FastAPI backend, PostgreSQL 15 database. ## Quick Start - Install: `make setup` - Test: `make test` - Full verification: `make check` ## Hard Constraints - All APIs must use OAuth 2.0 authentication - All database queries must use SQLAlchemy 2.0 syntax - All PRs must pass pytest + mypy --strict + ruff check ## Topic Docs - API Design Patterns (`docs/api-patterns.md`) — Required reading when adding endpoints - Database Rules (`docs/database-rules.md`) — Required when modifying database operations - Testing Standards (`docs/testing-standards.md`) — Reference when writing tests话题文档:每个 50–150 行
按主题组织,放在docs/目录或对应模块旁边。Agent 只在需要时读取。可以类比行李箱的收纳袋——内裤一格、洗漱用品一格、充电器一格;找东西时不需要把整个包倒空。
适合直接放进代码的信息
类型定义、接口注释、配置文件中的说明,Agent 读代码时自然会看到,不需要在指令里重复。
每条指令的生命周期管理
每条指令都应记录:
- 来源(「为什么加这条规则?」);
- 适用条件(「什么时候需要这条规则?」);
- 过期条件(「什么情况下可以删除这条规则?」)。
定期审计,删除过时、冗余、矛盾的内容。管理指令要像管理代码依赖一样——未使用的依赖应当移除,否则只会拖慢系统。
位置效应的正确利用
如果某条指令必须留在入口文件里,放在顶部或底部,永远不要放中部。「Lost in the Middle」告诉我们,LLM 对长文本两端信息的利用远好于中部。但更优的做法是把指令移入话题文档,实现按需加载。
行业共识
OpenAI 与 Anthropic 都认可这种拆分方式:OpenAI 认为入口文件应当「简短且路由导向」,Anthropic 认为面向长时运行 Agent 的控制信息应当「简洁且高优先级」。两者的意思相同——不要把一切都塞进单个文件。
六、仓库中的真实示例:本仓库自己就是拆分的范本
精简入口文件示例
讲义配套代码目录提供了可直接对照的极简入口文件:code/AGENTS-short.md,全文只有「Start Here」(读哪些文档、如何启动与校验)和三条 Hard Rules(不改层边界、不标完成不验证、给下个会话留干净状态),约 15 行——远低于 200 行上限,但足以让 Agent 起步。
反模式清单
code/anti-patterns.md 给出了五条反面清单,可作为自查工具:
- 把全部仓库知识塞进一个文件;
- 在多个地方重复同一条规则;
- 编码了没人审计的过时规则;
- 写出具体到几乎不生效的条件指令;
- 把长篇工具手册嵌入启动上下文。
可量化的对比模拟
code/split-vs-monolithic.ts 是一个可运行的模拟脚本:它生成一份约 200 行的单体指令文件(Project Overview / Code Style / Testing / Deployment 四个区段各 50 行),再拆成 4 个聚焦文件,然后模拟 Agent 搜索特定规则时各读取了多少行。
# 运行方式(工作目录:仓库根目录) npx tsx docs/en/lectures/lecture-04-why-one-giant-instruction-file-fails/code/split-vs-monolithic.ts从源码结构看,脚本的核心逻辑是两种搜索策略的对比:
searchMonolithic()从文件顶部逐行扫描直到命中规则,最坏情况要读全部 200 行;searchSplit()根据查询所属区段直接定位到对应文件(如03-testing.md),只读那 50 行。
四条模拟查询(返回类型规则、部署窗口规则、集成测试规则、测试文件结构规则)在两种策略下的平均行数差即为「节省」比例。脚本输出的 KEY INSIGHT 一句话点明了结论:单体文件下每次查询都要扫描最多 200 行,拆分后只需读取相关的 50 行文件——上下文占用更少、幻觉更少、执行更快。
真实项目中的入口文件:project-02 solution
配套实践项目 Project 02: Agent-Readable Workspace 的解决方案目录中,projects/project-02/solution/AGENTS.md 是一个现实世界里的「路由器」入口文件。它没有堆砌细节,而是:
- Startup Rules:规定写代码前按顺序完成 5 个动作(读本文件 → 读
docs/ARCHITECTURE.md→ 读docs/PRODUCT.md→ 跑npm install && npm run check→ 读feature_list.json); - Docs Hierarchy:只用 5 行说明
docs/下两个文档各自负责什么,把细节留给话题文档; - Electron Layer Boundaries:四个层的职责各用 3–4 行概括,详细约束指向
docs/ARCHITECTURE.md; - Conventions + Definition of Done + Session Handoff:收尾清单与交接约定放在底部(利用位置效应)。
对比项目 01 的入口文件 projects/project-01/solution/AGENTS.md 可以看到演进:project-01 的版本更长、把层边界细节直接写进了入口;project-02 则把细节下推到docs/,入口变得更短、更路由化。从仓库结构看,project-02 的 starter 目录同样保留了简短的 projects/project-02/starter/AGENTS.md,用于对照「薄 workspace」与「厚 workspace」下第二次会话的重新发现成本。
支撑入口文件的话题文档示例可见 projects/project-02/solution/docs/ARCHITECTURE.md:它完整描述了层架构图、preload 暴露的window.knowledgeBase类型化 API、导入流程的 11 步 IPC 调用链与数据存储目录结构——这些内容若全部塞进入口文件,就是典型的膨胀。
此外,仓库根目录的 CLAUDE.md 本身也是同样的拆分实践:项目概览、命令、仓库结构、架构、关键模式各占一小节,共约 60 行,细节全部由「阅读对应目录」的指引替代。
七、真实案例:SaaS 团队的拆分重构
某 SaaS 团队的AGENTS.md从 50 行膨胀到 600 行,混入了技术栈版本、编码标准、历史 bug 修复笔记、API 使用指南、部署流程、团队成员的个人偏好——什么都有,但找到与当前任务相关的部分如同大海捞针。
Agent 表现明显下滑:修简单 bug 时消耗大量上下文处理无关部署指令;第 300 行的安全约束「所有数据库查询必须使用参数化查询」频繁被忽略;三条互相矛盾的代码风格规则导致随机选择。
团队执行了拆分重构:
AGENTS.md精简到 80 行:只保留项目概览、运行命令、15 条全局硬约束;- 创建话题文档:
docs/api-patterns.md(120 行)、docs/database-rules.md(60 行)、docs/testing-standards.md(80 行); - 在入口文件中加入话题文档链接;
- 历史笔记要么转化为测试用例,要么直接删除。
重构后:同一任务集的成功率从 45% 提升到 72%;安全约束合规率从 60% 提升到 95%——因为规则从文件中部移到了入口文件顶部,不再「Lost in the Middle」。
八、关键要点
- 「加一条规则」是短期的止痛药、长期的毒药。加任何规则前,先想清楚它是否该进话题文档。
- 入口文件是路由器,不是百科全书。50–200 行:只放概览、硬约束与链接。
- 善用 Lost in the Middle 效应:重要信息放顶部或底部,次要内容移入话题文档。
- 像治理技术债一样治理指令膨胀:定期审计,每条指令都要有来源、适用条件、过期条件。
- 拆分后 SNR 提升,Agent 把更多上下文预算花在真实任务上,而不是处理无关指令。
九、动手练习
练习 1:SNR 审计。取出你当前的入口指令文件,列出所有指令条目;挑 5 种常见任务类型,逐一标记每条指令是否与该任务相关,计算每种任务的 SNR。对大多数任务都是噪音的指令,应移入话题文档。
练习 2:按需披露重构。如果你有超过 300 行的指令文件,把它拆成:(a) 小于 100 行的入口文件,(b) 3–5 个话题文档。重构前后运行同一组任务(至少 5 个),对比成功率。可参照 docs/en/projects/project-02-agent-readable-workspace/index.md 中 starter 与 solution 的对照实验设计。
练习 3:Lost in the Middle 验证。在一份长指令文件中,分别把一条关键约束放在顶部、中部、底部,每个位置至少运行 5 次同一任务集,观察合规率差异。位置效应的强度可能会让你吃惊。
十、延伸阅读
- OpenAI 官方文章《Harness Engineering》——入口文件「简短且路由导向」的观点来源;
- Anthropic 工程博客《Effective Harnesses for Long-Running Agents》——长时运行 Agent 控制信息「简洁且高优先级」的工程实践;
- 论文《Lost in the Middle: How Language Models Use Long Contexts》(Liu et al., 2023, arXiv 2307.03172)——本文所有位置效应结论的实证出处;
- HumanLayer 博客《Harness Engineering for Coding Agents》——面向编码 Agent 的 Harness 工程实践;
- Nielsen Norman Group 的 Progressive Disclosure 研究——「按需披露」设计原则的原始出处(好的 Harness 设计就是好的 UI 设计)。
【免费下载链接】learn-harness-engineering
Harness engineering beginner tutorial, from 0 to 1
相关推荐
为什么巨型 AGENTS.md 会让 Agent 失效:learn-harness-engineering 中的指令文件拆分工程
为什么巨型 AGENTS.md 会让 Agent 失效:learn harness engineering 中的指令文件拆分工程 本文是 learn harne
AGENTS.md 巨型指令文件为何失败:用 Progressive Disclosure 拆分指令路由(learn-harness-engineering 实战)
AGENTS.md 巨型指令文件为何失败:用 Progressive Disclosure 拆分指令路由(learn harness engineering 实
巨型指令文件为何让 Agent 失效:learn-harness-engineering 中的指令反模式与按需拆分实战
巨型指令文件为何让 Agent 失效:learn harness engineering 中的指令反模式与按需拆分实战 本篇技术指南围绕 learn harne
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考