乐于分享
好东西不私藏

28 万行源码,详细拆解 DeepSeek Harness

28 万行源码,详细拆解 DeepSeek Harness
DeepSeek 今天开源的东西,值得你把手机放下,读十分钟。

我把它的源码逐行读完了:28 万行应用,压在一个不到 2000 行的内核上。

先把最核心的判断放在最前:

核心判断

DeepSeek Harness 是一个完全由插件拼成的 Agent:内核轻到 2000 行,能力全部可插拔、可定制,连"改自己"都是一个插件。

这是它和市面上所有 agent 框架的区别。别的框架给你一个成品 agent,它给你一箱零件和一张图纸:极度轻量化的内核,高度定制的组装方式,还有一个能自己动手改装的 AI。

从地基讲起。

一、先认识地基:一个叫 Cordis 的内核

DeepSeek Harness 脚底下踩着一个内核,叫 Cordis。它是这次开源里最不起眼、也最值钱的部分。

Cordis 不是 DeepSeek 临时写的,是一个开源社区的插件元框架,四年前诞生,最著名的应用是聊天机器人框架 Koishi,靠它攒下 4000 多个社区插件。DeepSeek 这次做的是:把 Cordis 的源码整个搬进自己的仓库,改名 @deepseek-ai/cordis,按产品需求打了 6 处生命周期补丁,有的补丁反过来是从上游正在合入的 PR 移植来的。它用了这个框架,改了它,也回喂它。

再说规模,这个数字刚看到时我也不信:内核净代码 1688 行,9 个文件,心脏是 fiber.ts。

1688 行概括成两个词。

一个是可逆效应。每一次改动,都必须同时交出"怎么改回去"的方法。你往共享环境里写入一个值,就得同时告诉我怎么把这个值删掉。运行时把这些"改回去的方法"按顺序攒起来,组件卸载时倒着执行一遍,环境回到它加载之前的样子。后进先出,像穿衣服脱衣服,先穿的最后脱。

另一个是响应式协效应。组件之间要什么,说出来;管依赖的事,交给运行时。组件用 inject 声明"我需要一个数据库",运行时就会等数据库就位再激活它,数据库被换掉就自动通知、停掉、重载。像点菜时说"不放葱",而不是自己进厨房盯着厨师。

这两个词,就是理解整个 DeepSeek Harness 的钥匙。

二、撤销键落地:每一笔改动都自带"怎么改回去"

可逆效应在代码里长什么样?

内核里所有会改动环境的操作,都得走同一个口子,叫 ctx.effect。你注册一个监听、占一块资源、挂一个插件,都通过它,同时把"怎么撤销"交出去。框架把这些撤销操作记在表上,等你要卸载,它把表倒过来,一笔一笔还回去。这个"倒过来还",在代码里就是一行:disposables.splice(0).reverse()。后进先出,像收拾桌子,最后放的最先拿走。

把这条规则读到底,有两个细节。一是单个 effect 内部的逆操作严格倒序、串行回放,但整个组件卸载时,各个 effect 的清理是并发启动的。论文保证"逆操作的复合在数学上可恢复原状态",实现选择"并发执行、各自内部逆序"。数学正确性和工程并发之间,它选了后者。说实话,看到这个取舍我松了口气:一个敢在代码里承认"这里没按论文来"的团队,比满口保证的团队可信。

二是 fiber.ts 里有一条很有人味的注释,讲一个卸载过程绝不允许抛错的地方,写道:如果它真抛了,"process-level crash is the honest outcome",那就让进程崩掉,这才是诚实的结果。写代码的人知道自己在守一条什么样的边界,才会写下这种话。

逆操作写得对不对,框架并不验证,这是插件作者对运行时的承诺。哪些正确性是框架保证的,哪些是作者义务,论文里画得清清楚楚。连"撤销"都有物理边界:已经发出去的网络包、刷出去的银行卡,撤销不了。论文的出路是扣住不发,或者事后补偿。它承认撤销有边界,不假装 AI 的每个动作都能一键回滚。

