AI编程经验总结:把能写代码变成可靠地写代码
- 2026-11-05 02:11:08
QUOTE
工具会过时,解决问题的思路不会变。
本文看点
01
概念底座:Agent与Harness
02
问题梳理:过度服务、自作聪明、隐藏假设、全局缺失
03
实践经验:加限制、先规划、用工具、工作流协作
00
CODE QUALITY
开篇:代码质量问题
当前AI编程技术发展迅速,但评价AI写出的代码有三个递进的问题:能不能写出来,写得快不快,写出来的东西敢不敢应用在产品上。
三个问题,技术瓶颈各不相同,当前模型的生成能力已经越过可用线,但是生成的代码最终能不能被合入主干,应用在产品上,还有以下几个问题要考虑解决:需求有没有写清楚、执行有没有偏离,结果有没有被独立校验。
前两个问题,换更强的模型、完善的上下文管理就能解决;第三个问题主要技术手段是外围机制,约束、验证、留痕,这些不会随模型升级自动出现。
这篇文章不评测工具,更多的是基于本人这几个月的实践经验整理的一些提高AI编程质量的经验总结:理解Agent和Harness,正确高效的使用Agent,单模块团队协作规范、工作流设计等。由于跨业务模块,企业部门协作的AI研发平台,要考虑各种研发平台扩展,不同业务领域接口,涉及到的范围更广和更复杂,本文不做扩展。
AI编程对于个人开发效率的提高是毋庸置疑的,单人几个月时间完成了过去需要几个人至少一年甚至更长时间的代码开发,而且还构建了一套完善的开发环境工具,模块代码单测平均覆盖率也可以达到90%以上。但是整体的代码质量,团队协作开发,还是要考虑很多方面:架构的合理性,开发标准规范化,代码功能验证手段,知识沉淀积累等。
01
AI AGENT
AI Agent:三个组件与一个循环

1.1 一个公式:LLM + 上下文 + 工具
现代Agent的最小工程实现可以写成一个公式:Agent = LLM + 上下文 + 工具。公式描述的是Agent边界之内的组成,不包含与之交互的环境。三个组件各有明确职责:
Agent与环境是闭环交互的两方:环境返回观察,Agent依据上下文选择行动,行动改变环境状态,新状态产生下一次观察。这划定了工程手段的作用位置:能改的是Agent这一侧的观察与行动接口,改不了环境本身的状态转移规律。
1.2 观察空间与动作空间:能力的主要杠杆
观察通道与动作接口共同构成Agent与外部世界的边界。由此得到一条对工程实践最重要的推论:
没有通过观察通道进入上下文的信息,对模型而言等同于不存在;
没有被动作接口允许的操作,模型即使知道该怎么做,也只能停留在文字建议上。
所以在底层模型固定时,提升任务表现最主要的手段是扩展观察空间与动作空间。许多看似需要更强模型才能解决的问题,实质是接口问题:把任务所需的数据纳入上下文,或把所需操作封装成工具,原本不可解的任务就可能变为可解。产品能力的演进多数可以还原为这两个空间的扩张。
1.3 ReAct循环与上下文的两段结构
Agent执行任务的核心模式是ReAct(Reasoning + Acting):模型先思考当前该做什么,再调用工具行动,然后观察返回结果并继续思考,循环直到不再产生工具调用。

