新闻详情

新闻详情

首页 / 资讯中心 / 详情

找不到实习的我参考Claude Code做了一个Code Agent:TaoToken统一Key接入MCP与SubAgent

发布时间:2026/10/1 15:11:47来源:尧图网络
找不到实习的我参考Claude Code做了一个Code Agent:TaoToken统一Key接入MCP与SubAgent
1. 从零手搓 Code Agent为什么我卡在模型接入这一步找不到实习的那段时间我几乎把 Claude Code 的交互逻辑翻了个遍。它最吸引我的不是补全速度而是那种「先想再做、做完再看」的循环读文件、跑命令、看报错、改代码像有个耐心的搭档坐在终端里。于是我决定用 Python 复刻一个自己的 Code Agent名字叫 OneCode目标很朴素——能在终端里对话能调工具能把复杂任务拆给子智能体。真正动手才发现Agent 循环本身不难写难的是「模型从哪来」。Claude Code 背后是 Anthropic 的接口Codex 背后是 OpenAI 的接口而我本地想同时试 DeepSeek、Claude、GPT 几个模型就得维护三套 Key、三套 Base URL、三套鉴权头。每换一个模型代码里if provider ...的分支就多一层调试时经常是「工具调用格式不对」还是「Key 没配对」都分不清。后来我把模型接入层单独抽出来统一走一个兼容 OpenAI 协议的中转入口Key 只配一次模型 ID 按需切换。这样 Agent 核心逻辑不用动MCP 工具和 SubAgent 委托也能复用同一套请求封装。这篇文章就把这条路径完整写出来Python 底座怎么搭、MCP 怎么接、SubAgent 怎么拆任务以及本地跑通一次多步代码任务时该看哪些日志检查点。如果你也在做类似的小项目或者单纯想搞懂 Claude Code 那套 Agent 循环到底怎么落地下面的步骤可以跟着敲一遍。核心检索词就三个Code Agent、MCP、SubAgent全文围绕它们展开。2. TaoToken 统一 Key 前置准备一次配置多模型切换在写 Agent 循环之前先把模型接入这层理顺。我的做法是找一个兼容 OpenAI Chat Completions 协议的统一入口TaoToken 就是我在用的那个。它的价值在于你只需要一个 API Key 和一个 Base URL就能在 DeepSeek、Claude、GPT 这些模型之间切换不用为每个厂商单独写鉴权逻辑。先注册并拿到 Key。打开官网 https://taotoken.net/?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content 登录后在控制台里创建 API Key。这个 Key 就是你后面所有请求的凭证格式通常是一串sk-开头的字符串。创建完先复制到安全的地方页面刷新后不一定还能看到完整值。拿到 Key 之后记下两个地址Base URLhttps://taotoken.net/api注意这个不带任何查询参数就是纯接口根路径API Key你刚创建的那串模型 ID 这块不同模型名字不一样。比如 DeepSeek 系列常用deepseek-chatClaude 系列用claude-sonnet-4-20250514这类GPT 系列用gpt-4o这类。具体以控制台里模型列表显示的为准别硬背。我踩过的坑是把模型 ID 写成了展示名结果请求返回 404排查了半天才发现是名字对不上。为什么要在 Agent 项目里做这层统一因为 Code Agent 的请求封装通常长这样一个chat()函数接收 messages 和 tools返回模型输出。如果每个 provider 都写一套工具调用的 JSON 结构、流式返回的字段名都会有差异。统一走 OpenAI 兼容协议后tools参数、tool_calls字段、finish_reason这些都是一致的Agent 循环里只需要处理一种格式。这里给一个最小验证确认你的 Key 和 Base URL 是通的。用 curl 发一条最简单的请求curl https://taotoken.net/api/v1/chat/completions \ -H Content-Type: application/json \ -H Authorization: Bearer sk-你的Key \ -d { model: deepseek-chat, messages: [{role: user, content: 回复两个字收到}] }如果返回的 JSON 里choices[0].message.content是「收到」说明接入层没问题。这一步别跳过后面 Agent 报错时你才能确定是循环逻辑的问题还是接入的问题。注意Base URL 写https://taotoken.net/api就行代码里拼接/v1/chat/completions。有些 SDK 会自动补/v1有些不会建议先手动拼一次确认路径。3. 可复制配置Python 项目里的 settings 与 MCP 接入片段接入层验证通过后把它固化到项目配置里。我习惯用一个config.toml加一个settings.py的组合前者放敏感信息和模型参数后者做读取和默认值处理。这样换模型只改 TOML不动代码。先建目录结构参考 Claude Code 的分层思路onecode/ ├── config.toml ├── settings.py ├── core/ │ └── agent_loop.py ├── tools/ │ └── registry.py ├── mcp/ │ └── client.py └── subagent/ └── delegate.pyconfig.toml内容如下路径和字段名你可以直接抄[llm] base_url https://taotoken.net/api api_key sk-你的Key model deepseek-chat timeout 60 [mcp] enabled true servers [ { name filesystem, command npx, args [-y, modelcontextprotocol/server-filesystem, ./workspace] } ] [subagent] max_parallel 3 model claude-sonnet-4-20250514settings.py负责读取并暴露给上层import tomllib from pathlib import Path class Settings: def __init__(self, path: str config.toml): with open(path, rb) as f: data tomllib.load(f) self.base_url data[llm][base_url] self.api_key data[llm][api_key] self.model data[llm][model] self.timeout data[llm].get(timeout, 60) self.mcp_servers data.get(mcp, {}).get(servers, []) self.subagent_model data.get(subagent, {}).get(model, self.model) self.max_parallel data.get(subagent, {}).get(max_parallel, 3) settings Settings()MCP 接入这块核心是把外部工具的描述转成 OpenAI 的tools格式。MCP 服务器启动后会返回一个工具列表每个工具有 name、description、inputSchema。你只需要把它映射成def mcp_tool_to_openai(tool): return { type: function, function: { name: tool[name], description: tool[description], parameters: tool[inputSchema] } }然后在 Agent 循环里把本地工具和 MCP 工具合并成一个列表传给模型。模型返回tool_calls时根据 name 判断是本地执行还是转发给 MCP 客户端。这里的关键是MCP 工具的调用结果要原样塞回 messagesrole 用tool并带上tool_call_id否则模型下一轮会不知道哪个结果对应哪个调用。SubAgent 的配置单独说。它的本质是「用另一个模型实例跑一个独立的 Agent 循环」所以需要单独的 model 和并发上限。我在config.toml里把 subagent 的 model 设成 Claude主 Agent 用 DeepSeek这样规划类子任务和主循环可以走不同模型成本和效果都能兼顾。提示MCP 服务器的 command 和 args 要写对。npx -y是自动确认安装第一次跑会下载包网络慢的话耐心等。如果报command not found检查 Node.js 是否装了。4. 验证请求与成功结果跑通一次多步代码任务配置就绪后写一个最小的 Agent 循环来验证。核心逻辑是 ReAct模型输出思考或工具调用执行工具把结果回填再请求模型直到模型给出最终回答。import json import httpx from settings import settings def chat(messages, toolsNone): payload { model: settings.model, messages: messages, } if tools: payload[tools] tools payload[tool_choice] auto resp httpx.post( f{settings.base_url}/v1/chat/completions, headers{Authorization: fBearer {settings.api_key}}, jsonpayload, timeoutsettings.timeout ) resp.raise_for_status() return resp.json()[choices][0][message] def run_agent(user_input, tools, tool_executor, max_steps8): messages [{role: user, content: user_input}] for step in range(max_steps): msg chat(messages, tools) messages.append(msg) if not msg.get(tool_calls): print(f[最终回答] {msg[content]}) return msg[content] for call in msg[tool_calls]: name call[function][name] args json.loads(call[function][arguments]) print(f[步骤 {step1}] 调用工具 {name} 参数 {args}) result tool_executor(name, args) print(f[步骤 {step1}] 工具返回 {str(result)[:120]}) messages.append({ role: tool, tool_call_id: call[id], content: str(result) }) return None工具执行器先注册两个最基础的读文件和写文件。from pathlib import Path def read_file(path): return Path(path).read_text(encodingutf-8) def write_file(path, content): Path(path).parent.mkdir(parentsTrue, exist_okTrue) Path(path).write_text(content, encodingutf-8) return fwritten {len(content)} chars to {path} TOOLS [ {type: function, function: { name: read_file, description: 读取指定路径的文件内容, parameters: {type: object, properties: { path: {type: string} }, required: [path]} }}, {type: function, function: { name: write_file, description: 把内容写入指定路径, parameters: {type: object, properties: { path: {type: string}, content: {type: string} }, required: [path, content]} }} ] def executor(name, args): if name read_file: return read_file(args[path]) if name write_file: return write_file(args[path], args[content]) return funknown tool {name}跑一个多步任务试试run_agent( 在 workspace 下创建 hello.py内容是一个打印 hello 的函数然后读回来确认, TOOLS, executor )成功时你会看到类似日志[步骤 1] 调用工具 write_file 参数 {path: workspace/hello.py, content: def hello():\n print(hello)\n} [步骤 1] 工具返回 written 38 chars to workspace/hello.py [步骤 2] 调用工具 read_file 参数 {path: workspace/hello.py} [步骤 2] 工具返回 def hello():\n print(hello)\n [最终回答] 已创建并确认 workspace/hello.py这里有几个日志检查点值得盯第一tool_calls的arguments是不是合法 JSON如果模型输出带 markdown 代码块包裹json.loads会炸第二工具返回后 messages 里有没有正确追加tool_call_id漏了的话下一轮模型会重复调用同一个工具第三max_steps有没有触发如果 8 步还没结束说明任务拆得太粗或者工具描述不够清晰。SubAgent 的验证可以在这个基础上加一个delegate工具内部起一个新的run_agent用settings.subagent_model把子任务描述传进去返回最终回答。主 Agent 收到结果后继续。实测下来把「调研某个目录结构并总结」这类任务委托出去主循环的 token 消耗会明显下降。5. 本篇常见错排查401、local proxy failed 与 reading choices接入和循环跑起来之后报错基本集中在几个地方。我把踩过的坑按现象列出来对照着查。401 Unauthorized。最常见的原因是 Key 没带对。检查三处config.toml里的api_key是不是完整复制了有没有多余空格请求头是不是Authorization: Bearer sk-xxxBearer 后面有一个空格Base URL 是不是写成了https://taotoken.net/api/带了尾斜杠有些拼接逻辑会变成//v1。如果 Key 确认没问题还是 401去控制台看下这个 Key 是不是被禁用或者额度用完了。local proxy failed。这个报错通常出现在你本地配了 HTTP 代理但代理进程没起来或者端口不对。httpx 默认会读环境变量HTTP_PROXY和HTTPS_PROXY。如果你不需要代理在代码里显式关掉client httpx.Client(proxyNone, timeout60)或者启动前清掉环境变量。注意别把代理和「网络访问」混为一谈这里只是本地进程配置问题。reading choices 报 KeyError。这个说明返回的 JSON 里没有choices字段。先打印完整响应体看看通常是这几种情况模型 ID 写错了返回的是 error 对象请求体格式不对比如messages不是数组或者触发了内容审核返回了拒绝信息。我的做法是在chat()里加一层判断data resp.json() if choices not in data: raise RuntimeError(funexpected response: {data})这样报错时能直接看到原始返回比KeyError: choices有用得多。OAuth 相关报错。如果你用的是 Claude Code 或者 Codex 的 CLI可能会遇到 OAuth token 过期。这类工具走的是账号授权流程和 API Key 是两套东西。在 OneCode 这种自己写的 Agent 里统一用 API Key 就不会有 OAuth 问题。如果你在 CC Switch 或者 Cline 的 MCP 配置里看到 OAuth 报错检查是不是把 CLI 的登录态和 API Key 混用了。MCP 工具调用返回空。检查 MCP 服务器进程有没有正常启动npx下载的包版本对不对。可以在mcp/client.py里加日志把服务器返回的原始工具列表打出来。如果列表是空的说明服务器启动失败看 stderr 输出。SubAgent 结果丢失。子智能体跑完后主 Agent 收到的应该是文本结果。如果发现主循环卡住检查delegate工具是不是同步等待子循环结束。异步的话要加超时否则子任务卡死会拖垮主循环。注意所有报错排查的第一步都是打印原始响应。别急着改代码逻辑先确认请求和响应长什么样。6. 继续把 Code Agent 做下去从能跑到好用跑通最小循环只是起点。接下来我打算把计划模式补上让 Agent 先输出一个步骤列表我确认后再执行而不是直接动手改文件。这个流程在 Claude Code 里很自然自己实现的话需要在循环里加一个plan状态模型输出计划后暂停等用户输入y再继续。MCP 这块还可以再挖。现在只接了 filesystem后面想接 git 和 shell让 Agent 能自己提交、自己跑测试。SubAgent 的并发调度也值得优化目前是简单的asyncio.gather任务多了要考虑限流和失败重试。如果你也在做类似的项目建议先把接入层和循环跑通别一上来就堆功能。我最初想一口气把记忆、Skill、Task 全做了结果卡在模型返回格式不一致上整整两天。后来把统一 Key 这层抽出来后面所有模块都顺了。代码写到最后真正花时间的不是 Agent 循环本身而是那些边界情况工具参数解析失败怎么办、模型返回空内容怎么办、子任务超时怎么办。这些没有捷径只能一个个踩过去。等你看到终端里 Agent 自己读完文件、写完代码、跑完测试然后告诉你「完成了」那种感觉还是挺值的。
网站建设高端定制企业官网
RELATED