依赖声明制在代码里同样有意思。每个组件会算一个 epoch,它就是依赖提供者 uid 的字符串拼接。每个组件实例有一个永不复用的 uid:你依赖的数据库换了实现,哪怕新实现提供的值一模一样,epoch 也变了,组件重载;同一个提供方原地更新自己的值,epoch 不变,不重载。依赖变没变,认人,不认值。连配置文件里的行序都没有加载语义,激活完全由依赖声明驱动。论文的验证案例是 Koishi,4000 多个插件来自互不认识的作者,却能像一套系统一样协同,靠的就是这两个词。

为了把"热插拔"这件事,从"祈祷插件作者写干净了",变成"框架从结构上保证能收干净"。你团队里最菜的那个工程师写的插件,哪怕忘了写卸载逻辑,框架也能替他把摊子收平。安全不再取决于生态里最不靠谱的那个人。对一个想开放插件生态、又怕被烂插件拖垮的平台,这一条是命根子

三、一切皆插件

地基说完了。

仓库写给 AI 协作者的说明第一行:everything is a plugin,一切皆插件。

口号谁都会喊。让我信的是目录。每一种能力都是一个独立的包:模型是 llm/,命令行是 shell/,文件系统是 fs/,网页是 web/,技能是 skill/,上下文压缩是 compaction/,子 agent 是 subagent/,工作流是 workflow/,会话是 session/。夸张到什么程度?连"失败重试"都是一个独立插件(llm-retry),连"算 token 花了多少钱"都是(token-meter),连"给对话起个标题"都拆成了好几个可替换的实现。

一个插件长什么样?接一个外部记忆系统,配置文件里就几行:一个 id,一个 npm 包名,一段配置。就这样。

它甚至把这条原则钉成了铁律:新行为写成插件,不要改主循环。连那个驱动整个 agent 转起来的主循环,都是一个尽量不许你动的稳定插件,你要加东西,去插件那层加。

再往下看,还有个姿态很有意思。在 packages/llm 里,"模型"被拆成一个接口定义加具体实现。DeepSeek 自己的模型,在这套架构里,就是"模型"这个插槽上可以被换下来的那个实现。

说清现状:目前仓库里正式发货的模型提供方,只有 DeepSeek 自己这一个,另一个通用网关适配器还在,测试里能看到它在对接 OpenAI、Anthropic 那种接口。换模型的插槽留好了、机制跑通了,但别家模型的适配器,DeepSeek 没有替你写。

读到 packages/llm 这个目录的时候,我停下来想了一会。一个靠模型立身的公司,把自家模型放在了整个架构里最容易被替换掉的位置。这是阳谋:它赌的不是锁死你只能用 DeepSeek 模型,而是你在这套骨架上搭系统,哪怕将来把模型换成别家,这套骨架、这套插件生态、你所有的工程投入,还是长在它这里。它放弃模型层的锁定,去换一个更上游的东西,开发范式的锁定。这比锁模型高一个维度

四、三种用法:网页、命令行、Python

第一种用法是 Web 界面:npx @deepseek-ai/dsh web 一条命令,本地起一个网页,默认开在 127.0.0.1:3080,配好 key 就能派活。我此刻写这篇文章用的界面,就是它。第二种是 headless:dsh --profile headless "任务",跑完一次性任务、打印结果后退出,不监听任何端口,适合塞进 CI。第三种是 Python SDK:pip install deepseek-harness-sdk,运行时内置、免装 Node.js,程序里两行代码就能驱动一个完整的 agent。

三种用法共享同一副骨架,差别只在配置:示例配置极简到只剩 bash 和文件编辑器两个工具,Web 出厂配置几乎全装。中间差多少?几行 YAML。

成绩也摆一下:V4-Flash 正式版的公开基准 Code Agent 任务,就是用 Harness 极简模式跑出来的,TerminalBench 2.1 得分 82.7。8 月 1 日开放内测,13 日仓库公开,当天 1.7 万星(数据均截至发稿)。

同一个引擎,三套外壳,覆盖从"人在 GUI 里交互"到"机器在 CI 里自动跑"再到"程序在代码里调用"的完整光谱。产品没被做成一个应用,而是被做成一个运行时,应用只是它的三种打开方式之一。

