DeepSeek Harness 的模型都在 Web UI 的设置 → 模型里配。本文默认你已经把 Web UI 跑起来了。改完不必重启服务器,下一次请求就会用新配置。
页面上有三件事:给 DeepSeek 填密钥、从已安装目录加提供方、以及自己接公司网关或自建服务。自定义提供方如果还要传图,或网关自称兼容 OpenAI 实际却拒请求,就要改 $DSH_HOME/settings.yaml——表单里没有这些字段。
配置 DeepSeek
打开设置 → 模型,DeepSeek 卡片上有一个 API 密钥字段。填进去,保存即可。
密钥是只写的。保存之后,页面只会拿到脱敏描述符,永远看不到明文。明文落在 $DSH_HOME/.credentials.yaml 里,settings 只保留凭据引用。
添加目录提供方
选添加提供方,挑 Anthropic 或 OpenAI 这类已在目录里的服务,填它的 API 密钥再保存。端点、协议和模型列表由已安装目录给出,不用自己填。
Bedrock、Vertex、Azure、Codex 走各自的原生认证,只填 API 密钥字段配不完:
- Bedrock:AWS 凭据与区域
- Vertex:ADC 项目
- Azure:
api-version - Codex:OAuth
目录提供方的模型列表来自本地已安装目录,获取可用模型不会对它们发网络请求。
添加自定义提供方
公司网关、自建服务器,或目录里根本没有的服务,走添加自定义提供方。表单要你提供:
- 小写 Provider ID
- 基础 URL
- API 协议
- 凭据
- 至少一个模型
Provider ID 不能事后改名
Provider ID 是永久的。请求、已保存会话、模型默认值、凭据引用都拿它当键。显示名称、基础 URL、协议、凭据和模型以后还能改;ID 本身不行。真要换名字,只能再加一个提供方,把旧的删掉。
获取可用模型只改草稿
表单里的模型目录有获取可用模型。它用的是你此刻填在表单上的基础 URL 和凭据,去打 OpenAI 兼容的 GET /models。点选候选项只会改当前草稿,点保存之前,这个提供方还不会被存下来。
对方不提供 GET /models 时,请手动输入模型。返回 401 时先核密钥。
给自定义模型声明图片输入
手填的模型在自己声明之前,一律按纯文本对待——没有环节会去问端点到底收哪些模态。给这类模型附加图片,请求发出去之前就会被拒绝,报错会点名那个模型。
视觉模型要在 $DSH_HOME/settings.yaml 里给它加 input。表单没有这个字段。
单模型 input
input 只认 text 和 image,而且只作用于写了它的那一个模型。同一条路由可以一边挂纯文本、一边挂视觉:
llm-pi-ai:
providers:
my-gateway:
apiKeyEnv: GATEWAY_API_KEY
api: openai-completions
baseURL: https://gateway.example/v1
models:
- id: legacy-chat
- id: vision-preview
input: [text, image]
省略 input,或者写成空列表,意思一样:沿用已安装目录给该模型记的模态;目录没描述过的,回退到这条路由的 defaultInput。
路由级 defaultInput
手填的模型如果全都收图,不必每个都写一遍,在路由上设一次回退即可:
llm-pi-ai:
providers:
vision-gateway:
apiKeyEnv: GATEWAY_API_KEY
api: openai-completions
baseURL: https://vision.example/v1
defaultInput: [text, image]
models:
- id: first-model
- id: second-model
defaultInput 是回退,不是覆盖,默认值是 [text]。在目录提供方上,它只给目录没描述过的模型补答案,不会把目录里本来就能看图的模型的图片能力去掉。真要收窄某个目录模型,用它自己的 input。
除了模型自己的那份列表,每个列表至少要写一项模态。模型自己的空列表等于省略。未知模态写在任何位置都会被拒。
input 和 defaultInput 都是你对端点的断言,不是探测。模型声明了图片、端点其实不收,这里拦不住,会由提供方在请求时拒绝。
目录提供方用 modelOverrides
目录提供方没有可填的 models 列表,收窄或改写写在 modelOverrides 下,键是模型 id:
llm-pi-ai:
providers:
anthropic:
modelOverrides:
claude-sonnet-4-5:
input: [text]
DeepSeek 自己的 chat-completions 路由是纯文本,不能靠配置打开图片。
网关通了但仍被拒绝:请求兼容性
密钥有效、地址也打得通,网关仍可能拒绝每一个请求。pi-ai 看端点 URL 来决定请求长什么样:系统提示词放哪个角色、输出上限写哪个字段、思考级别怎么传。它认不出的地址,一律按 OpenAI 本身来发。多数「OpenAI 兼容」网关至少会拒绝 OpenAI 接受的某一样东西。
占绝大多数的是这两样:
- 声明了推理能力的模型,系统提示词会以
role: "developer"发出,很多网关直接拒。 - 输出上限写成
max_completion_tokens,只认max_tokens的服务端会拒。
表单里没有这两个开关,要在 $DSH_HOME/settings.yaml 的路由上改 compat:
llm-pi-ai:
providers:
my-gateway:
apiKeyEnv: GATEWAY_API_KEY
api: openai-completions
baseURL: https://gateway.example/v1
compat:
supportsDeveloperRole: false
maxTokensField: max_tokens
models:
- id: my-model
路由上的 compat 是这条路由上所有模型的默认值。某个模型自己写了同名字段,以模型为准,所以只修一个模型不用把整条路由重写一遍:
models:
- id: my-model
- id: my-reasoner
compat:
thinkingFormat: deepseek
路由和模型都没写的字段,沿用已安装目录给该模型记的值;目录也没描述,才落到 pi-ai 自己的检测。
写下来的开关必须带值。supportsDeveloperRole: 这种冒号后面空着的键会被拒绝,不会被忽略——空值会把目录里已知的信息抹掉,却给不出替代。任何协议都不认的名字同样会被拒,报错会列出当前能用的那些。
每个开关只属于声明了它的协议。某个 api 上合法的开关,换一个协议可能直接报错,报错会点名该协议实际提供哪些。和 input 一样,compat 也是断言:你打开一个网关其实不需要的开关,结果只是发出另一种形状的请求。
全部开关、各自能填的值、以及哪些协议接受它们,写在生成的 dsh-llm-pi-ai 配置参考的 PiAiCompatProfile 里。那份参考从源码生成,跟适配器实际接受的内容对齐。
选择模型
配好的提供方会出现在模型选择器里。选一个模型,同时会把它设成新会话的默认值。已经发过请求的会话,继续用自己日志里记下的那个模型,不会跟着默认值跑。
如果已保存的默认值指向一个已经删掉的提供方,输入框会显示选择模型,在你选别的模型之前,输入会被拦住。
排错
MISSING_CREDENTIAL:到模型页把提供方密钥存进去,或提供被引用的环境变量。UNKNOWN_MODEL:选一个已经配好的模型,或给自定义提供方补上缺失的模型。- 获取可用模型返回 401:先查密钥。模型发现走的是 OpenAI 兼容的
GET /models;对方没有这个端点,就手动输入模型。 - 密钥和地址都对,网关却拒绝每一个请求:请求形状和 OpenAI 不一样。先在路由上设
compat.supportsDeveloperRole: false和compat.maxTokensField: max_tokens。 - 只有推理模型失败:pi-ai 把它们的系统提示词以
developer角色发出,网关拒这个角色。设compat.supportsDeveloperRole: false。 - 某个 compat 开关因没有值而被拒绝:冒号后面是空的。给它一个值,或删掉这个键,让它沿用已安装目录的值。
- 图片在发送前被拒绝:该模型没声明图片模态。给自定义提供方的模型加上
input: [text, image]。DeepSeek 自己的 chat-completions 路由是纯文本,配置改不了。 - 提供方拒绝了带图片的请求:模型声明了端点其实没有的图片能力。从授予它图片能力的那个列表里去掉
image——可能是模型的input,也可能是路由的defaultInput——然后开一个新会话。已经附上的图片会留在会话日志里,旧会话不离开它,同一个请求会反复带图。
需要直接改 YAML 时看哪里
自动生成的插件配置目录会列出每个插件支持的字段和默认值。这里配的提供方段落对应 dsh-llm-pi-ai。直接改 settings.yaml、目录解析、推理控制、凭据和适配器错误,分别看 dsh-llm-pi-ai 和 dsh-llm-deepseek 的参考文档。