ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

从零搞懂 AI Agent:用 TaoToken 统一 Key 跑通 ReAct 模式与 Function Calling 代码实现

从零搞懂 AI Agent:用 TaoToken 统一 Key 跑通 ReAct 模式与 Function Calling 代码实现 1. 为什么你的 Agent 总是“想得多、做得少”很多人第一次写 AI Agent代码跑起来看着挺热闹模型输出一大段“我需要先查询天气然后计算温度差”但真正该调用的函数一次都没触发。问题不在模型笨而在于你只给了它一张嘴没给它一双手也没规定它“说话”的格式。AI Agent 的本质是一个能自主循环的程序它接收目标决定下一步动作执行动作拿到结果再决定下一步直到任务完成。这个循环最经典的实现就是 ReActReasoning Acting而让循环稳定落地的关键是 Function Calling 把“模型想调什么工具”变成结构化 JSON而不是靠正则去猜模型的小作文。这篇面向初次接触 Agent 的开发者我会用 TaoToken 作为统一 Key 和 API 通道把 ReAct 循环和 Function Calling 串成一条能跑通的链路。你会拿到可复制的 settings.json / config.toml 骨架、一个最小可运行的 Agent 示例以及验证推理轨迹和工具返回是否正确的具体动作。全程不需要你分别去注册一堆模型厂商账号一个 Key 就能切换模型。适合谁写过 Python 基础、知道什么是 API Key、但还没亲手跑通过一个完整 Agent 循环的人。读完你应该能自己判断我的 Agent 卡在推理、卡在工具解析还是卡在模型根本没返回 tool_calls。2. TaoToken 前置一个 Key 打通模型与工具调用链路在写 Agent 之前先把“模型从哪来”这件事解决掉。ReAct 循环里每一轮都要调用 LLM如果每换一个模型就换一套 SDK、换一个 Key、换一个 base_url调试成本会非常高。TaoToken 在这里的角色是统一入口你拿到一个 Key通过同一个 API 通道访问不同模型Agent 代码里的 client 配置基本不用动。先明确两个地址后面配置里会反复用到官网入口https://taotoken.net/?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_contentAPI 基地址https://taotoken.net/api 这个不加 UTM直接用于代码里的 base_url你需要做的准备只有三步注册后进入控制台创建 API Key把 Key 写进环境变量而不是硬编码确认你的调用方式兼容 OpenAI SDK 风格。TaoToken 的接口兼容 OpenAI 的 chat.completions 结构这意味着你现有的 openai 库代码只需要改 base_url 和 api_key 两行。注意Key 只放在环境变量或本地 .env 文件里不要提交到 Git。Agent 项目尤其容易把 Key 写进示例代码后忘记删。如果你还没创建 Key可以先去控制台生成一个再回来跟着下面的配置走。模型对话调试可以在模型对话页先验证 Key 是否可用确认能正常返回内容后再接入 Agent 循环能省掉一半排障时间。3. 可复制配置settings.json 与 config.toml 骨架Agent 项目最容易乱的地方是配置散落在代码各处。我习惯把模型、base_url、超时、最大循环步数集中到配置文件代码只读配置。下面给两份骨架你按自己习惯选一份即可。3.1 settings.json 骨架Python 项目通用{ llm: { provider: taotoken, base_url: https://taotoken.net/api, api_key_env: TAOTOKEN_API_KEY, model: gpt-4o-mini, timeout: 60, max_tokens: 2048 }, agent: { max_steps: 8, tool_choice: auto, verbose: true }, tools: { enabled: [get_weather, calculator, read_file] } }这里几个参数值得解释。base_url 固定指向 TaoToken 的 API 地址api_key_env 写的是环境变量名而不是 Key 本身这样代码里读的是 os.getenv(TAOTOKEN_API_KEY)。max_steps 是 ReAct 循环的硬上限防止模型陷入“反复调用同一个工具”的死循环。tool_choice 设为 auto让模型自己决定这一轮是回答还是调工具。3.2 config.toml 骨架更贴近工程化[llm] provider taotoken base_url https://taotoken.net/api api_key_env TAOTOKEN_API_KEY model gpt-4o-mini timeout 60 [agent] max_steps 8 tool_choice auto verbose true [tools.get_weather] description 查询指定城市的当前天气 parameters { city string } [tools.calculator] description 计算数学表达式 parameters { expression string }TOML 的好处是工具描述和参数能直接写在配置里后面生成 Function Calling 的 tools 数组时可以直接读不用在代码里手写一大段 JSON Schema。两种格式选一种就行关键是让“模型配置”和“工具配置”分离改模型不动工具加工具不动模型。配置写完后用一段最小代码验证读取是否正常import json, os from openai import OpenAI with open(settings.json, r, encodingutf-8) as f: cfg json.load(f) client OpenAI( base_urlcfg[llm][base_url], api_keyos.getenv(cfg[llm][api_key_env]), timeoutcfg[llm][timeout], ) resp client.chat.completions.create( modelcfg[llm][model], messages[{role: user, content: 只回复两个字就绪}], ) print(resp.choices[0].message.content)如果这里能打印出“就绪”说明 Key、base_url、模型名三者都对上了可以进入 Agent 主体。4. 最小可运行 AgentReAct 循环 Function Calling现在写核心。ReAct 的循环用一句话概括把用户问题、工具列表、历史对话一起发给模型模型要么返回 tool_calls要调工具要么返回普通文本最终答案如果是 tool_calls我们执行本地函数把结果作为 tool 角色消息追加回对话再进入下一轮。4.1 工具定义与本地实现先定义两个工具一个查天气模拟一个算数。注意 Function Calling 要求工具用 JSON Schema 描述参数。import json def get_weather(city: str) - str: fake_db {北京: 晴25°C, 上海: 多云28°C} return fake_db.get(city, f{city}暂无数据) def calculator(expression: str) - str: try: return str(eval(expression, {__builtins__: {}}, {})) except Exception as e: return f计算失败{e} TOOLS_SCHEMA [ { type: function, function: { name: get_weather, description: 查询指定城市的当前天气, parameters: { type: object, properties: {city: {type: string, description: 城市名称}}, required: [city], }, }, }, { type: function, function: { name: calculator, description: 计算数学表达式例如 12*83, parameters: { type: object, properties: {expression: {type: string}}, required: [expression], }, }, }, ] TOOL_MAP {get_weather: get_weather, calculator: calculator}4.2 ReAct 主循环def run_agent(user_input: str, max_steps: int 8): messages [ {role: system, content: 你是一个会使用工具的助手。需要外部信息时必须调用工具不要编造。}, {role: user, content: user_input}, ] for step in range(max_steps): resp client.chat.completions.create( modelcfg[llm][model], messagesmessages, toolsTOOLS_SCHEMA, tool_choiceauto, ) msg resp.choices[0].message messages.append(msg) if not msg.tool_calls: print(f[第{step1}轮] 最终答案{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_MAP[name](**args) print(f[第{step1}轮] 工具返回{result}) messages.append({ role: tool, tool_call_id: call.id, content: str(result), }) print(达到最大步数强制结束) return None跑起来run_agent(北京天气怎么样如果气温超过20度帮我算一下 25*4 是多少)4.3 推理轨迹长什么样正常运行时你会看到类似输出[第1轮] 调用工具 get_weather参数 {city: 北京} [第1轮] 工具返回晴25°C [第2轮] 调用工具 calculator参数 {expression: 25*4} [第2轮] 工具返回100 [第3轮] 最终答案北京今天晴25°C超过20度25*4 的结果是 100。这就是 ReAct 的 Thought-Action-Observation 循环在 Function Calling 下的形态模型不再输出“Action: get_weather(北京)”这种文本而是直接返回结构化的 tool_calls代码不用正则解析稳定性高一个量级。5. 验证请求与成功结果三个必须检查的动作代码能跑不等于链路正确。我一般用三个动作确认 Agent 真的在工作而不是模型在“假装调用”。第一个动作打印完整 messages。在每轮请求前把 messages 打出来确认 tool 角色的消息确实带上了 tool_call_id且内容非空。如果 tool_call_id 对不上模型下一轮会报错或忽略工具结果。第二个动作故意让工具返回错误。把 get_weather 改成对未知城市返回“工具执行失败”观察模型是否会换策略或如实告知用户。如果模型无视错误继续编造天气说明 system prompt 约束不够。第三个动作检查 tool_calls 的 arguments 是否是合法 JSON。有些模型偶尔会返回带注释的 JSONjson.loads 会直接抛异常。加一层容错try: args json.loads(call.function.arguments) except json.JSONDecodeError: args {} print(参数解析失败原始内容, call.function.arguments)成功结果的标准是工具被真实调用、返回值进入对话、最终答案引用了工具返回的数据。三者缺一链路就没通。6. 本篇常见错排查报错一TypeError: NoneType object is not subscriptable。多半是 msg.tool_calls 为 None 时你直接取了 [0]。先判断 if msg.tool_calls 再处理。报错二模型一直不调用工具只输出文字。检查 tools 参数是否真的传进去了以及 system prompt 是否明确要求“需要外部信息必须调用工具”。有些模型对 tool_choiceauto 比较保守可以临时改成强制指定某个函数来验证链路。报错三openai.BadRequestError: tool_call_id not found。说明你追加 tool 消息时 id 写错了或者把 assistant 消息丢了。assistant 那条带 tool_calls 的消息必须原样 append 进 messages。报错四循环停不下来。max_steps 是必须的另外可以在 system prompt 里加一条“如果同一个工具连续调用两次且结果相同必须停止并给出结论。”报错五中文乱码。所有文件读写加 encodingutf-8Windows 下尤其容易踩。如果你在接入阶段反复卡在鉴权或 base_url 上建议先去接入文档对照一遍参数再用 API Keys 页面确认 Key 状态。模型本身的行为差异可以在模型对话里单独测同一句 prompt排除是 Agent 代码问题还是模型选择问题。7. 从能跑到好用下一步怎么走跑通上面这个最小 Agent 后你会自然遇到两个瓶颈工具一多手写 JSON Schema 很烦对话一长上下文塞不下。前者对应 MCP 这类统一工具描述协议让工具以标准格式动态注册后者对应长期记忆把历史经验存进向量库在每轮 Thought 前检索注入。如果你打算把 Agent 用在长期编码或自动化任务上频繁调用模型会放大成本这时候可以了解 Coding Plan 这类面向持续调用的方案把 Key 和额度管理从代码里彻底剥离。先把 ReAct 循环和 Function Calling 这两块地基打牢后面加记忆、加多工具、加规划器都是在这个循环上做加法。
返回列表