
1. 从“只会聊天”到“能干活”智能体 AI Agent 到底缺了哪块拼图很多人第一次接触大模型都是从聊天框开始的问一句答一句写文案、改代码、翻译文档都挺顺手。但只要你让它“帮我把这周的服务器日志整理成报表再发到群里”它立刻就开始打太极——要么说做不到要么给你一段看起来像那么回事、实际根本跑不通的伪代码。这不是模型不够聪明而是聊天机器人和智能体 AI Agent 之间差了一整套“感知—规划—调用工具—执行”的闭环。我习惯把大模型比作一个知识渊博但被关在房间里的人他读过很多书能回答很多问题但手伸不出门没法查实时天气、没法读你本地的 CSV、没法调用支付接口。而智能体 AI Agent 做的事情就是给这个人配上一双手、一套工具和一个记事本。你告诉它目标它自己拆步骤、选工具、看结果、再决定下一步直到把任务交付。这个“手”在工程上最核心的落地形式就是工具调用Function Calling。所以这篇文章不打算停留在“什么是 Agent”的概念层面而是直接带你跑通一个最小闭环用统一的 Key 和 API 通道接入大模型让模型自己决定调用一个真实函数拿到返回值后再组织成自然语言回答。整个过程你会看到可复制的环境变量、Base URL 配置、一段最小 Agent 循环代码以及怎么用日志和返回结构判断这次调用到底成没成。适合已经会写一点 Python、想从“调 API 聊天”进阶到“让模型干活”的开发者。需要先明确一个边界Agent 不是把模型换掉而是在模型外面套一层调度逻辑。模型负责“想”代码负责“做”工具负责“碰真实世界”。三者缺一不可。下面所有操作都围绕这个分工展开。2. 前置准备用 TaoToken 统一 Key 打通模型通道与 Function Calling 调用在写 Agent 循环之前得先解决“模型从哪来”的问题。自己部署一套推理服务对多数人来说成本太高直接调各家官方 API 又要维护多套 Key、多套 Base URL、多套计费账号调试阶段光切换就够烦的。我实测下来用 TaoToken 这类统一通道做前期验证比较省事一个 Key、一个 Base URL就能覆盖多种主流模型Function Calling 的请求格式也保持 OpenAI 兼容代码几乎不用改。TaoToken 在这里扮演的角色是统一的模型接入层不是替代你的编辑器或 Agent 框架。你依然用自己熟悉的 Python、LangChain、Cline 或者 Claude Code只是把请求地址和鉴权换成它。官网入口是 https://taotoken.net/?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content API 根地址是 https://taotoken.net/api 注意这个 API 地址后面不加任何 UTM 参数直接写进代码里。你需要准备的东西很少一个 TaoToken 账号、一个 API Key、一个能跑 Python 的环境。Key 在控制台的 API Keys 页面生成地址是 https://taotoken.net/console/api-keys?utm_sourcetaotoken_aicg_blog_endutm_contentapi-keysutm_campaignrewrite 。生成后先复制到本地不要提交到 Git。环境变量建议这样组织避免把 Key 硬编码进脚本export TAOTOKEN_API_KEYsk-你的实际Key export TAOTOKEN_BASE_URLhttps://taotoken.net/api如果你用.env文件管理写成TAOTOKEN_API_KEYsk-你的实际Key TAOTOKEN_BASE_URLhttps://taotoken.net/api模型 ID 这块要注意不同通道对模型名的写法可能略有差异最稳妥的方式是先在模型对话页面确认当前可用的模型标识地址是 https://taotoken.net/models?utm_sourcetaotoken_aicg_blog_endutm_contentmodelsutm_campaignrewrite 。选一个支持 Function Calling 的模型比如常见的gpt-4o-mini或claude-3-5-sonnet这类具体以页面展示为准。选模型时优先看两点是否支持 tools 参数、上下文长度是否够你的任务。调试阶段用便宜的小模型完全够用等逻辑跑通再换大模型。这里有个容易踩的坑很多人把 Base URL 写成https://taotoken.net/api/v1结果请求 404。OpenAI 兼容的 SDK 通常会自动补/v1所以根地址给到/api即可。如果你用的是原生requests手写请求那就要自己拼完整的https://taotoken.net/api/v1/chat/completions。两种方式都对关键是别重复拼接。另外如果你后续要接 Claude Code 这类编码 Agent或者用 Cline 做 MCP 工具调用配置项同样是三件套Base URL、API Key、Model ID。这三者必须同时正确缺一个都会报鉴权或模型不存在。Coding Plan 适合长期编码和 Agent 场景入口在 https://taotoken.net/coding-plan?utm_sourcetaotoken_aicg_blog_endutm_contentcoding-planutm_campaignrewrite 调试阶段可以先不买用按量计费把流程跑通再说。3. 可复制配置最小 Agent 循环与 Function Calling 请求体现在进入正题。我们要让模型调用一个真实函数比如查询某个城市的天气。模型本身不知道天气但它能根据我们提供的工具描述决定“该调用 get_weather 了”并给出参数{city: 杭州}。我们的代码负责真正执行这个函数把结果塞回对话再让模型生成最终回答。这就是一次完整的工具调用闭环。先装依赖pip install openai python-dotenv然后写一个最小可运行脚本agent_demo.pyimport os import json from openai import OpenAI from dotenv import load_dotenv load_dotenv() client OpenAI( api_keyos.getenv(TAOTOKEN_API_KEY), base_urlos.getenv(TAOTOKEN_BASE_URL), ) # 1. 定义真实工具函数 def get_weather(city: str) - dict: fake_db { 杭州: {temp: 22, weather: 多云}, 北京: {temp: 18, weather: 晴}, 深圳: {temp: 28, weather: 阵雨}, } return fake_db.get(city, {temp: None, weather: 未知}) # 2. 用 JSON Schema 描述工具告诉模型它能调用什么 tools [ { type: function, function: { name: get_weather, description: 查询指定城市的当前天气, parameters: { type: object, properties: { city: { type: string, description: 城市名称例如 杭州, } }, required: [city], }, }, } ] # 3. 第一轮请求模型决定是否调用工具 messages [{role: user, content: 杭州现在天气怎么样}] response client.chat.completions.create( modelgpt-4o-mini, messagesmessages, toolstools, tool_choiceauto, ) msg response.choices[0].message print(第一轮返回:, msg) # 4. 如果模型要求调用工具就执行并把结果回传 if msg.tool_calls: messages.append(msg) for tool_call in msg.tool_calls: fn_name tool_call.function.name args json.loads(tool_call.function.arguments) print(f模型请求调用 {fn_name}参数 {args}) if fn_name get_weather: result get_weather(**args) else: result {error: unknown tool} messages.append({ role: tool, tool_call_id: tool_call.id, content: json.dumps(result, ensure_asciiFalse), }) # 5. 第二轮请求模型根据工具结果生成最终回答 final client.chat.completions.create( modelgpt-4o-mini, messagesmessages, ) print(最终回答:, final.choices[0].message.content) else: print(模型没有调用工具直接回答:, msg.content)这段代码里有几个关键点值得展开。第一tools参数用的是 JSON Schemadescription写得越清楚模型选对工具的概率越高。第二tool_choiceauto表示让模型自己决定调不调你也可以强制{type: function, function: {name: get_weather}}来测试。第三工具执行结果必须以role: tool的消息回传并且带上tool_call_id否则模型不知道这个结果对应哪次调用。如果你用配置文件管理可以写一个config.toml[llm] base_url https://taotoken.net/api api_key sk-你的实际Key model gpt-4o-mini [agent] max_turns 5 tool_choice auto或者用settings.json给支持 JSON 配置的客户端{ llm: { baseUrl: https://taotoken.net/api, apiKey: sk-你的实际Key, modelId: gpt-4o-mini }, agent: { maxTurns: 5, enableToolCall: true } }注意这里的baseUrl和apiKey、modelId就是前面说的三件套任何 Agent 框架接入时都要同时确认这三项。少一项或者写错一项最常见的表现就是 401 或者模型不存在。4. 验证请求用日志与返回结构确认工具调用真的跑通了代码写完不代表跑通。很多人看到终端没报错就以为成功了其实模型可能压根没调用工具而是自己编了一个天气答案。所以必须学会看返回结构。先运行脚本python agent_demo.py一次成功的输出应该长这样第一轮返回: ChatCompletionMessage( contentNone, tool_calls[ ChatCompletionMessageToolCall( idcall_abc123, functionFunction(nameget_weather, arguments{city:杭州}), typefunction ) ] ) 模型请求调用 get_weather参数 {city: 杭州} 最终回答: 杭州现在多云气温大约 22 摄氏度。判断成功的三个硬指标第一第一轮返回的content是None而tool_calls不为空说明模型确实选择了调用工具而不是直接回答。第二arguments是合法 JSON能被json.loads解析。第三最终回答里出现了工具返回的真实数据22 度和多云而不是模型编造的。如果第一轮tool_calls是空的content直接给了答案说明模型没走工具。常见原因是工具描述不够清楚或者模型本身不支持 Function Calling。这时候可以先把tool_choice强制指定为那个函数看模型是否配合。日志方面建议在请求前后打印关键字段import logging logging.basicConfig(levellogging.INFO) logging.info(请求模型: %s, gpt-4o-mini) logging.info(消息数: %d, len(messages)) logging.info(工具数: %d, len(tools))更完整的做法是把response整个序列化后落盘方便对比with open(last_response.json, w, encodingutf-8) as f: f.write(response.model_dump_json(indent2))这样出问题时可以直接翻文件看finish_reason是tool_calls还是stop。finish_reason是最直接的信号tool_calls表示模型要调工具stop表示它认为可以直接回答。还有一个验证技巧故意把工具函数改成抛异常看 Agent 循环会不会把错误信息回传给模型。一个健壮的 Agent 应该能处理工具失败而不是直接崩溃。你可以把get_weather改成raise ValueError(service down)然后在回传时把错误信息作为content传回去观察模型是否会道歉或换策略。这一步能帮你提前发现生产环境里的容错问题。如果你用 Cline 或 Claude Code 这类工具做 MCP 调用验证方式类似看工具面板里是否出现了你注册的函数调用后是否有真实的返回内容。Base URL、Key、Model ID 三件套在客户端设置里填好后先发一条最简单的“你好”确认通道通再测工具调用。5. 本篇常见错误排查401、local proxy failed、reading choices 与 OAuth 报错调试 Agent 时报错信息往往比代码本身更值得研究。下面这几个是我和读者反馈里出现频率最高的逐个拆解。401 Unauthorized。这是鉴权失败九成是 Key 的问题。先确认环境变量有没有真正加载在脚本里打印os.getenv(TAOTOKEN_API_KEY)[:8]看前几位对不对。如果用了.env确认load_dotenv()在读取环境变量之前调用。还有一种情况是 Key 复制时带了空格或换行肉眼看不出来建议重新生成一次。注意不要把 Key 写进前端代码或提交到公开仓库。local proxy failed / connection refused。这类报错通常出现在客户端配置了本地代理但代理没启动或者 Base URL 写成了localhost。如果你用的是 Cline、Claude Code 这类工具检查设置里的 Base URL 是不是https://taotoken.net/api而不是某个本地端口。另外公司网络环境如果有出口限制也可能导致连接失败这时候换一个网络环境测试即可。不要使用任何非正规的网络加速手段合规访问是前提。Error reading choices / choices 字段为空。这个报错说明请求发出去了但返回结构不符合预期。常见原因是 Base URL 多写了或漏写了/v1导致请求打到了错误的端点返回了一个 HTML 错误页而不是 JSON。用curl直接测一下curl -s https://taotoken.net/api/v1/chat/completions \ -H Authorization: Bearer $TAOTOKEN_API_KEY \ -H Content-Type: application/json \ -d {model:gpt-4o-mini,messages:[{role:user,content:hi}]}如果返回的是 JSON 且包含choices说明通道没问题问题在客户端配置。如果返回 HTML说明地址错了。OAuth 相关报错。有些编码 Agent 客户端默认走 OAuth 登录流程而不是 API Key。如果你看到OAuth token expired或invalid_grant说明客户端在尝试用账号体系鉴权而不是你配置的 Key。这时候要在设置里明确切换到 API Key 模式把 Base URL、Key、Model ID 三件套填全。Claude Code 接入 Anthropic 兼容通道时尤其要注意这点配置文档在 https://taotoken.net/doc?utm_sourcetaotoken_aicg_blog_endutm_contentdocutm_campaignrewrite 有说明照着填能少走弯路。模型返回 tool_calls 但参数解析失败。这通常是模型输出的arguments不是合法 JSON比如带了注释或尾逗号。解决方式是在json.loads外面包一层 try失败时把原始字符串回传给模型让它修正try: args json.loads(tool_call.function.arguments) except json.JSONDecodeError: args {} messages.append({ role: tool, tool_call_id: tool_call.id, content: 参数解析失败请重新生成合法 JSON, })循环停不下来。Agent 如果一直调工具不结束可能是max_turns没设。在循环里加一个计数器超过 5 轮就强制退出并返回当前结果。生产环境里这个上限必须设否则一次请求可能烧掉大量 token。排查时记住一个顺序先确认通道通curl 测再确认鉴权对Key 和 Base URL最后确认模型支持 Function Calling。大部分问题都出在前两步而不是代码逻辑。6. 从最小闭环到真实 Agent下一步该往哪走跑通上面这个天气查询的例子你已经摸到了 Agent 的门槛。但真实场景里的 Agent 要复杂得多多轮规划、多工具协作、记忆管理、错误重试、结果校验。这些能力不是靠一个函数就能解决的需要你在循环外面套更多逻辑。我的建议是先把“单工具单轮”扩展到“多工具多轮”。比如再加一个get_time工具让模型自己决定先查天气还是先查时间。然后引入一个简单的规划步骤让模型先输出一个步骤列表再逐步执行。这一步可以用同一个模型完成不需要额外框架。再往后你可以把工具调用接到真实系统上比如读数据库、调内部 API、发消息。但要注意权限边界不要让 Agent 直接操作生产库。调试阶段用 mock 数据上线前加审批和日志。如果你打算长期做编码类 AgentCoding Plan 会比按量计费更划算入口在 https://taotoken.net/coding-plan?utm_sourcetaotoken_aicg_blog_endutm_contentcoding-planutm_campaignrewrite 。模型对话页面适合快速验证某个模型是否支持你要的 Function Calling 格式地址是 https://taotoken.net/models?utm_sourcetaotoken_aicg_blog_endutm_contentmodelsutm_campaignrewrite 。API Key 管理和接入文档分别在 https://taotoken.net/console/api-keys?utm_sourcetaotoken_aicg_blog_endutm_contentapi-keysutm_campaignrewrite 和 https://taotoken.net/doc?utm_sourcetaotoken_aicg_blog_endutm_contentdocutm_campaignrewrite 。最后分享一个我踩过的坑早期我为了让 Agent “更聪明”一次性注册了十几个工具结果模型经常选错或者把参数填得乱七八糟。后来把工具数量压到三个以内每个工具的description写清楚使用场景和参数格式成功率立刻上来了。工具不是越多越好边界清晰比数量重要。你可以先从一两个工具开始等模型稳定了再逐步加。