Coshire90-1135/DSH-MnnChat-Provider ↗★ 0
dsh-mnn-chat
接入手机端MNN Chat作为LLM服务商 适合希望将手机端离线运行的MNN模型接入DSH进行对话的局域网用户。
安裝
npx -p @deepseek-ai/dsh dsh plugin --profile web add github:Coshire90-1135/DSH-MnnChat-Provider說明文件
閱讀完整 README ↗三、当前配置
- id: mnn-chat
name: dsh-mnn-chat
config:
baseURL: http://192.168.1.23:8080 # 手机端地址
displayName: MNN-chat # 选择器里的 provider 分组名(纯展示)
apiKeyEnv: MNN_CHAT_API_KEY # 密钥在 DSH 凭据里,此处不写明文
models: # 只是离线兜底;服务端在提供的会自动出现
- ModelScope/MNN/Qwen3-0.6B-MNN
modelLabel: prefixed # 显示成 mnn-chat/Qwen3-0.6B-MNN(可省,默认就是它)
contextWindow: 32768
maxTokens: 2048
| 字段 | 默认值 | 说明 |
|---|---|---|
baseURL | http://127.0.0.1:8080 | 手机端地址。http://ip:8080、…/、…/v1 三种写法都识别。 |
models | 必填(可只写一个) | 离线兜底名单。服务端此刻在提供的模型无需写在这里也会自动出现在选择器里;写在这里但服务端没提供的会标注出来。模型名是协议字段,必须与服务端报的一致。 |
provider | mnn-chat | 路由名(provider id)。想在 DSH 里挂两台手机就再装一份、改个名。 |
displayName | MNN Chat | 选择器里显示的名字,纯展示。 |
apiKeyEnv | 无 | 凭据名。MNN Chat 要鉴权,配上它(见下)。解析不到会明确报 MISSING_CREDENTIAL。 |
apiKey | 无 | 明文 Key,仅本地调试(会留在配置文件里)。 |
contextWindow | 32768 | 上报的上下文窗口。端侧模型通常 4K–32K,别报大,否则 DSH 压缩得晚、请求会被服务端截断。 |
maxTokens | 8192 | 单次回复上限。手机端建议 1024–4096。 |
timeoutMs | 120000 | 单次请求总超时。 |
streamIdleTimeoutMs | 300000 | 流空闲超时:这么久没有任何数据就中断,避免手机掉线后干等。 |
includeUsage | false | 是否请求 stream_options.include_usage。保持 false(见下)。 |
pathStyle | auto | auto 先用 /v1/chat/completions,404 时回退 /chat/completions;也可强制 openai / bare。 |
headers | 无 | 额外请求头。别覆盖 accept(见下)。 |
extraBody | 无 | 透传的额外请求体字段(如 top_p)。不覆盖插件已写的字段。 |
retryPolicy | 见下 | { mode, maxRetries, retryableCodes, initialDelayMs, maxDelayMs, jitterRatio };默认对 5xx/429/网络错误重试 3 次。 |
catalogRefreshMs | 30000 | 模型目录自动拉取的间隔(毫秒):后台每隔这么久探一次手机端 /v1/models,列表变化就更新缓存并持久化成「最近已知列表」,选择器自动跟上手机换模型的动作。0 = 关闭后台轮询(面板里仍可手动「立即刷新」)。 |
systemPrompt | 无 | 本插件往系统提示词里插一段话(见「系统提示词改在哪」的方式 3)。不配就完全不插,也能在悬浮面板里直接改。 |
systemPromptOrder | 9100 | 那段话在系统提示词里的位置。DSH 的段落顺序见下节。 |
modelLabel | prefixed | 模型在选择器里的显示名,三档:prefixed = ${provider}/${id 末段}(默认,mnn-chat/Qwen3-0.6B-MNN,前缀取路由名不是 displayName)、tail = 只留末段(Qwen3-0.6B-MNN)、full = 完整 id。只影响显示,不改协议字段(发给服务端的 model 永远是原 id)。尾段撞名时自动带上父段。悬浮面板上也能切。 |
系统提示词改在哪
系统提示词不是这个插件生成的,而是 dsh-system-prompt 在每个模型步骤前拼装出来的。
按「改动成本从低到高」有四种改法:
方式 1:该会话的人设(最常用)
改 profiles/desktop/cordis.patch.yml 里 dsh-system-prompt 那一行的 personaPrefix / personaSuffix:
- id: system-prompt
name: '@deepseek-ai/dsh-system-prompt'
config:
# 最前面(order 0),身份口径
personaPrefix: 你是一个只在本机工作的编程助手。
# 最后(order 10200),口径补充,会盖住前面的说法
personaSuffix: 回答尽量简短,先给结论再给理由。工作目录是 {{cwd}}。
可用变量:{{cwd}}、{{model}},以及插件注册的其它变量。改完保存即生效。
方式 2:某个会话预设单独一套人设
dsh-persona 按 preset 作用域覆盖 deployment:persona-prefix/suffix,只影响该预设起的会话:
- id: persona
name: '@deepseek-ai/dsh-persona'
config:
prefix: You are a terse systems engineer who answers in short commands.
# complete: true → 只用这段 prefix 当整个系统提示词,其它段落全部让位
# includeRuntimeContext: false → 连运行时上下文快照也不给
方式 3:给 MNN 这条路由加一段专属提示词(本插件)
两种写法,效果完全一样,面板更省事:
- 悬浮面板 → 「系统提示词」编辑框 → 保存(立刻生效,落在
$DSH_HOME/mnn-chat.panel.json); - 或者写进配置:
- id: mnn-chat
name: dsh-mnn-chat
config:
# …前面的配置…
systemPrompt: |
你现在跑在手机端侧的 MNN 小模型上,能力有限:
回答尽量短、不要长篇铺陈;一次只做一件事;不确定就说不知道。
systemPromptOrder: 9100
它注册成名为 provider:mnn-chat 的独立 section,不会去动 DSH 自带的
deployment:persona-prefix / deployment:persona-suffix(同名重复注册会直接抛错)。
这段文字按字面处理、不做 {{变量}} 展开——因为未注册的变量在 dsh-system-prompt 里是
抛异常(不是留原文),用户随手写一对花括号就会让之后每一次模型调用都失败。要用变量请走方式 1。
DSH 的段落顺序:
-1000 harness 身份 → 0 persona 前缀 → 500–3100 各工具指引 → 5000 Tools SDK
→ 9000 交付物引用 → 【9100 本插件】 → 9900 结构化输出
→ 10000 harness source → 10100 Web surface → 10200 persona 后缀
⚠️ 「极简模式」下方式 3 的段落会被预设整体压掉(这是 DSH 的设计,不是插件的 bug): 极简模式预设的 persona 行带
complete: true,装配后只剩那一段,其它段落(含本插件的) 全部让位,而且不报错。所以本插件额外做了一层兜底:把同一段提示词作为最后一条 system 消息直接挂到请求上(与用哪个预设无关)。也就是说在极简模式下你的提示词依然生效, 只是位置固定在最后、不再受systemPromptOrder控制。想精确控制位置就用标准模式。 根因、DSH 源码行号、真机 A/B 验证见 BUG.md 第 5 节。
方式 4:工作区指令文件(AGENTS.md)
profiles/desktop/cordis.patch.yml 里把 agent-instructions 放开即可(当前是 disabled: true):
- id: agent-instructions
name: '@deepseek-ai/dsh-agent-instructions'
disabled: false
config:
maxBytes: 65536
它按 $DSH_HOME/AGENTS.md → 项目根(以 .git 为标记)→ 会话工作目录的顺序,
把每一层的 AGENTS.md / CLAUDE.md(外加 AGENTS.local.md / CLAUDE.local.md)
拼成一条 user 角色的 `` 消息。注意它是历史消息而不是 system 段落,
权威性低于系统提示词,且受 maxBytes 限制。
别指望在这儿改工具说明:每个工具的介绍文字由拥有该工具的插件自己注册 (
TOOL_BASH、TOOL_READ… 各有固定 order),没有面向用户的编辑入口。
哪个能改,哪个不能
| 东西 | 能不能改 | 说明 |
|---|---|---|
displayName | 随便改 | 纯展示文字,不参与协议。 |
| 模型在选择器里显示的名字 | 随便改 | 纯显示层,三档:prefixed(默认,mnn-chat/Qwen3-0.6B-MNN)/tail(Qwen3-0.6B-MNN)/full(ModelScope/MNN/Qwen3-0.6B-MNN)。悬浮面板上也能切。 |
provider | 能改 | DSH 内部路由名。改了要同步改 agent-default-model 的 provider;历史会话记录的是旧名字,会找不到适配器。 |
models 里的模型名(id) | 不能乱改 | DSH 每次请求把它当 model 字段发给服务端,服务端靠它挑模型。显示名能改,这个 id 改不了。 |
加模型:在手机 App 里加载那个模型即可,什么都不用改——插件会问服务端
/v1/models。想让它在手机掉线时也列出来,再写进 models 兜底。
MNN Chat 一次只加载一个模型,所以服务端通常只报一个 ID。「同时多个可选」要在手机上换着加载; 配置里可以都写上,但只有服务端当前提供的能真正跑通,其余会标注「手机端此刻没有提供它」。
写密钥
密钥存在 DSH 凭据库里 —— $DSH_HOME/.credentials.yaml 的 refs: 段:
refs:
DEEPSEEK_API_KEY: sk-...
MNN_CHAT_API_KEY: 你的API密钥 # ← 加这一行
该文件是热监听的(chokidar),保存即生效,不用重启。