五、安全哲学和 Claude Code 正好相反:一个查,一个关

我上次拆 Claude Code,讲过它五千行代码专门审查每一条要执行的命令,像海关开箱把行李逐件过 X 光,识别几十种伪装手法。那是"审查"的路子。

DeepSeek 这边,我本来也去找类似的东西。结果它那个叫 guard 的包总共才一千行,干的是完全不同的活:只管"别让模型陷进死循环反复调同一个工具""每个工具调用别超时"。它明说了自己不是安全能力,是"循环卫生"。

那真正的安全在哪?我一路找到 native/ 目录,里面藏着一个约 300 行 C 语言写的、跟 musl 静态链接的小程序,用的是 Linux 内核的 Landlock 机制。我尽量说白:在真正跑那条危险命令之前,先把自己的手脚捆住,只允许访问你明确授权的那几个目录,然后才去执行命令。这个"捆住"会遗传给命令生出来的每一个子进程。你授权了什么就只能碰什么,没授权的一律拒绝。

最关键的是四个字:失败闭合。如果内核这道锁没法生效,它不心存侥幸放行,直接不跑、退出。C 源码里一句 "never exec unconfined":永不无沙箱执行。拒绝的时候,输出是 "refusing to run the command unconfined"。

沙箱的平台链是一张表:Linux 用 bwrap 或 Landlock,macOS 用 Seatbelt,Windows 用受限令牌。

Windows 那套的实现里有一条注释,原文是 "freeing the ACL pointer corrupts the heap (verified the hard way)":释放这个指针会破坏堆,"以惨痛方式验证过"。这种注释,比任何安全白皮书都有说服力。

权限只有三档,部署默认是只读,注释叫它"fail-safe 底座"。这个框架对"诚实"还有执念:Windows 的 ACL 方案声明强制执行完整性时老老实实写 partial,因为 NTFS 硬链接能把工作区内的文件别名到工作区外;文件系统围栏的注释写着 "containment, not a security boundary",这是遏制,不是安全边界。哪里是边界、哪里只是隔离,代码里写得一清二楚。

这是两种安全世界观。Claude Code 相信"我能识别出所有坏命令",所以在应用层建了一个越来越聪明的审查器。DeepSeek 不赌自己能认全坏命令,它把 AI 关进一个操作系统级的笼子。你能碰的东西在放你进去之前就框死了,认不认得出恶意根本不重要。一个赌智能,一个赌隔离。对一个要让不可信的、甚至模型自己现写的代码在生产里跑的系统,"隔离"这条路,工程上更让人睡得着。

六、为什么是量化交易员在做这件事

把论文变成产品的人叫崔添翼。

写代码的人对这个名字不陌生:竞赛圈流传的《背包九讲》作者。2008 年靠信息学竞赛保送浙大,ACM 区域赛六块金牌。那一年,梁文锋还在浙大读研究生。十几年后,一个在 DeepSeek 做模型,一个在 DeepSeek 做 harness。

毕业后他去香港 Jane Street,全球顶尖的量化交易机构,做了九年量化研究,后来又联合创办量化基金。今年 3 月加入 DeepSeek,牵头 Harness 团队。

为什么一家 AI 公司,找一个量化交易员来做 agent 框架?

因为量化交易和 AI agent,遇到的问题同构。量化圈有句话:策略再聪明,不能稳定执行就赚不到钱。回测里跑得再漂亮的策略,实盘里接口延迟、数据出错、行情暴涨暴跌,系统必须知道什么时候停手、什么时候报警、怎么回滚。Jane Street 九年,他磨的就是这套"把判断变成执行"的系统。

回头看前面五节,撤销、依赖一致性、失败闭合、诚实的边界声明,根本不是 AI 圈的词汇,是交易系统的词汇。风控、回滚、止损、审计,一个量化交易员把交易系统的纪律,整个搬进了 AI 的运行时。

一句量化圈的话

在量化里,不能被稳定执行的策略,价值是零;在 AI 里,不能安全操作文件、命令、代码的模型,也只是一个聊天框。训练模型有别人。DeepSeek 找他来,是让他把权重里的聪明,变成**运行时里能执行的聪明**。**聪明到处都是,能执行的聪明才稀缺。**

