<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
    <id>https://oakimov.github.io/claude-code-router/zh-CN/blog</id>
    <title>Claude Code Router Blog</title>
    <updated>2026-06-01T00:00:00.000Z</updated>
    <generator>https://github.com/jpmonette/feed</generator>
    <link rel="alternate" href="https://oakimov.github.io/claude-code-router/zh-CN/blog"/>
    <subtitle>Claude Code Router Blog</subtitle>
    <icon>https://oakimov.github.io/claude-code-router/zh-CN/img/favicon.ico</icon>
    <entry>
        <title type="html"><![CDATA[分支更新日志 — 新增功能一览]]></title>
        <id>https://oakimov.github.io/claude-code-router/zh-CN/blog/2026/06/01/fork-changelog</id>
        <link href="https://oakimov.github.io/claude-code-router/zh-CN/blog/2026/06/01/fork-changelog"/>
        <updated>2026-06-01T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[本分支在 claude-code-router 基础上新增了多项提供商集成、UI 改进和基础设施变更。以下是各功能的时间线。]]></summary>
        <content type="html"><![CDATA[<p>本分支在 claude-code-router 基础上新增了多项提供商集成、UI 改进和基础设施变更。以下是各功能的时间线。</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="2026-年-1-月--mistral-集成">2026 年 1 月 — Mistral 集成<a href="https://oakimov.github.io/claude-code-router/zh-CN/blog/2026/06/01/fork-changelog#2026-%E5%B9%B4-1-%E6%9C%88--mistral-%E9%9B%86%E6%88%90" class="hash-link" aria-label="2026 年 1 月 — Mistral 集成的直接链接" title="2026 年 1 月 — Mistral 集成的直接链接" translate="no">​</a></h2>
<p>添加了 <strong>Mistral AI 转换器</strong>，支持直接 API 调用、推理参数处理和专用的 Docker Compose 配置。将 Mistral 转换逻辑解耦为共享工具函数。</p>
<ul>
<li class=""><code>feat: add Mistral transformer for direct API support</code></li>
<li class=""><code>fix: correctly handle reasoning parameter for Mistral API</code></li>
</ul>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="2026-年-4-月--gemini-稳定性代码质量与构建流水线">2026 年 4 月 — Gemini 稳定性、代码质量与构建流水线<a href="https://oakimov.github.io/claude-code-router/zh-CN/blog/2026/06/01/fork-changelog#2026-%E5%B9%B4-4-%E6%9C%88--gemini-%E7%A8%B3%E5%AE%9A%E6%80%A7%E4%BB%A3%E7%A0%81%E8%B4%A8%E9%87%8F%E4%B8%8E%E6%9E%84%E5%BB%BA%E6%B5%81%E6%B0%B4%E7%BA%BF" class="hash-link" aria-label="2026 年 4 月 — Gemini 稳定性、代码质量与构建流水线的直接链接" title="2026 年 4 月 — Gemini 稳定性、代码质量与构建流水线的直接链接" translate="no">​</a></h2>
<p>大幅改进了 Gemini/Gemma 流式传输的可靠性。修复了因请求体中 <code>thoughtSignature</code> 位置错误导致的 Gemini 500 错误以及多轮对话中的工具调用失败。项目已完全本地化（所有注释翻译为英文）。<strong>UI 包已集成到 Docker 构建流程</strong>中，管理界面可直接从容器提供服务。</p>
<ul>
<li class=""><code>build: include UI package in Docker build process</code></li>
<li class=""><code>refactor: localize codebase by translating all comments to English</code></li>
<li class=""><code>fix: resolve Gemini 500 errors and tool use failures</code></li>
<li class=""><code>feat: add ThinkingSequencer for ordered Gemini streaming</code></li>
</ul>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="5-月-7-日--deepseek-推理重放">5 月 7 日 — DeepSeek 推理重放<a href="https://oakimov.github.io/claude-code-router/zh-CN/blog/2026/06/01/fork-changelog#5-%E6%9C%88-7-%E6%97%A5--deepseek-%E6%8E%A8%E7%90%86%E9%87%8D%E6%94%BE" class="hash-link" aria-label="5 月 7 日 — DeepSeek 推理重放的直接链接" title="5 月 7 日 — DeepSeek 推理重放的直接链接" translate="no">​</a></h2>
<p>实现了 DeepSeek 模型的<strong>强制推理重放</strong>。DeepSeek 要求将之前的助手推理内容包含在后续请求中 — 否则模型在多轮对话中会丢失上下文。<code>reasoning</code> 转换器自动捕获响应中的推理输出并在下一请求中重放。</p>
<ul>
<li class=""><code>feat: implement mandatory reasoning replay for DeepSeek provider</code></li>
</ul>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="5-月-7-日--codexchatgpt集成">5 月 7 日 — Codex（ChatGPT）集成<a href="https://oakimov.github.io/claude-code-router/zh-CN/blog/2026/06/01/fork-changelog#5-%E6%9C%88-7-%E6%97%A5--codexchatgpt%E9%9B%86%E6%88%90" class="hash-link" aria-label="5 月 7 日 — Codex（ChatGPT）集成的直接链接" title="5 月 7 日 — Codex（ChatGPT）集成的直接链接" translate="no">​</a></h2>
<p>添加了 <strong>Codex 转换器</strong>，支持 OpenAI Responses API，采用 PKCE 流程的 OAuth 认证（<code>ccr codex-auth</code>）。支持 SSE 流式传输、推理/思考内容、工具调用、网络搜索和图像处理。需要 ChatGPT Plus 或 Pro 订阅。</p>
<ul>
<li class=""><code>feat: add Codex transformer and support for Codex authentication</code></li>
</ul>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="5-月-8-日--模型发现">5 月 8 日 — 模型发现<a href="https://oakimov.github.io/claude-code-router/zh-CN/blog/2026/06/01/fork-changelog#5-%E6%9C%88-8-%E6%97%A5--%E6%A8%A1%E5%9E%8B%E5%8F%91%E7%8E%B0" class="hash-link" aria-label="5 月 8 日 — 模型发现的直接链接" title="5 月 8 日 — 模型发现的直接链接" translate="no">​</a></h2>
<p>添加了<strong>非交互式模型发现</strong>（<code>ccr model get</code>）。从任何提供商的 API 获取远程模型列表，解析自定义 JSON 结构，并将缺失的模型追加到本地配置中，不修改现有条目。</p>
<ul>
<li class=""><code>feat: add support for custom provider model discovery</code></li>
</ul>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="5-月-10-日--chrome-内置模型gemini-nano">5 月 10 日 — Chrome 内置模型（Gemini Nano）<a href="https://oakimov.github.io/claude-code-router/zh-CN/blog/2026/06/01/fork-changelog#5-%E6%9C%88-10-%E6%97%A5--chrome-%E5%86%85%E7%BD%AE%E6%A8%A1%E5%9E%8Bgemini-nano" class="hash-link" aria-label="5 月 10 日 — Chrome 内置模型（Gemini Nano）的直接链接" title="5 月 10 日 — Chrome 内置模型（Gemini Nano）的直接链接" translate="no">​</a></h2>
<p>添加了 <strong>Chrome 内置模型桥接和转换器</strong>，用于 Chrome 的 Gemini Nano 模型（约 4GB 本地 LLM）。通过 Chrome DevTools 协议（CDP）通信，提供零成本、零延迟的本地推理。支持卡死恢复（动态温度调节）、通过 <code>responseConstraint</code> 的结构化 JSON 输出以及完整 SSE 流式传输。</p>
<ul>
<li class=""><code>feat: add Chrome on-device bridge and transformer for Gemini Nano</code></li>
</ul>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="5-月-12-日--桥接稳定性改进">5 月 12 日 — 桥接稳定性改进<a href="https://oakimov.github.io/claude-code-router/zh-CN/blog/2026/06/01/fork-changelog#5-%E6%9C%88-12-%E6%97%A5--%E6%A1%A5%E6%8E%A5%E7%A8%B3%E5%AE%9A%E6%80%A7%E6%94%B9%E8%BF%9B" class="hash-link" aria-label="5 月 12 日 — 桥接稳定性改进的直接链接" title="5 月 12 日 — 桥接稳定性改进的直接链接" translate="no">​</a></h2>
<p>增强了 Chrome 桥接：多会话仪表板、空闲会话回收、通过反射检测改进了工具循环预防，以及优化了系统提示以保持工具交互的一致性。</p>
<ul>
<li class=""><code>feat(bridge): add multi-session dashboard, idle eviction</code></li>
<li class=""><code>refactor: migrate bridge to explicit &lt;tool_result&gt; XML tags</code></li>
</ul>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="5-月-18-日--透传模式与-deepseek-思考修复">5 月 18 日 — 透传模式与 DeepSeek 思考修复<a href="https://oakimov.github.io/claude-code-router/zh-CN/blog/2026/06/01/fork-changelog#5-%E6%9C%88-18-%E6%97%A5--%E9%80%8F%E4%BC%A0%E6%A8%A1%E5%BC%8F%E4%B8%8E-deepseek-%E6%80%9D%E8%80%83%E4%BF%AE%E5%A4%8D" class="hash-link" aria-label="5 月 18 日 — 透传模式与 DeepSeek 思考修复的直接链接" title="5 月 18 日 — 透传模式与 DeepSeek 思考修复的直接链接" translate="no">​</a></h2>
<p>添加了基于提供商的透传模式，支持直接的 Anthropic 风格认证处理，并修复了 DeepSeek 思考功能，无需客户端发送 reasoning 参数。</p>
<ul>
<li class=""><code>feat: add per-provider passthrough mode</code></li>
<li class=""><code>fix: enable DeepSeek thinking without client reasoning param</code></li>
</ul>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="5-月-25-日--codex-修复与-anthropic-effort-透传">5 月 25 日 — Codex 修复与 Anthropic Effort 透传<a href="https://oakimov.github.io/claude-code-router/zh-CN/blog/2026/06/01/fork-changelog#5-%E6%9C%88-25-%E6%97%A5--codex-%E4%BF%AE%E5%A4%8D%E4%B8%8E-anthropic-effort-%E9%80%8F%E4%BC%A0" class="hash-link" aria-label="5 月 25 日 — Codex 修复与 Anthropic Effort 透传的直接链接" title="5 月 25 日 — Codex 修复与 Anthropic Effort 透传的直接链接" translate="no">​</a></h2>
<p>修复了 Codex 转换器的工具调用参数，恢复了流式传输用量计算，并直接传递 Claude Code 的 effort 参数而非通过 budget_tokens 映射。</p>
<ul>
<li class=""><code>fix(anthropic): pass through Claude Code effort directly</code></li>
</ul>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="6-月-1-日--qwen-chat-集成">6 月 1 日 — Qwen Chat 集成<a href="https://oakimov.github.io/claude-code-router/zh-CN/blog/2026/06/01/fork-changelog#6-%E6%9C%88-1-%E6%97%A5--qwen-chat-%E9%9B%86%E6%88%90" class="hash-link" aria-label="6 月 1 日 — Qwen Chat 集成的直接链接" title="6 月 1 日 — Qwen Chat 集成的直接链接" translate="no">​</a></h2>
<p>添加了 <strong>Qwen Chat 认证转换器</strong>，支持基于 JWT 的认证（<code>ccr qwen-auth</code>），并在 <code>/qwen/auth</code> 提供基于浏览器的认证页面，支持书签工具以便从 <code>chat.qwen.ai</code> 轻松提取令牌。自动令牌轮换和移除 Qwen 响应中的 <code>&lt;details&gt;...&lt;/details&gt;</code> 元数据块。</p>
<ul>
<li class=""><code>feat(qwen): add Qwen Chat auth (ccr qwen-auth) and provider transformer</code></li>
</ul>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="文档">文档<a href="https://oakimov.github.io/claude-code-router/zh-CN/blog/2026/06/01/fork-changelog#%E6%96%87%E6%A1%A3" class="hash-link" aria-label="文档的直接链接" title="文档的直接链接" translate="no">​</a></h2>
<p>所有功能都有专门的集成指南文档：</p>
<ul>
<li class=""><a class="" href="https://oakimov.github.io/claude-code-router/zh-CN/zh/docs/server/guides/codex">Codex 集成</a></li>
<li class=""><a class="" href="https://oakimov.github.io/claude-code-router/zh-CN/zh/docs/server/guides/qwen">Qwen Chat 集成</a></li>
<li class=""><a class="" href="https://oakimov.github.io/claude-code-router/zh-CN/zh/docs/server/guides/chrome-on-device">Chrome 内置模型</a></li>
<li class=""><a class="" href="https://oakimov.github.io/claude-code-router/zh-CN/zh/docs/server/guides/deepseek-reasoning">DeepSeek 推理重放</a></li>
<li class=""><a class="" href="https://oakimov.github.io/claude-code-router/zh-CN/zh/docs/server/guides/model-discovery">模型发现</a></li>
</ul>]]></content>
        <category label="changelog" term="changelog"/>
        <category label="fork" term="fork"/>
        <category label="features" term="features"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[GLM-4.6支持思考及思维链回传]]></title>
        <id>https://oakimov.github.io/claude-code-router/zh-CN/blog/2025/11/18/glm-reasoning</id>
        <link href="https://oakimov.github.io/claude-code-router/zh-CN/blog/2025/11/18/glm-reasoning"/>
        <updated>2025-11-18T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[GLM-4.6在cluade code中启用思考]]></summary>
        <content type="html"><![CDATA[<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="glm-46在cluade-code中启用思考">GLM-4.6在cluade code中启用思考<a href="https://oakimov.github.io/claude-code-router/zh-CN/blog/2025/11/18/glm-reasoning#glm-46%E5%9C%A8cluade-code%E4%B8%AD%E5%90%AF%E7%94%A8%E6%80%9D%E8%80%83" class="hash-link" aria-label="GLM-4.6在cluade code中启用思考的直接链接" title="GLM-4.6在cluade code中启用思考的直接链接" translate="no">​</a></h2>
<p>GLM从4.5开始就对claude code进行了支持，我之前也一直在关注，很多用户反映在claude code中无法启用思考，刚好最近收到了来自智谱的赞助，就着手进行研究。</p>
<p>首先根据<a href="https://docs.bigmodel.cn/api-reference/%E6%A8%A1%E5%9E%8B-api/%E5%AF%B9%E8%AF%9D%E8%A1%A5%E5%85%A8" target="_blank" rel="noopener noreferrer" class="">官方文档</a>，我们发现<code>/chat/completions</code>端点是默认启用思考的，但是是由模型判断是否需要进行思考</p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">thinking object</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">仅 GLM-4.5 及以上模型支持此参数配置. 控制大模型是否开启思维链。</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">thinking.type enum&lt;string&gt; default:enabled</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">是否开启思维链(当开启后 GLM-4.6 GLM-4.5 为模型自动判断是否思考，GLM-4.5V 为强制思考), 默认: enabled.</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">Available options: enabled, disabled</span><br></div></code></pre></div></div>
<p>在claude code本身大量的提示词干扰下，会严重阻碍GLM模型本身的判断机制，导致模型很少进行思考。所以我们需要对模型进行引导，让模型认为需要进行思考。但是<code>claude-code-router</code>作为proxy，能做的只能是修改提示词/参数。</p>
<p>在最开始，我尝试直接删除claude code的系统提示词，模型确实进行了思考，但是这样就无法驱动claude code。所以我们需要进行提示词注入，明确告知模型需要进行思考。</p>
<div class="language-javascript codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-javascript codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token comment" style="color:#999988;font-style:italic">// transformer.ts</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">import</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"> UnifiedChatRequest </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">from</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"../types/llm"</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">import</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"> Transformer </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">from</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"../types/transformer"</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">export</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">class</span><span class="token plain"> </span><span class="token class-name">ForceReasoningTransformer</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">implements</span><span class="token plain"> </span><span class="token class-name">Transformer</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  name </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"forcereasoning"</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token keyword" style="color:#00009f">async</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">transformRequestIn</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token literal-property property" style="color:#36acaa">request</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> UnifiedChatRequest</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">)</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> Promise</span><span class="token operator" style="color:#393A34">&lt;</span><span class="token plain">UnifiedChatRequest</span><span class="token operator" style="color:#393A34">&gt;</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> systemMessage </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> request</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">messages</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">find</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token punctuation" style="color:#393A34">(</span><span class="token parameter">item</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=&gt;</span><span class="token plain"> item</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">role </span><span class="token operator" style="color:#393A34">===</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"system"</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">if</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">Array</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">isArray</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">systemMessage</span><span class="token operator" style="color:#393A34">?.</span><span class="token plain">content</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">      systemMessage</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">content</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">push</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token literal-property property" style="color:#36acaa">type</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"text"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token literal-property property" style="color:#36acaa">text</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"You are an expert reasoning model. \nAlways think step by step before answering. Even if the problem seems simple, always write down your reasoning process explicitly. \nNever skip your chain of thought. \nUse the following output format:\n&lt;reasoning_content&gt;(Write your full detailed thinking here.)&lt;/reasoning_content&gt;\n\nWrite your final conclusion here."</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> lastMessage </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> request</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">messages</span><span class="token punctuation" style="color:#393A34">[</span><span class="token plain">request</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">messages</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">length </span><span class="token operator" style="color:#393A34">-</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">1</span><span class="token punctuation" style="color:#393A34">]</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">if</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">lastMessage</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">role </span><span class="token operator" style="color:#393A34">===</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"user"</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">&amp;&amp;</span><span class="token plain"> Array</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">isArray</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">lastMessage</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">content</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">      lastMessage</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">content</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">push</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token literal-property property" style="color:#36acaa">type</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"text"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token literal-property property" style="color:#36acaa">text</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"You are an expert reasoning model. \nAlways think step by step before answering. Even if the problem seems simple, always write down your reasoning process explicitly. \nNever skip your chain of thought. \nUse the following output format:\n&lt;reasoning_content&gt;(Write your full detailed thinking here.)&lt;/reasoning_content&gt;\n\nWrite your final conclusion here."</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">if</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">lastMessage</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">role </span><span class="token operator" style="color:#393A34">===</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"tool"</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">      request</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">messages</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">push</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token literal-property property" style="color:#36acaa">role</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"user"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token literal-property property" style="color:#36acaa">content</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">[</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">          </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">            </span><span class="token literal-property property" style="color:#36acaa">type</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"text"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">            </span><span class="token literal-property property" style="color:#36acaa">text</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"You are an expert reasoning model. \nAlways think step by step before answering. Even if the problem seems simple, always write down your reasoning process explicitly. \nNever skip your chain of thought. \nUse the following output format:\n&lt;reasoning_content&gt;(Write your full detailed thinking here.)&lt;/reasoning_content&gt;\n\nWrite your final conclusion here."</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">          </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token punctuation" style="color:#393A34">]</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">return</span><span class="token plain"> request</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><br></div></code></pre></div></div>
<p>至于为什么让模型将思考内容放入reasoning_content标签而不是think标签有两个原因：</p>
<ol>
<li class="">直接使用think标签不能很好的激活思考，猜测是训练模型时以think标签作为数据集进行训练。</li>
<li class="">如果使用think标签，模型的推理内容会被拆分到单独的字段，这就涉及到我们接下来要说的思维链回传问题。</li>
</ol>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="思维链回传">思维链回传<a href="https://oakimov.github.io/claude-code-router/zh-CN/blog/2025/11/18/glm-reasoning#%E6%80%9D%E7%BB%B4%E9%93%BE%E5%9B%9E%E4%BC%A0" class="hash-link" aria-label="思维链回传的直接链接" title="思维链回传的直接链接" translate="no">​</a></h2>
<p>近期Minimax发布了Minimax-m2，与此同时，他们还发布了一篇<a href="https://www.minimaxi.com/news/why-is-interleaved-thinking-important-for-m2" target="_blank" rel="noopener noreferrer" class="">文章</a>介绍思维链回传。但是太阳底下无新鲜事，刚好借此来剖析一下。</p>
<ol>
<li class="">
<p>我们首先来看一下为什么需要回传思维链？
Minimax在文章中说的是Chat Completion API不支持在后续请求中传递推理内容。我们知道ChatGPT是最先支持推理的，但是OpenAI最初没有开放思维链给用户，所以对于Chat Completion API来讲并不需要支持思维链相关的东西。就连CoT的字段也是DeepSeek率先在Chat Completion API中加入的。</p>
</li>
<li class="">
<p>我们真的需要这些字段吗？
如果没有这些字段会怎么样？会影响到模型的思考吗？可以查看一下<a href="https://github.com/sgl-project/sglang/blob/main/python/sglang/srt/parser/reasoning_parser.py" target="_blank" rel="noopener noreferrer" class="">sglang的源码</a>发现思维链的信息原本就会在消息中按照特定的标记进行输出，假如我们不对其进行拆分，正常情况下在下轮对话中会自然包含这些信息。所以需要思维链回传的原因就是我们对模型的思维链内容进行拆分。</p>
</li>
</ol>
<p>我用上面不到40行的代码完成了对GLM-4.5/6支持思考以及思维链回传的简单探索(单纯是因为没时间做拆分，完全可以在transformer中响应时先做拆分，请求时再进行合并，这样对cc前端的展示适配会更好)，如果你有什么更好的想法也欢迎与我联系。</p>]]></content>
        <category label="glm" term="glm"/>
        <category label="思考" term="思考"/>
        <category label="思维链" term="思维链"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[或许我们能在 Router 中做更多事情]]></title>
        <id>https://oakimov.github.io/claude-code-router/zh-CN/blog/2025/11/18/router-exploration</id>
        <link href="https://oakimov.github.io/claude-code-router/zh-CN/blog/2025/11/18/router-exploration"/>
        <updated>2025-11-18T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[自从claude-code-router发布以来，我收到了很多用户的反馈，至今还有不少的 issues 未处理。其中大多都是关于不同的供应商的支持和deepseek模型调用工具不积极的问题。]]></summary>
        <content type="html"><![CDATA[<p>自从<code>claude-code-router</code>发布以来，我收到了很多用户的反馈，至今还有不少的 issues 未处理。其中大多都是关于不同的供应商的支持和<code>deepseek</code>模型调用工具不积极的问题。
之前开发这个项目主要是为了我自己能以较低成本使用上<code>claude code</code>，所以一开始的设计并没有考虑到多供应商的情况。在实际的排查问题中，我发现尽管市面上所有的供应商几乎都宣称兼容<code>OpenAI</code>格式调用，即通过<code>/chat/compeletions</code>接口调用，但是其中的细节差异非常多。例如:</p>
<ol>
<li class="">
<p>Gemini 的工具参数类型是 string 时，<code>format</code>参数只支持<code>date</code>和<code>date-time</code>，并且没有工具调用 ID。</p>
</li>
<li class="">
<p>OpenRouter 需要使用<code>cache_control</code>进行缓存。</p>
</li>
<li class="">
<p>DeepSeek 官方 API 的 <code>max_output</code> 为 8192，而火山引擎的会更大。</p>
</li>
</ol>
<p>除了这些问题之外，还有一些其他的小的供应商，他们或多或少参数都有点问题。于是，我打算开发一个新的项目<a href="https://github.com/musistudio/llms" target="_blank" rel="noopener noreferrer" class="">musistudio/llms</a>来处理这种不同服务商的兼容问题。该项目使用 OpenAI 格式为基础的通用格式，提供了一个<code>Transformer</code>接口，该接口用于处理转换请求和响应。当我们给不同的服务商都实现了<code>Transformer</code>后，我们可以实现不同服务商的混合调用。比如我在<code>AnthropicTransformer</code>中实现了<code>Anthropic</code> &lt;-&gt; <code>OpenAI</code>格式的互相转换，并监听了<code>/v1/messages</code>端点，在<code>GeminiTransformer</code>中实现了<code>Gemini</code> &lt;-&gt; <code>OpenAI</code>格式的互相转换，并监听了<code>/v1beta/models/:modelAndAction</code>端点，当他们的请求和响应都被转换成一个通用格式的时候，就可以实现他们的互相调用。</p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">AnthropicRequest -&gt; AnthropicTransformer -&gt; OpenAIRequest -&gt; GeminiTransformer -&gt; GeminiRequest -&gt; GeminiServer</span><br></div></code></pre></div></div>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">GeminiReseponse -&gt; GeminiTransformer -&gt; OpenAIResponse -&gt; AnthropicTransformer -&gt; AnthropicResponse</span><br></div></code></pre></div></div>
<p>虽然使用中间层抹平差异可能会带来一些性能问题，但是该项目最初的目的是为了让<code>claude-code-router</code>支持不同的供应商。</p>
<p>至于<code>deepseek</code>模型调用工具不积极的问题，我发现这是由于<code>deepseek</code>在长上下文中的指令遵循不佳导致的。现象就是刚开始模型会主动调用工具，但是在经过几轮对话后模型只会返回文本。一开始的解决方案是通过注入一个系统提示词告知模型需要积极去使用工具以解决用户的问题，但是后面测试发现在长上下文中模型会遗忘该指令。
查看<code>deepseek</code>文档后发现模型支持<code>tool_choice</code>参数，可以强制让模型最少调用 1 个工具，我尝试将该值设置为<code>required</code>，发现模型调用工具的积极性大大增加，现在我们只需要在合适的时候取消这个参数即可。借助<a href="https://github.com/musistudio/llms" target="_blank" rel="noopener noreferrer" class="">musistudio/llms</a>的<code>Transformer</code>可以让我们在发送请求前和收到响应后做点什么，所以我参考<code>claude code</code>的<code>Plan Mode</code>，实现了一个使用与<code>deepseek</code>的<code>Tool Mode</code></p>
<div class="language-typescript codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-typescript codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token keyword module" style="color:#00009f">export</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">class</span><span class="token plain"> </span><span class="token class-name maybe-class-name">TooluseTransformer</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">implements</span><span class="token plain"> </span><span class="token class-name maybe-class-name">Transformer</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  name </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"tooluse"</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token function" style="color:#d73a49">transformRequestIn</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">request</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token maybe-class-name">UnifiedChatRequest</span><span class="token punctuation" style="color:#393A34">)</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token maybe-class-name">UnifiedChatRequest</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword control-flow" style="color:#00009f">if</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">request</span><span class="token punctuation" style="color:#393A34">.</span><span class="token property-access">tools</span><span class="token operator" style="color:#393A34">?.</span><span class="token plain">length</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">      request</span><span class="token punctuation" style="color:#393A34">.</span><span class="token property-access">messages</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">push</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        role</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"system"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        content</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token template-string template-punctuation string" style="color:#e3116c">`</span><span class="token template-string string" style="color:#e3116c">&lt;system-reminder&gt;Tool mode is active. The user expects you to proactively execute the most suitable tool to help complete the task.</span><br></div><div class="token-line" style="color:#393A34"><span class="token template-string string" style="color:#e3116c">Before invoking a tool, you must carefully evaluate whether it matches the current task. If no available tool is appropriate for the task, you MUST call the \`ExitTool\` to exit tool mode — this is the only valid way to terminate tool mode.</span><br></div><div class="token-line" style="color:#393A34"><span class="token template-string string" style="color:#e3116c">Always prioritize completing the user's task effectively and efficiently by using tools whenever appropriate.&lt;/system-reminder&gt;</span><span class="token template-string template-punctuation string" style="color:#e3116c">`</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">      request</span><span class="token punctuation" style="color:#393A34">.</span><span class="token property-access">tool_choice</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"required"</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">      request</span><span class="token punctuation" style="color:#393A34">.</span><span class="token property-access">tools</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">unshift</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        type</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"function"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token keyword" style="color:#00009f">function</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">          name</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"ExitTool"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">          description</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token template-string template-punctuation string" style="color:#e3116c">`</span><span class="token template-string string" style="color:#e3116c">Use this tool when you are in tool mode and have completed the task. This is the only valid way to exit tool mode.</span><br></div><div class="token-line" style="color:#393A34"><span class="token template-string string" style="color:#e3116c">IMPORTANT: Before using this tool, ensure that none of the available tools are applicable to the current task. You must evaluate all available options — only if no suitable tool can help you complete the task should you use ExitTool to terminate tool mode.</span><br></div><div class="token-line" style="color:#393A34"><span class="token template-string string" style="color:#e3116c">Examples:</span><br></div><div class="token-line" style="color:#393A34"><span class="token template-string string" style="color:#e3116c">1. Task: "Use a tool to summarize this document" — Do not use ExitTool if a summarization tool is available.</span><br></div><div class="token-line" style="color:#393A34"><span class="token template-string string" style="color:#e3116c">2. Task: "What's the weather today?" — If no tool is available to answer, use ExitTool after reasoning that none can fulfill the task.</span><span class="token template-string template-punctuation string" style="color:#e3116c">`</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">          parameters</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">            type</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"object"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">            properties</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">              response</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">                type</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"string"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">                description</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">                  </span><span class="token string" style="color:#e3116c">"Your response will be forwarded to the user exactly as returned — the tool will not modify or post-process it in any way."</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">              </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">            </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">            required</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">[</span><span class="token string" style="color:#e3116c">"response"</span><span class="token punctuation" style="color:#393A34">]</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">          </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword control-flow" style="color:#00009f">return</span><span class="token plain"> request</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token keyword" style="color:#00009f">async</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">transformResponseOut</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">response</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token maybe-class-name">Response</span><span class="token punctuation" style="color:#393A34">)</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token known-class-name class-name">Promise</span><span class="token operator" style="color:#393A34">&lt;</span><span class="token maybe-class-name">Response</span><span class="token operator" style="color:#393A34">&gt;</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword control-flow" style="color:#00009f">if</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">response</span><span class="token punctuation" style="color:#393A34">.</span><span class="token property-access">headers</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">get</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">"Content-Type"</span><span class="token punctuation" style="color:#393A34">)</span><span class="token operator" style="color:#393A34">?.</span><span class="token method function property-access" style="color:#d73a49">includes</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">"application/json"</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> jsonResponse </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token keyword control-flow" style="color:#00009f">await</span><span class="token plain"> response</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">json</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token keyword control-flow" style="color:#00009f">if</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        jsonResponse</span><span class="token operator" style="color:#393A34">?.</span><span class="token plain">choices</span><span class="token punctuation" style="color:#393A34">[</span><span class="token number" style="color:#36acaa">0</span><span class="token punctuation" style="color:#393A34">]</span><span class="token operator" style="color:#393A34">?.</span><span class="token plain">message</span><span class="token punctuation" style="color:#393A34">.</span><span class="token property-access">tool_calls</span><span class="token operator" style="color:#393A34">?.</span><span class="token plain">length </span><span class="token operator" style="color:#393A34">&amp;&amp;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        jsonResponse</span><span class="token operator" style="color:#393A34">?.</span><span class="token plain">choices</span><span class="token punctuation" style="color:#393A34">[</span><span class="token number" style="color:#36acaa">0</span><span class="token punctuation" style="color:#393A34">]</span><span class="token operator" style="color:#393A34">?.</span><span class="token plain">message</span><span class="token punctuation" style="color:#393A34">.</span><span class="token property-access">tool_calls</span><span class="token punctuation" style="color:#393A34">[</span><span class="token number" style="color:#36acaa">0</span><span class="token punctuation" style="color:#393A34">]</span><span class="token operator" style="color:#393A34">?.</span><span class="token plain">function</span><span class="token operator" style="color:#393A34">?.</span><span class="token plain">name </span><span class="token operator" style="color:#393A34">===</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">          </span><span class="token string" style="color:#e3116c">"ExitTool"</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> toolArguments </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token known-class-name class-name">JSON</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">parse</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">toolCall</span><span class="token punctuation" style="color:#393A34">.</span><span class="token property-access">function</span><span class="token punctuation" style="color:#393A34">.</span><span class="token property-access">arguments</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">||</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"{}"</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        jsonResponse</span><span class="token punctuation" style="color:#393A34">.</span><span class="token property-access">choices</span><span class="token punctuation" style="color:#393A34">[</span><span class="token number" style="color:#36acaa">0</span><span class="token punctuation" style="color:#393A34">]</span><span class="token punctuation" style="color:#393A34">.</span><span class="token property-access">message</span><span class="token punctuation" style="color:#393A34">.</span><span class="token property-access">content</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> toolArguments</span><span class="token punctuation" style="color:#393A34">.</span><span class="token property-access">response</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">||</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">""</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token keyword" style="color:#00009f">delete</span><span class="token plain"> jsonResponse</span><span class="token punctuation" style="color:#393A34">.</span><span class="token property-access">choices</span><span class="token punctuation" style="color:#393A34">[</span><span class="token number" style="color:#36acaa">0</span><span class="token punctuation" style="color:#393A34">]</span><span class="token punctuation" style="color:#393A34">.</span><span class="token property-access">message</span><span class="token punctuation" style="color:#393A34">.</span><span class="token property-access">tool_calls</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token comment" style="color:#999988;font-style:italic">// Handle non-streaming response if needed</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token keyword control-flow" style="color:#00009f">return</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">new</span><span class="token plain"> </span><span class="token class-name maybe-class-name">Response</span><span class="token punctuation" style="color:#393A34">(</span><span class="token known-class-name class-name">JSON</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">stringify</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">jsonResponse</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        status</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> response</span><span class="token punctuation" style="color:#393A34">.</span><span class="token property-access">status</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        statusText</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> response</span><span class="token punctuation" style="color:#393A34">.</span><span class="token property-access">statusText</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        headers</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> response</span><span class="token punctuation" style="color:#393A34">.</span><span class="token property-access">headers</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"> </span><span class="token keyword control-flow" style="color:#00009f">else</span><span class="token plain"> </span><span class="token keyword control-flow" style="color:#00009f">if</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">response</span><span class="token punctuation" style="color:#393A34">.</span><span class="token property-access">headers</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">get</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">"Content-Type"</span><span class="token punctuation" style="color:#393A34">)</span><span class="token operator" style="color:#393A34">?.</span><span class="token method function property-access" style="color:#d73a49">includes</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">"stream"</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token comment" style="color:#999988;font-style:italic">// ...</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword control-flow" style="color:#00009f">return</span><span class="token plain"> response</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><br></div></code></pre></div></div>
<p>该工具将始终让模型至少调用一个工具，如果没有合适的工具或者任务已完成可以调用<code>ExitTool</code>来退出工具模式，因为是依靠<code>tool_choice</code>参数实现的，所以仅适用于支持该参数的模型。经过测试，该工具能显著增加<code>deepseek</code>的工具调用次数，弊端是可能会有跟任务无关或者没有必要的工具调用导致增加任务执行事件和消耗的 <code>token</code> 数。</p>
<p>这次更新仅仅是在 Router 中实现一个<code>agent</code>的一次小探索，或许还能做更多其他有趣的事也说不定...</p>]]></content>
        <category label="router" term="router"/>
        <category label="transformer" term="transformer"/>
        <category label="deepseek" term="deepseek"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[项目初衷及原理]]></title>
        <id>https://oakimov.github.io/claude-code-router/zh-CN/blog/2025/02/25/project-motivation</id>
        <link href="https://oakimov.github.io/claude-code-router/zh-CN/blog/2025/02/25/project-motivation"/>
        <updated>2025-02-25T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[早在 Claude Code 发布的第二天(2025-02-25)，我就尝试并完成了对该项目的逆向。当时要使用 Claude Code 你需要注册一个 Anthropic 账号，然后申请 waitlist，等待通过后才能使用。但是因为众所周知的原因，Anthropic 屏蔽了中国区的用户，所以通过正常手段我无法使用，通过已知的信息，我发现：]]></summary>
        <content type="html"><![CDATA[<p>早在 Claude Code 发布的第二天(2025-02-25)，我就尝试并完成了对该项目的逆向。当时要使用 Claude Code 你需要注册一个 Anthropic 账号，然后申请 waitlist，等待通过后才能使用。但是因为众所周知的原因，Anthropic 屏蔽了中国区的用户，所以通过正常手段我无法使用，通过已知的信息，我发现：</p>
<ol>
<li class="">Claude Code 使用 npm 进行安装，所以很大可能其使用 Node.js 进行开发。</li>
<li class="">Node.js 调试手段众多，可以简单使用<code>console.log</code>获取想要的信息，也可以使用<code>--inspect</code>将其接入<code>Chrome Devtools</code>，甚至你可以使用<code>d8</code>去调试某些加密混淆的代码。</li>
</ol>
<p>由于我的目标是让我在没有 Anthropic 账号的情况下使用<code>Claude Code</code>，我并不需要获得完整的源代码，只需要将<code>Claude Code</code>请求 Anthropic 模型时将其转发到我自定义的接口即可。接下来我就开启了我的逆向过程：</p>
<ol>
<li class="">首先安装<code>Claude Code</code></li>
</ol>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token function" style="color:#d73a49">npm</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">install</span><span class="token plain"> </span><span class="token parameter variable" style="color:#36acaa">-g</span><span class="token plain"> @anthropic-ai/claude-code</span><br></div></code></pre></div></div>
<ol start="2">
<li class="">安装后该项目被放在了<code>~/.nvm/versions/node/v20.10.0/lib/node_modules/@anthropic-ai/claude-code</code>中，因为我使用了<code>nvm</code>作为我的 node 版本控制器，当前使用<code>node-v20.10.0</code>，所以该路径会因人而异。</li>
<li class="">找到项目路径之后可通过 package.json 分析包入口,内容如下：</li>
</ol>
<div class="language-package.json codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-package.json codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">{</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  "name": "@anthropic-ai/claude-code",</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  "version": "1.0.24",</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  "main": "sdk.mjs",</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  "types": "sdk.d.ts",</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  "bin": {</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    "claude": "cli.js"</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  },</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  "engines": {</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    "node": "&gt;=18.0.0"</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  },</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  "type": "module",</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  "author": "Boris Cherny &lt;boris@anthropic.com&gt;",</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  "license": "SEE LICENSE IN README.md",</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  "description": "Use Claude, Anthropic's AI assistant, right from your terminal. Claude can understand your codebase, edit files, run terminal commands, and handle entire workflows for you.",</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  "homepage": "https://github.com/anthropics/claude-code",</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  "bugs": {</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    "url": "https://github.com/anthropics/claude-code/issues"</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  },</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  "scripts": {</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    "prepare": "node -e \"if (!process.env.AUTHORIZED) { console.error('ERROR: Direct publishing is not allowed.\\nPlease use the publish-external.sh script to publish this package.'); process.exit(1); }\"",</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    "preinstall": "node scripts/preinstall.js"</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  },</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  "dependencies": {},</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  "optionalDependencies": {</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    "@img/sharp-darwin-arm64": "^0.33.5",</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    "@img/sharp-darwin-x64": "^0.33.5",</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    "@img/sharp-linux-arm": "^0.33.5",</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    "@img/sharp-linux-arm64": "^0.33.5",</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    "@img/sharp-linux-x64": "^0.33.5",</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    "@img/sharp-win32-x64": "^0.33.5"</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  }</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">}</span><br></div></code></pre></div></div>
<p>其中<code>"claude": "cli.js"</code>就是我们要找的入口，打开 cli.js，发现代码被压缩混淆过了。没关系，借助<code>webstorm</code>的<code>Formate File</code>功能可以重新格式化，让代码变得稍微好看一点。就像这样：
<img decoding="async" loading="lazy" alt="webstorm-formate-file" src="https://oakimov.github.io/claude-code-router/zh-CN/assets/images/webstorm-formate-file-6f0d9de12c63cc99d85bc36522b53c5a.png" width="3218" height="2082" class="img_ev3q"></p>
<p>现在，你可以通过阅读部分代码来了解<code>Claude Code</code>的内容工具原理与提示词。你也可以在关键地方使用<code>console.log</code>来获得更多信息，当然，也可以使用<code>Chrome Devtools</code>来进行断点调试，使用以下命令启动<code>Claude Code</code>:</p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token assign-left variable" style="color:#36acaa">NODE_OPTIONS</span><span class="token operator" style="color:#393A34">=</span><span class="token string" style="color:#e3116c">"--inspect-brk=9229"</span><span class="token plain"> claude</span><br></div></code></pre></div></div>
<p>该命令会以调试模式启动<code>Claude Code</code>，并将调试的端口设置为<code>9229</code>。这时候通过 Chrome 访问<code>chrome://inspect/</code>即可看到当前的<code>Claude Code</code>进程，点击<code>inspect</code>即可进行调试。
<img decoding="async" loading="lazy" alt="chrome-devtools" src="https://oakimov.github.io/claude-code-router/zh-CN/assets/images/chrome-inspect-38499e7f3ad61207e7f7a402d1c07c4d.png" width="3098" height="1716" class="img_ev3q">
<img decoding="async" loading="lazy" alt="chrome-devtools" src="https://oakimov.github.io/claude-code-router/zh-CN/assets/images/chrome-devtools-9fb03a216664e64b9358877c6dcd21ee.png" width="3248" height="1922" class="img_ev3q"></p>
<p>通过搜索关键字符<code>api.anthropic.com</code>很容易能找到<code>Claude Code</code>用来发请求的地方，根据上下文的查看，很容易发现这里的<code>baseURL</code>可以通过环境变量<code>ANTHROPIC_BASE_URL</code>进行覆盖，<code>apiKey</code>和<code>authToken</code>也同理。
<img decoding="async" loading="lazy" alt="search" src="https://oakimov.github.io/claude-code-router/zh-CN/assets/images/search-8bab61f834826571afe5c7ac34db708c.png" width="3248" height="1922" class="img_ev3q"></p>
<p>到目前为止，我们获得关键信息：</p>
<ol>
<li class="">
<p>可以使用环境变量覆盖<code>Claude Code</code>的<code>BaseURL</code>和<code>apiKey</code>的配置</p>
</li>
<li class="">
<p><code>Claude Code</code>使用<a href="https://docs.anthropic.com/en/api/overview" target="_blank" rel="noopener noreferrer" class="">Anthropic API</a>的规范</p>
</li>
</ol>
<p>所以我们需要：</p>
<ol>
<li class="">
<p>实现一个服务用来将<code>OpenAI API</code>的规范转换成<code>Anthropic API</code>格式。</p>
</li>
<li class="">
<p>启动<code>Claude Code</code>之前写入环境变量将<code>baseURL</code>指向到该服务。</p>
</li>
</ol>
<p>于是，<code>claude-code-router</code>就诞生了，该项目使用<code>Express.js</code>作为 HTTP 服务，实现<code>/v1/messages</code>端点，使用<code>middlewares</code>处理请求/响应的格式转换以及请求重写功能(可以用来重写 Claude Code 的提示词以针对单个模型进行调优)。
在 2 月份由于<code>DeepSeek</code>全系列模型对<code>Function Call</code>的支持不佳导致无法直接使用<code>DeepSeek</code>模型，所以在当时我选择了<code>qwen-max</code>模型，一切表现的都很好，但是<code>qwen-max</code>不支持<code>KV Cache</code>，意味着我要消耗大量的 token，但是却无法获取<code>Claude Code</code>原生的体验。
所以我又尝试了<code>Router</code>模式，即使用一个小模型对任务进行分发，一共分为四个模型:<code>router</code>、<code>tool</code>、<code>think</code>和<code>coder</code>，所有的请求先经过一个免费的小模型，由小模型去判断应该是进行思考还是编码还是调用工具，再进行任务的分发，如果是思考和编码任务将会进行循环调用，直到最终使用工具写入或修改文件。但是实践下来发现免费的小模型不足以很好的完成任务的分发，再加上整个 Agnet 的设计存在缺陷，导致并不能很好的驱动<code>Claude Code</code>。
直到 5 月底，<code>Claude Code</code>被正式推出，这时<code>DeepSeek</code>全系列模型(R1 于 05-28)均支持<code>Function Call</code>，我开始重新设计该项目。在与 AI 的结对编程中我修复了之前的请求和响应转换问题，在某些场景下模型输出 JSON 响应而不是<code>Function Call</code>。这次直接使用<code>DeepSeek-v3</code>模型，它工作的比我想象中要好：能完成绝大多数工具调用，还支持用步骤规划解决任务，最关键的是<code>DeepSeek</code>的价格不到<code>claude Sonnet 3.5</code>的十分之一。正式发布的<code>Claude Code</code>对 Agent 的组织也不同于测试版，于是在分析了<code>Claude Code</code>的请求调用之后，我重新组织了<code>Router</code>模式：现在它还是四个模型：默认模型、<code>background</code>、<code>think</code>和<code>longContext</code>。</p>
<ul>
<li class="">
<p>默认模型作为最终的兜底和日常处理</p>
</li>
<li class="">
<p><code>background</code>是用来处理一些后台任务，据 Anthropic 官方说主要用<code>Claude Haiku 3.5</code>模型去处理一些小任务，如俳句生成和对话摘要，于是我将其路由到了本地的<code>ollama</code>服务。</p>
</li>
<li class="">
<p><code>think</code>模型用于让<code>Claude Code</code>进行思考或者在<code>Plan Mode</code>下使用，这里我使用的是<code>DeepSeek-R1</code>，由于其不支持推理成本控制，所以<code>Think</code>和<code>UltraThink</code>是一样的逻辑。</p>
</li>
<li class="">
<p><code>longContext</code>是用于处理长下上文的场景，该项目会对每次请求使用tiktoken实时计算上下文长度，如果上下文大于32K则使用该模型，旨在弥补<code>DeepSeek</code>在长上下文处理不佳的情况。</p>
</li>
</ul>
<p>以上就是该项目的发展历程以及我的一些思考，通过巧妙的使用环境变量覆盖的手段在不修改<code>Claude Code</code>源码的情况下完成请求的转发和修改，这就使得在可以得到 Anthropic 更新的同时使用自己的模型，自定义自己的提示词。该项目只是在 Anthropic 封禁中国区用户的情况下使用<code>Claude Code</code>并且达到成本和性能平衡的一种手段。如果可以的话，还是官方的Max Plan体验最好。</p>]]></content>
        <category label="claude-code" term="claude-code"/>
        <category label="逆向工程" term="逆向工程"/>
        <category label="教程" term="教程"/>
    </entry>
</feed>