DevAssistant Pro 接入 Claude/OpenAI 双模型,Base URL 填 TaoToken
2026/9/19 14:12:50 网站建设 项目流程

从 DevAssistant Pro 的双模型接入说起:一个 Agent 应用为什么要统一 Base URL

在《第13章-从零构建-企业级Agent应用完整实战》的 Day 1-18 交付主线里,13.1.4 技术选型把 LLM 接入定为 Claude API + OpenAI API,13.2.4 的packages/agent-core/src/llm/provider.tsrouter.ts负责模型调用。真正动手时你会发现一个很现实的问题:一个 Agent 应用要同时管理两家模型的 Key、两套入口、两套计费口径,provider.ts里到处是分支判断,router.ts的路由表越写越长。这篇就把原文“申请/填入模型 Key”这一步改写成先打开 https://taotoken.net/?utm_source=taotoken_aicg_blog_end 注册并创建 Key,回到provider.ts/router.ts时把模型供应商的 Base URL 填https://taotoken.net/api,让 Claude 与 OpenAI 走同一个入口。需要先说清楚:TaoToken 只提供 Key 与 Base URL,不替代 DevAssistant Pro 的 Agent/Harness/RAG 逻辑,你的上下文管理器、工具执行器、Token 用量表该怎么写还怎么写。

一、原问题与场景:双模型接入的 Key 与入口之痛

原文 13.2.4 的provider.ts大致是这样的结构:一个createLLMProvider(model)工厂,根据模型名判断走 Anthropic SDK 还是 OpenAI SDK。问题在于:

  • Key 管理分散ANTHROPIC_API_KEYOPENAI_API_KEY两套环境变量,团队里谁用哪个模型就得配哪套 Key,新人 onboarding 经常卡在这一步。
  • 入口不统一:Anthropic 的 base 是https://api.anthropic.com,OpenAI 的 base 是https://api.openai.com/v1router.ts里要维护两张映射表。
  • 切换成本高:想在claude-sonnet-4-6gpt-4o之间做 A/B,或者按任务类型路由(代码生成走 Claude、推理走 OpenAI),每次都要改 provider 分支。
  • 用量统计割裂:13.2.1 的token_usage表要按模型分别统计,但两家返回的 usage 字段结构不同,estimatedCost很难对齐。

场景很具体:你在 Day 1-5 搭完基础设施,Day 6-10 开始接 Harness 组件,agent.tsthis.llm.chat({ messages, tools, temperature })这一行要能同时喂给 Claude 和 OpenAI。如果 provider 层不收敛,后面 13.3 的上下文管理器、工具执行器、安全护栏都会被拖累。

二、TaoToken 前置:注册、创建 Key、拿到 Base URL

这一步替代原文的“申请/填入模型 Key”。流程很短:

  1. 打开 https://taotoken.net/?utm_source=taotoken_aicg_blog_end 注册账号。
  2. 进入控制台创建 API Key,得到形如YOUR_API_KEY的凭证。
  3. 记下 Base URL:https://taotoken.net/api。注意这里不带/v1,也不加 UTM 参数,直接就是这一串。
  4. 如果你要核对 Key 状态或看接入文档,走这两个入口:
    • API Keys 管理:https://taotoken.net/console/api-keys?utm_source=taotoken_aicg_blog_end&utm_content=api_keys&utm_campaign=rewrite
    • 接入文档:https://taotoken.net/doc?utm_source=taotoken_aicg_blog_end&utm_content=doc&utm_campaign=rewrite

拿到 Key 和 Base URL 后,回到 DevAssistant Pro 的packages/agent-core/src/llm/目录。TaoToken 在这里的角色是“统一入口”:Claude 和 OpenAI 的请求都发往https://taotoken.net/api,由它按模型 ID 转发。你的provider.ts不再需要维护两套 base URL,router.ts也不再需要两套 SDK 初始化逻辑。

三、可复制配置:改造 provider.ts 与 router.ts

