DeepSeek Harness 添加本地 Qwen3.8-27B 模型要这样控制思考深度,亲测有效,也许你们都已经成功了,但我今天才认真考虑解决这个问题,主要是太难等了!
-
DeepSeek Harness 添加本地 Qwen3.8-27B 模型完整指南(llama.cpp × dsh)
四档推理深度(关/低/中/高)全量生效实测 · 可直接复制配置 · 踩坑记录
这篇是写给另一台机器上的 Hermes 看的操作文档:照着做就能把本地 Qwen3.8-27B(含 UC 版)完整配置进 DeepSeek Harness(dsh),四档推理深度全部真实生效。
前提:llama.cpp 的 llama-server 已经在 127.0.0.1:8000 跑起来(
--jinja --reasoning on --reasoning-preserve),dsh web 已装好。本文只讲「把模型加进 dsh」这一步。
目录
- 先给结论
- 名词白话解释
- 最终配置(可直接复制)
- 四档推理深度机制(为什么必须这么配)
- 踩过的坑(4 个,都流了血)
- 验证清单(照做一遍)
- 附录:完整操作流程
1. 先给结论
项目 结果 配置位置 ~/.dsh/settings.yaml的llm-pi-ai.providers下加 provider模型条目 qwen3.8-27B+qwen3.8-27B-UC两个推理深度 关/低/中/高 四档全部真实生效(抓包验证) 关键 光配 reasoningEfforts不够,必须配compat块一句话 reasoning_effort: "none"关不掉 Qwen3.8 的思考,必须走chat_template_kwargs.enable_thinking: false最终配置效果(tcpdump 抓包实测):
- 关 →
enable_thinking: false(思考彻底关闭,秒回) - 低 →
enable_thinking: true, reasoning_effort: "low"(思考最简短) - 中 →
enable_thinking: true, reasoning_effort: "medium" - 高 →
enable_thinking: true, reasoning_effort: "xhigh"(官方最高档)
2. 名词白话解释
名词 白话解释 dsh DeepSeek Harness,DeepSeek 官方开源的 agent harness, dsh web是它的 Web UI(本机 127.0.0.1:3080)llama.cpp / llama-server 本地跑 GGUF 模型的推理引擎,提供 OpenAI 兼容 API( /v1/chat/completions)reasoningEfforts dsh 里给每个模型声明的「推理深度档位 → 端点参数」映射表 thinkingFormat dsh 的 compat 配置,决定「把推理档位翻译成哪种端点的请求格式」 chat_template_kwargs llama.cpp 端点认识的请求字段,Qwen3.8 的 jinja 模板用 enable_thinking控制是否思考enable_thinking Qwen3.8 模板真正的思考开关。 false= 不思考,true= 思考
3. 最终配置(可直接复制)
打开
~/.dsh/settings.yaml,在llm-pi-ai.providers下加入(或合并到已有的 qwen provider 里):llm-pi-ai: providers: qwen-local: displayName: qwen-local apiKeyEnv: QWEN_LOCAL_API_KEY # 任意命名,~/.dsh/.env 里加 QWEN_LOCAL_API_KEY=local(本地不校验) api: openai-completions baseURL: http://127.0.0.1:8000/v1 models: - id: qwen3.8-27B name: qwen3.8-27B contextWindow: 153600 maxTokens: 32768 reasoningEfforts: 'off': none low: low medium: medium high: xhigh # ⚠️ 必须是 xhigh!Qwen3.8 模板不认 high,会直接 500 compat: thinkingFormat: chat-template # ⚠️ 必须是 chat-template,不是 qwen-chat-template! chatTemplateKwargs: enable_thinking: {$var: thinking.enabled} reasoning_effort: {$var: thinking.effort, omitWhenOff: true} preserve_thinking: true - id: qwen3.8-27B-UC name: qwen3.8-27B-UC contextWindow: 153600 maxTokens: 32768 reasoningEfforts: 'off': none low: low medium: medium high: xhigh compat: thinkingFormat: chat-template chatTemplateKwargs: enable_thinking: {$var: thinking.enabled} reasoning_effort: {$var: thinking.effort, omitWhenOff: true} preserve_thinking: true然后:
# 1. 备份 cp ~/.dsh/settings.yaml ~/.dsh/settings.yaml.bak.$(date +%Y%m%d-%H%M%S) # 2. .env 补 apiKeyEnv 对应的变量(本地端点不校验 key 值,任意非空即可) echo 'QWEN_LOCAL_API_KEY=local' >> ~/.dsh/.env # 3. 默认模型指向本地(可选,按需) # agent-default-model: # provider: qwen-local # model: qwen3.8-27B-UC # reasoningEffort: 'off' # ⚠️ off 必须带引号! # 4. 重启 systemctl --user restart dsh-web.service sleep 6 systemctl --user is-active dsh-web.service # 期望 active curl -s -o /dev/null -w '%{http_code}\n' http://127.0.0.1:3080/ # 期望 200
4. 四档推理深度机制(为什么必须这么配)
4.1 Qwen3.8 模板只认 xhigh / medium / low
从 Qwen3.8 GGUF 里直接提取的 jinja 模板源码:
{%- if enable_thinking is undefined or enable_thinking is true %} {%- set resolved_reasoning_effort = reasoning_effort|default('xhigh') %} {%- if resolved_reasoning_effort not in ('xhigh', 'medium', 'low') %} {{- raise_exception('Unexpected reasoning effort ' ~ reasoning_effort ~ '. Supported types are xhigh (default), medium, and low.') }} {%- endif %}none不是合法档位 → 顶层 API 传reasoning_effort: none时被 llama.cpp 归一化剥掉(不传给模板),模板走默认 xhigh 满档思考——实测 none 思考最长(4631 字符)high不是合法档位 → 若直接把high塞进chat_template_kwargs.reasoning_effort传给模板,模板 raise_exception → HTTP 500(实测确认)- 所以 UI 四档映射:关 →
enable_thinking: false;低 →low;中 →medium;高 →xhigh
4.2 为什么必须用
chat-template而不是qwen-chat-templatedsh 源码(pi-ai 的 openai-completions.js)里有两个 Qwen 分支:
// qwen-chat-template 分支:只发开关,不带 effort → 低/中/高三档没区别! else if (compat.thinkingFormat === "qwen-chat-template" && model.reasoning) { params.chat_template_kwargs = { enable_thinking: !!options?.reasoningEffort, preserve_thinking: true, }; } // chat-template 分支:走 buildChatTemplateKwargs → 支持 $var 占位符,带 effort! else if (compat.thinkingFormat === "chat-template" && model.reasoning) { const chatTemplateKwargs = buildChatTemplateKwargs(model, options, compat); ... }qwen-chat-template分支只发enable_thinking开关(低/中/高都变成「开思考」+ 默认 xhigh 满档),必须用chat-template分支 +chatTemplateKwargs里的$var: thinking.effort才能把档位传下去。4.3
$var是 dsh 官方占位符chatTemplateKwargs的 value 支持两种写法:- 字面量:
string/number/boolean/null - 占位符:
{$var: "thinking.enabled"}或{$var: "thinking.effort", omitWhenOff: true}
thinking.effort解析逻辑(dsh 源码 resolveChatTemplateKwargValue):- 有 effort(低/中/高)→ 查
thinkingLevelMap→ 发对应值 - off →
omitWhenOff: true让它不发(思考由 enable_thinking: false 关掉)
5. 踩过的坑(4 个,都流了血)
坑 1:光配 reasoningEfforts 关不掉思考(off 无效)
症状:dsh 里把推理深度设「关」,模型还在不停思考。
根因:dsh 走通用分支发reasoning_effort: "none",但 Qwen3.8 模板不认 none → 默认 xhigh 满档思考。实测reasoning_effort=none思考最长(4631 字符)。
修复:配 compat 走 chat-template 分支,发chat_template_kwargs.enable_thinking: false(实测思考归零)。坑 2:
reasoning_effort: {}空对象 → 整个 provider 挂掉,模型从 dsh 消失症状:
NO_ADAPTER: no adapter registered for provider "qwen-local",dsh 里模型全没了。
根因:dsh 的 schema(chatTemplateKwarg)只接受 string/number/boolean/null/带必填$var的对象。空对象{}校验失败 → 整个 provider 被拒。
修复:reasoning_effort用{$var: thinking.effort, omitWhenOff: true}。
血泪:改完必须验证——dsh --profile headless '测试'能回话才算真活。坑 3:PyYAML 把
off重写成布尔 false症状:用 Python yaml 库改 settings.yaml 后,
reasoningEffort: off变成reasoningEffort: false。
根因:PyYAML 按 YAML 1.1 解析,off/on/yes/no是布尔关键字;dsh 用 js-yaml 按 YAML 1.2 解析,off是字符串。
修复:写回时显式带引号'off',改完 grep 检查reasoningEffort行。
血泪:'off'键也要带引号——PyYAML 会把off: none的键off解析成布尔 False。坑 4:
high档直接 500症状:选「高」档,请求 500 错误。
根因:模板只认 xhigh/medium/low,high触发 raise_exception。
修复:reasoningEfforts.high映射到xhigh(官方最高档)。
6. 验证清单(照做一遍)
# 1. 服务健康 systemctl --user is-active dsh-web.service # active curl -s -o /dev/null -w '%{http_code}\n' http://127.0.0.1:3080/ # 200 # 2. headless 实测(能回话 = provider 真活着) dsh --profile headless '27乘以43等于多少?一行答案。' # 期望:秒回「1161」这类答案(不是 NO_ADAPTER) # 3. 四档抓包验证(可选但推荐) # 临时改 agent-default-model.reasoningEffort 到 off/low/medium/high 各测一次 sudo tcpdump -i lo -A -s 0 'tcp port 8000' > /tmp/dsh_cap.txt & dsh --profile headless '27乘以43等于多少?' grep -o 'chat_template_kwargs[^,}]*' /tmp/dsh_cap.txt # 期望:off → enable_thinking:false # 低 → reasoning_effort:"low",中 → "medium",高 → "xhigh"
7. 附录:完整操作流程(给执行方 Hermes)
- 确认前提:
curl -s http://127.0.0.1:8000/v1/models返回模型列表(llama-server 活着) - 确认 dsh 存在:
ls ~/.dsh/settings.yaml+systemctl --user is-active dsh-web.service - 备份:
cp ~/.dsh/settings.yaml ~/.dsh/settings.yaml.bak.$(date +%Y%m%d-%H%M%S) - 改配置:按第 3 节 YAML 加入 provider + 模型条目(或合并到已有 provider)
- 补 .env:
echo 'QWEN_LOCAL_API_KEY=local' >> ~/.dsh/.env(apiKeyEnv 对应变量,本地不校验值) - 重启:
systemctl --user restart dsh-web.service - 验证:is-active=active + curl 3080=200 +
dsh --profile headless '测试'回话 - 四档验证(可选):按第 6 节抓包确认各档位参数
- 收尾:web UI 里能看到模型,选推理深度各档位可切换
注意:dsh 的
--dump-config输出 profile 树,不含 llm-pi-ai 的 model 条目——grep 不到模型条目属正常,不能用来验证模型级配置。验证用第 6 节的方法。
实测日期:2026-08-30 · 环境:Ubuntu + llama.cpp(CUDA 12.9)+ Qwen3.8-27B Q4_K_XL / Q4_K_P · dsh web :3080 · 全文配置均经抓包与 headless 实测验证
-
-