DeepSeek Harness 发布后,我没急着跑 Demo,先把 `.agents/` 翻了一遍

DeepSeek Harness 开源以后,我把仓库拉了下来。

README 里最醒目的当然是那句 everything is a plugin。再往下看,模型、工具、Session、子 Agent、终端、沙箱,东西不少。packages/ 下面一共能数出 219 个两级 workspace 包。

但真正让我停下来的,是根目录里这个不起眼的文件夹:

text 复制代码
.agents/
  notes/
  skills/

我原本以为里面只是几份给 Claude Code 或 Codex 用的提示词。结果数了一遍:11 个 Skill,684 份英文 Agent Note(包含归档记录),每份 Note 通常还有中文版本和配对文件。

这就不是"顺手写几句提示词"了。

我继续往里翻,发现 DeepSeek Harness 在做一件挺少见的事:它没有赌 Coding Agent 每次都能理解项目,而是把"AI 应该怎么改这个仓库"拆成了规则、操作流程、历史决策和自动检查。

先说明一下,仓库并没有说全部代码都是 AI 生成的。本文讨论的是它如何让 Coding Agent 参与开发,不是给项目统计一个没有依据的"AI 含量"。

.agents/ 到底装了什么?

先别被目录名绕进去。

开发规范的总入口其实是根目录的 AGENTS.md,不在 .agents/ 里面。.agents/ 更像是它的配套材料:skills/ 放做事流程,notes/ 放设计决策。

整个关系可以压成下面几行:

text 复制代码
AGENTS.md            长期有效的仓库规则
*/AGENTS.md          某个目录自己的附加规则
.agents/skills/      一类任务该怎么做
.agents/notes/       当初为什么这么做
scripts + hooks + CI 检查有没有做到

这几个东西分开很有必要。

比如"新增模型可见内容必须写入 Session Log",适合放在 AGENTS.md,因为它是一直有效的架构要求。

"推送前该跑哪些测试",不适合塞进每次对话的上下文,它应该做成一个按需加载的 Skill。

"为什么 Session 要保存原始 assistant/chunk",也不该写成代码旁边一大段注释,它属于 Agent Note。代码负责告诉你现在怎么运行,Note 负责留下当初的取舍。

很多团队把这三种内容混在同一份超长提示词里。文件越写越长,真正干活时反而没人愿意从头读。

AGENTS.md 写的不是"请帮我写好代码"

DeepSeek Harness 根目录的 AGENTS.md 很长,但里面很少出现"代码要优雅""注意最佳实践"这种没法验收的话。

它写得很具体。例如:

text 复制代码
Registrations are effects.
Model-visible <=> logged.
Plugins, not loop changes.
Non-trivial changes MUST include an Agent Note.

这几条翻译一下:

  • 插件注册必须能够随生命周期撤销;
  • 模型能看到的东西,必须能从 Session Log 重新构建;
  • 新行为优先接到现有扩展点,不要直接修改 Agent Loop;
  • 只要改动涉及行为、架构或跨包约定,就要补一份决策记录。

我最喜欢的是 Model-visible <=> logged

Agent 项目最怕一种问题:模型做了奇怪的决定,你去查日志,却发现当时临时拼进 Prompt 的那段内容根本没有保存。于是代码、聊天记录和模型真正看到的上下文对不上,排查只能靠猜。

DeepSeek Harness 直接把这件事堵死。只要内容进入模型请求,就必须有对应的 Session Event,后面能从日志重建。

这是一条能指导代码评审的规则。有人新增上下文注入,却没设计事件,reviewer 可以直接指出不合格,不需要讨论"日志是不是最好再完善一下"。

它没有让一个文件管完整个仓库

根目录之外,packages/docs/scripts/examples/vendor/ 等位置还有各自的 AGENTS.md

text 复制代码
AGENTS.md
packages/AGENTS.md
packages/client/AGENTS.md
docs/AGENTS.md
scripts/AGENTS.md
.agents/notes/AGENTS.md
.agents/notes/implemented/AGENTS.md

改普通包时,不需要把文档站和归档 Note 的全部规定都塞进上下文。进入对应目录,再读取那里的附加规则就够了。

这点看起来很普通,实际很适合大型仓库。AI 上下文不是越多越好。无关规则太多,模型一样会漏掉真正重要的那条。