先看环境变量。在项目根目录的.env(或docker-compose.yml的 environment 段)里加:

TAOTOKEN_API_KEY=YOUR_API_KEY TAOTOKEN_BASE_URL=https://taotoken.net/api

然后是packages/agent-core/src/llm/provider.ts的改造。原文的createLLMProvider可以收敛成一个统一的 OpenAI 兼容客户端,因为 TaoToken 的入口对 Claude 和 OpenAI 都提供 OpenAI 兼容的 chat 接口:

// packages/agent-core/src/llm/provider.ts import OpenAI from "openai"; export interface LLMProvider { chat(params: { messages: Message[]; tools?: ToolDefinition[]; temperature?: number; model?: string; }): Promise<LLMResponse>; } export function createLLMProvider(defaultModel: string): LLMProvider { const client = new OpenAI({ apiKey: process.env.TAOTOKEN_API_KEY!, baseURL: process.env.TAOTOKEN_BASE_URL || "https://taotoken.net/api", }); return { async chat({ messages, tools, temperature = 0.3, model }) { const response = await client.chat.completions.create({ model: model || defaultModel, messages, tools: tools?.length ? tools : undefined, temperature, }); const choice = response.choices[0]; return { content: choice.message.content || "", toolCalls: choice.message.tool_calls?.map((tc) => ({ id: tc.id, name: tc.function.name, parameters: JSON.parse(tc.function.arguments), })), tokensUsed: response.usage?.total_tokens || 0, }; }, }; }

再看router.ts。原文的 router 负责按任务类型选模型,改造后只需要维护一张“任务类型 → 模型 ID”的表,不再关心供应商:

// packages/agent-core/src/llm/router.ts export type TaskType = "code_write" | "code_review" | "reasoning" | "doc_write"; const MODEL_ROUTING: Record<TaskType, string> = { code_write: "claude-sonnet-4-6", code_review: "claude-sonnet-4-6", reasoning: "gpt-4o", doc_write: "gpt-4o-mini", }; export function routeModel(taskType: TaskType): string { return MODEL_ROUTING[taskType] || "claude-sonnet-4-6"; }

这样agent.ts里的调用完全不用改,this.llm.chat({ messages, tools, temperature })照旧,只是底层入口从两家变成了https://taotoken.net/api一家。13.2.1 的token_usage表也不用改结构,model字段照填,inputTokens/outputTokens从统一的usage字段取。

如果你在本地想先用 CLI 快速验证 Key 是否可用,可以装一下:

npm i -g @taotoken/taotoken taotoken cc -k YOUR_API_KEY -u https://taotoken.net/api -m claude-sonnet-4-6

这条命令只是验证通道,不替代你项目里的 provider 实现。

四、验证请求:先跑通双模型 chat,再接 Harness

配置改完后,别急着接 13.3 的上下文管理器和工具执行器。先写一个最小验证脚本,确认 Claude 和 OpenAI 两个模型都能通过同一个 Base URL 返回:

// scripts/verify-llm.ts import { createLLMProvider } from "../packages/agent-core/src/llm/provider"; async function main() { const provider = createLLMProvider("claude-sonnet-4-6"); const claudeResp = await provider.chat({ messages: [{ role: "user", content: "用一句话说明什么是 ReAct 循环" }], model: "claude-sonnet-4-6", }); console.log("[Claude]", claudeResp.content, "tokens:", claudeResp.tokensUsed); const openaiResp = await provider.chat({ messages: [{ role: "user", content: "用一句话说明什么是 ReAct 循环" }], model: "gpt-4o", }); console.log("[OpenAI]", openaiResp.content, "tokens:", openaiResp.tokensUsed); } main().catch(console.error);

成功的结果是:两个请求都返回非空contenttokensUsed都有数值,控制台没有 401/404/429。如果 Claude 和 OpenAI 都通了,说明provider.ts的 Base URL 和 Key 配置正确,可以继续按原文接 13.3.1 的ContextManager、13.3.2 的ToolExecutor、13.3.3 的ReasoningController。工具调用这块要特别注意:tools参数传进去后,返回的toolCalls结构要能被ToolExecutor.execute消费,字段名对齐id/name/parameters

