Skip to content

教学版项目 · 总览:我们复刻什么、简化什么

前 8 章 + 8 个 Demo 让你"用懂"了 DeepSeek Harness。从这一篇开始,我们反过来走一遍:从零亲手实现一个 mini-harness。代码在 final-project/,每一步都对应前面的一个机制。

为什么要亲手再写一遍

"读过"和"会写"之间隔着一条河。当你写自己的实现时,会被迫回答那些阅读时被忽略的问题:

  • 事件总线怎么处理"监听器抛错"?
  • 插件卸载时,它注册的监听器和定时器怎么一个不漏地拆掉?
  • 工具执行失败时,错误怎么回到模型那边?
  • turn 被用户取消时,日志怎么保证闭环?

这些问题,dsh 用 2700 行 Cordis + 1000 行 session 回答了。我们用约 900 行核心代码回答一个诚实简化版——保留骨架思想,砍掉生产级复杂度。

复刻清单(什么必须留)

机制对应 dsh在 mini-harness 里
一切皆插件Cordis插件三形态 + inject 依赖等待
可逆副作用ctx.effect / fiberctx.effect() 记录 disposer,卸载逆序执行
服务容器ctx.<key> 服务解析ctx.provide/get,每个服务唯一提供者
四种分发模式emit/parallel/serial/waterfall同语义,实现约 60 行
类型化事件declare module 声明合并同款写法(@mini/harness/events
LLM 接缝LlmRuntime + LlmAdapter同结构 + llm/stream 瀑布
统一词汇表StreamChunk 协议义务同协议:usage 先于 finish、block-end 收尾
Agent 循环turn/step + 事件瀑布agent/pre-stepagent/requestagent/turn-stopping
会话日志append-only + deriveMessages同思想 + fork
工具管线pre/execute/post 瀑布同四道闸门(ask 降级为 deny)
组合profile/bundle/patch简化为 bootstrap() 函数式组装(见第 5 步)

简化清单(什么先砍掉)

dsh 有而我们没有为什么可以砍
Context 的 Proxy 代理教学版直接对象访问,语义不变
isolate/intercept 作用域服务名全局唯一即可,作用域是进阶主题
fiber 状态机与 HMR不需要热重载,插件生命周期只有 start/dispose
配置 schema 校验(schemastery)类型系统 + 手工检查够用
持久化(JSONL/SQLite)日志留在内存;fork 保留 API 演示血缘
沙箱 / 审批面 / 遥测属于产品层而非框架内核
subagent / workflow / goals高阶编排,超出本教程范围

每砍一项,我们都在正文里说清楚"真实 dsh 为什么需要它"——简化是为了教学,不是为了偷懒。

端到端效果

跑起来长这样(npm run demo 的节选输出):

text
[mock-adapter] provider "mock" 已注册
[echo-tool] echo 工具已注册

== 任务 2:触发工具循环 ==
[observer] 日志事件:turn/start
[observer] 日志事件:step/start
[observer] 第 2 次模型调用:mock/mock-1
[observer] 日志事件:tool/call
[observer] 日志事件:tool/result
[observer] 日志事件:step/end
[observer] 日志事件:step/start          ← 工具循环后自动开第二个 step
[observer] 第 3 次模型调用:mock/mock-1
[observer] 日志事件:step/end
[observer] 日志事件:turn/end

以及浏览器界面(React + Node 后端):

六步路线

步骤内容对应文件
第一步迷你 Cordis:Context、事件总线、插件与 effectsrc/context.ts src/events.ts src/plugin.ts src/service.ts
第二步LLM 接缝:词汇表、适配器注册表、两个适配器src/llm/*
第三步会话日志与 Agent 循环src/agent/session.ts src/agent/agent.ts
第四步工具注册表与四道闸门src/agent/tools.ts
第五步Node 后端:bootstrap 组装 + SSEapps/server/*
第六步React 前端:聊天与事件面板apps/web/*

先跑起来再读代码:

sh
cd final-project
npm install
npm run demo            # 核心库示例(第 1–4 步的合体)
npm run dev:server      # 后端(第 5 步)
npm run dev:web         # 前端(第 6 步)

基于 DeepSeek Harness(开发者预览版 0.1.0-rc.6)与 Cordis 撰写