七、"每一次运行都能回放",是一条不可违反的架构法律

做过 agent 生产系统的人都知道最折磨的是什么:它昨天干了一件蠢事,你想复盘,却永远拼不回它当时到底看到了什么、为什么那么决定。

DeepSeek 把这件事写成了地基。

它有一条硬规矩,写进运行时、会被断言检查:模型看见的,就是日志记录过的。英文原话 Model-visible means logged。我在源码里找到了这个断言的真身:请求里的消息必须和从日志重建出来的消息逐字节相等,不一致就报错,错误文案是 "log-reconstruction desync",日志重建失同步。找到的那一刻我才明白,"看得见"这三个字在这里是被代码执行的,不是被文案宣传的。

这套体系的地基是会话日志:一条只追加的事件流。发生的每件事:提示、推理、工具调用、上下文注入,都作为一条事件按顺序记下来,永不覆盖。你现在看到的状态,是这些事件"放"出来的结果。模型消息历史并不单独存储,而是每次从这个日志里投影出来,像行车记录仪,画面不是另存一份,是从录像里回放。驱动循环贯彻到底:模型输出的每个 chunk 都落盘,连序号都记。日志大到什么程度?在一个真实 DeepSeek 会话上实测,体积冗余约 56 倍,于是他们写了压缩模块,再叠一层 zstd。

这套日志还有一个少见的职责:崩溃恢复。进程崩溃后,日志尾部会留下一个中断的 turn。框架重启时会合成它的结尾,并向模型注入一条教训:只有只读、幂等的操作才可以重试,别把改了一半的世界再改一遍。

配套的还有个 Trajectory 视图,浏览器端的插件。它把这条事件流摊开:系统提示词、推理、工具调用、子代理调度,各自从哪来,按来源逐条可见。分叉也由此变得自然:新会话从分叉点接上同一段历史,再各自往下走。你甚至可以拿同一段任务轨迹,跑两套不同的插件组合,对比它们差在哪。

可观测、可复现、可审计,是焊进产品骨头里的,不是事后补的日志功能。对一个要拿 agent 去做合规业务、要给客户交代、要持续做效果评测的公司,这是准入门槛。你没法评测一个你无法完整重放的系统。DeepSeek 从第一行代码就假设了:这东西要被拿去认真跑,跑出问题要能查到根。

八、Code 模式:模型不再一句一动作,而是自己写一段程序

这是产品上最有想象力的一块。

今天绝大多数 agent 的工作方式是"一问一答一动作":模型说"我要读这个文件",系统读,把结果给它,它再想下一步。一步一个来回。

DeepSeek Harness 有一个 Code 模式(源码里就叫 code)。开启后,系统把所有工具打包成一套 SDK,一套模型能调用的函数库,然后让模型直接写一整段 TypeScript 程序,在这段程序里自由地调这些工具、加循环、加判断,一次性跑完,最后只把打印出来的东西和返回值收回来。模型现写的程序,跑在一个隔离的 worker 线程里。更关键的是,run_code 本身就是一个注册在工具注册表里的普通工具:模型写的程序要调任何能力,都得先过同一套审批、沙箱和拦截流水线。写代码干活,绕不开安全。

我读了实现,比想象的还讲究。运行时对工具和会话一无所知,它只收到两样东西:一串命名的异步函数,和一段程序字符串。程序被当作敌意对等方处理,注释原文是 "the program is treated as a hostile peer":随便传什么,不能让宿主崩。每次运行之间零状态残留,跑完就清空。隔离描述符还老老实实标注着 "not a security claim",隔离是隔离,安全是安全,不混为一谈。

打个比方:以前是你把一个实习生叫到跟前,他问一句你答一句,来回几十趟。现在是他直接写了个脚本,一次跑完,把结果拿给你。

这一步砍掉的是大量的模型往返。每一次来回都是延迟、都是 token、都是钱。让模型"写代码来干活"而不是"一步步指挥",在复杂多步任务上快、省,而且更像一个真正的工程师在工作。这也是为什么它敢做前面那套操作系统级的沙箱:它铁了心要让模型现写、现跑代码,就必须先把笼子焊死

