第 1 卷
张嘉熙 · DeepSeek Harness 前沿工程实践




你好,我是张嘉熙。
第 13 讲把六个包装成了一个会跑的 Agent。可同一个应用里,Agent 要干的活通常不一样:
有的要帮用户改代码,需要的是跑命令那类工具;有的只写散文、小说,需要的是写作那类工具。人设也得跟着换,一个是严谨的程序员,一个是文艺的作家。而默认情况下,每个 Agent
拿到的都是同一套工具与人设,就是第 13 讲那种进程里装一套、谁用都一样的局面。
把一套工具与人设预组装成一份并存下来,创建 Agent 时按名字取一份即可,这就是 Agent Preset(下称 preset)。
不同 Agent 在工具与人设上的差异,写在哪?
怎么造一份新的 preset?
怎么按名字把 preset 装到 Agent 上?
自工具与人设的可见范围),彼此够不着。本讲就按这两步展开。
关于环境,本讲新增三个包:@deepseek-ai/dsh-agent-presets(preset 的发现与挂载)、@deepseek-ai/dsh-persona(把“人设”做成一个可组装的行)、
@deepseek-ai/dsh-atomic-write(dsh-agent-presets 的 peer 依赖,本讲不展开)。已加入本项目的 package.json,npm install --legacy-peer-deps 装上
即可。
关于示例:npm run start:ch14 在临时目录里现写两份 preset(coder / writer),用它们各组装一个 agent,再打印各自能看到的工具和人设。示例不跑对话、
不联网、不需要 API Key。
一个目录,一份 agent.cordis.yml
第一个问题:不同 Agent 在工具与人设上的差异,写在哪?
写在一个目录里:差异就写在这个根目录下各自的子目录里。所有 preset 都放在同一个根目录下,根目录是挂 AgentPresets 时用 roots 配出来的,而 AgentPresets 是本讲新包
@deepseek-ai/dsh-agent-presets 导出的主插件:
复制代码 1await ctx.plugin(AgentPresets, {
2default: 'coder', 3roots: [{ path: root, trust: 'user' }],*// trust:system = 应用自带,user = 用户
4})
装好之后,它在 ctx 上留下一个服务 ctx.agentPresets,官方叫它 roster(名单),既负责找出这些 preset,也负责把它们常驻挂载,第四问细讲。这里先看它怎么发现这些
preset:扫描根目录,list() 列出全部,resolve(id) 按名字取一个。示例第一段打印的就是 roster 发现的结果:
打开这个根目录,里面每个子目录就是一个 preset,子目录名就是它的 id(必须符合 [az0-9][a-z0-9-]*)。
这个 id 不只是为了方便点名。preset 决定模型看到哪些工具和人设,而模型看到的东⻄必须能从日志重建,会话恢复、分叉时,靠这个 id 就能还原出当时那一套。所以差异必须是一份
按名字可取的目录,而不是散在代码里的一堆配置。
每个 preset 目录里都放一份 agent.cordis.yml,内容是插件行的列表,文件顶层直接就是一个数组,每一项就是一个插件行:工具、人设、提示词段落等。列表里的每一行和你在
ctx.plugin(...) 里装的那些是同一类东⻄,只是写成了 YAML,和第 04 讲的 cordis.yml 是同一套机制,交给 Loader 就长成自己的一棵插件树:
复制代码 1- id: tool
2name: /abs/path/to/tool.js 3config:
4tool: run_command 5
6- id: persona 7name: '@deepseek-ai/dsh-persona'
8config:
9text: 你是个严谨的程序员,写代码一丝不苟。
同一个目录里还可以有第二个文件 preset.yml(可选),放这份 preset 的 name 和 description。agent.cordis.yml 是个插件行数组,塞不下这类信息,所以单独成文
件。
往里看 agent.cordis.yml 的每一行:它最终都会变成一个插件实例。本讲工具与人设的差异就写在其中的两行上。