每一次调用时,模型接收的完整上下文由两部分构成:
静态前缀包含系统提示词与工具定义,全程不变。轨迹是不断增长的动态消息历史,包含用户消息、模型回复与工具执行结果。
trajectory = [user_request]repeat:context = stable_prefix + trajectorydecision = Model(context)trajectory.append(decision)if decision has no tool call:return decision.answerfor call in decision.tool_calls: # 无依赖的调用可并行validated_call = Harness.validate(call)observation = Environment.execute(validated_call)trajectory.append(observation)
在这种设计中上下文不断追加,每次调用都能看到完整轨迹,清楚任务进行到哪一步、此前尝试过什么;轨迹的结构化也便于解释、调试与聚合分析。代价也随之而来:轨迹只增不减,而上下文窗口是有限的。
1.4 上下文哪些内容能省,哪些不能
轨迹只增不减,窗口却有限,于是必须做取舍:删掉哪一部分,代价最小。
系统性消融实验(逐一去掉一类上下文内容,观察行为变化)给出的结论是:各类内容并不等价,衡量标准是它承载的信息能否从别处重建:
对工程实践最关键的一条是:"给出了回答"不等于"完成了任务"。 上下文残缺时典型的失败不是报错退出,而是一个看上去毫无破绽的答案。提示词里"不得自行估计"这类约束只能降低编造概率,无法消除。
这张表也是所有上下文管理手段的依据:能被重建的内容可以压缩甚至丢弃,承载不可替代信息的内容必须保留。
1.5 模型即Agent,与更新路径
先进模型通过后训练把工具调用内化为原生能力:何时调用、调哪个、传什么参数,都由模型自己决定。但要分清归属:写进参数的是决策,工具本身及其执行仍在模型之外——真实实现、沙盒环境、调用的发起与结果回传,都由外围基础设施完成。
相应地,Agent的行为改变有三条路径,按持续时间与可回滚程度排列:
本文后续大部分经验都落在第二条上:把规则、契约与验证写成可执行、可审计的外部产物,而不是依赖模型临场发挥或等待模型迭代。
02
HARNESS ENGINEERING
Harness:模型之外、Agent边界之内
第一节说明Agent由什么构成,本节说明它在生产环境里靠什么变得可靠:Harness。
2.1 Harness是什么:一条边界
从工程视角可以把LLM抽象为核心组件Model,把Agent边界内负责支撑模型运行、以及模型与环境交互的代码、配置和服务统称为Harness。生产形态的完整组成是:
两个公式是同一事物在两种抽象层次上的描述:Agent = LLM + 上下文 + 工具是最小工程实现,Agent = Model + Harness是它在生产形态下的展开。
Harness原指马具:不是限制马奔跑,而是把力量引导到正确方向。模型是那匹强大但不可预测的马,Harness是把它的能力引导成可靠任务执行的工程外壳。
Harness不是"模型之外的一切",而是"Agent边界内、模型之外":
2.2 让Agent从"能做事"到"可靠地做事"的要素
五个要素构成闭环:上下文与工具让Agent能做事;约束预防错误,验证发现偏差,纠正使闭环成立,三者让Agent不做错事。生产级系统的重心在后三者。
2.3 相关核心概念区别
涉及到Agent的概念比较多,有LLM、Prompt、Rules、Skill、MCP、Subagent、Hook、Harness。下表是这些概念的区别对比:
Hook是这套体系里唯一不经过模型的机制。前面几个概念最终都要落到上下文里,由模型读取后决定是否遵守;Hook不进上下文,它在Agent生命周期的固定点位(工具调用前后、会话结束、任务提交)执行一段确定性脚本,可以阻止动作、注入反馈或强制改写输入。因此它是软约束与硬约束的分界线:写在规则文件里的"禁止强制推送"是建议,注册在调用前的Hook是拦截。
下表是与Hook相关的机制,这些机制共同构成约束的执行面:
判断一条约束是否真的生效,标准只有一个:它被无视时,是否有一个不经过模型的机制拦得住。
两个易混点需要单独说明。
其一,MCP只解决"能做什么",不解决"该不该做"。 接入外部系统属于能力扩张,不在约束层。Agent接入十余个MCP后表现明显下降,原因是工具描述本身占用上下文,且不会提示此刻哪个工具不该用。能力越多,约束层的负担越重。
其二,Harness是总称,不是某个具体文件。 一份CLAUDE.md是Harness的一部分,pre-commit钩子是,CI流水线也是。判断标准是:它是否在Agent边界内、模型之外做事。
2.4 工具的类别与规模
"工具"常被理解为"能调用的函数",这个理解过窄。按调用方向划分有五类:感知(获取信息,控制输出量防上下文爆炸)、执行(改变世界,安全约束是核心)、协作(驱动其他Agent或人类)、用户沟通(异步触达)、事件触发(声明关心的事件,由外部回调唤醒)。编码Agent日常的读写文件、执行命令、搜索主要落在前两类。
工具规模本身就会影响正确性:数量过多时,即使最先进的模型也容易在工具选择上出错;全部平铺进上下文还要占去大量token。工具使用的优化策略主要是以下三条:
Skill的实现策略更轻量:启动时只看到一份薄目录(每个Skill的名称与描述,合计数百token),当前上下文真的需要时才读取正文。专用工具要达到同样的渐进式披露,必须在工具之外另建一层检索基础设施。这就是Skill比同等数量的MCP工具省上下文的原因。
2.5 范式演进:五层包含关系
回顾AI应用工程的发展,具有一条清晰的演进路线,后者包含前者:
提示工程 优化输入给模型的自然语言指令└ 上下文工程 系统管理模型能看到的所有信息└ Harness工程 扩展到Agent如何组织模型运行并与环境交互└ Loop工程 跨轮次的持续自主运转└ Graph工程 把循环、确定性程序与人工审批组织成显式执行图
当各家模型的能力趋于接近,竞争优势转移到模型之外的工程实践。
关于模型变强之后Harness是否会被吃掉:结论是会,但被吃掉的部分有明确范围。凡是给模型能力短板打补丁的适配层,few-shot示例、"一步一步思考"这类提示技巧、输出格式修复与JSON解析容错,都已被指令微调、推理能力与结构化输出内化。未被内化的是约束与验证:业务约束与团队偏好无法一次写进参数,且训练以月为单位推进,跟不上工程现场的变化速度。
模型当前的能力边界,就是Harness当前的价值所在。每一轮内化消灭的是脚手架,不是缰绳。
2.6 Harness构建原则与护栏
保持简单。 每多一层抽象,都会成为后续调试时新的盲区。
保持透明。 显式展示规划步骤、执行日志与决策轨迹。黑箱里的错误一旦发生,外部观察者既无法定位也无法纠正。
设计好ACI(Agent-Computer Interface)。工具应对应Agent的目标而非底层API操作,从Agent视角而非程序员视角设计接口。容易误用的地方要从设计上让错误无法发生,设计实现防呆机制。模型与工具之间唯一的沟通通道就是接口本身,模糊的接口会被模型放大成系统性错误。
工具描述层面有两条实用规则:
列出边界条件比描述能力更重要。 多数调用失败的根因不是模型不知道工具能做什么,而是不知道工具不能做什么。
参数说明用具体例子代替抽象规范。 为每个工具附1至5个真实调用示例,可将调用准确率大幅提升。
护栏按被绕过的难度分为三层,越靠下的层越不依赖模型自身的判断:
上下文层有结构性上限:处在同一个上下文里的Agent,很难判断自己是否已被注入;执行层的复核必须由上下文之外的机制完成。数据层的价值在于不依赖上面两层:即使提示注入得手、生成的代码漏写了权限判断,越权操作仍会在数据层被拒绝。评估护栏还要防另一类失败——误拒绝:不能只测"该拒的是否被拦截",还要测"明确允许的是否能正常完成"。
03
FAILURE MODES
AI编程的问题:过度服务、自作聪明、隐藏假设、缺乏"全局视野"
"敢不敢合入主干"是一句直觉判断,拆开之后是三条可判定标准:
三条都过关,才能"敢"。前两条多数团队已经在管,真正稀缺的是第三条:而且前两条会随模型变强自发改善,第三条不会,它的证据在工程机制里,不建就没有。
下表是AI出现的典型异常问题。
3.1 上下文过长导致的腐化,而非遗忘
长上下文里表现下降,通常不是遗忘,而是上下文腐化(Context Rot)。两者的区别很重要:溢出是"装不下了",腐化是"装得下但找不到了"。后者更隐蔽,Agent表面上仍在工作,决策质量却在下降。
机制上的原因是:一,注意力权重被分摊到更多token上,每个token 获得的权重变小;二,无关内容的占比上升,偶尔才用到的知识每次都加载、稳定规则与动态状态混在一起,有用部分越来越难被注意到。
还有一层更根本的机制:注意力机制擅长在已有内容里查找,不擅长在一次前向传播里主动归纳统计——上下文学习更接近检索而非推理。因此"把更多信息塞进上下文"的收益存在上限,主动提炼出高密度结论("目前已知:A 是……,还缺 C")比堆原文有效得多。这也解释了为什么"把规则写清楚"本身无效:清楚不等于有权重,规则还在上下文里,权重掉下去了。
对策方向因此确定:不是增加规则数量(那只会加速腐化),而是:
减少常驻量:只把稳定规则放进静态前缀,其余按需加载; 提高信息密度:把需要思考才能得到的结论显式提炼出来; 隔离优于压缩:让大体积中间信息根本不进入主上下文。委派一个子Agent 在代码库中大范围搜索,主上下文只增加两条消息——一条任务描述、一条结论,中间过程的数万token随子Agent的上下文一起被丢弃。
3.2 概率模型会优化你能观测的东西
LLM是概率模型。
相同输入,不同输出。"上次让它这么做是对的"不构成任何保证。
给什么指标,就优化什么指标。 只提"测试覆盖率达标",覆盖率会被做上去,至于测试本身是否有效,不在优化目标内。当验收阈值以脚本默认值的形式存在时,模型可以通过修改判定条件让检查通过,覆盖率照样达标,检查形同虚设。修正方式是把阈值移到独立的红线配置,任何改动触发门禁,工作流停下等待人工确认。
由此得到一条硬规则:凡是可被模型观测到的验收标准,都必须设计成它无法单独篡改的形式。
3.3 模型不能给自己当裁判
同一个Agent既写代码又做评审,结论几乎总是"没问题"。这不是欺骗,是自我确认偏差:它评审的是自己刚刚构建的东西,带着同一条推理路径。
规则只有一条:写与评必须是两个独立上下文。
3.4 局部最优,全局恶化
模型写的局部代码通常质量不错,但每个新需求对它都是一次重新开始。项目越大,需要遵守的既有准则越多,一旦检索词过窄或根本没检索到类似实现,就会自行另起炉灶。更麻烦的是正反馈:当它发现同一功能已有多种实现时,不收敛,反而叠加补丁。
04
CONSTRAINTS FIRST
经验一:给Agents加限制
约束成本最低,收益最直接。多数团队做不好这一层,原因不是没写规则,而是规则写得不可执行。
4.1 规则的三条写法原则
原则一:写成可判定的,不要写成好听的
差别在于:前者需要模型做主观判断,后者照做即可判定是否违反。
原则二:声明"什么时候可以不遵守"
一套偏谨慎的规则若对所有任务一视同仁,模型会走向全遵守或全无视两个极端。好的规则自己声明边界,例如"这些准则偏向谨慎而非速度,琐碎任务请自行判断"。
原则三:把成功标准写进任务,而不是写进流程
强成功标准让模型能自主循环,弱成功标准迫使它反复回来确认。
4.2 可参考的限制模板
首先是Karpathy Guidelines,这是一套由Andrej Karpathy(前Tesla AI总监、OpenAI创始成员)总结的行为指南,专门针对使用LLM进行代码编写的场景。
它源于Karpathy对LLM编码陷阱的大量观察。不同于传统的编码规范(如 Google Style Guide),这套指南不是关于命名规范或代码格式,而是关于如何思考和行动。核心哲学是:偏向谨慎而非速度。宁可多花一分钟思考,也不要花一天时间修复原本可以避免的问题。
https://github.com/multica-ai/andrej-karpathy-skills.gitKarpathy Guidelines共四条,覆盖最高频失效点:
编码前先思考。 核心要点:明确说明你的假设;如果不确定,主动问;如果有多种解释,列出来,不要默默选择一个;如果有更简单的方案,说出来; 简单优先。核心要点:只写被要求的功能;不为"将来可能需要"添加功能;不为"灵活性"添加配置项;如果200行可以写成50行,重写; 外科手术式改动。 核心要点:不"顺便"修复其他问题,不重写不相关的代码,匹配现有代码风格,即使你不会这样做,只删除你自己引入的无用代码; 目标驱动执行。 核心要点:将模糊的任务转化为可验证的目标,先写测试,再写实现,为多步骤任务制定简要计划;
https://github.com/DietrichGebert/ponytail.git这东西真的需要存在吗?(跳过没人要求的特性、选项、灵活性) 代码库里已经有了吗?(用现有的 helper/组件/服务/模式) 标准库或平台特性有吗?(除非项目有自己的约定) 已装的依赖能解决吗?(永远不为几行代码加新依赖) 能写成一眼看懂的一行吗? 否则:写能工作的最少代码。
4.3 Rule未程序化,等于未写
// 例:把"禁止高危操作"从提示词搬进配置{"permissions": {"deny": ["Bash(git push --force*)", "Bash(rm -rf *)"],"allow": ["Bash(npm test*)", "Bash(openspec validate*)"]}}
判断标准很简单:这条规则能不能写成一条机器判定。能写成就移出提示词;写不成的留在提示词里,并接受它只是一句建议。
05
PLAN MODE
经验二:优先使用PLAN模式,先规划再执行
5.1 PLAN模式:暂扣执行权
PLAN模式指:让Agent在本轮只读、只分析、只规划,不修改代码。产出一份计划和一组待确认问题,确认后进入执行。
这一步的价值在于改变默认行为。模型的默认反应是"拿到需求就动手",PLAN模式不增加能力,只把默认路径从执行改为规划。一个PLAN轮次应要求回答三件事:
准备修改哪些位置:调用方、测试、fixture、配置、导出,列全; 遇到了哪些歧义:存在多种理解时列出,不能默选一个; 每一步的验证方式,格式统一为"步骤 → verify: 检查项"。
5.2 强化验证:不止看覆盖率
验证要自动化,但自动化的指标必须选对。覆盖率只能证明"覆盖到了",不能证明"测到了点上"。 当同一模型既写实现又写测试,容易产出定制化断言:错误的行为、错误的参数,测试一样通过。
解法是变异测试:自动把源码故意改坏(把 > 改成 >=、反转条件),再跑完整测试。测试没有失败,说明断言不够严谨,需要重新设计测试用例。
5.3 人工验收:上移一层,而非逐行阅读
模型产出速度持续提升,逐行读完再合入已不现实,瓶颈转移为"读懂才能放心"。业界有两种取向:
Addy Osmani:工程师不退出代码审查,而是上移一层,抽查代码、审计方案,把有限的注意力投向更关键的位置。
Antirez:基本不读代码,只控制模型的想法与设计。前提是有能力判断方向是否正确,且存在可靠的检测机制。
可行方案是四类读物的优先级排序:验证需求与设计 → 裁决分歧 → 精读关键路径代码 → 查看验收报告。 注意力按此顺序分配。目的不是取消代码阅读,而是把逐行阅读从机械性内容中解放出来。
https://addyosmani.com/blog/agentic-code-review/https://antirez.com/news/16906
CONTEXT WINDOW
经验三:熟练使用现有指令,把上下文窗口管起来
前面两个实践经验聚焦在解决"做什么"和"怎么做",这个经验解决一个日常问题:同一件事做到一半,这段对话该怎么处置。
主流编程Agent都内置了若干上下文管理指令。它们常被当作功能开关使用,实际上做的是同一类工作,管理上下文窗口。区别在于对"历史"的处置方式:分叉是复制,无损、开新分支;压缩是摘要,有损、单线继续。以下以具备完整实现的一类编程Agent为例说明,具体命令名以所用工具为准。
6.1 窗口是双重约束,不只是容量
窗口之所以需要主动管理,是因为它同时构成两类约束:
因此每个上下文动作都是在做一笔显式交易。六种常见动作按信息保全程度排列:
分叉与压缩正是"无损但更贵"与"便宜但失真"的两端。
6.2 分叉与压缩:两个端点
分叉保留源会话的完整历史,从同一出发点开一条独立会话,用于探索替代方案而不破坏原来的讨论;两条分支都继承源会话的Agent与模型配置。它有两个边界要记住:不隔离文件改动——同一目录或Worktree下的分叉会改同一批文件,要隔离代码只能新建Worktree;不省token——历史原样复制一份,两条分支各付一次,解决不了窗口不够用的问题。它真正划算的地方在于:探索的账记在一条可丢弃的分支上,主线保持干净的一手记录;且两条分支共享同一份前缀,Prompt Cache仍然可用,成本远低于"新开会话再解释一遍背景"。
压缩把较早的历史总结成摘要,释放上下文空间。窗口填满时Agents本来就会自动压缩,手动执行的价值不在"能否压缩",而在由人来选择时机与保留内容。它同样有两个边界:有损——摘要会把"为什么这么决策"压成结论,典型的失败形态是对一个被压平的决策极度自信地做错。压缩只能在阶段边界做——任务中途压缩会切断线索,中途要么继续,要么把剩余工作拆给子代理。
6.3 决策顺序
按顺序判断,规则如下:

分叉不在这五档之内,因为它解决的是另一类问题:同一Agents、同一目录、还要保留完整推理链的分支比较。典型用法是在当前设计的基础上比较另一套方案,同时明令不改任何文件。
6.4 落盘优先于压缩
压缩只能释放空间,不能承担记忆责任。 压缩必然丢失的是"为什么",而这恰恰是ADR、spec、契约文件应该承载的内容。把决策写进文件之后,压缩就不必再为保留这些决策负责;反之,若所有决策只活在对话里,任何一次压缩或清空都会造成不可逆的信息损失。
操作顺序是:先落盘,再压缩。阶段结束时的动作是把结论写进仓库,然后才考虑是否需要压缩窗口。这也解释了为什么把"外部产物更新"列为跨任务持久化的主要路径:它是唯一不随上下文处置而丢失的机制。
07
DUAL-LAYER WORKFLOW
经验四:使用工作流,规范团队开发标准,保证代码质量
当任务跨会话、跨人、需要留痕时。意图与验收标准必须落盘,使其不依赖任何一次对话而存在。而且多人协作开发,需要统一规则和标准,保证团队的代码交付质量。
当前针对编程的工作流Skills有很多,比如OpenSpec / Spec Kit:侧重上下文管理(spec/规范)和约束(Constitution、变更管理),让Agent先明确“干什么”再动手;Superpowers:侧重约束(强制七阶段流程)和验证(强制 TDD、两阶段代码审查),让Agent“不做错事”;MattPocock/Skills:侧重工具接口(工程技能模块)和需求澄清、实现验证(grill-me需求审查、TDD),把工程实践编码为可调用模块;Addyosmani/agent-skills:把资深工程师的工作流(spec → plan → build → verify → review → ship)编码成结构化的Skill,让编码Agent在开发的每个阶段都能一致地执行这些工作流与质量门禁。
上述每个Skill都非常优秀,在不同的应用场景下都可以发挥巨大的作用。作为使用者,不需要也不建议每个Skill都安装使用,根据使用习惯或者团队模块需求,选择合理的Skill就行。下文根据本人实际使用经验,说明如何根据开发需求组合、修改这些工作流Skill。
本人在实际开发中,主要使用了OpenSpec和MattPocock/Skills,并根据实际使用需求完成了工作流修改和组合。下面主要是针对这套方案的说明和思路。
7.1 两个工具分别解决什么
https://github.com/Fission-AI/OpenSpec.githttps://github.com/mattpocock/skills.gitOpenSpec的优势:变更制品结构化,validate --strict提供不经过模型的结构校验,可直接接入CI;归档目录带日期、delta回写specs,天然审计留痕。
OpenSpec的短板:只校验结构,不评价代码质量,也没有TDD纪律;并发执行能力弱;上下文管理停留在提示级——官方文档建议"实现前清空上下文",属于人工约定而非机制;依赖强推理模型,弱模型上明显退化。
MattPocock的优势:覆盖实现全链路——带阻塞边的ticket拆分、TDD红-绿-重构、调试决策树、双轴review;ready frontier模型允许多个实现子代理在各自worktree上并行;上下文管理在机制级——子代理使用新鲜上下文,配合上下文指针与统一术语表;统一语言与领域建模有方法论支撑。
MattPocock的短板:无持久化状态机,产物就是仓库里的普通文件,跨会话恢复靠人;无可挂CI的确定性校验;无归档与审计留痕;重度依赖worktree与后台子代理,在能力较弱的harness上退化为串行。
7.2 组合的必要性
团队单用任一技能,在否些方面都存在缺陷:
两个Skill部分实现存在重叠,组合必然有代价,主要冲突有两处:
上下文膨胀。 两套规则文件同时进入上下文,会加重上下文的负担。
7.3 组合方案:需要考虑哪些方面
组合两个工具的本质,是定义一套跨工具的约束结构。下面几个方面是需要处理的内容,每个方面给的是思路与判据,可以根据团队实际使用调整设计。
一:先定职责
OpenSpec管"写下来":行为契约、变更制品、阶段状态、归档生命周期。 Matt管"写得好":任务拆分、TDD、实现编排、双轴评审。 ADR架构关键决策管"为什么":长期架构决策及其权衡。 GLOSSARY.md术语表管"词是什么":领域术语的唯一含义。
术语表 这个词是什么意思? → 长期决策记录 为什么这么架构? → 长期,靠新增记录supersede行为契约 系统当前必须怎样表现? → 持续演进变更目录 这次要改什么、怎么改? → 随变更归档
由此得到以下设计规则:
OpenSpec执行流程是唯一主时间轴:propose -> validate -> apply -> verify -> archive。 Matt/to-tickets是进入apply的准备闸门:implement -> tdd -> code-review在apply内执行,不得跳过、替换或重排OpenSpec阶段。 OpenSpec tasks.md是任务标题、验收条件和完成状态的事实源。
tickets/是Matt的执行投影,不得改变tasks.md的验收语义。
每个Scenario的独立THEN必须能翻译为至少一个可执行断言。
已接受ADR不得被spec或实现静默推翻;改变决策必须新增superseding ADR。
二:指令分层
Agent约束来自以下几类指令,作用域与加载时机各不相同,在团队项目中使用时,需要综合考虑“4.2限制模板“和Skill的配合。
三:证据策略
单向数据流。 契约是事实源,执行票据是投影。投影可补充"怎么做",不得新增、弱化或改写验收语义,否则"实施时偷偷放宽验收"在机械层无法被发现。改验收的唯一合法路径是先改契约再重新投影。
新增行为必须附失败记录。 新增可观察行为的覆盖项必须附一条失败证据(命令、非零退出、诊断输出),否则红绿无从区分,测试可以是事后补的。已有行为允许复用既有成功证据,不强迫造红。
评审范围要固定基点与边界。 以固定基点到工作区的完整差异为准:已跟踪与已暂存全收,相关未跟踪文件显式列出,构建输出显式排除。默认以 HEAD 为基准的三点差异会漏掉未提交实现,而这恰恰是常态。
评审轴可扩展。 除规范符合度与契约忠实度两轴外,可按需增加"架构决策一致性":相关决策是否已识别、是否违反已接受决策、改变决策是否有 superseding记录。
关键动作核验两次且不合并。 以归档为例:同步主契约之前验一次,同步之后、移动目录之前再验一次。第二次不是重复——同步会改写主契约,第一次看到的与最终落地的未必一致;若合并成最后验一次,同步阶段可能已经在错误基线上动了主契约。
四:上下文、冲突与边界
由于组合使用会重新编排上游技能的使用策略,修改一些产物的默认位置,所以针对OpenSpec和Matt的原始技能,需要区分使用。而且Matt/Skill是通用实现,直接接入OpenSpec流水线会出现产物落点不一致、语义双向污染、指令重复三类问题。需要逐项处理。
Matt/Skill需要的最小指令集如下:
setup-matt-pocock-skills # 必须最先执行,生成项目约定,单个项目执行一次grill-with-docs # 需求对齐与术语统一to-tickets # 带阻塞边的任务图implement-spec # ready frontier并发编排tdd # 红-绿-重构code-review # 双轴评审diagnosing-bugs # 调试决策树improve-codebase-architecture # 周期性架构勘察
OpenSpec初始化之后,会在项目目录下生成如下文件夹,用来保存变更文件。
openspec/├── config.yaml # 项目配置├── specs/ # 已生效的能力规格│ └── .gitkeep # 空目录锚点└── changes/ # 进行中的变更└── archive/ # 已归档变更└── .gitkeep # 空目录锚点
Matt执行setup-matt-pocock-skills之后,会在项目目录下生成如下文件夹,用来记录ADR架构决策、agents定义路由等文件,在项目根目录下生成GLOSSARY.md术语表。
docs/├── adr/ # 编号架构决策记录└── agents/ # agent 工作流与票据协议├── domain.md # 如何消费本仓库领域文档(GLOSSARY / ADR / 语言政策)├── issue-tracker.md # Matt票据的本地Markdown存放与流转规则└── triage-labels.md # `/triage`五个角色对应的 label 字符串
所以使用openspec文件夹保存项目修改变更和能力规格,使用Matt的相关文件保存架构相关文档,但是由于Matt/to-tickets技能默认是将文件保存在项目根目录.scratch/<feature>/issues/。
这些属于单次变更记录而且和OpenSpec changes相关,所以需要修改docs/agents/issue-tracker.md,将文件保存迁移到openspec/changes/<change-id>/tickets/。
openspec/changes/<change-id>/├── tickets/ ← to-tickets的输出├── review.md ← code-review双轴结论└── tasks.md ← 事实源,由OpenSpec生成
Matt/to-tickets生成的ticket是tasks.md的投影,只能补充"怎么做",不得新增、弱化或改写验收语义。投影不能反向修改事实源——这条单向数据流需要写进Skill说明,否则模型会在实现阶段自行调整验收条件。
Matt/code-review的Spec轴回答"是否忠实实现了原始契约",需要把结论落盘为结构化条目,供OpenSpe的verify阶段读取。约定格式:
# review.md## Standards 轴- [ ] 无重复实现 / 复用既有 helper- [ ] 错误处理未越界## Spec 轴- [ ] Scenario: 目标 App 未安装 → 断言存在且通过- [ ] 未实现项:无## 结论PASS / FAIL(FAIL 需列出违反的具体条目)
五:最终设计清单
开发的过程按照阶段,可以分为:需求->设计->实现->验证->审核。所以工作流的设计实现也是按照这个流程完成。工作流程如下:

项目Agent相关文档规范设计如下:
GLOSSARY.md 这个词是什么意思? 长期docs/adr/ 为什么这么架构? 长期,靠新增 ADR supersedeopenspec/specs/ 系统当前必须怎样表现? 持续演进openspec/changes/<change-id>/ 这次要改什么、怎么改? 随变更归档├── proposal.md 本次的问题、范围、影响├── specs/ 本次行为契约 delta├── design.md 本次实现设计├── tasks.md 任务、验收条件、完成状态├── tickets/ to-tickets 的投影└── review.md 双轴评审证据
定义三个交接接口,工具组合的难点不在安装,在交接格式。必须自己定义三处:
接口 1:
tasks.md→ tickets。 约定每个二级标题对应一个ticket,每个 checkbox对应一条验收条件,阻塞边从章节语义依赖或显式标注<!-- blocks: G-1 -->读取。接口 2:Scenario → 测试。 约定每个Scenario的THEN子句必须能翻译成至少一个可执行断言,执行层据此生成失败测试(红),再实现(绿)。
接口 3:review.md → verify。 verify阶段读取review.md做最后一公里核对,通过后归档。
组合Skill实现五个指令,完成交接接口、执行、验收的流程触发。更多集中在流程靠后阶段。
生成并校验项目 ticket projection | ||
在ticket、blocker和项目开发约束下调用 | ||
调用 | ||
运行项目自有的OpenSpec、ticket、evidence校验 | ||
verify、sync、再次verify后归档 |
使用OpenSpec和Matt原始指令如下,主要集中在需求、设计、实现等阶段。
| ||
|
上述所有的设计都是针对Agent读取使用,考虑到项目需要有开发人员参与,所以根据开发过程中的文档类别,设计了更完善的文档归档策略。
系统现在是什么结构,边界在哪 |
| 只写跨多个 change 仍成立的架构事实;实施过程、验收数据和历史差异不进这里 |
现在怎么做这件事,命令和参数是什么 |
| 命令、路径、参数或配置语义变化时同步更新;失效的步骤直接删除 |
有哪些方案,证据和取舍是什么 |
| 明确 |
这件事做到哪一步,下一位怎么接 |
| 只记录短期交接现场,不替代任务系统或长期设计;完成后删除 |
这个问题为什么发生,怎么防复发 |
| 只沉淀跨问题可复用的经验;单次审计的过程记录不写进来 |
文档流转按以下边界执行:

完成工作流设计之后,需要考虑一个实际问题,真正企业级别的代码,几十个模块,几万行代码,一堆历史文档。Agent如何快速地找到合适的东西,如何降低Token消耗,是两个必须考虑的问题。所以需要给工作流添加知识图谱,经过评估选用Graphify和CodeGraph。
Graphify和CodeGraph作为可选的"知识感知层",通过MCP协议提供服务。工作流各阶段的规范文件里加上"优先用知识图谱查询,不可用时回退grep/Read"的指引。编排层不需要知道底层是SQLite还是JSON,只管调MCP工具。
https://github.com/Graphify-Labs/graphify.githttps://github.com/colbymchenry/codegraph.git最后在AGENTS.md中完成项目规范的路由和规范定义,由于在项目中涉及多个文档的编写和阶段流转,一个值得注意的细节时,将文档根据不同的类型规范使用不用的语言,便于开发者阅读和避免流程歧义,类似如下规范:
Agent instructions and workflow contracts use English. Domain and behavior prose usesChinese. OpenSpec structural keywords, code identifiers, paths, commands, API names, andprotocol fields remain unchanged. Seedocs/agents/domain.md for the document language policy.
08
CLOSING NOTES
写在最后
约束比能力重要。 模型能力已经越过可用线,产出质量取决于外围套了多少层可靠机制。
软约束必须配硬执行。 写进CLAUDE.md的规则,若没有一个不经过模型就能执行的检查兜底,只是一句建议。
验证必须独立于实现者。 三条里优先级最高的一条:模型不能给自己当裁判,人也不能因为"看起来对"就放行。
写代码的成本在下降。没有跟着变便宜的是另外几件事:把需求想清楚、在开发过程中守住工程判断、把最终结果验清楚。
技术发展迅速,对于开发者和公司,都需要根据技术发展调整自己的开发方式和组织方式。

李博杰《深入理解 AI Agent:设计原理与工程实践》
Addy Osmani《Agentic Code Review》
Antirez《Control the ideas, not the code》