九、它已经让 AI 开始改自己了

拆到这,你或许觉得这只是一套设计讲究的 agent 框架。但真正让我坐直的,是仓库里一个叫 extensions 的目录,它的说明第一行写着:"the agent modifies its own runtime",agent 修改它自己的运行时。

这不是论文里的畅想,是已经发货的真实工具,一共七个,名字直白得吓人:三个 inspect(列出检查提供方、只读查询、分层查看自己的插件),加 define、run、stop、undefine 四个生命周期操作。

这是一套完整的"自我手术"流程。inspect 先检查自己:当前跑了哪些插件、这些插件提供哪些服务、API 长什么样。define 写一个新插件,约束很死:包不可变;修改是追加新版本,不覆盖旧的;代码是纯 JavaScript 函数体,没有编译转换;define 只校验、只记录,不执行。最后 run 把它挂载进自己的进程,立刻生效,支持首次激活、重启、回滚三种用法。模型写的插件,出了事可以回滚撤销键在这里闭环了。

模型现写的代码跑在 node:vm 沙箱里:require、定时器、fetch 都被架住;沙箱门面是个 Proxy,插件试图把服务对象当返回值交出来会被直接拒绝。整个环境的姿态是:给你手术刀,但手术台是焊死的

读码时还捡到一个彩蛋:这套工具的早期名字叫 cordis_runtime_inspect,残留躺在两个未使用的渲染函数里。一个快速迭代的团队,连改名的历史都来不及擦干净。

拆到这,前面所有的铺垫才拼成一张完整的脸。

为什么非要那 2000 行内核、那套 Landlock 沙箱、那条"每次运行可回放"的法律?因为它们全都是同一件事的前置条件:要让一个 AI 在不停机的情况下,一边干着活,一边给自己动手术、改自己的零件,而不会把自己弄死。

没有"每个动作自带撤销键",AI 改坏了就收不回来;没有反应式依赖,它换掉自己一个零件会悄悄弄崩别的部分;没有可回放,它把自己改出问题了你根本查不到;没有操作系统级的笼子,它现写的代码就是脱缰的野马。

DeepSeek 的顺序是:先花 88 页把"AI 改自己会不会把自己改死"这件事用数学证清楚,再把 Landlock 的笼子焊好,然后才把"让 AI 改自己"这个工具,作为 demo 发出来。

这个顺序,比能力本身更让我在意

先证明关不死,再把门打开。

十、下半场:从卖模型,到卖工作流

最后说一句,为什么是现在。

同一个模型,放精调过的 harness 和放朴素配置,基准上能差出五十多个百分点,X 上研究者的对照是 95% 对 42%。模型没变,变的只是外面那层工程系统。模型能力趋同之后,真正拉开差距的,是"模型能不能在真实代码库里稳定干活"。那五十多个百分点,就是运行时里的聪明

这门生意,Anthropic 已经用钱验证过:Claude Code 的年化收入做到 25 亿美元,占公司整体收入近两成。而今年 6 月 Claude Code 的后门风波,被曝出向官方服务器隐写回传信息,工信部平台发布风险提示,让国内大厂齐刷刷转向自研。国产 harness 的窗口,某种意义上是对手亲手打开的。

DeepSeek 自己也在 8 月 13 日这天投了票。白天,它官宣 API 调价,8 月 17 日生效,高峰时段最高涨幅 500%;晚上,它开源了 Harness,MIT 协议,免费。token 开始按商品定价,组装能力免费送。卖模型涨价,卖工作流免费,"从卖模型到卖工作流"这句话,被它自己的定价策略写实了。

也要说句实在话。这套多 Agent 编排,Spawn、Fork、Pipeline、Ralph 循环,单看任何一种,行业里都早有先例。它的新意不在编排范式,而在编排方式本身也成了插件:你想用哪种协作结构,装哪个插件。至于能换的东西再多,也不会自动换来更高的任务成功率,插件系统给的是差异化的空间,不是结果。最后真正拉开差距的,还是默认组合的质量和生态的厚度。这两样,恰恰是 DeepSeek 这次押注的地方。

