[{"data":1,"prerenderedAt":769},["ShallowReactive",2],{"blog-post-/zh/blogs/deepseek-harness-teardown":3},{"id":4,"title":5,"body":6,"description":752,"extension":753,"meta":754,"navigation":242,"ogImage":756,"path":765,"seo":766,"stem":767,"__hash__":768},"zh/blogs/zh/30.deepseek-harness-teardown.md","我从 DeepSeek Harness 学到的",{"type":7,"value":8,"toc":744},"minimal",[9,21,30,38,43,46,57,60,66,69,76,79,82,85,94,97,100,103,107,110,186,193,329,332,335,380,387,390,435,442,449,452,456,459,462,468,476,479,485,488,577,580,583,590,593,596,600,622,630,637,640,647,655,661,664,667,670,674,689,697,710,713,719,722,725,731,734,740],[10,11,12,13,20],"p",{},"8 月 13 日，DeepSeek 把自己的 agent harness 开源，MIT 协议，和 V4-Pro 转正是同一天。再往前两天，",[14,15,19],"a",{"href":16,"rel":17},"https://composio.dev/content/best-agent-harness-deepseek-v4-flash",[18],"nofollow","Composio 的实验","刚好给这类东西定了调：同一个模型放进八个 harness 跑三十个真实工作流，成功率从 46.7% 摆到 66.7%，每完成一个任务的成本差七倍。",[10,22,23,24,29],{},"发布后最让我上心的评价，来自本该最挑剔的那个人。Composio 那场测试里成绩最好的 harness 是 Pi（这个名次 Composio 自己也说别当真——Pi 用的推理设置和别家不同），而 Pi 背后公司 Earendil 的联合创始人 Armin Ronacher ",[14,25,28],{"href":26,"rel":27},"https://www.theregister.com/ai-and-ml/2026/08/14/deepseeks-innovative-harness-treats-everything-as-a-plug-in/5288095",[18],"看完仓库后说","：\"我不觉得 DeepSeek Harness 是完美的，但这确实是我第一次看着这个领域里的新东西，很想回头重新审视我们自己的一些选择。\"赢家看完对手的作业，说想回去改自己的——这一句比任何发布稿都有分量。",[10,31,32,33,37],{},"所以我没停在别人的评价上，自己花了几天钻进仓库：十四个分析 agent 扫过源码树，锚定在 47f9438 这个 commit，逐文件核对了几百条论断。六月我写过，",[14,34,36],{"href":35},"/zh/blogs/fable-5-managing-ai-autonomy","AI 工作的单位已经从一次回答变成一次运行","，稀缺的技能是给运行立规矩——这个仓库是第一次能把一家厂商的整套规矩从头读到尾。下面是我学到的四个重要的设计。",[39,40,42],"h2",{"id":41},"一模型只被允许看到日志里的东西","一、模型只被允许看到日志里的东西",[10,44,45],{},"DeepSeek Harness 的每个会话是一条只增不改的事件日志。仓库定义了 44 种事件，其中只有 3 种是模型看得见的：你说的话、它说的话、工具返回的结果。剩下 41 种——审批、轮次边界、配置变更、计费——全是记给人和审计看的账。画出来大概是这样：",[47,48,54],"pre",{"className":49,"code":51,"language":52,"meta":53},[50],"language-text","seq 101  user/message       你的指令                     → 模型可见\nseq 102  assistant/message  模型的回复（含工具调用）       → 模型可见\nseq 103  approval/decision  你点了「允许」                → 只进日志\nseq 104  tool/result        工具的返回                   → 模型可见\nseq 105  turn/end           本轮结账（token 用量）         → 只进日志\n","text","",[55,56,51],"code",{"__ignoreMap":53},[10,58,59],{},"让我停下来的是这个细节：系统里没有单独存一份\"发给模型的对话\"。存的只有日志——每次请求之前，那份对话都从日志现算出来。熟悉区块链的人会觉得眼熟：账本是唯一的事实，账户余额从账本推导，没人把\"某人有五个币\"单独记成一条数据。这里借的正是这一条思想——状态是历史的纯函数——而且不需要共识和加密那些重机器。\"模型看到的一切必须能从日志重建\"也不是文档承诺，是一个真的会拦你的运行时检查，机制说白了就是：",[47,61,64],{"className":62,"code":63,"language":52,"meta":53},[50],"每次调用模型之前：\n    期望的上下文 = 从会话日志重新推导出来\n    if 期望的上下文 != 即将发出的请求:\n        拒绝发送（报错：日志重建不一致）\n",[55,65,63],{"__ignoreMap":53},[10,67,68],{},"换句话说，任何代码想\"偷偷\"给模型塞一段上下文，都过不了这道闸——不写进日志，就发不出去。",[10,70,71],{},[72,73],"img",{"alt":74,"src":75},"会话账本推导出三张卡片，依次穿过绿色闸门送往信封；一张绕行的卡片在闸门之前就被拦下","/blogs-img/2026-08-16-harness-01.webp",[10,77,78],{},"这换来什么？说两个你大概率遇到过的场景。",[10,80,81],{},"第一个：agent 突然做了件莫名其妙的事——引用了一段你从没给过它的旧代码，或者放着现成的文件不读、自己编了一个。在大多数工具里，这时候你只能猜：是压缩的时候把关键内容吞了？是哪个插件偷偷注入了什么？在这套设计里不用猜。把日志推导到那一步，模型当时看到的上下文逐字节摆在你面前——是摘要吞了信息，还是注入出了问题，一眼定案。",[10,83,84],{},"第二个：跑了两小时的长任务在第 80 步断了，进程崩了，或者你合上了电脑。因为上下文本来就是从日志现算的，重启后从同一份日志接着算，模型看到的和断之前逐字节相同，任务接着跑。想从第 50 步分叉出去试另一条路？复制日志前缀就行。顺带的好处还在往上摞：token 用量盖在每个事件上，月底账单吓到你的时候，日志能直接告诉你钱花在哪个环节；他们的测试系统也骑在同一条性质上——录一次真实会话，日志本身就是回放脚本，CI 里不需要 API key。",[10,86,87,88,93],{},"代价也是实打实的，而且值得放慢讲，因为 Anthropic 在同一个问题上选了反方向。他们的",[14,89,92],{"href":90,"rel":91},"https://platform.claude.com/docs/en/agents-and-tools/tool-use/code-execution-tool",[18],"代码执行接口","支持常驻执行环境：模型写的程序跑完一步，变量还留在内存里，下一步接着用——就像一直开着的 Jupyter notebook，上一个单元格算出的变量，下一个单元格直接拿来用。好处很直接：模型在处理一份大数据集时，解析结果留在内存里，后面十步不用重新加载，也不用把中间结果搬进上下文窗口，又快又省。",[10,95,96],{},"DeepSeek 的设计笔记里写了他们为什么拒绝这条路：变量留在内存里，就意味着 agent 的一部分状态不在日志里——会话断了接不上，回放对不齐，\"模型为什么这么做\"又变回悬案。而守住\"每个请求都能从日志重建\"，代价是每个要紧的中间结果都得走一遍日志，多花 token，多花时间。",[10,98,99],{},"这笔账两边都摊得开：Anthropic 那个接口面向开发者跑计算，性能优先；DeepSeek 造的是产品级 agent 平台，可恢复、可审计本身就是产品承诺。没有谁对谁错，但你给自己的系统选型时，这就是那条要划的线——省下来的性能，是用\"出了事说不清\"换的。另外日志只会越来越长：压缩只是把旧内容从模型视野里遮掉，一个字节不删。省的是 token，不是硬盘。",[10,101,102],{},"如果只能带走一样，我带那条断言。在自己的系统里加五行：每次请求前，把要发出去的上下文和日志里推导出来的比一遍，不一致就报错。它给你的东西很具体：模型行为不对，你查得到它当时到底看到了什么；长任务断了，能原样接上；哪段代码偷偷改了上下文，当场暴露，不用等上线之后靠猜。",[39,104,106],{"id":105},"二agent-主循环就是一行配置","二、Agent 主循环就是一行配置",[10,108,109],{},"\"一切皆插件\"听起来像营销话术，在这里是字面意思。驱动 agent 的主循环——决定什么时候调模型、跑工具、继续还是停下的那个东西——在默认配置里就是普通的一行：",[47,111,115],{"className":112,"code":113,"language":114,"meta":53,"style":53},"language-yaml shiki shiki-themes dracula","# packages/bundle/base/cordis.patch.yml\n- id: agent-loop\n  name: '@deepseek-ai/dsh-agent-loop'\n  config:\n    agents: []   # 预配置的常驻 agent 清单，留空表示按需创建\n","yaml",[55,116,117,126,144,162,171],{"__ignoreMap":53},[118,119,122],"span",{"class":120,"line":121},"line",1,[118,123,125],{"class":124},"shSDL","# packages/bundle/base/cordis.patch.yml\n",[118,127,129,133,137,140],{"class":120,"line":128},2,[118,130,132],{"class":131},"s0Tla","-",[118,134,136],{"class":135},"sLL85"," id",[118,138,139],{"class":131},":",[118,141,143],{"class":142},"s-mGx"," agent-loop\n",[118,145,147,150,152,156,159],{"class":120,"line":146},3,[118,148,149],{"class":135},"  name",[118,151,139],{"class":131},[118,153,155],{"class":154},"seVfx"," '",[118,157,158],{"class":142},"@deepseek-ai/dsh-agent-loop",[118,160,161],{"class":154},"'\n",[118,163,165,168],{"class":120,"line":164},4,[118,166,167],{"class":135},"  config",[118,169,170],{"class":131},":\n",[118,172,174,177,179,183],{"class":120,"line":173},5,[118,175,176],{"class":135},"    agents",[118,178,139],{"class":131},[118,180,182],{"class":181},"sCdxs"," []   ",[118,184,185],{"class":124},"# 预配置的常驻 agent 清单，留空表示按需创建\n",[10,187,188,189,192],{},"关掉它不用改代码：",[55,190,191],{},"disabled: true"," 是每一行配置都认的开关，加在哪一行，哪个插件就不挂载。这不是理论上的能力，出厂配置自己就在用。同一份文件里，bash 沙箱和 PowerShell 沙箱靠两个相反的平台条件各挂各的，还有一个插件发了货、又在默认配置里关着：",[47,194,196],{"className":112,"code":195,"language":114,"meta":53,"style":53},"- id: bash-sandbox\n  name: '@deepseek-ai/dsh-bash-sandbox'\n  disabled: !!js process.platform === 'win32'   # Windows 上不挂载\n\n- id: pwsh-sandbox\n  name: '@deepseek-ai/dsh-pwsh-sandbox'\n  disabled: !!js process.platform !== 'win32'   # 只在 Windows 挂载\n\n- id: skill-badge\n  name: '@deepseek-ai/dsh-skill-badge'\n  disabled: true                                # 发了这个功能，默认关闭\n",[55,197,198,209,222,238,244,255,269,284,289,301,315],{"__ignoreMap":53},[118,199,200,202,204,206],{"class":120,"line":121},[118,201,132],{"class":131},[118,203,136],{"class":135},[118,205,139],{"class":131},[118,207,208],{"class":142}," bash-sandbox\n",[118,210,211,213,215,217,220],{"class":120,"line":128},[118,212,149],{"class":135},[118,214,139],{"class":131},[118,216,155],{"class":154},[118,218,219],{"class":142},"@deepseek-ai/dsh-bash-sandbox",[118,221,161],{"class":154},[118,223,224,227,229,232,235],{"class":120,"line":146},[118,225,226],{"class":135},"  disabled",[118,228,139],{"class":131},[118,230,231],{"class":131}," !!js",[118,233,234],{"class":142}," process.platform === 'win32'",[118,236,237],{"class":124},"   # Windows 上不挂载\n",[118,239,240],{"class":120,"line":164},[118,241,243],{"emptyLinePlaceholder":242},true,"\n",[118,245,246,248,250,252],{"class":120,"line":173},[118,247,132],{"class":131},[118,249,136],{"class":135},[118,251,139],{"class":131},[118,253,254],{"class":142}," pwsh-sandbox\n",[118,256,258,260,262,264,267],{"class":120,"line":257},6,[118,259,149],{"class":135},[118,261,139],{"class":131},[118,263,155],{"class":154},[118,265,266],{"class":142},"@deepseek-ai/dsh-pwsh-sandbox",[118,268,161],{"class":154},[118,270,272,274,276,278,281],{"class":120,"line":271},7,[118,273,226],{"class":135},[118,275,139],{"class":131},[118,277,231],{"class":131},[118,279,280],{"class":142}," process.platform !== 'win32'",[118,282,283],{"class":124},"   # 只在 Windows 挂载\n",[118,285,287],{"class":120,"line":286},8,[118,288,243],{"emptyLinePlaceholder":242},[118,290,292,294,296,298],{"class":120,"line":291},9,[118,293,132],{"class":131},[118,295,136],{"class":135},[118,297,139],{"class":131},[118,299,300],{"class":142}," skill-badge\n",[118,302,304,306,308,310,313],{"class":120,"line":303},10,[118,305,149],{"class":135},[118,307,139],{"class":131},[118,309,155],{"class":154},[118,311,312],{"class":142},"@deepseek-ai/dsh-skill-badge",[118,314,161],{"class":154},[118,316,318,320,322,326],{"class":120,"line":317},11,[118,319,226],{"class":135},[118,321,139],{"class":131},[118,323,325],{"class":324},"sIQBb"," true",[118,327,328],{"class":124},"                                # 发了这个功能，默认关闭\n",[10,330,331],{},"把同一个开关放到 agent-loop 那一行上，就没有 agent 了。主循环和一个小徽章插件，在配置系统眼里是平级的。",[10,333,334],{},"对你来说，这意味着攒一个自己的 agent 是配置活，不是开发活。极简模式整个 agent 只有 62 行，开头长这样：",[47,336,338],{"className":112,"code":337,"language":114,"meta":53,"style":53},"- id: persona\n  name: '@deepseek-ai/dsh-persona'\n  config:\n    text: You are a helpful software engineer assistant.\n",[55,339,340,351,364,370],{"__ignoreMap":53},[118,341,342,344,346,348],{"class":120,"line":121},[118,343,132],{"class":131},[118,345,136],{"class":135},[118,347,139],{"class":131},[118,349,350],{"class":142}," persona\n",[118,352,353,355,357,359,362],{"class":120,"line":128},[118,354,149],{"class":135},[118,356,139],{"class":131},[118,358,155],{"class":154},[118,360,361],{"class":142},"@deepseek-ai/dsh-persona",[118,363,161],{"class":154},[118,365,366,368],{"class":120,"line":146},[118,367,167],{"class":135},[118,369,170],{"class":131},[118,371,372,375,377],{"class":120,"line":164},[118,373,374],{"class":135},"    text",[118,376,139],{"class":131},[118,378,379],{"class":142}," You are a helpful software engineer assistant.\n",[10,381,382,383,386],{},"一行 persona，一个持久 bash，一个文件编辑器，就是一个能干活的 agent。想换性格、砍工具、改模型路由，动的都是这样的行。想知道自己机器上到底跑着什么，",[55,384,385],{},"dsh --dump-config"," 把实际启动的整棵树打出来，每段配置上方注明它来自哪个文件、被哪几层补丁改过，打印出的每一行都能被你自己的补丁覆盖。可换到什么程度？把文件系统和子进程这两行 provider 从本地实现换成 E2B 的远程实现，Bash、终端、LSP 整套工具跟着搬进远程沙箱——工具本身一行代码不用改。",[10,388,389],{},"界面上的四种\"模式\"（标准、代码、极简、创造）就是四份这样的 YAML。最能说明问题的对比是代码模式和标准模式：抛开注释，两份文件的配置一模一样——同样的 bash、文件工具、skill、压缩——差别只有末尾追加的一行：",[47,391,393],{"className":112,"code":392,"language":114,"meta":53,"style":53},"- id: tool-presentation\n  name: '@deepseek-ai/dsh-agent-tool-presentation'\n  config:\n    mode: code\n",[55,394,395,406,419,425],{"__ignoreMap":53},[118,396,397,399,401,403],{"class":120,"line":121},[118,398,132],{"class":131},[118,400,136],{"class":135},[118,402,139],{"class":131},[118,404,405],{"class":142}," tool-presentation\n",[118,407,408,410,412,414,417],{"class":120,"line":128},[118,409,149],{"class":135},[118,411,139],{"class":131},[118,413,155],{"class":154},[118,415,416],{"class":142},"@deepseek-ai/dsh-agent-tool-presentation",[118,418,161],{"class":154},[118,420,421,423],{"class":120,"line":146},[118,422,167],{"class":135},[118,424,170],{"class":131},[118,426,427,430,432],{"class":120,"line":164},[118,428,429],{"class":135},"    mode",[118,431,139],{"class":131},[118,433,434],{"class":142}," code\n",[10,436,437,438,441],{},"这一行改的是\"工具怎么呈现给模型\"。标准模式下，模型看到二十多个工具的说明书，一个一个直接调用；加上 ",[55,439,440],{},"mode: code","，模型看到的变成一个 run_code 工具加一份自动生成的 TypeScript 接口——它改成写一段程序来编排这些工具，中间结果留在程序里，不占上下文窗口。整个交互方式翻转了，只动了一行——因为\"工具的呈现方式\"在这套架构里也是一个可替换的插件。",[10,443,444,445,448],{},"这种灵活性绕不开一个问题：配置写错了怎么办？代码写错，编译器会拦；YAML 写错，没人拦，而且错得特别安静。DeepSeek 自己翻过两次车。一次是一个条件表达式写错了位置，文件读写工具在所有模式下集体消失——不报错，就是没了。另一次是插件多写了一行 ",[55,446,447],{},"export default","，加载器悄悄丢掉了它的依赖声明：178 个测试全绿、覆盖率 100%，产品一连上真实编辑器就崩。他们的对策也直接：每翻一次车，就加一道发布前的静态检查，专门拦那一类错。这样的检查现在有 27 道——等于把编译器的活，用脚本一件一件买回来。想用\"一切皆配置\"这套思路，就得连这笔账一起接下来。",[10,450,451],{},"我的判断：对押注生态的平台，这笔交易是自洽的。对我们大多数人，值得学习的是它的透明度和开关纪律——系统实际跑什么，一条命令可见；每个组件，一行配置可关；每一类踩过的配置错误，配一道机器检查。",[39,453,455],{"id":454},"三缓存纪律用-ci-强制执行","三、缓存纪律，用 CI 强制执行",[10,457,458],{},"先看钱。按发布那周的定价，DeepSeek 的缓存命中价格大约是未命中的五十分之一（V4-Flash）到一百二十分之一（V4-Pro）——北京时间 8 月 17 日 00:00 起改为分时定价，倍数压到 30 倍左右，但量级摆在那。对一家卖 token 的公司，你的请求有没有命中缓存，不是性能细节，是毛利。",[10,460,461],{},"这里得先补一个很多人（包括写这篇之前的我）都模糊的背景：这个缓存到底是谁在管、怎么工作的。打个比方：模型读你的提示词，像一位按小时计费的律师读合同。第一次，他从头读到尾，全价。第二次你拿来同一份合同，只在末尾加了一条新条款——他不用重读前面，从新条款读起，前面的部分按\"记忆费\"收个零头。但要是你把第一页改了一个字，他就得从那里起整份重读，因为他对每一段的理解都建立在前文之上。LLM 完全一样：服务商把你上次请求里已经\"读过\"的前缀的计算结果存着，下次请求若以逐字节相同的内容开头，存过的部分按折扣价收，从第一个不同的字节开始才全价重算。",[10,463,464],{},[72,465],{"alt":466,"src":467},"读者掀起长合同扬起的纸页——一个小红标记之后的每一页都得重读，桌角的计数器还在走","/blogs-img/2026-08-16-harness-02.webp",[10,469,470,471,475],{},"所以分工是这样的：",[472,473,474],"strong",{},"缓存发生在模型服务商那一端，命中与否却由 harness 决定。"," 各家的开法不太一样——DeepSeek 和 OpenAI 自动缓存前缀，Anthropic 要你显式标记缓存点——但道理相同：存不存是服务商的事，你发过去的内容对不对得上，全看 harness 怎么组装请求。服务商负责存，harness 负责别把钥匙弄丢。",[10,477,478],{},"而弄丢钥匙非常容易。最常见的一种：很多框架的默认模板会把当前时间写进系统提示词开头——",[47,480,483],{"className":481,"code":482,"language":52,"meta":53},[50],"坏：系统提示词第一行「当前时间：2026-08-19 09:32:07」\n    → 每秒都在变，前缀从第一行起就对不上，每个请求整份全价\n\n好：系统提示词里没有时间\n    → 真需要时间时，作为一条普通消息追加到对话末尾\n      （DSH 默认压根不注入时钟）\n    → 前缀逐字节不变，只有新增的尾部按全价算\n",[55,484,482],{"__ignoreMap":53},[10,486,487],{},"DSH 就是按\"好\"的那种做的。第二种丢法：工具说明书的顺序跟着插件加载顺序走，加载顺序一变，说明书重排，前缀就碎了——所以 DSH 不信加载顺序，一律按固定的字典序排。第三种最隐蔽：随便哪个新插件往提示词里塞了点会变的东西，全团队的缓存跟着碎，还没人知道是谁干的——所以他们规定每个包的 README 必须写一节\"KV Cache effect\"，声明自己对前缀的影响，缺了 CI 直接红（只有四个审计过、与模型无关的包豁免）。最狠的一道是连真实 API 的测试，直接断言缓存必须命中：",[47,489,493],{"className":490,"code":491,"language":492,"meta":53,"style":53},"language-ts shiki shiki-themes dracula","// packages/core/agent-loop/tests/request-cache.e2e.ts\n// 会话里除第一个请求外，每个请求都必须报告缓存命中\nfor (const usage of usages.slice(1)) {\n  expect(usage!.cacheReadTokens ?? 0).toBeGreaterThan(0)\n}\n","ts",[55,494,495,500,505,538,572],{"__ignoreMap":53},[118,496,497],{"class":120,"line":121},[118,498,499],{"class":124},"// packages/core/agent-loop/tests/request-cache.e2e.ts\n",[118,501,502],{"class":120,"line":128},[118,503,504],{"class":124},"// 会话里除第一个请求外，每个请求都必须报告缓存命中\n",[118,506,507,510,513,516,519,522,525,529,532,535],{"class":120,"line":146},[118,508,509],{"class":131},"for",[118,511,512],{"class":181}," (",[118,514,515],{"class":131},"const",[118,517,518],{"class":181}," usage ",[118,520,521],{"class":131},"of",[118,523,524],{"class":181}," usages.",[118,526,528],{"class":527},"sAOxA","slice",[118,530,531],{"class":181},"(",[118,533,534],{"class":324},"1",[118,536,537],{"class":181},")) {\n",[118,539,540,543,546,549,552,555,558,561,564,566,569],{"class":120,"line":164},[118,541,542],{"class":527},"  expect",[118,544,545],{"class":181},"(usage",[118,547,548],{"class":131},"!",[118,550,551],{"class":181},".cacheReadTokens ",[118,553,554],{"class":131},"??",[118,556,557],{"class":324}," 0",[118,559,560],{"class":181},").",[118,562,563],{"class":527},"toBeGreaterThan",[118,565,531],{"class":181},[118,567,568],{"class":324},"0",[118,570,571],{"class":181},")\n",[118,573,574],{"class":120,"line":173},[118,575,576],{"class":181},"}\n",[10,578,579],{},"它敢这么断言，靠的是第一节那套日志设计：每个请求都是上一个请求的延长，前缀天然稳定——两套设计在这里咬合上了。任何打碎前缀的回归，在烧到钱之前，CI 先红。",[10,581,582],{},"这套纪律值多少钱，拿一个长会话算一下就明白。一次请求的前缀——系统提示词加工具说明书加全部历史——动辄上万 token；一个几十步的任务，要把这个前缀反复发几十遍。命中，这几十遍按零头计价；不命中，遍遍全价。同一个任务，账单能差出一个量级。大多数框架没有人管这件事，模板里带着时间戳、工具顺序随加载而变，命中与否全凭运气；DSH 把它当成带测试的不变量来管。这也是\"谁造的、为什么造\"最清晰的指纹——只有模型公司会围绕自家价目表设计 harness。",[10,584,585,586,589],{},"但这套纪律管的全是字节，管不到时间——而每份缓存都有寿命。DeepSeek 自己的文档写着，不再使用的缓存会被自动清空，\"时间一般为几个小时到几天\"，并且明说整套机制是\"尽力而为\"；Anthropic 那边紧得多：五分钟没被用到就过期，而且计时是从",[472,587,588],{},"上一次用到它","那一刻起算的。钟走的是闲置时长，不是年龄，而且都不归你调。周末搁下，周一回来，第一个请求要为整个前缀重新付一遍——在写缓存要加价的那几家，比全价还贵。不是你哪里拼错了，是保险箱趁你不在的时候自己清空了。",[10,591,592],{},"DSH 没有解决这件事，它把边界写了下来。那条管着所有 README 的规矩里写得很清楚：服务商缓存的\"可用性与逐出不在包契约范围内\"。会话恢复能不能复用缓存，也只看重建出的历史、当前信封和模型路由对不对得上——没有\"你离开了多久\"这一项。harness 只认字节稳定，时间明确不归它管。这是诚实的分工，也是这几个设计第二次咬合的地方：搁久了，折扣没了，会话照样一字不差地重放——因为留下来的是日志，不是缓存。",[10,594,595],{},"这三样：固定排序、易变内容出前缀、缓存命中断言，任何技术栈这周就能用上，跑谁家的模型都省钱。",[39,597,599],{"id":598},"四它是ai-建造复杂系统迄今最清晰的公开标本","四、它是\"AI 建造复杂系统\"迄今最清晰的公开标本",[10,601,602,603,606,607,610,611,614,615,618,619,621],{},"这个仓库用 64 天写了 12,293 次提交。37 位署名作者里，第一名一个人提交了 5,235 次，占全仓 42.6%。仓库里 markdown 文件比 TypeScript 文件还多。我又数了一遍合并记录里的分支名：",[55,604,605],{},"worktree/"," 出现 210 次，",[55,608,609],{},"codex/"," 209 次，",[55,612,613],{},"agent/"," 15 次，",[55,616,617],{},"claude/"," 3 次——",[55,620,609],{}," 是编码 agent 建分支的默认命名，两百多次不是手滑。产码的主体不是人。",[10,623,624,629],{},[14,625,628],{"href":626,"rel":627},"https://x.com/sawyerhood/status/2087930588582093033",[18],"Sawyer Hood 那句玩笑","——\"2026 是 harness 自己建造自己的一年\"——这个仓库就是实物。而它真正值得学的，是围绕这个事实建起来的整套打法。",[10,631,632,633,636],{},"开工第二天的一篇流程笔记把理论说破了：相比写在文档里的约定，agent 遵守被强制执行的检查要可靠得多；而当劳动由 agent 完成时，\"工作量太大\"就不再构成反对理由。往下全是这句话的推论。每个非平凡改动必须附带设计笔记，现在有 683 篇。有一个 ",[55,634,635],{},"rejected/"," 目录冻结着被否决的方案和否决理由，只要那份理由还拦得住一个诱人的错误，就一直留着——用过 AI 的人都认得这是什么，一套防止 AI 重提死方案的免疫系统。事故复盘不许以\"教训\"收尾，必须以机器检查收尾，还得验证过\"把 bug 恢复回去，检查真的会红\"。",[10,638,639],{},"明显的反驳是：文档既然由 agent 来写，数量什么也证明不了——683 篇也可能只是机器吐出来的废纸。这套制度的回答长在自己的规则里：否决记录一旦拦不住错误就删掉，被取代的笔记移进冻结档案，复盘要验证过\"检查真的会红\"才算数。值钱的是那道过滤，不是那个数字。",[10,641,642,643,646],{},"我在这上面停的时间最长，因为它回答的问题比 harness 大：",[472,644,645],{},"让 AI 大规模建造复杂软件，已经从演示变成了常规操作——而这个仓库把操作手册留在了明面上。"," 展开说是三层。",[10,648,649,650,654],{},"团队形态变了。37 个人、两个月、一万两千次提交，人的岗位从写代码挪到了设定规则、裁决证据、审批合并。这正是我七月写的 ",[14,651,653],{"href":652},"/zh/blogs/one-person-project-ai-coding","one-person project"," 在工业尺度上的样子：一个负责人握住上下文，AI 执行，团队管边界和证据——只不过这里的\"一个人\"带着一整支 agent 车队。",[10,656,657],{},[72,658],{"alt":659,"src":660},"三个人在小桌前分卡、盖章、审读，一长队一模一样的纸片人举着亮卡穿过绿门走向远方","/blogs-img/2026-08-16-harness-03.webp",[10,662,663],{},"流程的经济学反转了。\"每个改动配一篇文档\"在人力团队里是官僚主义，会上活不过三分钟；在 agent 团队里是防漂移的护栏，因为写的人不喊累。于是规则可以定得比以前密得多。他们画的那条线也值得直接拿来用：机器能检查的，全部交给机器；需要判断力的，留给人。他们刻意留给人的那条规则，是判断\"这个改动重要到需要写一篇设计笔记吗\"——这件事机器判不了。",[10,665,666],{},"质量的定义也变了。覆盖率和绿色测试在这个仓库里被自己的事故证明过靠不住（上面那个 178 个绿测试的故事），所以他们把质量押在别处：真实加载路径的端到端测试、验证过会变红的闸门、被冻结的否决理由。这些不是工程洁癖，是把\"AI 会犯的错\"翻译成系统约束的管理结构。",[10,668,669],{},"就算 DSH 一直像 Ronacher 说的那样\"不完美\"，最后也没流行起来，这本操作手册已经公开了。对任何在用 AI 做东西的团队，这是仓库里最值钱的部分。",[39,671,673],{"id":672},"从代码里看-dsh-的战略","从代码里看 DSH 的战略",[10,675,676,677,680,681,684,685,688],{},"三个动作，都能去仓库里验证。第一，它直接采用了对手的标准：skill 用的就是 SKILL.md 格式（设计笔记显示他们把自家字段拼写改成了 Claude 的写法，连兼容旧拼写的别名都拒绝保留），零配置读取 ",[55,678,679],{},"~/.agents/skills","，优先加载 ",[55,682,683],{},"AGENTS.md","、兼容 ",[55,686,687],{},"CLAUDE.md","——你的 skill 和指令文件第一天就能用。第二，不支持的功能它明说：Claude Code hooks 兼容层的 README 写明 30 种事件有 23 种不支持，不装克隆。第三，它把竞争对手变成了自己的插件：Claude Code 和 Codex 被接成 subagent，任务可以直接委托给对手的产品跑。",[10,690,691,692,696],{},"有一种更省事的解释：把一个体验还落后的 harness 白送出去，DeepSeek 没什么损失，开源还白赚一波好感。这个解释到此为止都对——但它解释不了上面那三个动作。赚好感犯不着去做那些不露脸的工程活：兼容对手的格式，还把自己不支持什么写成文档。我的读法——也只能是读法，因为意图不写在仓库里：Anthropic 把 harness 闭源、和订阅绑定，是给模型修护城河；DeepSeek 把 harness 白送、让它读所有人的格式，是给自己真正卖的东西修漏斗：token。七月我论证过",[14,693,695],{"href":694},"/zh/blogs/why-ai-companies-are-becoming-deployment-companies","稀缺的是 deployment 能力，不是模型访问权","，当时的证据是各家在部署工程师身上砸几十亿美金，这次是同一个赌注的软件形态。这里面还有一层：当一家厂商采用对手的文件格式，对手用户手里的资产就变成可携带的了。可携带性是把双刃剑，DeepSeek 主动把它磨快了。",[10,698,699,700,703,704,709],{},"最后说说它现在的状态，以下都是仓库自己写在文档里的：防止模型死循环的机制只会发提醒，不能强制打断，提醒发够次数之后就不再管了；文件读、写、编辑三个工具没有任何超时，bash 的超时也不归守卫插件管，只有 shell 执行器自带的默认兜底；Claude Code hooks 兼容层收到\"拦截\"指令（",[55,701,702],{},"continue: false","）时只记录下来，并不真的拦。一位提前拿到仓库权限的开发者",[14,705,708],{"href":706,"rel":707},"https://x.com/jiayuan_jy/status/2087911060154314963",[18],"说得很直白","：日常体验还落后于 Claude Code 和 Codex。Ronacher 那句\"不完美\"是准的——这周就要干活，它还不是你的首选。",[39,711,712],{"id":712},"我学到了什么",[10,714,715,716,718],{},"三件事我会直接用到自己的系统里。第一，请求前断言：五行代码，每次调模型前核对上下文和日志一致，出问题当场报错。第二，缓存三件套：工具固定排序、时间这类会变的信息不进提示词前缀、加一条测试盯着缓存命中。第三，在自己的仓库里建一个 ",[55,717,635],{}," 目录，把否决过的方案和理由存下来——我的 agent 也会把上个月毙掉的想法再提一遍。",[10,720,721],{},"看大局，我的结论也更清楚了。模型是租来的，本来就设计成可以换。harness 这一层还会大改——仓库自己都用全大写警告\"兼容性说破就破\"，现在花大力气深度绑定任何一家，很可能白费。真正属于你、而且越攒越值钱的，是每个 harness 都会读的那层：你的 skill、你的指令文件、你记下来的\"什么有效、什么被否决\"。",[10,723,724],{},"所以我给自己定的规则，也推荐给你：模型随时可换，harness 别深度绑定，重点攒每个 harness 都认的那层资产。这周花一小时，把你的 AI 资产列两栏——能带走的、被锁死的。这张清单比任何评测都更能告诉你，接下来该把时间花在哪。",[10,726,727],{},[72,728],{"alt":729,"src":730},"一个人把几张卡片和一本笔记装进小行李箱，精良的机器留在架子上，被螺栓妥帖固定","/blogs-img/2026-08-16-harness-04.webp",[732,733],"hr",{},[10,735,736],{},[737,738,739],"em",{},"本系列下一篇：第一次请求的账单。在你对 agent 打出第一个字之前，你已经在付一笔固定的入场费——我会在自己的技术栈上复现 token 级的测量，看看我的入场费是多少。订阅邮件列表，第一时间收到。",[741,742,743],"style",{},"html pre.shiki code .shSDL, html code.shiki .shSDL{--shiki-default:#6272A4}html pre.shiki code .s0Tla, html code.shiki .s0Tla{--shiki-default:#FF79C6}html pre.shiki code .sLL85, html code.shiki .sLL85{--shiki-default:#8BE9FD}html pre.shiki code .s-mGx, html code.shiki .s-mGx{--shiki-default:#F1FA8C}html pre.shiki code .seVfx, html code.shiki .seVfx{--shiki-default:#E9F284}html pre.shiki code .sCdxs, html code.shiki .sCdxs{--shiki-default:#F8F8F2}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html pre.shiki code .sIQBb, html code.shiki .sIQBb{--shiki-default:#BD93F9}html pre.shiki code .sAOxA, html code.shiki .sAOxA{--shiki-default:#50FA7B}",{"title":53,"searchDepth":128,"depth":128,"links":745},[746,747,748,749,750,751],{"id":41,"depth":128,"text":42},{"id":105,"depth":128,"text":106},{"id":454,"depth":128,"text":455},{"id":598,"depth":128,"text":599},{"id":672,"depth":128,"text":673},{"id":712,"depth":128,"text":712},"花几天钻进 DeepSeek 开源的 agent harness，锚定一个 commit 逐条核验：模型逃不出的日志、一行配置的主循环、CI 强制的缓存纪律、以及一万二千次 agent 提交背后的流程操作系统——还有建造者真正该攒的那层资产。","md",{"date":755,"image":756,"alt":757,"category":758,"tags":759,"youtube":764,"published":242},"16th Aug 2026","/blogs-img/2026-08-16-harness-cover.webp","44 条档案纸带中，只有三张亮卡穿过窄玻璃口来到伏案读者面前","ai-native-systems",[760,761,762,763],"agent-harness","deepseek","agent-架构","ai-战略","https://youtu.be/5vEEBhbfUWw","/blogs/zh/deepseek-harness-teardown",{"title":5,"description":752},"blogs/zh/30.deepseek-harness-teardown","Urs_hnrxTX0RYcTuyrlk1384nt7bm3IM50jcXuMcnnc",1786875956447]