仓库还把 CLAUDE.md 链接到对应的 AGENTS.md。Claude Code 和 Codex 不需要各养一套内容相近、过几个月必然不一致的规范。规则尽量只有一个来源,工具差异放到调用元数据里处理。

Skill 解决的是"现在该怎么做"

打开 .agents/skills/dsh-pre-push-checks/SKILL.md,最上面是这样的:

yaml 复制代码
---
name: dsh-pre-push-checks
description: Use before pushing, force-pushing, marking ready for review...
---

description 不是介绍文案,它告诉 Coding Agent 什么时候该加载这份流程。

这个 Skill 做的事情也很实际:先看当前分支和完整 diff,再决定需要哪些证据。改一个包的局部行为,就跑对应测试;改了模型或用户能看到的输出,就跑 snapshot;碰了导出、bin、worker 或构建配置,再补 build、hygiene 和 built smoke。

它还明确说,不要因为准备 push,就机械地把全仓库测试再跑一遍。CI 负责完整覆盖和平台矩阵,本地验证应该对准这次改动。

这比一句"提交前请确保所有测试通过"有用得多。

其他 Skill 也都是类似的窄任务:怎么做代码评审,怎么维护文档,怎么归档旧 Agent Note,怎么录制浏览器 GIF,怎么检查仓库里有没有过度设计。

还有一个细节挺有意思。文档翻译 Skill 被设置为只能由用户显式调用,模型不能自己触发。原因不难理解:批量翻译影响范围大,也可能调用模型,不能因为 AI 觉得"顺便更新一下"就开跑。

为了避免 Claude Code 和 Codex 对同一个 Skill 的调用权限不一致,仓库里甚至有一个 verify-skill-invocation-metadata.ts 专门检查两边的配置。

684 份 Agent Note,不是 684 篇开发日志

.agents/notes/ 更值得看。

它按状态分成四类:

text 复制代码
proposed/     还在讨论,尚未完整落地
implemented/  已经实现,并且要和当前代码保持一致
rejected/     认真考虑过,但没有采用
archived/     已冻结的历史记录

下面再按 featurebug-fixarchitecturesimplificationprocesstesting 分类。

一份 Note 的基本结构并不复杂:

markdown 复制代码
# Agent Note: <标题>

Status: implemented

## Problem

## Decision

## Alternatives considered

## Consequences

我觉得这里最值钱的不是 Decision,而是强制要求写的 Alternatives considered

维护老项目的人都碰到过这种情况:新人提出一个"明显更简单"的改法,团队讨论半天,最后才有人想起来,两年前其实试过,卡在某个边界条件上。代码只留下最后方案,不会主动告诉后来人那条路为什么走不通。

对 Coding Agent 来说,这个问题更严重。它很擅长根据眼前代码重新推导一个看似合理的方案,却不知道这个方案是不是三个月前刚被否掉。

把失败过的选择和放弃的能力写下来,才算给 AI 留了能用的项目记忆。

这些 Note 也不是只增不改的流水账。implemented 必须描述当前已经落地的机制,路径、名称和默认值变了,就要跟着更新。已经失去维护价值的记录可以移进 archived,但归档后冻结,不能再拿它当当前文档。

这套规则有维护成本,684 份绝对不轻。后面我会讲为什么不建议普通项目原样照搬。但对一个 219 包的 Agent monorepo 来说,它至少解决了设计理由散落在 PR、聊天记录和某个人记忆里的问题。

假设 AI 要新增一个工具,它会经历什么?

按照这个仓库的规矩,Coding Agent 不应该搜索到 agent-loop,然后直接往里面塞一个分支。

它先读根规则和 packages/AGENTS.md,再看架构文档与 adding-a-tool cookbook。接着搜索现有 Agent Note,确认这项能力是不是已经讨论过,应该接在哪个扩展点上。

工具本身要考虑的不只是一个执行函数。这里的 capability seam 通常要分清 Service Definition、Provider 和 Consumer。模型能看到的新 Schema 或上下文需要进入 Session Log;参数来自模型 JSON,要在这个不可信边界校验;工具结果会影响用户界面,还要确定它按 genericterminal 还是 diff 渲染。

实现完成后,局部逻辑用单元测试覆盖。只要模型输出、工具展示或用户流程变了,还得补一个真实 runnable example 的 keyless snapshot。非简单改动同时新增或更新 Agent Note,把为什么这样接、放弃了什么写清楚。

