L3 · 模型接入
Lesson 03 · 模块 A · 会用

接入任意模型:
provider 与凭据。

这套 harness 的名字里有 DeepSeek,但它并不绑定任何一家模型厂商。 GPT、Kimi、Claude 在这里都是可替换的 provider——换一个模型,是改一份配置, 而不是改一行源码。这一课学会在 Web UI 里配置模型、接入 OpenAI 兼容端点, 并用凭据引用把密钥管在安全的地方。

精读 20 分钟 练习 10 分钟 · 6 题 前置 见课程首页
学完你将能够
  • 说清「模型只是插件」的机制:llm 能力缝隙的三角色与 ctx.llm 注册表
  • 在 Web UI 的「设置 → 模型」页配置 DeepSeek 与目录提供方(Anthropic / OpenAI 等)
  • 用「添加自定义提供方」接入任意 OpenAI 兼容端点,并说清 DEEPSEEK_BASE_URL 的作用
  • 用凭据引用管理密钥:.env 归属、引用而非明文、永不提交凭据
01 · Model as Plugin

模型只是插件:llm 能力缝隙

在这套 harness 里,「模型」不是写死在循环里的组件,而是能力缝隙(capability seam)上的一个注册项。 每条缝隙由三个角色组成:Service Definition 定义与厂商无关的词汇表与服务接口; Provider 把某个具体服务接进来;Consumer 只面向接口编程,不关心对面是谁。

llm 这条缝隙的三角色是:llm 包提供消息与流式词汇表,加上适配器注册表 ctx.llmllm-deepseekllm-pi-ai 这类 provider 把 DeepSeek 官方 API、OpenAI 兼容端点等 具体服务注册成适配器;agent-loopcompaction-basic 是 consumer—— 它们发起模型请求时,根本不需要知道对面是哪家厂商。

架构文档把扩展方法浓缩成一句话:添加模型提供方 = 在 ctx.llm 上注册其适配器。 GPT、Kimi、Claude 对 agent loop 而言没有任何区别——它们都只是注册表里的一个条目。 这就是为什么「换模型」在这套框架里是运维动作(改配置),而不是开发动作(改代码)。

Web UI pnpm dsh web · 浏览器 Headless CLI --profile headless "任务" ACP / SDK 自动化协议 · 双语言 SDK ctx.llm · LLM 适配器注册表(capability seam) agent-loop 只面向这个与厂商无关的接口发起请求 llm-deepseek 适配器 插件 · 可替换 · DeepSeek 官方路由 openai-completions 适配器 插件 · 可替换 · llm-pi-ai 提供 api.deepseek.com HTTPS · 可用 DEEPSEEK_BASE_URL 改指向 你的 OpenAI 兼容端点 baseURL + 凭据 · GPT / Kimi / 网关
图 3-1 · 请求流向:任何入口的请求都经 ctx.llm 到达一个适配器插件,再由它翻译成 provider 的 HTTP API 调用。中间一层是插件,可整体替换。

这一课你只操作现成的适配器;L9 会亲手写一个模型适配器挂到 ctx.llm。 现在先把直觉建立起来:模型服务之于 harness,就像外设之于操作系统——插拔自由,内核不动。

会话与模型的关系

在模型选择器里选中一个模型,会同时把它设为新会话的默认值;已经发送过请求的会话则保留自己日志里记录的模型。 换 provider 不会改写历史会话的上下文——会话日志才是一切的源头(L6 展开)。

02 · Settings → Models

在 Web UI 配置 provider

启动 pnpm dsh web 后打开设置 → 模型,这就是模型管理的全部入口。 所有模型变更都会在下一次请求时生效,不需要重启服务器

  • DeepSeek 卡片:一个 API 密钥字段,输入并保存即可。密钥是只写的——保存后页面只会收到脱敏描述符,永远收不到明文;密钥本体存在 $DSH_HOME/.credentials.yaml,settings 里只保留它的凭据引用(04 节详解)。
  • 添加提供方(目录提供方):选取 Anthropic 或 OpenAI 等提供方,输入 API 密钥并保存。已安装目录自带端点、协议和模型列表,不需要手填。
  • 原生认证的例外:Bedrock、Vertex、Azure、Codex 分别要 AWS 凭据与区域、ADC 项目、api-version、OAuth——只填 API 密钥字段无法完成配置。
  • 选择模型:已配置的提供方会出现在模型选择器中;选择模型同时把它设为新会话的默认值。如果保存的默认值指向了已删除的提供方,输入框会显示「选择模型」并阻止输入,直到你另选一个。
