DeepSeek Harness 的技能可以自己装,五分钟够用:把带 SKILL.md 的目录放进被扫描的位置,新开会话就能调用。真正费时间的是两种失败,一是目录多套了一层,二是名字不合规,这两种情况客户端都不会给你明确提示,技能就是不出现。
本文核对的是桌面端 0.2.1-rc.5 的实际行为,命令都能直接粘。
五个扫描根,先放对地方
技能在磁盘上是普通文件,没有数据库,也没有导入步骤。客户端起会话时按固定顺序扫几层目录,把每个技能的 YAML 头部解析成一条目录项,模型用到时才读正文。所以装技能等于把目录摆到正确的路径上。
| rank | 扫描目录 | 生效范围 | 适合放什么 |
|---|---|---|---|
| 100 | <项目根>/.dsh/skills | 只在当前项目 | 要跟仓库一起提交、只服务这个项目的技能 |
| 200 | <项目根>/.agents/skills | 当前项目,跨 agent 工具共用 | 团队里还有别的 agent 客户端在同一个仓库干活 |
| 300 | customSkillDirs 配置的目录 | 自定义 | 技能放在另一块盘或共享目录 |
| 400 | ~/.dsh/skills | 所有会话 | 自己长期用的通用技能,默认从这里起步 |
| 500 | ~/.agents/skills | 跨工具的用户级目录 | 同一批技能还要喂给别的 agent 客户端 |
rank 的数字越小越先被扫到,两个位置出现同名技能时靠前的那个生效。所以项目里放一份同名技能,能盖住用户目录里的旧版本,这个特性用来做单项目覆盖很方便。
项目根并不等于终端当前所在的目录。正确算法是从工作目录往上找最近的、带 .git 的那个祖先目录,一个都没有时才退回当前目录。这条最容易判断错:你在某个子目录里敲命令,但上一级才是仓库根,技能就得放到仓库根下的 .dsh/skills。
# 用户级技能根,默认就在这里
ls -la ~/.dsh/skills
# 确认仓库根,也就是项目根
cd 你的项目目录 && git rev-parse --show-toplevel
用户级目录固定是 $DSH_HOME 下的 skills,$DSH_HOME 默认等于 ~/.dsh。这个目录下面的 .system 子目录会被跳过,那是客户端放内置技能的位置,手写技能别往里塞,塞了也不会被当成你的技能。
最小可用的一个技能
目录形式是 名字/SKILL.md,中间不能再夹一层,正文以外可以再带 references、scripts、assets 等资源目录。下面这个技能不到二十行,是能跑的最小形态。
mkdir -p ~/.dsh/skills/fb-draft-check
cat > ~/.dsh/skills/fb-draft-check/SKILL.md <<'EOF'
---
name: fb-draft-check
description: 验收一篇稿件是否达标:汉字数、h2 数量、站内内链数。当需要判断稿件能不能发、或想知道差哪几项时使用。
---
# fb-draft-check
## 步骤
1. 取正文 HTML,剥掉标签后统计汉字数。
2. 统计 h2 数量与指向本站的内链数量。
3. 任意一项不达标,直接报出实际数字与差值。
EOF
头部只有 name 和 description 是必填。缺任何一个字段,或者 YAML 本身写坏(制表符缩进、冒号后面没空格、引号没闭合),整个文件被跳过,会话目录里不会留下任何痕迹。
头部字段哪些真被读
解析器认的字段不多,其余键不会报错也不会生效。真正的差别在于写错之后是整条丢弃,还是只影响一半功能。
| 字段 | 必填 | 取值规则 | 写错的后果 |
|---|---|---|---|
| name | 是 | 小写字母与数字,用连字符分段 | 整条技能被丢弃 |
| description | 是 | 一句话写清能力与触发场景 | 缺失则整条被丢弃,过长则在目录里被截断 |
| whenToUse | 否 | 字符串 | 无影响,属于补充说明 |
| disable-model-invocation | 否 | 严格布尔值 | 值不合法则整条被丢弃 |
| user-invocable | 否 | 严格布尔值 | 值不合法则整条被丢弃 |
| metadata | 否 | 自定义键值对 | 原样带着,客户端不解析 |
name 的规则很硬,等价于这条正则:^[a-z0-9]+(-[a-z0-9]+)*$。大写字母、下划线、点、中文、连续两个连字符、首尾连字符,全部不合法。合法的只有 my-skill、fb2-check 这种形态。
布尔字段同样是硬规则,只认 true 与 false、yes 与 no、on 与 off、1 与 0,大小写不敏感。写成 sometimes、maybe、空值,解析直接抛错,整条技能被丢掉。
平铺单文件与软链接
扫描根直属的一层里,除了目录包,也认单独的 名字.md 文件。技能只有一个文件、不带脚本和参考资料时,平铺最省事,省掉一层目录。
# 平铺装法,文件名就是技能名
cp my-skill.md ~/.dsh/skills/my-skill.md
软链接也认,符号链接的目录和文件都能正常打开,技能里记录的仍是链接路径。想把技能留在代码仓库里维护、又不想每次复制两份,直接链过去就行。
ln -s ~/code/my-skills/fb-draft-check ~/.dsh/skills/fb-draft-check
资源子目录怎么用
正文之外的资源放在技能目录里,正文用相对路径引用。模型加载技能时会同时拿到这个技能的资源基路径,脚本和参考文档按需读,不用一次全塞进上下文。
长文档型技能尤其要这么拆:把大表格、完整参数表、几十个报错样例放进 references/ 下的单个文件,正文只留触发条件、判断顺序和执行步骤。加载成本能降一个量级,触发准确率反而更高,因为描述里只留了场景,没有堆背景。
刷新粒度这里有个差别要记住。SKILL.md 正文每次加载都重新读文件,改完立刻是新的;references、scripts、assets 下的改动不会触发技能目录刷新,但同样是按需读取,所以也不用重启。
踩坑一:多套一层目录等于没装
扫描只到每个根的第一层,形如 skills/写作/长文/SKILL.md 的嵌套结构是故意不发现的。很多人按分类先建一层子目录,把写作、编程、运营各放一个文件夹,结果整批技能一起消失,看上去像客户端坏了。
判断方法只有一个,看实际深度。正确形态是 ~/.dsh/skills/名字/SKILL.md,两级;出现三级就是放错了,把中间那层分类目录去掉,分类交给描述里的关键词解决。
# 只应该列出两级路径
find ~/.dsh/skills -maxdepth 2 -name SKILL.md
如果确实需要分类,用文件名前缀代替目录层级,比如 fb-draft-check、fb-report-scan,排序时自然聚在一起。
踩坑二:名字带大写或中文,静默消失
名字不合法不会弹窗,客户端只在自己的日志里留一行忽略记录,模型侧的技能目录里既没有这条技能,也没有任何诊断信息。你从会话界面根本区分不出「没装」和「装错了」,这是排查时最浪费时间的一点。
所以先自检,再怀疑别的。下面这条命令用的是同一套规则,返回 ok 才说明名字能过。
python3 -c "import re,sys;n=sys.argv[1];print('ok' if re.fullmatch(r'[a-z0-9]+(-[a-z0-9]+)*',n) else 'invalid')" fb-draft-check
还要注意目录名与头部 name 的落差。目录名随便叫,发现时看的是头部 name,但用起来容易混淆,建议两者写一致,改的时候一起改。
踩坑三:布尔字段写错,连带整条被丢
disable-model-invocation 与 user-invocable 决定技能出现在哪一侧,两个都不写时两侧全开,这是默认行为,绝大多数技能也就该这么写。写反或者都关掉,技能等于装了用不上。
| 写法 | 模型能否加载 | 斜杠菜单能否调用 |
|---|---|---|
| 两个字段都不写 | 能 | 能 |
| disable-model-invocation: true | 不能 | 能 |
| user-invocable: false | 能 | 不能 |
| 两个都限制 | 不能 | 不能 |
第一行之外的三行都有明确用途:要人工兜底的分步流程关掉模型侧,避免模型自己乱调;纯内部约定、不想出现在斜杠菜单里的关掉人工侧,减少干扰。写之前想清楚这一条技能是给自己敲还是给模型挑。
两个长度上限
目录里给模型看的描述默认最多 500 个字符,这个值可以配,下限是 3。描述写成一整段背景介绍,模型看到的只是前面 500 字,触发条件被切掉,技能就调不动了。写法上把「什么时候用」放在第一句,能力说明放后面。
正文侧的上限是 8192 字符。超过这个长度,加载结果会被工具结果的裁剪机制处理,后半段可能看不到。手写长技能时,正文留判断逻辑和步骤,细节拆进 references/,这条规矩对五十行以上的技能都成立。
用命令行验证要过的第一道门
桌面端自带命令行,dsh tui 起终端界面,dsh web 起网页界面,dsh headless 跑单轮任务后退出。想不开图形界面确认技能是否被加载,最省事的做法是跑一次 headless,让它只回一句话。
实测第一次跑会直接停在凭据上,报错原文是这样的:
MISSING_CREDENTIAL: llm-deepseek: no API key for provider route "deepseek-official"
原因很直接,命令行不继承图形界面里已经登录的凭据,得显式给一把 key。两条路,导出环境变量,或者先在网页版 Models 页把这把 key 存进凭据服务。导出之后重跑同一条命令即可。
export DEEPSEEK_API_KEY=你的key
dsh headless "只输出两个字:好的"
这一步过了,才轮得到验证技能:把技能写进提示词,观察它是否按 SKILL.md 里的步骤执行。桌面端怎么装、四种会话模式分别干什么,写在桌面端安装教程里,这里不再重复。
改完怎么生效
技能目录靠文件监听维护,监听深度只到每个根的第一层。会触发目录刷新的改动有四种:新增或删除目录包、新增或删除平铺的 md 文件、新增或删除或修改 SKILL.md。资源子目录里的改动不触发刷新,因为它们本来就在加载时按需读。
正文改动不需要任何重启,下一次加载就是新内容,这点比插件宽松得多。插件要靠 profile 里的组合层生效,改动得走 dsh plugin 那条路径,具体分级见插件四档分级。
有一处容易误判:命令行的斜杠菜单会缓存目录。磁盘上增删技能之后,已经打开的会话会继续列出旧的技能表,直到切换一次预设、执行一次插件管理操作或者重置连接。遇到「装了不显示」,先切换预设再下结论,别急着改文件。
常见问题
技能放用户目录还是项目目录?
自己攒的通用技能放 ~/.dsh/skills,装一次所有会话都能用,维护成本最低。只在某个仓库生效、并且需要跟代码一起提交的放 <项目根>/.dsh/skills。两处同名时项目目录优先,所以覆盖单项目行为不用改用户目录里的原件。
装了没反应,按什么顺序排查?
四步就够。先用 find 确认真实深度是两级,再自检 name 是否全小写连字符,然后看两个布尔字段有没有把需要的那一侧关掉,最后切换一次预设清掉斜杠菜单缓存。四步都过还不行,才需要怀疑 YAML 语法,检查缩进是不是用了制表符。
技能和插件是一回事吗?
两回事,装法也完全不同。技能只是一份按需加载的说明文档,放进目录就被发现,不涉及任何代码执行。插件是装进 profile 的机制扩展,能挂工具、中间件和界面插槽,要用 dsh plugin 命令安装并重启 profile。想给模型加一套固定流程用技能,想改客户端自身行为才需要插件。
站内关于本体的其他实测还有接本地 Ollama 的三个坑,版本变化与安装方式看桌面版 0.2 发布说明。
延伸阅读
- 英特尔至强6+落地腾讯云:288核单颗支撑1000个智能体4 天前
- OpenClaw v2026.10.5 更新发布3 周前
- 腾讯内测 AI 互动社区《懂了鸭》:一句话生成 3D 课件,8 个模型可选2 周前
- OpenAI Code Studio 发布:动动嘴就能造 Game Boy 游戏1 月前
继续读
同一批更新里这几篇值得一看:
- DeepSeek Harness 接本地 Ollama:8192 上下文必崩的三个坑2026-11-06
- DeepSeek Super-agent 深度:P95 15.7 分钟对比 29.5 分钟2026-11-04
- 腾讯混元 Hy4 正式版:770B 参数首现视觉与电脑操作2026-11-04
想快速查定义?对应的词条在这里:
- DeepSeek词条 · AI 自学笔记