临近推送时,再调用 pre-push Skill,根据 diff 选择测试。提交时 hooks 检查 staged lint、空白、翻译配对和归档文件;推送时跑 typecheck;CI 再接手 coverage、snapshot、build、hygiene 和平台矩阵。

整个过程里,AI 当然还是会写错代码。但它很难悄悄绕过架构、忘记设计记录、只跑一个顺手的单测就宣布完成。

这才是我理解的 AI 开发规范:不要求模型表现得像一个永不犯错的高级工程师,而是把它放进正常的软件工程约束里。

我挑一份 Agent Note 拆开看:ACP 快照测试

其中最适合拿来做案例的是 .agents/notes/implemented/testing/2026-06-19-acp-snapshot-tests.zh.md 这份文档。

它的标题是"ACP 快照测试,一次录制,确定性回放"。选它不是因为名字好听,而是因为这份 Note 把一项测试设计从头到尾说清楚了:问题、方案、没有采用的方案,以及最后承担的代价。

它先承认,现有测试中间有个洞

单元测试可以测工具注册、事件处理和某个函数的分支,却不一定会启动完整的 Loader、Agent 子进程和 ACP 协议。

另一边的真实 API 测试虽然更接近产品,却有两个麻烦:模型输出不稳定,而且 CI 未必有 API Key。

所以会出现一种很典型的假绿色:单元测试全绿,真实模型测试因为没密钥跳过,结果 Loader 接线、协议输出或者构建后的入口坏了,也没有测试能告诉你。

这不是凭空担心。Note 里直接链接了一个事故复盘:一个默认导出让 Loader 丢掉了需要的 inject,局部测试没抓住,真实装配才暴露出来。

它没有选择"再写一个更聪明的 Mock"

方案是录制一次真实运行,然后回放模型流。

录制时用真实 API 跑 ACP 示例,保存普通的 session.jsonl。这份日志里不只有模型文字,还有 assistant/chunk、工具调用、工具结果、轮次和步骤边界。回放时,cordis.snapshot.ymlllm-replay 换掉真实 LLM 适配器,但 Loader、Agent Loop、工具和持久化仍然使用正式组合。

换句话说,测试替换的只有最不稳定的那一层。其他部分照常跑。

仓库里的 tool-call-turn 场景很适合看这个过程。输入要求 Agent 执行 echo SNAPSHOT_OK,模型先产生 bash tool-call,真实工具返回 SNAPSHOT_OK,然后模型再输出 DONE。回放不是直接把 DONE 写进预期文件,而是让这套流程重新走一遍。

llm-replay 实际上做了什么

deriveReplayScript() 会读取日志里的 assistant/chunk,按 (turn, step) 分组,遇到 finish 就结束一次模型调用。内存里得到的不是一份模糊的字符串,而是带有分片顺序的脚本:

text 复制代码
{ kind: 'chunks', chunks: [...] }
{ kind: 'throw', chunks: [...], message, code }
{ kind: 'hang' }

正常模型流可以从日志推导。模型还没输出任何分片就抛异常、流挂起或需要在特定时机取消,这些信息不能从普通 chunk 完整推断,就单独放进 replay.override.json

回放启动后,每一次 llm/stream 调用按顺序消费一条脚本。脚本提前用完,说明代码多调用了模型;测试结束还剩条目,说明代码少调用了模型。两种情况都会报错,不会让场景悄悄通过。

它比较的不是一张快照,而是两个表面

第一张是 ACP 客户端看到的 stdout transcript,例如初始化响应、session/update 里的 DONE 和最终的 end_turn

第二张是回放后重新持久化的 Session JSONL。它能看到协议输出里被省略的工具调用、事件顺序和轮次结构。

时间戳、Session ID、临时路径、进程 ID 这类每次都会变的东西会被归一化,但连续的 seq 和事件关系会保留。这样既不会因为临时目录不同导致误报,也不会把真正的顺序变化抹掉。

Note 里还认真写了"为什么不用别的方案"

最早的想法是手写一个 llm.json,里面放模型分片。后来放弃了,因为真实 Session 日志已经包含这些数据,手工 fixture 反而会和产品行为脱节。

也考虑过 Polly、nock、MSW 一类 HTTP 录制工具,最后没有采用。它们录的是适配器和 SSE 字节,不是 Harness 想验证的 Agent 组合;一旦更换 Provider,录制文件和测试价值都会跟着变化。

