ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

Agent模型调参指南——从硬编码到自动路由 附claude code的做法

Agent模型调参指南——从硬编码到自动路由 附claude code的做法 1. 从硬编码到自动路由Agent 模型调参的真实痛点Agent 模型调参这件事很多人第一反应是「把 temperature 设成 0.7 不就行了」。我一开始也这么干直到线上 Agent 在代码生成任务里偶尔冒出一行语法正确但逻辑完全跑偏的代码排查半天才发现是采样参数在作祟。Agent 模型调参的核心是让不同阶段、不同子任务匹配到合适的模型与参数组合而不是一套参数打天下。自动路由则是把这套匹配逻辑从开发者脑子里搬进 Agent 运行时让它按任务阶段自己切换。这篇文章面向正在写 Agent 流程的开发者尤其是用 Java、Python 或 TypeScript 手写过 AgentLoop 的人。你会看到四种调参方式从粗糙到精细的演进路径拿到可复制的路由配置片段以及一张能直接对照的参数表。Claude Code 的实践会作为参照系出现但重点始终落在「你自己的 Agent 怎么落地」。先说清楚一个概念模型调参不等于只调 temperature。采样控制组temperature、topP、frequencyPenalty、presencePenalty、输出边界组maxCompletionTokens、stop、推理控制组reasoningEffort、returnThinking三组参数共同决定输出形态。硬编码的问题在于它把这三组参数冻结成常量而 Agent 的任务类型是动态变化的。我见过太多 Demo 项目卡在方式一所有请求共用temperature0.7, maxTokens4096。写代码和头脑风暴用同一套参数两种任务都达不到最佳效果。更隐蔽的坑是工具调用场景——高温采样会让结构化输出的字段名发生漂移下游解析直接报错。所以调参的第一步是承认「一套参数走天下」在 Agent 里行不通。自动路由要解决的问题更具体Agent 在一次完整任务里会经历规划、执行、审查等多个阶段每个阶段对模型能力的需求不同。规划阶段需要强推理、低随机性执行阶段需要高吞吐、稳定输出审查阶段需要中等严谨度。如果全程用同一个模型同一套参数要么贵得离谱要么质量不稳。自动路由就是让 Agent 在阶段切换时自动换模型、换参数用户无感知。下面从最粗糙的硬编码开始一步步走到自动路由每一层都给可运行的代码和配置。2. TaoToken 前置准备Base URL、API Key 与 Model ID 三件套在写路由逻辑之前得先把模型调用通道打通。我用 TaoToken 作为统一入口原因是它把多家模型的调用协议收敛成一套 OpenAI 兼容接口路由切换时不用改底层 SDK。你需要准备三样东西Base URL、API Key、Model ID。这三件套在任何路由配置里都会反复出现先记牢。Base URL 是https://taotoken.net/api注意这个地址不带任何查询参数直接作为 OpenAI 客户端的 base_url 使用。API Key 在控制台的 API Keys 页面创建格式是一串以sk-开头的字符串。Model ID 则取决于你要路由到哪些模型比如claude-sonnet-4-20250514、gpt-4o、deepseek-chat这类标识符。创建 Key 的入口在 TaoToken API Keys登录后点「新建密钥」复制出来存到环境变量里。不要硬编码进代码后面路由配置会从环境变量读取。export TAOTOKEN_API_KEYsk-你的密钥 export TAOTOKEN_BASE_URLhttps://taotoken.net/api验证通道是否打通用一条 curl 请求即可。注意model字段填你实际要用的 Model IDmessages里给一句简单指令。curl -s $TAOTOKEN_BASE_URL/v1/chat/completions \ -H Authorization: Bearer $TAOTOKEN_API_KEY \ -H Content-Type: application/json \ -d { model: claude-sonnet-4-20250514, messages: [{role: user, content: 回复 OK 两个字母}], temperature: 0.1, max_tokens: 16 }如果返回体里choices[0].message.content是OK说明三件套配置正确。这一步看起来简单但后面所有路由逻辑都建立在这个通道之上通道不通路由配置写得再漂亮也没用。关于 Model ID 的获取可以在 TaoToken 模型对话 页面直接试跑确认某个模型可用后再写进路由表。我习惯先在对话页把候选模型都跑一遍记录下每个模型的实际响应速度和输出风格再决定路由策略里谁负责规划、谁负责执行。还有一个细节TaoToken 的接口兼容 OpenAI 的chat/completions路径所以任何支持自定义 base_url 的 OpenAI SDK 都能直接指向它。Java 用 OkHttp 手写请求也行Python 用openai库也行TypeScript 用openainpm 包也行。路由逻辑本身与语言无关关键是三件套要能从配置里读出来。3. 可复制的路由配置从任务映射到自动路由的 JSON 片段这一节给可直接复制的配置片段。我按四种调参方式递进每种都给一份配置你可以根据项目阶段选用。配置文件统一放在项目根目录的agent-routing.json运行时读取。方式一全局硬编码。这是起点也是反面教材。所有请求共用一套参数配置里只有一个default块。{ mode: hardcoded, default: { base_url: https://taotoken.net/api, api_key_env: TAOTOKEN_API_KEY, model: claude-sonnet-4-20250514, temperature: 0.7, max_tokens: 4096 } }方式二按任务类型映射。这是大部分生产项目该用的方式。配置里维护一张任务类型到参数的映射表Agent 判断当前任务类型后查表。{ mode: task_mapping, base_url: https://taotoken.net/api, api_key_env: TAOTOKEN_API_KEY, task_types: { code_generation: { model: claude-sonnet-4-20250514, temperature: 0.1, max_tokens: 8192, stop: [\n用户:, \nUser:] }, code_review: { model: claude-sonnet-4-20250514, temperature: 0.3, max_tokens: 4096 }, brainstorm: { model: gpt-4o, temperature: 0.9, max_tokens: 2048 }, math_reasoning: { model: deepseek-reasoner, temperature: 0, reasoning_effort: high } } }方式三Effort Level 快捷。用户不直接设 temperature而是设思维深度框架内部翻译成具体参数组合。配置里定义 effort 等级到参数的映射。{ mode: effort_level, base_url: https://taotoken.net/api, api_key_env: TAOTOKEN_API_KEY, effort_levels: { low: { model: claude-haiku-4-20250514, temperature: 0.2, max_tokens: 1024, reasoning_effort: low }, high: { model: claude-sonnet-4-20250514, temperature: 0.3, max_tokens: 8192, reasoning_effort: medium }, max: { model: claude-opus-4-20250514, temperature: 0.1, max_tokens: 16384, reasoning_effort: high } } }方式四自动路由。Agent 内部判断当前处于什么阶段自动切换模型和参数。配置里定义阶段到参数的映射以及阶段切换的触发条件。{ mode: auto_route, base_url: https://taotoken.net/api, api_key_env: TAOTOKEN_API_KEY, stages: { planning: { model: claude-opus-4-20250514, temperature: 0.1, max_tokens: 8192, reasoning_effort: high, trigger: task_start }, execution: { model: claude-sonnet-4-20250514, temperature: 0.2, max_tokens: 16384, trigger: plan_approved }, review: { model: claude-sonnet-4-20250514, temperature: 0.3, max_tokens: 4096, trigger: execution_done }, quick_lookup: { model: claude-haiku-4-20250514, temperature: 0.1, max_tokens: 1024, trigger: file_search } }, sub_agents: { code_explorer: { model: claude-haiku-4-20250514, temperature: 0.1, max_tokens: 2048 }, architect: { model: claude-opus-4-20250514, temperature: 0.1, max_tokens: 8192, reasoning_effort: high } } }这份自动路由配置里stages定义主流程的阶段切换sub_agents定义子 Agent 的独立模型分配。注意每个块都写全了 Base URL、API Key 环境变量、Model ID 三件套这是路由能跑通的前提。如果你用 Claude Code 或 Cline 这类工具配置文件的路径和字段名会不同。Claude Code 的 settings 文件里模型配置走model字段Effort Level 走/effort命令。Cline 的 MCP 配置里模型走apiProvider和modelId。但底层逻辑一致都是把三件套和参数组合绑定到某个任务或阶段上。配置写完后运行时读取逻辑大致是这样Agent 在每次发起模型请求前先确定当前阶段或任务类型从配置里查出对应的参数块再用这些参数构造请求。阶段切换的触发条件可以是显式的事件如plan_approved也可以是隐式的判断如检测到工具调用返回了文件搜索结果。4. 验证自动路由生效请求日志与参数对照表配置写完不等于路由生效。你需要一套验证动作确认 Agent 在阶段切换时真的换了模型和参数。我常用的方法是打开请求日志在每次模型调用时打印出实际使用的 model、temperature、max_tokens然后跑一个多阶段任务看日志里的参数是否按预期变化。先给一个最小可运行的验证脚本用 Python 写读取上面的agent-routing.json模拟三个阶段各发一次请求打印实际参数。import json import os from openai import OpenAI with open(agent-routing.json) as f: config json.load(f) client OpenAI( base_urlconfig[base_url], api_keyos.environ[config[api_key_env]] ) def call_stage(stage_name): stage config[stages][stage_name] print(f[stage{stage_name}] model{stage[model]} temp{stage[temperature]} max_tokens{stage[max_tokens]}) resp client.chat.completions.create( modelstage[model], messages[{role: user, content: f当前阶段是 {stage_name}回复收到}], temperaturestage[temperature], max_tokensstage[max_tokens] ) print(f - {resp.choices[0].message.content}) for s in [planning, execution, review]: call_stage(s)跑完后日志里应该看到三次调用分别用了 Opus、Sonnet、Sonnettemperature 从 0.1 变到 0.2 再变到 0.3。如果三次都是同一个模型同一个温度说明路由没生效回去检查配置读取逻辑。下面这张对照表是我实测下来各场景的推荐参数可以直接抄进你的路由配置。任务类型推荐模型档位temperaturemax_tokens关键参数代码生成Sonnet0.18192stop 序列防替用户说话代码审查Sonnet0.34096允许不同表达架构规划Opus0.18192reasoning_efforthigh文件搜索Haiku0.11024低延迟优先头脑风暴GPT-4o0.92048高多样性数学推理DeepSeek-R108192reasoning_efforthigh翻译摘要Sonnet0.34096忠实原文日常对话Sonnet0.72048自然但不离谱验证自动路由还有一个关键动作在阶段切换点打日志。比如规划阶段结束、执行阶段开始时打印一行route_switch: planning - execution同时打印切换前后的 model 和 temperature。这样出问题时能快速定位是切换逻辑没触发还是切换后参数没更新。我踩过的坑是配置里写了sub_agents但主流程没调用子 Agent 的配置读取函数导致子 Agent 实际用的还是主流程的模型。排查方法是在子 Agent 的请求构造处加一行日志确认它读的是sub_agents.code_explorer而不是stages.execution。如果你用 Claude Code验证方式更直接在会话里输入/effort high然后看后续请求的模型是否切到 Sonnet 或 Opus。Claude Code 的 opusplan 模式会在规划阶段自动用 Opus执行阶段自动切 Sonnet你可以在终端日志里看到模型切换的记录。5. 常见报错排查401、local proxy failed、reading choices、OAuth路由配置跑起来后最常见的四类报错我都遇到过逐个说排查路径。第一类401 Unauthorized。报错信息通常是{error:{message:Invalid API key,type:invalid_request_error}}。原因无非三个API Key 没设进环境变量、Key 复制时带了空格、Key 被撤销了。排查动作是先echo $TAOTOKEN_API_KEY确认环境变量有值再用 curl 直接打一次接口排除代码读取配置的问题。如果 curl 也 401去 TaoToken API Keys 页面确认 Key 状态。第二类local proxy failed。这个报错通常出现在你本地配了 HTTP 代理但代理进程没起来或端口不对。报错信息类似Error: connect ECONNREFUSED 127.0.0.1:7890。排查动作是检查环境变量HTTP_PROXY和HTTPS_PROXY是否指向了一个不存在的端口。如果你不需要代理直接unset HTTP_PROXY HTTPS_PROXY再跑。注意 TaoToken 的接口是直连的不需要额外代理配置。第三类reading choices 报错。完整报错是Cannot read properties of undefined (reading choices)意思是响应体里没有choices字段。原因通常是请求根本没成功返回的是错误对象但代码直接去读resp.choices[0]。排查动作是在读取choices之前先打印完整响应体看error字段说了什么。常见触发场景是 Model ID 写错了比如把claude-sonnet-4-20250514写成了claude-sonnet-4接口返回模型不存在。第四类OAuth 相关报错。如果你用 Claude Code 或 Codex 这类工具可能会遇到OAuth token expired或refresh token failed。这类报错跟 TaoToken 的 API Key 无关是工具自身的登录态过期。排查动作是重新走一遍工具的登录流程。如果你在 Claude Code 里配置了自定义 Base URL 指向 TaoToken注意 OAuth 和 API Key 是两套认证不要混用。下面给一个排查用的请求日志模板把关键信息都打出来出问题时一眼能定位。import json import os from openai import OpenAI client OpenAI( base_urlhttps://taotoken.net/api, api_keyos.environ[TAOTOKEN_API_KEY] ) try: resp client.chat.completions.create( modelclaude-sonnet-4-20250514, messages[{role: user, content: ping}], temperature0.1, max_tokens16 ) print(status: ok) print(model:, resp.model) print(content:, resp.choices[0].message.content) except Exception as e: print(status: error) print(error_type:, type(e).__name__) print(error_msg:, str(e))这个模板跑通后再把 model 换成你路由配置里的各个 Model ID逐个验证。全部通过后路由配置的通道层就没问题了。还有一个隐蔽的坑max_tokens设得太小导致输出被截断但接口不报错只是finish_reason是length。排查动作是检查resp.choices[0].finish_reason如果是length说明需要调大max_tokens。在自动路由配置里规划阶段和执行阶段的max_tokens要分开设执行阶段通常需要更大的值。6. 把路由策略落到你的 Agent 流程里走到这里你已经有了可复制的配置片段、验证脚本和排错清单。最后一步是把这些落到你自己的 Agent 流程里。我的建议是从方式二按任务类型映射开始不要一上来就搞自动路由。方式二的配置改动最小收益最直接能甩开大部分 Demo 项目。具体落地路径先在 Agent 的任务分发处加一个task_type判断把当前请求归类到code_generation、code_review、brainstorm等类型然后从agent-routing.json的task_types里查出对应参数最后用这些参数构造模型请求。整个过程不需要改 Agent 的主循环逻辑只在请求构造处加一层查表。等你对任务类型的判断稳定了再往方式三Effort Level迁移。方式三的好处是用户接口更友好用户说「这个任务多想一点」比说「temperature 设 0.3」更自然。迁移时把task_types的映射关系重新组织成effort_levels内部翻译逻辑不变。方式四自动路由适合多阶段 Agent。如果你的 Agent 有明确的规划、执行、审查阶段且阶段切换有明确的事件触发就可以上自动路由。配置里的stages和sub_agents分别管主流程和子 Agent两者可以独立配置。Claude Code 的 opusplan 是自动路由的一个好参照规划阶段用 Opus 做深度推理执行阶段切 Sonnet 做高效编码用户批准计划后自动切换全程无感知。你的 Agent 不一定要用 Opus 和 Sonnet但「按阶段选模型」这个思路可以直接搬。如果你在找长期编码场景的模型调用方案可以看看 TaoToken Coding Plan它把常用编码模型的调用额度打包适合 Agent 这种高频调用的场景。接入文档在 TaoToken 文档里面有各语言 SDK 的配置示例。最后给一个实用技巧在路由配置里加一个fallback块当主模型调用失败时自动降级到备用模型。比如规划阶段 Opus 超时自动切 Sonnet 继续。这个降级逻辑不需要复杂在请求构造处加一层 try-catch 即可。{ fallback: { model: claude-sonnet-4-20250514, temperature: 0.2, max_tokens: 8192 } }路由策略不是一次配好就完事随着 Agent 任务类型变化映射表需要持续调整。我的做法是每周看一次请求日志统计各任务类型的实际输出质量质量不达标的就调参数或换模型。调参这件事数据比直觉可靠。
RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进