相关资讯

更多精彩内容,欢迎继续阅读

较早相关资讯

最新相关资讯

期货量化策略绩效分析实战:从回测收益到风险指标的深度拆解 2026/10/1 18:18:29

期货量化策略绩效分析实战:从回测收益到风险指标的深度拆解

做量化这几年,我见过太多人跑完回测第一件事就是看总收益率。翻了一倍,开心得不行;亏了20%,立马开始怀疑人生。说句实在话,只盯着收益率的账户,就像只看体重不看体脂率的人——你可能瘦了,但掉的…

阅读更多 →
AI合同审查工具在消费纠纷中的落地配置 2026/10/1 18:18:23

AI合同审查工具在消费纠纷中的落地配置

我无法根据您提供的输入内容生成符合要求的博文。原因如下:输入中缺少关键必要字段:按照您设定的严格输入格式,必须包含:项目标题: [标题]项目正文: [原始描述]关键词: [关键词1, 关键词2, ...]摘要描述: [一句话简介]而当前输入仅…

阅读更多 →
BP神经网络信贷信用评估实战:从预处理到违约概率预测 2026/10/1 18:18:23

BP神经网络信贷信用评估实战:从预处理到违约概率预测

简介:基于BP神经网络的个人信贷信用评估,是一份面向金融风控入门者与机器学习初学者的MATLAB实现方案。资源围绕信用评估场景,利用BP神经网络对个人信贷数据进行分类识别,包含完整可运行的main.m主脚本,以及配套的germ…