验证通过后,13.2.1 的token_usage表可以正常写入,13.4.3 的可观测性平台也能从统一的usage字段采集 Token 指标。整个链路是:agent.tsreasoning.tsprovider.tshttps://taotoken.net/api→ 模型。

五、本篇常见错排查

错误 1:Base URL 多写了/v1这是最常见的。https://taotoken.net/api就是完整入口,不要写成https://taotoken.net/api/v1,否则会 404。OpenAI SDK 的baseURL字段本身会拼/chat/completions,你只需要给到/api

错误 2:Key 没生效,报 401。检查.envTAOTOKEN_API_KEY是否真的被加载。Node.js 项目里process.env不会自动读.env,需要dotenv或在docker-compose.yml里显式声明。另外确认 Key 没有多余空格或换行。

错误 3:provider.ts里还留着旧的 Anthropic SDK 分支。改造后应该只保留一个 OpenAI 兼容客户端。如果router.ts还在import Anthropic from "@anthropic-ai/sdk",说明改造没完成,会出现两套 base URL 并存。

错误 4:工具调用返回的parameters解析失败。有些模型返回的function.arguments是空字符串或非 JSON,JSON.parse会抛异常。在provider.ts里加一层 try/catch,解析失败时返回空对象,让ToolExecutor去处理。

错误 5:模型 ID 写错。claude-sonnet-4-6gpt-4ogpt-4o-mini这些 ID 要和你实际可用的模型对齐。如果报“model not found”,先去模型对话页确认可用模型列表:https://taotoken.net/chat?utm_source=taotoken_aicg_blog_end&utm_content=model_chat&utm_campaign=rewrite

错误 6:CORS 或网络问题。如果你在浏览器端直接调,注意apps/api/src/app.ts里的 CORS 配置。服务端调用不受影响,但前端直连要确认origin白名单。

六、语义一致:Key 与 Base URL 之外,Agent 逻辑仍归你

回到原文的主线。TaoToken 在这条链路里只做两件事:提供 Key、提供 Base URL。DevAssistant Pro 的 Agent 运行时(agent.ts)、Harness 组件(context.ts/tools.ts/safety.ts/reasoning.ts/memory.ts)、RAG 系统(13.4.1)、Multi-Agent 编排(13.4.2)、可观测性平台(13.4.3)全部由你自己实现和维护。provider.tsrouter.ts的改造只是把“两家模型的 Key 与入口”收敛成“一个入口 + 一张路由表”,让 13.3 之后的组件不用关心底层供应商差异。

如果你在接入过程中遇到 Key 或 Base URL 的问题,走 API Keys 管理页和接入文档:

  • API Keys:https://taotoken.net/console/api-keys?utm_source=taotoken_aicg_blog_end&utm_content=api_keys&utm_campaign=rewrite
  • 接入文档:https://taotoken.net/doc?utm_source=taotoken_aicg_blog_end&utm_content=doc&utm_campaign=rewrite

如果你准备长期跑 Agent 编码任务,比如让 DevAssistant Pro 持续做代码生成、审查、测试生成,可以看 Coding Plan:https://taotoken.net/coding-plan?utm_source=taotoken_aicg_blog_end&utm_content=coding_plan&utm_campaign=rewrite

验证模型是否可用,直接去模型对话页试一条请求:https://taotoken.net/chat?utm_source=taotoken_aicg_blog_end&utm_content=model_chat&utm_campaign=rewrite

下一步就是原文第14章的生产部署。在那之前,确保你的provider.ts只认https://taotoken.net/api这一个 Base URL,router.ts只维护一张模型路由表,token_usage表能正常写入。这三件事做完,Day 1-18 的交付主线就不会在 LLM 接入这一环卡住。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询