还有一种诱人的偷懒:从 turn/end { error } 推断模型是抛错还是取消。Note 也否掉了这个方案,因为轮次结束原因是有损的,401、流中途失败和取消可能落成相似的结果,不能靠猜。

这些"为什么不用"比"我们用了什么库"更有用。以后有人想把回放改成 HTTP 录制,先读 Note 就知道这场争论已经发生过。

这套方案买到了什么,又付出了什么

代价是明显的:每个场景需要输入、Session 日志、stdout 预期输出,有时还要 workspace 和 override 文件;录制和刷新也要有人认真 review fixture。

换来的则是无密钥、可重复的组装测试。CI 不需要调用真实模型,也能检查 Loader 是否接对、工具是否真的执行、Session 是否按预期落盘、ACP 输出有没有变化。

它也没有假装解决所有问题。回放不能证明今天的真实模型会给出同样答案,所以真实 API e2e 仍然保留;并发子 Agent 的脚本绑定也有明确限制。把边界写出来,比宣称"全量确定性"可靠得多。

这就是我觉得 Agent Note 有价值的地方:它不只是告诉 AI 一个结论,还告诉 AI 这个结论的适用范围。

哪些东西我会抄,哪些不会

如果让我给自己的项目加一套类似机制,我不会先建 684 份 Note,也不会立刻上双语文档、每文件 100% coverage 和几十个 gate。

那是 DeepSeek Harness 当前体量和风险面的产物。小项目照搬,只会多出一堆没人维护的 Markdown。

我会先抄四件事。

第一,把长期规则、任务流程、设计原因分开。AGENTS.md 不负责教完所有工作,Skill 不负责解释整个架构,Note 也不写成操作手册。

第二,规则按目录收窄。根目录只保留全局要求,前端、后端、文档、脚本各自补充自己的约束。

第三,非简单改动留一份短决策记录,尤其写清没有采用什么。Note 不求多,能阻止团队第二次踩同一个坑就有价值。

第四,至少把一种规则接进 CI。没有自动检查的规范,很快就会变成仓库里一份礼貌性文件。

最小目录其实可以很小:

text 复制代码
your-repo/
  AGENTS.md
  docs/architecture.md
  .agents/
    skills/
      pre-push/SKILL.md
      code-review/SKILL.md
    notes/
      proposed/
      implemented/
      rejected/
  scripts/
    verify-agent-notes.*

一开始甚至只需要两条硬规则:新增能力从哪个扩展点进入,用户或模型可见变化要用什么测试证明。等真实问题出现,再增加 Skill 和 Note。

说到底,我想抄的只有这一点

看完 .agents/,我没有得到一套可以直接复制粘贴的"DeepSeek AI 编程提示词"。这反而是好事。

DeepSeek Harness 值得抄的并不是某一句 Prompt,而是它给不同内容安排了不同位置:规则写进 AGENTS.md,流程做成 Skill,理由放进 Agent Note,能自动判断的部分交给 hooks 和 CI。

模型能力再强,也不可能天然知道一个项目过去做过哪些取舍,更不会自动选择最合适的测试。仓库需要把这些信息组织出来。

对大多数团队来说,不用从 684 份 Note 开始。先写一页真正能执行的 AGENTS.md,做两个常用 Skill,留一个决策模板,再让 CI 拒绝一种明确不合格的改动,已经比继续堆提示词有效得多。

相关推荐
名字还没想好☜1 小时前
Next.js 用 Server Components 直连数据库:去掉 API 层的边界,和三条别踩的安全红线
前端·javascript·数据库·安全·react·next.js
学习zhao极致it1 小时前
2020全新React教程全家桶实战redux+antd+React Hooks前端js视频
前端
用户921080262861 小时前
Bubble 消息操作区改造:复制、重新生成和反馈
前端
Nturmoils1 小时前
不在公司,也能连回办公电脑:用 Natapp 打通 Windows 远程桌面
后端
LEE1 小时前
AI Agent 都在疯狂加功能,它说:我全砍了
前端·后端
张清悠1 小时前
用 TRAE Work 把 PRD + 设计稿注释,整理成 20 分钟可排期前端任务清单
前端
桦说编程1 小时前
记一次 Coding Agent 改动带来的bug与启示
后端·agent·vibecoding
302wanger1 小时前
Mole-在终端里给Mac做减法
后端
一心只读圣贤书2 小时前
本地后端环境与前端联调总结(前端小白视角)
后端