)
1. 从一次“工具调用失败”说起Agent 到底难在哪很多人第一次写 Agent卡住的地方不是模型不会思考而是模型“想调工具却调不动”。我见过最典型的场景你写好了get_weather函数把描述塞进 prompt模型也乖乖输出了{tool: get_weather, args: {city: 杭州}}结果你的代码没接住或者接住了但参数名对不上最后模型收到一句Error: unknown tool整个循环就断了。这就是 Agent 和普通 LLM 应用的分界线。普通调用是一问一答模型只负责生成文本Agent 是让模型自己决定“下一步做什么”——查数据库、调 API、写文件、再总结直到任务完成。它本质是一个 LLM 驱动的事件循环加状态机感知输入、规划下一步、执行动作、观察结果然后回到感知继续循环。你写过后端消息消费者或者流处理循环基本就懂了大半。这一篇聚焦 Agent 基础架构与四大核心能力Tool Use、Function Calling、MCP 协议、Computer-use。我会用 TaoToken 的统一 Key 和 API 通道来演示多工具调用配置交付可复制的工具注册配置、Function Calling 参数模板、MCP 服务端接入示例以及 Computer-use 任务编排的验证步骤和调试清单。适合已经会调模型 API、想往 Agent 方向走的后端或全栈同学。先说清楚一个概念Agent 等于 LLM 加工具加规划加记忆加循环。LLM 是大脑工具是手脚规划是分步思考记忆是上下文循环是根据反馈迭代。普通 LLM 调用无状态、不能行动Agent 能自主决定调什么工具、看结果、再决定下一步。关键区别在于“LLM 自己决定下一步”而不是代码写死的 if-else 流程。这就像规则引擎和动态路由的区别运行时决策而非编译期写死。2. TaoToken 统一 Key 接入把模型通道先打通在写 Agent 之前得先把模型通道打通。Agent 会频繁调用模型尤其是 Function Calling 场景一次任务可能触发五六轮模型请求。如果每个模型都单独配 Key、单独改 Base URL调试成本会非常高。TaoToken 的价值就在这里它提供统一的 Key 和 API 通道你可以在一个地方管理多个模型的调用Agent 代码里只需要维护一份配置。先拿 Key。访问官网 https://taotoken.net/?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content 注册后进入控制台在 API Keys 页面创建一个新 Key。建议给 Agent 项目单独建一个 Key方便后续按项目排查用量。创建后复制保存页面只显示一次。拿到 Key 后API 入口是 https://taotoken.net/api。注意这个地址不带 UTM 参数是纯 API 端点。你的 Agent 代码里 Base URL 填这个Key 填刚才复制的。这里有个容易踩的坑很多人把 Base URL 写成官网首页地址结果请求 404。API 端点和官网是两个地址别混。另外如果你用的是 OpenAI SDK 兼容的调用方式Base URL 通常需要带上/v1路径具体看你用的 SDK 版本。我实测下来OpenAI Python SDK 1.x 版本填https://taotoken.net/api/v1能正常跑通。配置建议用环境变量管理别硬编码在代码里export TAOTOKEN_API_KEYsk-你的Key export TAOTOKEN_BASE_URLhttps://taotoken.net/api/v1然后代码里读取import os from openai import OpenAI client OpenAI( api_keyos.environ[TAOTOKEN_API_KEY], base_urlos.environ[TAOTOKEN_BASE_URL], )这样你的 Agent 项目在本地、测试、生产环境切换时只需要改环境变量不用动代码。对于 Agent 这种需要反复调试的项目这个习惯能省很多事。模型选择上Function Calling 场景建议用原生支持工具调用的模型。你可以在模型对话页面先手动测试一下模型是否能正确输出结构化工具调用确认没问题再写进 Agent 代码。模型对话入口在 https://taotoken.net/models?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content 可以先在那里验证。如果你打算长期跑 Agent 任务比如自动化编码或者多步骤工作流可以了解一下 Coding Plan入口在 https://taotoken.net/coding-plan?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content 。它更适合高频、长时间的 Agent 调用场景。3. 可复制配置Function Calling 工具注册与参数模板这一节是核心直接给可复制的配置。Agent 的工具注册分两部分工具描述给模型看的 schema和执行函数应用侧真正跑的代码。模型只负责输出“调哪个工具、传什么参数”执行永远由你的应用代码做。模型在沙箱里它不能直接执行任何东西。先看工具描述的 JSON Schema。这是 Function Calling 的契约写不好模型就不会用工具。每个工具要包含名字、用途描述、参数 schema、返回格式说明。下面是一个查询数据库的工具注册示例{ type: function, function: { name: query_sales_db, description: 查询销售数据库返回指定时间范围内的销售记录。当用户询问销量、销售额、品类排名时使用此工具。不用于查询用户信息或库存。, parameters: { type: object, properties: { start_date: { type: string, description: 开始日期格式 YYYY-MM-DD }, end_date: { type: string, description: 结束日期格式 YYYY-MM-DD }, category: { type: string, description: 商品品类可选。不传则查询全部品类 }, limit: { type: integer, description: 返回记录数上限默认 100, default: 100 } }, required: [start_date, end_date] } } }注意 description 里写了“何时该用、何时不该用”。这是最容易被忽略的点。模型靠描述决定是否调用工具描述模糊就会乱调或者不调。比如你只写“查询销售数据”模型可能在用户问“上周哪个品类卖得好”时犹豫因为它不确定这个工具能不能做排序。写清楚“当用户询问销量、销售额、品类排名时使用”命中率会高很多。再看执行函数的映射。应用侧维护一个工具名到函数的字典import json def query_sales_db(start_date, end_date, categoryNone, limit100): # 实际查库逻辑 sql SELECT category, SUM(amount) as total FROM sales WHERE date BETWEEN %s AND %s params [start_date, end_date] if category: sql AND category %s params.append(category) sql GROUP BY category ORDER BY total DESC LIMIT %s params.append(limit) # 假设 db 是你的数据库连接 rows db.execute(sql, params).fetchall() return json.dumps([dict(r) for r in rows], ensure_asciiFalse) TOOL_REGISTRY { query_sales_db: query_sales_db, }然后是完整的 Agent 循环。这是 Function Calling 的骨架你可以直接复制改def run_agent(user_input, tools_schema, max_turns10): messages [ {role: system, content: 你是一个数据分析助手可以调用工具查询数据。}, {role: user, content: user_input}, ] for turn in range(max_turns): response client.chat.completions.create( modelgpt-4o-mini, messagesmessages, toolstools_schema, tool_choiceauto, ) msg response.choices[0].message messages.append(msg) if not msg.tool_calls: return msg.content for tool_call in msg.tool_calls: fn_name tool_call.function.name fn_args json.loads(tool_call.function.arguments) if fn_name not in TOOL_REGISTRY: result fError: unknown tool {fn_name} else: try: result TOOL_REGISTRY[fn_name](**fn_args) except Exception as e: result fError: {str(e)} messages.append({ role: tool, tool_call_id: tool_call.id, content: result, }) return 达到最大轮次任务未完成这段代码里有几个关键点。第一tool_choiceauto让模型自己决定是否调工具。第二工具执行结果要以role: tool的消息回传并且带上tool_call_id否则模型不知道这是哪个调用的结果。第三异常要捕获并作为结果回传让模型知道工具失败了它可能会换个方式重试或者告诉用户。如果你用 MCP 协议工具注册会变成服务端配置。MCP 是 Anthropic 提出的开放协议标准化 LLM 应用与外部工具、数据源的连接可以理解为“AI 的 USB-C”。它把 N 个模型乘 M 个工具的集成矩阵降为 N 加 M。工具方写一次 MCP Server所有支持 MCP 的客户端都能用。一个 MCP Server 的配置示例以 Claude Desktop 的配置文件为例路径在~/Library/Application Support/Claude/claude_desktop_config.json{ mcpServers: { sales-db: { command: python, args: [/path/to/sales_mcp_server.py], env: { DB_CONNECTION: postgresql://localhost/sales } } } }MCP Server 本身暴露三类能力Tools 工具、Resources 数据、Prompts 提示模板。一个成熟的 MCP Server 不只是工具接口而是能力管理平台包含 Tool Registry 工具注册发现、Context Provider 动态上下文注入、Resource Provider 统一资源访问。Context Provider 按需注入上下文而非全量塞入能显著降低 Prompt 长度和 Token 成本。如果你用 Cline 或者 Claude Code 这类工具MCP 配置通常在 settings 里。以 Cline 的 MCP 配置为例需要填三件套Base URL、Key、Model ID。Base URL 填https://taotoken.net/api/v1Key 填你的 TaoToken KeyModel ID 填你选的模型。这三件套缺一不可少填一个就会报连接错误。4. 验证请求从单工具到多工具编排的成功结果配置写完了得验证。验证分三步单工具调用、多工具串联、Computer-use 任务编排。第一步单工具调用。用上面的run_agent跑一个简单查询result run_agent( 上周销量最高的三个品类是什么, tools_schema[sales_tool_schema], ) print(result)预期结果模型先输出一个tool_calls调用query_sales_db参数是start_date和end_date。你的代码执行查询把结果回传模型再输出最终的自然语言总结类似“上周销量最高的三个品类是 A、B、C分别卖了 X、Y、Z 件”。如果模型没有调工具直接回答了说明工具描述不够清晰或者模型不支持 Function Calling。先换一个原生支持工具调用的模型试试。第二步多工具串联。注册两个工具比如query_sales_db和send_email让 Agent 完成“查上周销量并邮件发给老板”tools_schema [sales_tool_schema, email_tool_schema] result run_agent(查一下上周销量然后邮件发给老板, tools_schema)预期行为模型第一轮调query_sales_db拿到结果后第二轮调send_email参数里包含查询结果的摘要。这就是多工具编排模型自己决定调用顺序你的代码只负责执行。第三步Computer-use 任务编排。Computer-use Agent 直接操作图形界面看屏幕截图、移动鼠标、点击、输入、滚动。它的循环是截图、模型看图决定动作、执行、再截图本质是 ReAct 循环只是工具换成了 GUI 操作观察换成了截图。验证 Computer-use 需要一个沙箱环境。别在生产环境上试。可以用虚拟机或者容器跑一个浏览器让 Agent 完成“打开网页、填写表单、提交”的任务。验证步骤# 伪代码展示 Computer-use 循环结构 while not task_done: screenshot capture_screen() action model.decide_action(screenshot, task_description) if action.type click: click(action.x, action.y) elif action.type type: type_text(action.text) elif action.type done: task_done True成功结果是 Agent 能连续执行多个 GUI 动作直到任务完成。但 Computer-use 很脆弱截图分辨率影响 token 消耗坐标定位可能不准页面动态变化会导致误操作。所以必须沙箱隔离、权限最小化、高危操作人工确认、全程录屏审计。5. 常见报错排查401、local proxy failed、reading choices、OAuthAgent 调试过程中会遇到几类典型报错这一节对照真实错误给排查路径。401 Unauthorized。最常见Key 不对或者没传。检查三件事环境变量是否生效、Key 是否复制完整、Base URL 是否带了正确的路径。如果你用 OpenAI SDKBase URL 填https://taotoken.net/api/v1别填成官网首页。另外Key 前面有没有多余空格复制时容易带上。local proxy failed / connection error。这类错误通常是网络层问题。检查你的 Base URL 是否可达可以用 curl 先测curl -X POST 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}]}如果 curl 能通但代码不通检查代码里的代理设置或者 SDK 版本。有些 SDK 会读取系统代理环境变量导致请求走错通道。Error reading choices / choices 为空。这个错误通常出现在模型返回了非预期结构时。Function Calling 场景下如果模型输出了工具调用choices[0].message.content可能是空的而tool_calls有值。你的代码如果直接读content就会报错。正确做法是先判断msg.tool_calls是否存在再决定读 content 还是处理工具调用。OAuth / authentication failed。如果你用 Claude Code 或者某些 IDE 插件它们可能走 OAuth 流程而不是 API Key。这时候需要在插件设置里切换到 API Key 模式填入 TaoToken 的 Key 和 Base URL。以 Claude Code 为例配置在~/.claude/settings.json或者项目级的.claude/settings.json需要写全三件套Base URL、Key、Model ID。少一个都会报 OAuth 失败。工具调用参数解析失败。模型输出的arguments是 JSON 字符串有时候会带 markdown 代码块标记比如json ... 。直接json.loads会失败。加一层清洗def parse_tool_args(raw): raw raw.strip() if raw.startswith(): raw raw.split(\n, 1)[1] raw raw.rsplit(, 1)[0] return json.loads(raw)MCP Server 启动失败。检查 command 路径是否正确、Python 环境是否有依赖、env 里的连接串是否可达。MCP Server 是独立进程它的日志和主应用是分开的排查时要单独看 Server 的 stderr 输出。Computer-use 坐标偏移。截图分辨率和实际屏幕分辨率不一致会导致点击位置偏移。确保截图和坐标系统一必要时做缩放换算。另外多显示器环境下要指定操作哪个屏幕。6. 继续往下走把 Agent 通道固定下来Agent 基础部分到这里就打通了。你有了统一的模型通道、可复制的工具注册配置、Function Calling 循环骨架、MCP 接入示例以及一份报错排查清单。接下来要做的是把这个通道固定下来别每次调试都重新配 Key 和 Base URL。我的建议是在项目里建一个config.py或者.env文件把 Base URL、Key、默认模型 ID 集中管理。Agent 代码只读配置不硬编码。这样你换模型、换环境、加工具的时候改动范围可控。如果你要长期跑 Agent 任务比如自动化编码、多步骤工作流、定时任务可以看看 Coding Plan入口在 https://taotoken.net/coding-plan?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content 。它更适合高频调用场景。API Key 管理在 https://taotoken.net/api-keys?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content 接入文档在 https://taotoken.net/doc?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content 遇到协议细节可以查文档。下一篇会讲 Agent 的推理模式与记忆系统ReAct、Plan-Execute-Replan、Reflexion、ToT 和快慢思考。那是让 Agent 从“能调工具”变成“会规划”的关键一步。这一篇先把工具通道和调用循环跑通下一篇再往上叠推理策略。