ByteNoteByteNote
DeepSeek Harness 系统提示词组装机制拆解
字

字节笔记本

2026年10月6日 · 约 6 分钟读完

DeepSeek Harness 系统提示词组装机制拆解

API中转
¥120

DeepSeek Harness(简称 dsh)是 DeepSeek 开源的智能体框架,主打一切皆插件的架构,底层由 Cordis 依赖注入框架驱动。在这样一个高度插件化的系统里,有个很现实的问题:系统提示词到底该由谁来写?dsh 给出的答案是,没有人单独拥有它。任何插件都可以贡献自己的段落,由 system-prompt 包在每次调用模型之前,把这些贡献组装成最终的系统提示词。按照官方文档的定位,这个包负责管理提示词贡献者与一次组装调用之间交换的全部数据。本文基于它的接口文档与源码注解,拆解这套组装机制的核心类型、注册规则与执行流程。

DeepSeek Harness 系统提示词组装架构总览

四个核心类型

AssembleContext 标识一次组装所解析的作用域层,并可携带本次请求的显式控制信号。它被设计成可合并扩展的结构:dsh-agent 插件会在其上添加可选的 agent 字段来携带当前智能体实例,配套的 assembleContextFor 辅助函数则一次性设置这些显式字段。不带作用域也不带信号的裸组装同样合法,此时只有全局提供方与无主体的监听者参与。

PromptSection 是提示词段落的只读注册约定,也是整套机制中最重要的类型:

ts
interface PromptSection {
  name: string    // 唯一名称,重复注册直接抛错
  order: number   // 升序拼接,约定见下文
  text: string | ((context: AssembleContext) => string)
  complete?: boolean  // 声明接管完整提示词
}

order 字段有一套明确的项目约定:-100 留给 harness 自身身份,0 是部署人格,工具使用指导使用 100 到 199,其他负数段落也渲染在人格之前。text 既可以是静态文本,也可以是一个函数,在每次组装时按当时的上下文求值;文本里可以引用变量占位符,留到渲染阶段由 renderPrompt 插值。最特殊的是 complete 标记:声明它的贡献意味着完整提示词由我提供,组装流程仍会照常执行,让工具、上下文与变量都能正常解析,但最后会把这一段恢复为唯一的提示词段落;如果出现多于一个有效的 complete 段,组装直接失败。

PromptContext 是与段落相对应的动态上下文,定位是一个缓存安全的结构。组装会把各处贡献解析、排序,并物化成一份持久的 user 角色快照;智能体循环只有在完整快照发生变化,或快照被上下文压缩移除时,才会把它写进保留的模型历史。换句话说,上下文内容没有变化就不会重复进入对话历史,这个设计直接服务于提示缓存的稳定性。

ToolProviderResult 承载工具提供方在一次组装中的输出。schemas 是本次组装中对模型可见的工具 schema 集合;knownNames 则是提供方在限制之前的名称全集,默认就是 schemas 的名称列表。区分两者是为了配置校验的体验:系统能分辨配置里写错了一个工具名,与某个已知工具在此作用域被有意隐藏,这两种完全不同的情况。

注册接口与作用域规则

插件通过上下文服务 ctx.systemPrompt 注册上述贡献,一共五个方法:section 注册段落,context 注册动态上下文,tools 注册工具 schema 提供方,variable 注册提示词变量,suppressRuntimeContext 则在不改动相关服务的前提下,压制当前作用域的所有动态运行时上下文贡献。

作用域规则贯穿始终:本作用域注册的段落、上下文与变量会遮蔽全局同名条目;同一层内的重复注册、非法变量名与非有限的 order 值都会抛错;注册与注销动作都会发出 system-prompt/change 事件;每个注册方法都返回精确的资源释放函数。工具提供方如果返回保留名 TOOL_ORDER_REST,组装会失败。变量的提供方允许返回 undefined,但之后渲染引用了该变量的段落时会失败。

组装流程与两个事件

调用 assemble 方法时,组装器先收集全局与作用域内的全部提供方,分离工具参数,做规范排序,然后进入 system-prompt/assemble 瀑布事件。

DeepSeek Harness system-prompt 的组装流程时序与失败路径

system-prompt/assemble 是一个专家瀑布事件,监听对象是组装好的段落、上下文、工具与变量。事件分发按作用域过滤,作用域内的监听者只会收到该作用域的组装。文档强调了两条纪律:其一,事件的返回值是权威结果;其二,传入的信号只控制这一次显式组装请求,不允许被保留下来去控制后续轮次。complete 段是在瀑布之后才恢复的,所以监听者既无法往提示词里追加内容,也无法整体替换它。

另一个事件 system-prompt/change 则是无过滤的全局通知,任何提示词提供方的注册或注销都会触发,因为一个全局变更会影响所有作用域。

几个值得借鉴的取舍

从这些约定里能读出几处值得借鉴的设计。第一,段落与上下文分离:段落是提示词文本,上下文是模型历史里的持久快照,两者的更新语义不同,分开建模让缓存与压缩各自成立。第二,knownNames 把配置错误与有意隐藏区分开,这是工具集裁剪场景里很容易被忽略的细节。第三,complete 段放在瀑布之后恢复,既给了生态最大的组合自由,又用多于一个即失败的约束守住了最终解释权。第四,动态上下文以快照变化为准写入历史,避免每轮重复注入同一份内容。

需要提醒的是,DeepSeek Harness 目前处于开发者预览阶段,官方明确提示未来会出现破坏兼容性的变更,这套接口也还会继续演化。项目已在 GitHub 开源,仓库为 deepseek-ai/deepseek-harness。对于正在设计多插件智能体框架的团队,这份子系统文档是一份难得的参考:它把提示词是谁写的这个模糊问题,变成了可注册、可排序、可遮蔽、可校验的工程问题。

相关文章

分享: