每个可配置插件都以包名为标识符,patch 命中这个标识符,要么整行替换配置、要么插入新行。把 patch 写在 $DSH_HOME/profiles/<名字>/cordis.patch.yml,然后用 dsh --profile <名字> --dump-config 确认四层应用后的组装结果。
DeepSeek Harness 里每一项能力都是插件,而每个可配置插件都以包名为标识。就这一件事,让整套配置系统 变得可学:你从来不是在找一个「设置项」,你是在找一行。
config catalog
仓库带了一份目录,按包 ID 组织,列出每一个可配置插件。每条包含四样东西:
- 标识符——包名,如
@deepseek-ai/dsh-agent-loop - 用途——这个插件配置什么
- 服务依赖——以
Requires:列出,如agents、sessions、llm - 配置结构——一个展示全部可接受字段的 TypeScript 接口
最后这项是「该读目录而不是靠猜」的理由:那个接口就是这一行能接受什么的完整清单。
几条值得知道的:
| 包 | 配置什么 |
|---|---|
@deepseek-ai/dsh-agent-loop | maxParallelToolCalls,以及一个装 agent 启动定义的 agents 数组 |
@deepseek-ai/dsh-llm-deepseek | DeepSeek provider:API key 环境变量、endpoint、thinking 模式策略、token 上限、重试行为 |
@deepseek-ai/dsh-session-persistence-jsonl | JSONL 会话日志存储:根目录、压缩方式(zstd 或 none)、分块打包策略、缓存大小 |
写一个 patch
patch 是以行标识符为键的 YAML:
# 配置 agent-loop 的并发
@deepseek-ai/dsh-agent-loop:
maxParallelToolCalls: 4
agents:
- id: primary-agent
sessionId: session-123
cwd: /workspace放进 profile 自己的文件:
$DSH_HOME/profiles/web/cordis.patch.yml
patch 按标识符命中一行,要么整行替换配置、要么插入新行。把被命中的行当成被替换而不是被合并—— 写出你要的完整配置,而不是只写你改的那个字段。
层的顺序决定谁赢
patch 应用到一个空条目列表上,顺序:
- profile 叠的每个 bundle,按次序
- profile 的
cordis.patch.yml - home 级的
$DSH_HOME/cordis.patch.yml - 运行时的任何
--patch覆盖
后面的层赢。所以 home 级文件压过你的 profile 文件——对一个本就意在「到处生效」的东西来说这是正确行为, 也是 profile 级改动看起来毫无作用的最常见原因。
两个改之前值得想想的设置
maxParallelToolCalls 限制同时跑多少个工具调用。调高会让大面积机械工作更快,也会让 agent 的行为
更难跟——交错的输出会丢掉叙事顺序。做大扫除时调高;还在摸清这个 agent 会干什么的阶段,就先留低。
会话持久化的压缩方式。 长期运行选默认的 zstd 是对的。只有当你确实想用普通文本工具直接读会话
日志时才切到 none——而且要记住,一份记录模型所见一切的只追加日志,增长速度比直觉快得多。
永远要验证
dsh --profile web --dump-config打印组装结果。再和干净基线比:
dsh --profile web --dump-default-config > /tmp/base.txt
dsh --profile web --dump-config > /tmp/mine.txt
diff /tmp/base.txt /tmp/mine.txt这份 diff 精确地等于你的层所做的全部改动。你要的东西不在里面,patch 就没生效;在里面但不对,就是更靠 后的层改写了它。
把 patch 文件纳入版本控制
一个 profile 的 cordis.patch.yml,就是「你的 agent 与出厂状态有何不同」的完整描述。它很小、是纯文本、
而且正是你之后要拿去跟同事解释、或者在一次糟糕实验后回滚的那个东西。
$DSH_HOME/profiles/web/cordis.patch.yml → 提交这个
$DSH_HOME/.credentials.yaml → 永远别提交这个
常见问题
怎么知道一个插件能接受哪些字段?
仓库带了一份 config catalog,按包 ID 列出每个可配置插件、它的用途、它依赖的服务,以及一个展示全部可接受字段的 TypeScript 接口。
patch 是合并还是替换?
patch 按标识符命中一行,要么整行替换配置、要么插入新行。把它当成对目标行的替换,写出你要的完整配置。
patch 该放哪个文件?
profile 专属的放 profile 自己的 cordis.patch.yml。home 级那份对所有 profile 生效且会压过 profile 自己的,只用来放你确实希望到处生效的东西。