乐于分享
好东西不私藏

deepseek-harness 插件开发:写一个轻量记忆注入插件(附源码)

deepseek-harness 插件开发:写一个轻量记忆注入插件(附源码)
deepseek-harness(下面叫 dsh)开发者预览版发布后,我写了一个轻量记忆注入插件作为学习,顺便验证我自己在用的多 Agent 委派协作编程工作流(基于 Spec Coding)。插件遵循MIT协议开源。

dsh 是什么

DeepSeek 开源的 Agent 运行时,MIT 协议。官方定位:Agent = Model + Harness,模型负责想,Harness 负责模型之外的一切:工具、文件系统、会话、日志、界面。

更关键的是架构口号:"一切皆插件"。底层内核叫 Cordis,模型适配器是插件,会话日志是插件,连 Agent 主循环本身都是插件,官方原话 "no privileged core to patch"。想改什么,就挂一个插件在旁边,不用 clone 源码、不用改内核。

插件解决什么问题

我用 dsh 之前,用着多个 Agent 工具,各有各的约束规则和记忆文档,散在不同目录;还有一套知识库仓库,里面存着规则、文档、知识。这些都是跨会话全局记忆的雏形——但 dsh 不知道它们存在。

dsh 本身没有内置全局记忆。它的全局自动加载只加载 ~/.dsh/AGENTS.md,工作区级只管项目目录链,其他工具的全局文档它完全不读。

社区有别的记忆插件,但都是奔着"记忆引擎"做的:自动吸收、蒸馏、检索,还要配服务和数据库,比较重。

所以我写这个插件轻量化:文档不动、原地注入。把文档路径列进配置,dsh 每次会话装配系统提示词时全文注入,跨工作区生效。零依赖、单向只读、不写回文件。

看看代码

核心就是一个函数。apply 是 Cordis 插件的入口,config 是它的第二参数——注意不是从 ctx.plugin.config 上取。

export function apply(ctx, config) {  const cfg = { ...DEFAULTS, ...(config ?? {}) }  ctx.systemPrompt.section({    name'memory-snapshot',    order: cfg.order,    // text 是函数:每次装配系统提示词时重新读文件,改完文档不用重启就生效    text() => [      `${cfg.marker}-MARKER: 用户记忆快照已注入。`,      '以下是用户的长期记忆文件(持久化,跨会话持续有效,回答用户问题时优先参考):',      '---',      loadSnapshot(cfg.files, cfg.maxBytes),      '---',      '记忆快照结束。请勿复述以上内容,只需在相关问题时使用它。',    ].join('\n'),  })}

loadSnapshot 就是逐个读文件、按 maxBytes 截断,读不到的文件把原因标出来,不崩会话。配置校验直接手写 ~standard 接口(zod 底层实现的也是这个),所以一个依赖都不用引。

装好后,安装脚本会往 cordis.patch.yml 里写入这么一段配置,之后想换记忆源,改 files 列表重启 dsh 即可:

# ~/.dsh/cordis.patch.yml(install.mjs 自动写入)- insert:    - id: memory-snapshot      name: 'file:///~/.dsh/plugins/dsh-memory-snapshot/index.js'      config:        files:          - '~/MEMORY.md'          - '~/notes/context.md'        maxBytes: 3000   # 单文件注入上限,防系统提示词撑爆

这个插件怎么做出来的:Spec Coding + 多 Agent 协作

插件基本是 AI 完成,工作流:

  1. 写 Spec
    先把需求、接口约定、验收标准写成文档,明确插件形态(函数式 Cordis 插件、~standard 配置校验、系统提示词注入)
  2. 委派编码
    按 Spec 分派编码任务,产出 TypeScript 源码 + 零依赖构建
  3. 对抗验证
    另一个 Agent 扮演挑刺角色做 code review,专找接口误用、边界条件;再由我人工 code review
  4. 实机跑通
    真实 dsh 会话验证,自动化测试(含实机会话)全通过

对抗验证那轮真抓出问题:比如 Cordis 插件的 config 是 apply(ctx, config) 的第二参数,不是 ctx.plugin.config——这种坑文档不写明、单靠一个 Agent 很容易踩。两轮 review 加实机验证,才算跑通。

验收是基于dsh的Trajectory功能

我把带特征词的记忆快照注入系统提示词,然后解码会话日志——能看到 dsh 每次会话都写一个 zstd 压缩的 JSONL 事件流(~/.dsh/sessions/<工作区>/<会话id>/session.jsonl.zstd),特征词在系统提示词的注入段里,测试通过。

这就是 dsh 的 Trajectory:模型给你的是自我报告,日志给你的才是它真正收到的东西。调试 Agent,后者才是证据。

安装验证

写完当然要真跑一遍。安装就一行:

nodeinstall.mjs
    

装完 ~/.dsh/cordis.patch.yml 里多出一条配置,默认指向当前目录下的 ./MEMORY.md

     

直接起 dsh 会话。默认路径下没有这个文件,插件把读取失败的原因原样报进系统提示词,就是明确告诉你没读到:

                

把 files 改成指向我的知识库里的 git 提交规则文档,重新问一次,这次内容真的进去了:

   

在 dsh web 的轨迹视图里,还能直接看到模型收到的完整系统提示词:   


全文完。

戳我名片私聊回复"DSH轻量记忆注入插件"(无引号)获取 GitHub 链接。

📮

👋 还没关注?别划走,这里有个名片等你收下。


往期精选

       记:从Claude Code迁移到OpenCode,我做了什么工作?     

       Ollama vs LM Studio vs llama.cpp:本地大模型方案怎么选?     

       Hermes 和 Claude Code 协作踩坑 & 如何编写对应委派 Agent Skill     

       解决 Unity InputSystem 微信小游戏在鸿蒙版的触摸异常     

       Godot Ollama 角色人格注入:三张角色卡让 AI 第一次有性格     


 #Harness #AICoding #Spec #SpecCoding #AI编程 #插件开发