第 3 章 · 02 DeepSeek 预设与双模型协作 本节摘要:本节把上一节的 Provider 抽象落到 Reasonix 最核心的场景——DeepSeek。DeepSeek 在 Reasonix 里是一个"预设",本质是预配置好的 provider 实例,endpoint 指向 。本节先讲 DeepSeek 预设的每个字段含义、 与 等推理控制,再深讲 Reasonix 最独特的能力之一——双模型 executor + planner 协作:为什么必须开两个独立会话、为什么不能在共享会话里切模型、planner 的"轻量/完整/仅计划/待批准"四种深度档位、计划如何作为结构化文本交给 executor。
本节摘要:本节把上一节的 Provider 抽象落到 Reasonix 最核心的场景——DeepSeek。DeepSeek 在 Reasonix 里是一个"预设",本质是预配置好的
kind = "openai"provider 实例,endpoint 指向https://api.deepseek.com。本节先讲 DeepSeek 预设的每个字段含义、reasoning_language与effort等推理控制,再深讲 Reasonix 最独特的能力之一——双模型 executor + planner 协作:为什么必须开两个独立会话、为什么不能在共享会话里切模型、planner 的"轻量/完整/仅计划/待批准"四种深度档位、计划如何作为结构化文本交给 executor。最后回到那句贯穿全书的论断——"任何 OpenAI 兼容端点只是配置项不是代码",这是"薄 harness"在 Provider 层的最佳兑现。
内容来源:原项目源码
docs/SPEC.md§3.4/§3.5/§5、reasonix.example.toml、internal/provider/openai/openai.go、REASONING_PROVIDERS.md/REASONING_LANGUAGE.md文档。
⚠️ 注意:双模型协作不是"两个模型同时跑同一个会话",而是"两个独立会话各跑一个模型"。混淆这一点会误解整个设计意图——它的首要目标是保持各自的 prefix cache 稳定,其次才是分工。
阅读完本节,你应当能够:
effort 与 reasoning_language 如何控制推理行为。第 2 章第 2 节已经看过 DeepSeek 预设的配置块,本节从 Provider 视角再读一遍(reasonix.example.toml:59-74):
[[providers]] name = "deepseek" kind = "openai" base_url = "https://api.deepseek.com" models = ["deepseek-v4-flash", "deepseek-v4-pro"] default = "deepseek-v4-flash" api_key_env = "DEEPSEEK_API_KEY" context_window = 1000000 effort = "high"
从 Provider 抽象看,这段配置做了三件事:
"deepseek",注册表 kind "openai"。reasonix setup 或运行时,internal/config 把它解析成 provider.Config{Name: "deepseek", BaseURL: "https://api.deepseek.com", APIKey: <从 .env 读出>, ...}。models = [...] 让一个 endpoint 暴露多个模型;default 指定列表的默认项。SPEC §3.1(docs/SPEC.md:97-99):An entry declares either a single
model = "..."or amodels = ["...", "..."]list (with an optionaldefault); the list form lets one vendor expose several models without re-declaring the endpoint/key.
context_window 是 provider 级上下文窗口(接近时触发压缩),api_key_env 命名密钥环境变量。kind = "openai" 的运行时含义:internal/provider/openai.New(cfg) 被调用,返回一个实现了 Provider interface 的 openai 结构体。它负责:
Request 序列化成 OpenAI /chat/completions 请求体。base_url + "/chat/completions"。prompt_cache_hit_tokens 与 OpenAI 的 prompt_tokens_details.cached_tokens 都映射成 Usage.CacheHitTokens)。docs/SPEC.md:84-85),代理后的 DeepSeek 也靠模型名识别;reasoning_protocol = "none" 可禁用,"openai" 可强制普通 reasoning_effort。关键认知:DeepSeek 不是特殊 provider kind,它就是 kind = "openai" 的一个配置实例。Reasonix 没有任何 if provider == "deepseek" 的硬编码分支(那会违反 SPEC §1.1)。DeepSeek 的特殊性全在 endpoint 端——DeepSeek 服务器实现了 OpenAI 兼容协议 + 自动 prefix cache,客户端(provider/openai 实现)只需把 DeepSeek 特有的 usage 字段规范化。
DeepSeek thinking 始终开启,effort 控制推理强度。example.toml 注释(reasonix.example.toml:73-74):
# DeepSeek thinking is always on; effort: high | max. Omit for auto (provider default). effort = "high"
/effort 命令在 TUI 里运行时切换强度。DeepSeek 模型支持 high/max;Anthropic 支持 low/medium/high/xhigh/max。自定义 [[providers]] 可通过 supported_efforts 与 default_effort 暴露自定义档位(reasonix.example.toml:80-96)。
reasoning_language(reasonix.example.toml:36):
# reasoning_language = "auto" # visible reasoning text: auto|zh|en
控制可见推理文本的语言:auto(跟随 UI 语言)、zh(中文)、en(英文)。这是 Reasonix 作为中国开发者社区项目的本地化细节——让 DeepSeek 的思维链用中文输出,对中国用户更友好。相关文档见 REASONING_PROVIDERS.md(哪些 provider 支持推理)与 REASONING_LANGUAGE.md(推理语言控制)。
💡 契约要点:
reasoning_language只影响可见推理文本,不影响 Reasonix 内部决策或工具调用。它通过 provider 实现层的提示控制实现,不污染 prefix cache 稳定前缀(因为是放在 turn tail,不是 system prompt)。
SPEC §3.5 是 Reasonix 最精巧的设计之一。开篇(docs/SPEC.md:200-204):
When
agent.planner_modelnames a provider different from the executor, aCoordinatorruns two models in separate sessions to keep each one's prompt prefix cache-stable.
机制:
Agent,跑在自己的会话里,带着全部工具,执行 planner 给出的计划。Coordinator 满足 Runner interface(SPEC §3.4,docs/SPEC.md:195-197):
A
Runneris anything withRun(ctx, input) error; bothAgentandCoordinatorsatisfy it, so the CLI is agnostic to single- vs two-model mode.
Runner 是 Run(ctx, input) error 的任何东西,Agent 与 Coordinator 都满足它,所以 CLI 不关心是单模型还是双模型模式——这是"核心只懂接口"的又一次兑现。
SPEC §3.5 最后一段点睛(docs/SPEC.md:237-240):
The sessions never mix, so neither model's prefix is disturbed by the other's turns; both grow prepend-only and stay cache-friendly. This reconciles "cache-first" with "two-model collaboration": switching models inside one shared conversation would break the prefix and tank cache hits, so we don't.
为什么"在同一个共享会话里切换模型"会击穿 prefix cache?
prefix cache 的工作原理是:provider 服务器缓存"请求前缀的 KV cache",下次请求前缀字节相同就复用。前缀包括 system prompt + tools schema + 历史消息。如果中途换模型:
所以 Reasonix 的解法是开两个会话:executor 会话只跟 executor 模型对话,planner 会话只跟 planner 模型对话,计划作为结构化文本在两会话间传递(不是共享消息历史)。这样两个会话各自 prepend-only 增长,各自 prefix cache 稳定——把"缓存优先"与"双模型协作"调和起来。
planner 不是无脑"先规划再执行"。SPEC §3.5 描述了一个确定性 host 策略(docs/SPEC.md:206-215),根据原始用户文本 + 可信轮次元数据,选择五种路由:
关键设计:
<planner-turn> 块随用户轮次变化(docs/SPEC.md:219-221):The depth contract stays in one stable system prompt; only a small host-authored
<planner-turn>block changes per user turn.
这又是 prefix cache 友好——深度契约(系统提示)字节稳定,只有小的轮次块变。
docs/SPEC.md:222-225):若 planner 在有界研究 + 宽限轮次后仍未定稿,plan-and-execute 回退到 executor 用原始任务;plan-only 与 plan-for-approval 保持 fail-closed(失败即停,不回退)。不完整的 planner 轮次被回滚,而非作为残缺的手动延续暴露。SPEC §3.5(docs/SPEC.md:234-236):
The plan is handed off as structured text to the executor — a full tool-using
Agentin its own session — which validates candidate assumptions and carries it out.
计划以结构化文本形式交给 executor——不是函数调用、不是共享内存、不是消息历史拼接。executor 在自己的会话里收到这段文本,作为新的用户轮次,验证候选假设并执行。
这个设计有几个好处:
回到 SPEC §3.1 那句贯穿全书的话(docs/SPEC.md:91-93):
OpenAI-compatible vendors are config instances of
kind = "openai", differing only inbase_url/model/api_key_env. Adding another OpenAI-compatible model is a config edit, not a code change.
DeepSeek、Kimi、GLM、MiniMax、Qwen、Ollama Cloud……它们在 Reasonix 里都是 kind = "openai" 的配置实例。example.toml 第 50-58 行的注释列出了桌面"Settings -> Model -> Access -> Add provider"内置的推荐预设:Kimi CN/Global、Kimi Coding Plan、MiMo API、MiniMax CN/Global、GLM/Z.AI、Qwen/DashScope、Token Rhythm、StepFun、NovitaAI、GMI、Vercel AI Gateway、HuggingFace、NVIDIA、KiloCode、Ollama Cloud。
加一个新模型,改 config 即可,不写一行 Go 代码——这是"薄 harness"在 Provider 层的最佳兑现,也是 Reasonix 能用一套代码对接几十个模型的根本原因。
💡 契约要点:薄 harness 的力量在于"接口稳定 + 注册表扩展 + 配置声明"。Provider interface 两个方法不变,注册表机制不变,新模型通过 config 接入。开发者只需理解一个 interface,就能对接整个 OpenAI 兼容生态。
kind = "openai" 的配置实例,endpoint 指向 https://api.deepseek.com;DeepSeek 不是特殊 kind,无硬编码 if provider == "deepseek"。effort(high/max)控制强度;reasoning_language(auto/zh/en)控制可见推理文本语言;都放在 turn tail,不污染 prefix。planner_model 开启 Coordinator,executor 与 planner 跑在两个独立会话,各自 prepend-only、各自 prefix cache 稳定。<planner-turn> 块变。下一章进入 Tool——SPEC §3.2 的 Tool interface 与 Registry,看 Reasonix 如何用与 Provider 同构的注册表模式管理内置工具与插件工具。