两个最常见的错误码

MISSING_CREDENTIAL:通过模型页存储提供方密钥,或提供被引用的环境变量。 UNKNOWN_MODEL:选择已配置的模型,或向自定义提供方添加缺失的模型。看到这两个码先查配置,不要怀疑网络。

03 · OpenAI-Compatible

自定义 OpenAI 兼容端点

OpenAI 兼容 API 是一套 HTTP 约定:chat completions 的请求/响应格式,外加一个 GET /models 发现端点。 任何服务只要讲这套「语言」——OpenAI 官方、Kimi 等厂商的兼容入口、公司网关、自建代理—— harness 里现成的 openai-completions 适配器就能直接驱动它。 「接入任意模型」的真正含义是:复用同一个适配器,指向不同的 baseURL,而不是为每家厂商写代码。

目录里没有的服务(公司网关、自建服务器),走添加自定义提供方。表单字段各有讲究:

  • Provider ID:小写,且永久——请求、已保存会话、模型默认值和凭据引用都会使用它。想改名只能加新提供方再删旧的;显示名称、基础 URL、协议、凭据和模型则随时可编辑。
  • 基础 URL 与 API 协议:例如 https://gateway.example/v1openai-completions
  • 凭据与至少一个模型:模型可以手动录入 id,也可以在「模型目录」里点获取可用模型——它用表单当前的 baseURL 和凭据去查询 OpenAI 兼容的 GET /models。候选项只更新草稿,保存前不落盘;目录提供方用已安装目录,不发起网络请求。返回 401 就查密钥;端点不提供 /models 就手动输入。

另一个入口是环境变量 DEEPSEEK_BASE_URL(L1 排错时见过):它把内置 DeepSeek 路由的请求指向你的兼容端点。 与自定义提供方分工不同——一个改内置路由的指向,一个新增一条完全独立的 provider 记录。

# .env(仓库根目录,gitignored) DEEPSEEK_API_KEY=sk-... # 可选:把内置 DeepSeek 路由指向公司网关 / 代理 DEEPSEEK_BASE_URL=https://your-gateway.example/v1

习惯直接编辑配置的话,$DSH_HOME/settings.yaml 里的等价写法长这样——注意 apiKeyEnv环境变量名,不是密钥本身:

# $DSH_HOME/settings.yaml llm-pi-ai: providers: my-gateway: apiKeyEnv: GATEWAY_API_KEY # 凭据引用,不是明文 api: openai-completions baseURL: https://gateway.example/v1 models: - id: legacy-chat
04 · Credentials Seam

凭据管理:引用而非明文

上一节的 apiKeyEnv 已经展示了核心思想:配置里只放引用,不放机密。 这背后是另一条能力缝隙 dsh-credentials——settings 分节与 cordis.yml 条目携带的是 凭据引用(POSIX 风格的环境变量名),值归 dsh-credentials-local 这类 provider 所有。

  • 按操作解析:消费方每个操作重新 resolve(ref),绝不跨操作缓存——LLM 适配器每次模型请求解析一次,所以轮换后的凭据无需重启即可作用于紧随其后的下一次请求。
  • 描述不泄露describe(ref) 只回答「是否已配置 / 来自哪一层 / 当前能否写入」,绝不暴露值——配置界面的「已配置」徽标由此而来。由当前进程环境供值的引用会被报告为 writable: false,因为那样的写入会表面成功、解析却持续返回遮蔽值,seam 直接拒绝。
  • 本地 provider 的来源层envfileproject-envuser-env——仓库根目录的 .env 就是 project-env 层。一条 seam 级规则约束所有 provider:空的存储值在任何地方都视为不存在

对你的日常操作,结论只有三条:密钥写进根目录 .env(已被 gitignore); 配置里永远只写环境变量名;永不提交凭据——不进 git 历史,不贴进任何会提交的 YAML。

陷阱 · 明文进仓库是永久泄露

把明文密钥写进 cordis.yml 或 settings 并提交,等于把它永久刻进 git 历史——事后删文件救不回来,只能轮换密钥。 正确姿势永远是引用:apiKeyEnv: GATEWAY_API_KEY,值留在 gitignored 的 .env 里。

05 · Try It

动手试:接入一个兼容端点并验证

动手试 · 5 分钟

