智能体开发1:智能体工具调用从LangChain到MCP的落地实践与TaoToken统一Key配置
1. 智能体工具调用到底难在哪从 LangChain Agent 到 MCP 的链路拆解智能体工具调用说白了就是让大模型自己决定「什么时候该去查网页、什么时候该读本地表格、什么时候该调接口拉数据」而不是你写死 if-else 去分发。它适合已经会用 Python 写函数、但被「模型不按预期调工具」「鉴权 Key 到处散落」折磨过的开发者。我试过把同一套金融数据任务分别用 LangChain 原生tool和 MCP 协议各跑一遍踩的坑高度重合工具描述写不清、参数类型对不上、Base URL 和 Key 配错导致 401、MCP 服务端口没起来直接 connection refused。先厘清两条链路。第一条是 LangChain 原生工具LLM ↔ Python Function工具函数跑在你的应用进程里靠tool装饰器把普通函数包装成 LangChain 能识别的对象。第二条是 MCPModel Context ProtocolLLM ↔ JSON-RPC ↔ MCP Server ↔ Tool工具跑在独立的 Server 进程里通过 HTTP 端口监听、用 JSON-RPC 跨进程通信。MCP 的定位像 AI 应用的 USB-C 口——同一个工具服务Claude Desktop、LangChain、LlamaIndex 都能接。两者最核心的差异在通用性和运行位置。LangChaintool只能在 LangChain 框架内直接用直接代码调用MCP 工具独立成服务任何支持 MCP 的客户端都能复用。这意味着当你从「单脚本 Agent」走向「多客户端共享工具」时MCP 是更省心的选择但接入复杂度也上来了——多了一层进程通信就多了一层鉴权和连接要配。真正让新手卡住的往往不是概念而是三个具体动作工具函数怎么写才能被模型正确识别、MCP 服务怎么注册和暴露、模型请求的 Base URL 和 Key 怎么统一管理。前两个是「工具调用链路」问题第三个是「鉴权配置」问题。这篇就按这三块拆开每一步都给可复制的片段最后用统一的 API 通道把鉴权收口跑通一次完整的工具调用。2. TaoToken 前置准备统一 Key 与 API 通道解决鉴权散落问题在写工具之前先把「模型从哪来、Key 放哪」这件事定下来。很多工具调用失败的根因不在工具本身而在模型请求这一层Base URL 写错、Key 过期、不同工具各自读不同的环境变量排查起来像大海捞针。我的做法是把模型访问统一到一个 API 通道上所有 Agent、所有工具、所有 MCP 服务都走同一个 Base URL 和同一把 Key。TaoToken 在这里扮演的就是这个统一入口。它的 API 地址是https://taotoken.net/api兼容 OpenAI 风格的调用方式所以 LangChain 的ChatOpenAI可以直接把base_url指过去不用改业务代码。官网在https://taotoken.net/?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content注册后在控制台生成 Key 即可。前置准备分三步。第一步拿到 Key。登录后进入控制台在 API Keys 页面创建一个新 Key复制保存——它只会完整显示一次。第二步确认你要用的模型 ID。不同模型在工具调用function calling上的支持程度不一样选一个明确支持 tool_calls 的模型比如glm-4.5-air这类否则模型可能压根不返回tool_calls字段Agent 就永远停在文本回复。第三步把 Base URL、Key、Model ID 三件套写进环境变量别硬编码在代码里。# .env 文件三件套统一管理 OPENAI_API_BASEhttps://taotoken.net/api OPENAI_API_KEYsk-你的TaoToken密钥 OPENAI_MODELglm-4.5-air这里有个容易忽略的点LangChain 的ChatOpenAI默认读OPENAI_API_KEY和OPENAI_API_BASE但字段名在不同版本里可能是base_url或openai_api_base。我建议显式传参别依赖默认读取避免版本升级后静默失效。另外MCP 服务如果也要调模型比如某些 MCP Server 内部做二次推理同样让它读这套环境变量保证全链路一把 Key。注意Key 不要提交到 Git。把.env加进.gitignore团队协作时用.env.example占位。工具调用链路一旦涉及多个进程Key 泄露面会变大统一管理反而更安全。前置做完你会得到一个稳定的模型访问入口。接下来所有工具调用无论走 LangChain 还是 MCP模型请求都指向同一个 Base URL出问题时只需要检查这一处排查成本大幅下降。3. 可复制配置LangChain tool 与 MCP 工具注册片段这一节给两套可直接跑的配置。先看 LangChain 原生工具三个函数分别对应读网页、分析 CSV、下载股价数据每个都用tool装饰关键是类型提示和 docstring 要写清楚——模型就是靠这两样判断「这个工具干什么、要传什么参数」。import os import requests import pandas as pd from langchain.tools import tool # Tool 1: 读取网页内容 tool def read_url(url: str, max_chars: int 1500) - str: Read and return text content from a web page. r requests.get(url, timeout10) r.raise_for_status() text r.text.replace(\n, ) return text[:max_chars] # Tool 2: 分析本地 CSV tool def analyze_csv(file_path: str, max_rows: int 5) - str: Analyze a local CSV file. if not os.path.exists(file_path): return fFile not found: {file_path} df pd.read_csv(file_path) return ( fShape: {df.shape}\n fColumns: {list(df.columns)}\n\n fHead:\n{df.head(max_rows).to_string(indexFalse)} ) # Tool 3: 下载股价数据 tool def download_stock_price( Ashare_code: str, end_date: str, days: int 10, file_path: str data, file_name: str stock_data.csv ) - str: Download last N trading days of stock price, save to CSV. if not os.getenv(TUSHARE_TOKEN): return TUSHARE_TOKEN not set. # 初始化与下载逻辑省略核心是返回保存路径 os.makedirs(file_path, exist_okTrue) save_path os.path.join(file_path, file_name) return fData saved to {save_path}Agent 初始化时把三个工具塞进tools列表模型用ChatOpenAI指向 TaoToken 的 Base URLfrom langchain_openai import ChatOpenAI from langchain.agents import create_agent llm ChatOpenAI( modelos.getenv(OPENAI_MODEL, glm-4.5-air), api_keyos.getenv(OPENAI_API_KEY), base_urlos.getenv(OPENAI_API_BASE, https://taotoken.net/api), temperature0, ) agent create_agent( tools[read_url, analyze_csv, download_stock_price], modelllm, system_prompt你是一个会编程的金融分析专家必要时使用提供的 tools, )再看 MCP 侧。MCP 工具用FastMCP注册跑在独立进程里通过端口暴露。下面是一个最小 MCP Server把同样的读网页能力注册成 MCP 工具from fastmcp import FastMCP import requests mcp FastMCP(TradeTools) mcp.tool() def read_url(url: str, max_chars: int 1500) - str: Read and return text content from a web page. r requests.get(url, timeout10) r.raise_for_status() return r.text.replace(\n, )[:max_chars] if __name__ __main__: mcp.run(transporthttp, host127.0.0.1, port8000)启动后MCP Server 在127.0.0.1:8000监听客户端通过 JSON-RPC 调用。如果你用 Claude Code 或 Cline 这类支持 MCP 的客户端配置片段长这样以 Cline MCP 为例写入cline_mcp_settings.json{ mcpServers: { trade-tools: { url: http://127.0.0.1:8000/mcp, transport: http } } }如果你走 Claude Code 的 MCP 接入配置写在~/.claude/settings.json或项目级.mcp.json结构类似把url指向你的 MCP Server 即可。这里三件套同样要齐MCP Server 的地址Base URL、如果 Server 内部要调模型则配 TaoToken 的 Key、以及模型 ID。缺任何一个链路都会断在某一环。4. 验证请求跑通一次完整工具调用并读懂返回结构配置写完跑一次完整调用验证。prompt 里塞三个任务让 Agent 自己决定调哪个工具prompt 有三个任务 1. 用100字总结网页: https://finance.eastmoney.com/a/202512173594061460.html 2. 用100字分析CSV文件: ./data/daily_prices_sse_50.csv 3. 下载20251217之前20天的股票数据到data文件夹代码600519.SH result agent.invoke({messages: [{role: user, content: prompt}]}) print(result)成功时返回的messages列表里会出现三类消息按顺序排列。第一类是HumanMessage你的原始指令。第二类是AIMessage关键看它的tool_calls字段——模型在这里决定调哪几个工具、传什么参数。第三类是ToolMessage每个工具执行后的返回值它的tool_call_id必须和AIMessage里对应tool_calls的id一一匹配这是链路完整性的验证点。AIMessage里几个字段值得盯。finish_reason如果是tool_calls说明模型正常发起了工具调用如果是stop说明模型直接给了文本回复、没调工具通常意味着工具描述没让模型理解该用工具。response_metadata.token_usage给出prompt_tokens、completion_tokens、total_tokens工具调用会显著推高 token 消耗因为工具返回的原始数据比如整页 HTML也会进上下文。usage_metadata是 LangChain 统一封装后的统计input_token_details.cache_read表示命中缓存的 token 数这部分通常不计费或低价。一次成功的输出大致是这样AIMessage里tool_calls列出三个调用read_url带url和max_charsanalyze_csv带file_pathdownload_stock_price带股票代码和日期随后三条ToolMessage分别返回网页文本、CSV 的 shape 和 head、以及保存路径最后再来一条AIMessagefinish_reason为stop内容是三个任务的总结。看到这个结构说明工具调用链路完全跑通。验证 MCP 侧时用 MCP 客户端连上 Server 后先列工具列表确认注册成功再发一次调用请求观察 JSON-RPC 的响应。如果 Server 日志里打印出工具被调用、客户端收到结果MCP 链路就通了。两条链路都验证过你就有了一套可切换的工具调用方案。5. 本篇常见错排查401、local proxy failed、reading choices、OAuth工具调用报错集中在几类逐个对照。401 Unauthorized。最常见Key 错、Key 过期、或者 Base URL 和 Key 不匹配。检查OPENAI_API_KEY是否完整复制有没有多余空格、OPENAI_API_BASE是否指向https://taotoken.net/api。如果 MCP Server 内部也调模型确认它读的是同一套环境变量别一个进程读.env、另一个读系统变量。local proxy failed / connection refused。MCP 场景高发。MCP Server 没启动、端口被占、或者客户端配的url和 Server 实际监听地址不一致。先curl http://127.0.0.1:8000/mcp确认端口活着再检查客户端配置里的transport是不是http。如果 Server 跑在容器里127.0.0.1在客户端侧指向的是客户端自己要换成容器可达的地址。reading choices of undefined。模型返回体里没有choices字段通常是 Base URL 指错了——请求打到了非 OpenAI 兼容的端点或者返回的是错误页 HTML。打印原始响应体确认检查base_url末尾有没有多余的/v1或路径拼接错误。TaoToken 的 API 地址是https://taotoken.net/api按这个填。OAuth / 鉴权跳转。某些 MCP 客户端或 Claude Code 在接入远程服务时会走 OAuth 流程如果服务端没配好回调会卡在授权页。本地开发阶段优先用无鉴权的本地 MCP Server把链路跑通后再加鉴权层。Claude Code 的 MCP 配置如果报 OAuth 相关错误检查settings.json里的服务定义是否误加了auth字段。工具没被调用模型直接文本回复。不是报错但结果不对。根因是工具描述不清或参数类型不明确。docstring 要写清楚工具用途参数用类型提示标注必要时在system_prompt里明确「必须使用工具完成任务」。模型对工具的选择高度依赖描述质量。tool_call_id 不匹配。ToolMessage的tool_call_id和AIMessage的tool_calls[].id对不上链路会断。这通常是手动构造消息时出的错用create_agent自动编排一般不会遇到。如果自己拼消息确保 id 严格对应。排查顺序建议先确认模型请求通401/choices 类再确认 MCP 服务通connection refused 类最后确认工具被正确调用描述类。一层层往下别跳步。6. 把工具调用收口到统一通道下一步怎么走跑通一次完整调用后你会发现真正需要长期维护的不是工具函数本身而是鉴权和通道的稳定性。工具会越加越多MCP Server 会越起越多如果每个都各自管 Key、各自配 Base URL迟早乱套。把模型访问统一到 TaoToken 的 API 通道上所有 Agent 和 MCP 服务共用一套三件套Base URL Key Model ID是让链路可维护的关键一步。具体动作上短期编码和 Agent 调试可以走 Coding Plan把模型调用额度集中管理需要验证某个模型在工具调用上的表现时用模型对话快速试接入细节和参数对照查接入文档。Key 在 API Keys 页面统一生成和轮换别在代码里散落硬编码。下一步可以做的把 MCP Server 从本地127.0.0.1迁到内网可访问的地址让多个客户端共享给工具加一层参数校验避免模型传错类型导致工具内部异常把tool_calls的执行轨迹落库方便回溯每次调用的 token 消耗和耗时。这些都是在「跑通」之后让工具调用真正可用的工程化动作。