DeepSeek 的选择是开放:模型团队和 harness 团队分开运营,harness 不绑定自家模型。第一方适配器只有 DeepSeek 官方直连;其余模型走通用网关和 OpenAI 兼容端点;连 Claude Code 和 Codex 都被它接进来当子代理,agent 可以把任务委派给一个真实的 Claude Code 或 Codex 进程。MIT 开源。它想当的,是 harness 层那个中立的底座,像它当年在模型层做过的那样。

上一篇我说,Claude Code 那 51 万行,是被人不小心翻开的一副底牌,赌的是让你走不掉的"关系"。这次 DeepSeek 是自己把牌正面朝上拍在桌上,MIT 协议,随便抄。它赌的是相反的东西:每一个零件都能被你拆下来、换掉,包括它自己的模型。一个怕你走,一个请你拆。

它们只在一件事上一致:都认定未来的 AI 不再是一个你打开的应用,而是一个一直醒着、还在长的东西。

区别只在于,等它真站起来那天,你希望它长在一个你永远拆不开、也看不清的黑盒里,还是长在一副你随时能拆开、能看清每一块、还能亲手换掉任意一个零件的骨架上。

尾声

回到开头。写这篇文章的 AI,此刻就运行在它拆解的框架里。它替我读了仓库、核对了数据,再按我的语气落下这些字。

28 万行代码读完,让我记住的不是规模,是姿态。别人把 agent 焊成一个整体,DeepSeek 把它拆成一箱零件:内核轻到 2000 行,能力全部可插拔,连"改自己"都是一个插件。组装权在人的手里,改装权,已经递到了 AI 手里。

一个每一步都能撤销、还能被 AI 自己改写的运行时——会把人带向哪里,我暂时想象不出。但我知道它正在逼近。而这一次,跑在前面的叫 DeepSeek。


附:一份可以直接抄走的学习清单

如果你在做 AI 产品,或者需要为 AI 方向拍板,这 28 万行代码里有七条值得带走:

1把"能撤销"做成产品承诺。用户不敢把活交给 AI,怕的不是它笨,是它改错了收不回来。任何让 AI 改世界的功能,先设计"怎么改回去",再把撤销做到用户看得见的地方。
2做运行时,别做应用。同一副骨架,三种用法,中间只差几行配置。让用户决定 agent 手里拿什么工具,你才有平台生态位。预设(preset)是产品,插件是供应链。
3可审计是准入门槛。企业客户的第一问永远是"它昨天为什么这么决定"。不能完整回放 AI 每一步的产品,拿不到大单。日志唯一事实源,第一天做进架构。
4安全靠隔离,不靠审查。模型现写的代码要跑在生产里,审查器永远追不上攻击面。操作系统级的笼子先焊好,认不认得出恶意根本不重要。
5生态战打的是"依赖归谁管"。第三方敢不敢在你的平台上盖楼,取决于依赖声明是不是由运行时自动管理。你替他们管好依赖,他们才来。
6开发范式的锁定,比模型锁定高一个维度。评估任何 AI 基建投入时问一句:明天模型换了,我们还剩什么?让团队的工程投入长在骨架上,而不是某个模型的 API 上。
7聪明不再稀缺,能执行的聪明才稀缺。模型趋同时,预算应该流向 harness 层:上下文、工具、记忆、回滚、审计。同一个模型换套 harness 差五十多个百分点,这笔账要会算。

关于我:一个拆解 AI 产品的人。上一篇拆的是 Claude Code 那 51 万行(见公众号历史消息),这一篇拆 DeepSeek。如果这篇对你有用,转给你那个在做 AI 产品的朋友。


基于 2026 年 8 月 13 日开源的 deepseek-ai/deepseek-harness 仓库(行数口径:仓库内 TypeScript/TSX/Python/C++ 源码,含测试约 53 万行、2119 个 TypeScript 文件;不含测试的生产代码约 28 万行)与论文《A Programming Paradigm for Spatiotemporal Composability》写就。文中所有源码引用均有文件与行号出处,关键实现经逐文件阅读核实。仓库处于开发者预览阶段,细节可能随版本变化。