两条路径任选其一(有兼容端点就接真实的;没有就用公共 DeepSeek API 走一遍流程):

  1. Web UI 路径pnpm dsh web → 设置 → 模型 → 添加自定义提供方 → 填小写 Provider ID、基础 URL(https://…/v1)、API 协议 openai-completions、API 密钥、至少一个模型 id → 保存 → 在模型选择器选中它 → 发一句话。
  2. .env 路径:在仓库根目录 .env 写入 DEEPSEEK_API_KEYDEEPSEEK_BASE_URL(指向你的兼容端点),然后用 headless 跑一句话验证:
pnpm dsh --profile headless "用一句话介绍你自己"

验证标准:看到模型的正常回答,而不是 TRANSPORT 或 MISSING_CREDENTIAL 报错,即接入成功。

失败时按码排查

MISSING_CREDENTIAL → 密钥没配,或被引用的环境变量不存在;获取可用模型返回 401 → 密钥本身有问题; UNKNOWN_MODEL → 模型 id 没录进这个 provider。三个码都不涉及 harness 本身的缺陷。

06 · Quiz · 10 分钟

课堂练习

2 单选 + 2 多选 + 2 问答。选择即时批改,问答先写下你的答案再对照。成绩保存在本地浏览器。
单选
环境变量 DEEPSEEK_BASE_URL 的用途是什么?

正文 03 节:DEEPSEEK_BASE_URL 是环境变量版的「自定义端点」,把内置 DeepSeek provider 的请求指向你的网关或代理。模型 id 在 provider 的 models 列表里配置,超时与日志不归它管。

单选
在这套 harness 里,API 密钥的正确放置方式是?

正文 04 节:settings 与 cordis.yml 只携带凭据引用(环境变量名),值归 credentials provider 的来源层——.env 属于 project-env 层且已被 gitignore。其余三项都会把机密泄露给所有能看到代码或聊天记录的人。

多选
哪些服务可以通过 OpenAI 兼容端点(或目录提供方)接进这套 harness?(选出所有正确项)

D 与「模型只是插件」直接矛盾:agent-loop 是 consumer,只面向与厂商无关的 ctx.llm 接口编程(01 节)。A、B 走兼容端点或目录,C 走 Anthropic 目录提供方,都不需要动一行 loop 源码。

多选
关于凭据引用,哪些说法正确?

A、B 是 04 节原话:引用而非明文,且 credentials 本身就是一条完整缝隙。C 错:.env 已 gitignore,任何 key 都永不提交——明文进 git 历史只能靠轮换补救。D 错:cordis.yml 元数据保持字面量,机密以引用形式出现,写明文恰是反模式。

问答为什么说在这套 harness 下模型只是一个插件?这对用户意味着什么?写下答案后点击对照

参考要点:① 机制上,llm 是 capability seam——ctx.llm 适配器注册表 + provider 插件 + 只面向接口的 consumer(agent-loop),模型服务只是注册表里的一个条目;② 可替换:换模型是改配置而非改代码;③ 多模型并存:目录提供方与自定义兼容端点可同时配置,模型选择器随时切换,历史会话保留各自日志里的模型;④ 不被锁定:厂商差异被收敛为 baseURL + 凭据 + 协议,迁移成本约等于填一张表单。

问答描述接入一个新的 OpenAI 兼容 provider 的完整步骤与验证方法。写下答案后点击对照

参考要点:① 准备三样东西:端点 baseURL、API 密钥、至少一个模型 id;② Web UI → 设置 → 模型 → 添加自定义提供方,填小写 Provider ID(永久)、基础 URL、openai-completions 协议、凭据、模型并保存(或改内置路由:.env 里 DEEPSEEK_BASE_URL 指向端点);③ 可用「获取可用模型」对 GET /models 先校验端点与凭据;④ 验证:模型选择器选中后发一句话,或 pnpm dsh --profile headless "…" 跑通且无 TRANSPORT / MISSING_CREDENTIAL 报错即成功;失败按错误码排查(401 查密钥、UNKNOWN_MODEL 补录模型)。

本课小结

模型在这套 harness 里不再是黑盒组件,而是 ctx.llm 上一个可替换的插件: 你会在「设置 → 模型」里配置目录提供方,用自定义提供方接入任意 OpenAI 兼容端点, 也懂得了凭据引用与「永不提交」的红线。模块 A 到此收官——你已经会用这套框架了。 下一课进入模块 B,潜入 Cordis 微内核,读懂「一切皆插件」究竟是怎么运转的。