资讯详情

从零开始做一个AI Agent(附录五)Agent 工具注册表详解:用 TaoToken 统一 Key 打通工具调用链路

📅 2026/10/1 6:48:28 | 华诺云谱 👁 阅读
从零开始做一个AI Agent(附录五)Agent 工具注册表详解:用 TaoToken 统一 Key 打通工具调用链路
1. 为什么 Agent 需要一个工具注册表很多人第一次写 AI Agent会把所有能力都塞进主流程里检索写一段、生成写一段、发邮件再写一段。刚开始跑得挺顺等到工具数量涨到五六个主流程文件就会变成一锅粥改一个参数要翻半天加一个新工具还得动核心逻辑。工具注册表Tool Registry就是来解决这个问题的它把「Agent 能调用哪些工具」这件事从主流程里抽出来集中登记每个工具的名字、说明、输入格式和执行函数。你可以把它理解成公司前台的一张通讯录。Agent 不需要知道每个工具内部怎么实现只要按名字去通讯录里查拿到对应的执行入口把参数递进去就行。工具内部是查数据库、调大模型还是读文件Agent 完全不关心。这样一来新增能力就变成「往通讯录里加一条」而不是「重写主流程」。在真实项目里工具注册表通常要解决四件事注册工具怎么登记进来、发现Agent 怎么知道有哪些工具、路由按名字找到对应执行函数、失败重试工具报错后怎么兜底。这四件事做扎实了后面接大模型的 function calling 才有稳定的地基。本文以 Python FastAPI 的 Agent 项目为例把注册表从零搭起来并用 TaoToken 统一管理模型调用的 Key 和 API 通道让工具链路里的模型请求走同一个入口。适合谁看已经写过一个能跑的最小 Agent、准备把能力模块化的开发者或者正在做 RAG 学习助手、客服机器人这类多工具项目的人。下面所有代码都可以直接复制到你的项目里改。2. TaoToken 前置准备统一 Key 与 API 通道工具注册表本身不依赖某个特定平台但工具执行时经常要调大模型比如「生成题目」「总结文档」这类工具内部就是一次 LLM 请求。如果每个工具各自维护一套 Key 和 Base URL配置会散得到处都是换模型时改到崩溃。我的做法是所有模型调用统一走 TaoToken 的 API 通道工具只拿一个环境变量里的 Key。TaoToken 是一个兼容 OpenAI 接口规范的模型调用入口你可以把它当成「一个 Base URL 一个 Key 调多家模型」的网关。对 Agent 项目来说好处是工具里的模型请求不用改代码就能换模型Key 也只在一个地方管理。官网地址是 https://taotoken.net/?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content API 根地址是 https://taotoken.net/api 。先在你的项目根目录建一个.env文件把 Key 和 Base URL 写进去# .env TAOTOKEN_API_KEYsk-你的key TAOTOKEN_BASE_URLhttps://taotoken.net/api TAOTOKEN_MODELclaude-sonnet-4-20250514Key 的获取入口在控制台的 API Keys 页面登录后新建一个即可。注意不要把.env提交到 Git在.gitignore里加一行.env。然后在 Python 侧读取配置。我用pydantic-settings做统一配置管理这样工具和主流程读的是同一份配置# backend/app/core/config.py from pydantic_settings import BaseSettings class Settings(BaseSettings): taotoken_api_key: str taotoken_base_url: str https://taotoken.net/api taotoken_model: str claude-sonnet-4-20250514 class Config: env_file .env settings Settings()这里有个容易踩的坑Base URL 末尾不要多加/v1。TaoToken 的根地址就是https://taotoken.net/apiOpenAI SDK 会自动拼接/chat/completions。如果你手动写成https://taotoken.net/api/v1请求路径会变成/api/v1/chat/completions可能返回 404。实测下来直接用根地址最稳。配置好之后工具里调模型就统一用这个客户端# backend/app/services/llm_client.py from openai import OpenAI from app.core.config import settings client OpenAI( api_keysettings.taotoken_api_key, base_urlsettings.taotoken_base_url, ) def chat(prompt: str, system: str ) - str: messages [] if system: messages.append({role: system, content: system}) messages.append({role: user, content: prompt}) resp client.chat.completions.create( modelsettings.taotoken_model, messagesmessages, ) return resp.choices[0].message.content这样任何工具需要模型能力直接from app.services.llm_client import chat就行Key 和模型名都从配置来。想换模型只改.env一行不用动工具代码。这就是「统一 Key 打通工具调用链路」的实际含义不是每个工具各连各的而是共享一条通道。3. 可复制的工具注册表配置与实现这一节是核心把注册表的数据结构、注册方式、发现接口和路由逻辑全部写出来。你可以按文件路径直接建文件。先定义工具的数据结构。我用dataclass加frozenTrue保证工具定义不可变避免运行时被意外修改# backend/app/services/agent_tools.py from dataclasses import dataclass from typing import Any, Callable ToolRunner Callable[[dict[str, Any]], dict[str, Any]] dataclass(frozenTrue) class AgentTool: name: str description: str input_schema: dict[str, str] run: ToolRunner每个工具至少要有四个字段name是调用时的唯一标识description给模型或前端看input_schema描述参数run是真正执行的函数。接下来实现第一个工具retrieve_course_context从已上传的课程资料里检索相关片段def _retrieve_course_context(args: dict[str, Any]) - dict[str, Any]: query str(args.get(query, )) top_k int(args.get(top_k, 5)) chunks retrieve_chunks(query, top_ktop_k) return { chunks: chunks, observation: fretrieved {len(chunks)} chunk(s), }注意返回里的observation字段它会进入 Agent 的执行步骤记录前端能看到「retrieve_course_context - retrieved 3 chunk(s)」这样的轨迹。这是可观测性的关键别省。然后是注册表本体。用一个模块级字典集中登记TOOLS: dict[str, AgentTool] { retrieve_course_context: AgentTool( nameretrieve_course_context, descriptionRetrieve relevant chunks from uploaded course materials., input_schema{ query: Student or teacher task used as the retrieval query., top_k: Maximum number of chunks to retrieve., }, run_retrieve_course_context, ), }再补两个访问函数供 Agent 主流程和 API 层使用def list_agent_tools() - list[dict[str, Any]]: return [ { name: t.name, description: t.description, input_schema: t.input_schema, } for t in TOOLS.values() ] def get_agent_tool(name: str) - AgentTool: if name not in TOOLS: raise KeyError(ftool not registered: {name}) return TOOLS[name]新增工具时只要往TOOLS里加一条再写一个_xxx执行函数即可。比如后面要加「生成题目」TOOLS[generate_exam_questions] AgentTool( namegenerate_exam_questions, descriptionGenerate exam questions from course materials., input_schema{ topic: Chapter topic., count: Number of questions., }, run_generate_exam_questions, )主流程不用改一行。这就是注册表的价值能力扩展和主流程解耦。如果你用配置文件驱动注册比如从 YAML 读工具清单可以加一段加载逻辑。下面是一个可复制的 TOML 片段放在backend/config/tools.toml[[tools]] name retrieve_course_context description Retrieve relevant chunks from uploaded course materials. module app.services.agent_tools handler _retrieve_course_context [[tools]] name generate_exam_questions description Generate exam questions from course materials. module app.services.agent_tools handler _generate_exam_questions启动时读这个文件动态注册适合工具数量多、需要按环境开关的场景。小项目直接用字典就够别过度设计。4. 端到端验证一次工具调用跑通注册表写好了得验证它真的能跑通。分两步先验证发现接口再验证一次完整的工具调用。先加一个 API 路由暴露工具列表# backend/app/api/agent.py from fastapi import APIRouter from app.services.agent_tools import list_agent_tools router APIRouter(prefix/api/agent, tags[agent]) router.get(/tools) def get_tools(): return list_agent_tools()启动服务后打开 Swaggerhttp://127.0.0.1:8000/docs找到GET /api/agent/tools点 Try it out 再 Execute。正常返回类似[ { name: retrieve_course_context, description: Retrieve relevant chunks from uploaded course materials., input_schema: { query: Student or teacher task used as the retrieval query., top_k: Maximum number of chunks to retrieve. } } ]看到这个说明注册和发现都通了。接下来验证路由和执行。在 Agent 主流程里把原来直接调retrieve_chunks的地方改成走注册表# backend/app/services/agent.py from app.services.agent_tools import get_agent_tool def run_agent(task: str, top_k: int 5): steps [] tool get_agent_tool(retrieve_course_context) result tool.run({query: task, top_k: top_k}) chunks result[chunks] steps.append({tool: tool.name, observation: result[observation]}) # 后续用 chunks 构造 prompt 调模型 answer chat(build_prompt(task, chunks)) return {answer: answer, steps: steps}用一个真实任务测一下比如「Java Web 里 Servlet 的生命周期是什么」。请求 Agent 接口后返回的steps里应该能看到{ answer: Servlet 的生命周期分为加载、初始化、服务和销毁四个阶段……, steps: [ {tool: retrieve_course_context, observation: retrieved 3 chunk(s)} ] }到这一步注册、发现、路由、执行四个环节全部跑通。工具内部调模型时走的是 TaoToken 通道你可以在工具里加一个generate_exam_questions内部用chat()生成题目验证模型调用也正常。如果模型请求返回正常文本说明统一 Key 的链路是通的。想单独验证模型通道可以用模型对话页面发一条测试消息确认 Key 和模型名没问题再回到项目里跑工具。这样能把「模型通道问题」和「工具注册问题」分开排查省很多时间。5. 常见报错与排查对照工具链路跑不通报错通常集中在几个地方。下面按真实遇到的错误对照排查。401 Unauthorized / invalid api keyKey 没读到或写错了。先确认.env里TAOTOKEN_API_KEY没有多余空格再确认Settings真的加载了.env。可以在启动时打印settings.taotoken_api_key[:8]看前几位对不对。如果 Key 是从控制台复制的注意别把前后引号也复制进去。local proxy failed / connection errorBase URL 写错或网络不通。检查TAOTOKEN_BASE_URL是不是https://taotoken.net/api末尾不要带/v1。如果公司网络有出口限制确认能访问该域名。这类错误和工具注册表无关是通道层问题先单独用chat()测一次。reading choices of undefined模型返回结构不符合预期通常是请求体格式问题。检查model字段是不是有效模型名messages是不是标准格式。如果用了自定义封装确认没有把messages包成字符串。这个报错本质是resp.choices为空打印完整resp就能看到服务端返回的错误信息。KeyError: tool not registered调用了没注册的工具名。检查TOOLS字典里的 key 和get_agent_tool()传入的名字是否完全一致大小写、下划线都要对上。建议在get_agent_tool里把可用工具名一起抛出来方便定位def get_agent_tool(name: str) - AgentTool: if name not in TOOLS: raise KeyError(ftool not registered: {name}, available: {list(TOOLS)}) return TOOLS[name]OAuth / token expired如果你用的是需要 OAuth 的模型服务token 过期会报这个。TaoToken 用 API Key 方式一般不会遇到 OAuth 流程。如果确实看到 OAuth 相关报错先确认没有误配其他服务的凭证。工具执行超时检索或模型调用太慢。给工具执行加超时和重试别让一个慢工具拖死整个 Agentimport time def run_with_retry(tool: AgentTool, args: dict, retries: int 2): for i in range(retries 1): try: return tool.run(args) except Exception as e: if i retries: raise time.sleep(0.5 * (i 1))重试要区分错误类型网络抖动可以重试参数错误重试也没用。建议只对超时和 5xx 重试4xx 直接抛出。排查顺序建议先单独测模型通道chat()能否返回再测工具发现接口/api/agent/tools最后测完整调用。一层层往下问题定位会快很多。6. 把注册表用起来接入与后续扩展工具注册表搭好之后日常开发就变成「加工具」这一件事。新增一个工具的标准动作是写执行函数、往TOOLS注册、在发现接口里自动出现、主流程按名字调用。不需要动 Agent 核心逻辑也不需要改 API 层。如果你准备把模型调用也统一管理建议把 Key 和 Base URL 都收进配置工具里只依赖chat()这个封装。这样换模型、换通道都只改一处。需要新建 Key 或查看用量去控制台的 API Keys 页面操作接入细节可以对照接入文档里面有各语言的示例。后续往 function calling 演进时注册表里的input_schema可以直接转成模型能识别的工具描述格式list_agent_tools()的输出就是现成的工具清单。到那时让模型根据任务选择工具、后端校验参数、执行后把结果回传给模型继续推理整条链路的地基就是现在这个注册表。先把注册、发现、路由、重试这四件事做扎实后面升级会顺很多。
📝

华诺云谱内容团队

资深建站顾问 · 行业研究员

10年+企业数字化服务经验,专注智能建站、SEO优化与品牌营销,持续输出建站技巧、行业洞察与营销干货,已帮助5000+企业实现数字化增长。

你可能需要的服务

订阅华诺云谱资讯周报

每周一封,精选建站技巧、SEO与营销干货,直达邮箱。已有 8,000+ 企业主订阅,助你少走弯路。

↑