阅读更多 →
DMS渠道数据采集分析管理系统选型:从报表工具到数字化管理中枢 2026/10/1 18:18:23

DMS渠道数据采集分析管理系统选型:从报表工具到数字化管理中枢

DMS渠道数据采集、分析、管理系统这行干久了,你会发现一个奇怪的现象:很多企业花了大几百万上DMS,最后用得最频繁的功能却是“查报表”。不是大家不想用,而是大多数DMS服务商只给你一套录入界面和一堆图表,没有真正把渠…

阅读更多 →
拆解敏感肌修护真相:从皮肤屏障重建到避开智商税 2026/10/1 18:18:23

拆解敏感肌修护真相:从皮肤屏障重建到避开智商税

“外油内干、敷片状面膜刺痛、一换季就两颊泛红发烫”——如果你也有这些症状,那你大概率已经被护肤品牌们盯上了,因为敏感肌修护是护肤品里最典型的“情绪税”重灾区。我当了快十年的护肤编辑,自己也是从烂脸期一步步爬过来的,不…

阅读更多 →
电动汽车集群并网调度中的分布式鲁棒优化Matlab实战 2026/10/1 18:18:22

电动汽车集群并网调度中的分布式鲁棒优化Matlab实战

电动汽车集群并网这个方向,近几年不管是发论文还是做工程项目,都是实打实的热点。我自己在Matlab里把这套分布式鲁棒优化调度模型完整跑通了一遍,从建模到求解器配置再到结果分析,踩了不少坑,也积累了一些经验。这篇就…

阅读更多 →

今日资讯

本周资讯

本月资讯

看完文章仍有疑问?

联系尧图顾问,获取一对一建站咨询

立即免费咨询 📞 400-888-8888
📞 ✉