Archives
All the articles I've archived.
从零学透 DeepSeek Harness:系列路线图
围绕 DeepSeek 开源的 Agent Harness(代号 dsh),我写了八篇源码解读和十三课配套课程。这一页是路线图——说清楚每份材料管什么、按什么顺序读。
第 13 课 · 工程文化与门禁:把正确变成机器可执行
前十二课讲「系统如何工作」,最后一课讲「系统如何保持正确」。dsh 跟别的项目最不一样的地方:架构规则大多不靠评审自觉,直接接进了可执行的顶层门禁。读懂这套,你才能跟别人讲清「这些设计凭什么能维持」。
第 12 课 · Web 客户端:Slots、模块图与三层分层
第 07 课结尾提到 host/client 双编译面。现在看浏览器那一面:Web UI 的每个面板、每个工具卡片,是怎么被组合出来的?为什么说在浏览器里写 UI 组件和写宿主插件是两套语法?
第 11 课 · 自扩展:skill 与 extensions
「一切皆插件」再往前一步:让模型在运行时自己写插件。dsh 靠两套机制做到——skill(内容注入)与 extensions(代码求值 + 插件挂载)。这一课讲清两套机制的边界,顺带精读四篇 postmortem,看这个系统怎么被现实教育。
第 10 课 · 毕业项目:写一个完整插件
从零走完一次「扩展 dsh」的完整闭环:写插件 → 装进 profile → 组合验证 → 行为验证 → 留下决策记录。这是本课程的毕业项目:前九课学没学会,做一遍就见分晓。
第 09 课 · 工具执行管线与安全三旋钮
第 04 课的工具调用事件流跳过了执行本身。这一课补上最敏感的一段:模型说「帮我删这个文件」,从决策到落地之间有几道闸门?谁有权拦?拦了之后怎么审计? dsh 的答案:四道关卡 + 三个正交旋钮 + 一条铁律——fail-closed。
第 08 课 · 能力接缝:三角色与两种形态
前七课你理解了骨架、事件、主干、组合。现在看扩展模型的核心抽象:dsh 怎么让「文件系统在本地还是远程」「模型是 DeepSeek 还是别的」这类问题变成改两行补丁的事? 答案是 Capability Seam:把一种能力切成三个角色,让接口、实现、消费者独立演进。
第 07 课 · Profile 与 Bundle:组合即配置
第 02 课说插件条目来自显式声明,第 01 课你见过 --dump-config 的组合树。这一课补上中间的机制:dsh-base 的 80 余行插件、你的自定义行为、应用层,是怎么叠成一棵树的? 一句话答案:Profile = 有序 Bundle 列表 +…
第 06 课 · 持久层、投影与「日志化状态」
第 05 课说内存日志是「上半身」。这一课看下半身:重启之后会话怎么回来?状态(计划、目标、待办)存在哪? dsh 给出的统一答案有点反直觉:状态就是日志的纯函数。没有独立的状态机,恢复即重放。
模型看到的必须在日志里:dsh 的 Turn 执行流
[上一篇](/posts/dsh-overview)讲了 dsh 的插件架构。这篇看它的心脏:一条用户输入进来之后,「模型思考 → 调工具 → 再思考」的循环怎么被驱动,以及每一步为什么都要留痕。(约 6 分钟)
逐文件 100% 覆盖:dsh 的质量门禁长什么样
前三篇讲了 dsh 的架构、执行流和能力接缝。这些设计靠什么守住?答案藏在根目录 package.json 里:44 个 verify- 脚本,加上一条毫不客气的覆盖率注释。(约 7 分钟)
第 05 课 · 会话日志与「模型可见 ⟺ 已记录」
第 04 课你看到请求体来自 session.deriveMessages()。这一课回答随之而来的问题:这个日志凭什么能重建请求?如果有人往日志里塞了一个模型看得见但没走正常通道的事件呢? dsh 的答案是三层防御,并且每一层都有具体的代码载体。
崩溃的 turn 要关闭,不是截断:dsh 的会话持久化
第二篇说过,session log 是 dsh 的唯一事实来源。那这条日志怎么落盘、崩了怎么办、又能从里面长出什么?这篇讲 packages/session/ 这个组。(约 6 分钟)
一切皆插件:读 DeepSeek Harness 的架构
DeepSeek 开源了一个 Agent Harness,代号 dsh。装起来一行命令:npx @deepseek-ai/dsh web,默认在 127.0.0.1:3080 起一个 Web UI。(约 6 分钟)
第 04 课 · 一次 Turn 的完整旅程
前两课是骨架和语法,现在看产品主干:用户发一句话,到模型回复并执行完工具,中间到底发生了什么? 答案浓缩成一句:kick() 就是 while (await this.turn()) {}(packages/core/agent-loop/src/agent.…
状态就是日志:plan、todo、goal 在 dsh 里怎么存
agent 产品里常见一批「状态」:计划模式开了没、待办列表写了啥、长期目标推进到哪。多数实现里它们是运行时内存对象或独立存储。dsh 给出的答案是同一个词:_logged state_——状态就是日志事件折叠出来的结果。(约 6 分钟)
压缩自己也进日志:dsh 的 Compaction 设计
长会话总会撞上下文上限,做 agent 的都逃不掉压缩这个课题。多数做法是「改历史」——把旧消息替换成摘要。dsh 的做法不太一样:压缩产生的摘要不是历史的一部分,压缩这个动作本身才进日志。(约 5 分钟)
第 03 课 · 五种事件分发模式:协作的语法
第 02 课解决了「谁先激活」。这一课解决「事件发生时,多个监听器如何协作」。 dsh 的事件不是一种泛型广播,而是五种语义——同一个 on() 注册,按事件名声明的模式被调度。选错模式的后果从「副作用顺序错乱」到「整条链被意外否决」不等,所以这是写插件的语法课。
声明即授权:dsh Web 客户端的 slot 体系
dsh 的浏览器端同样是插件系统,但 UI 组合有个额外难题:谁有权把组件渲染进谁的洞里?前端插件化项目在这里常常退化成约定俗成,dsh 把它做成了加载期的硬约束。(约 6 分钟)
Capability Seam:让 shell、文件系统和沙箱都可替换
读 dsh 源码最大的一个疑问:为什么 packages/shell/ 这一个「能力域」下面有九个包,一个跑 bash 的活儿至于拆这么细吗?看到 docs/glossary.md 里的一个词才反应过来:seam(接缝)。(约 6 分钟)
第 02 课 · 一切皆插件:Cordis 骨架二十分钟
第 01 课的组合树里每一条都是「插件」。问题是:插件之间怎么找到彼此?谁先加载?卸载时谁先走? dsh 的回答是把这些问题全部交给运行时骨架 Cordis(vendor 进仓库:vendor/cordis/),并且给出三条统一规则:属性访问即服务解析、可用性即…
第 01 课 · 跑起来:三种运行形态与观察窗口
先别管架构图。假设你拿到这个仓库,第一个问题一定是:这东西怎么跑?跑起来之后,状态存在哪? 这一课不读源码,只做三件事:跑起来、看配置、找日志。后面的每一课都会反复用到这些观察窗口。
把 CI 构建从 90 秒降到 12 秒
先说结论:PR 的 CI 反馈时间从 92 秒降到 12 秒,改动只有三处——缓存 key、一个 postinstall 脚本、任务编排。没有换工具链。(约 5 分钟)