☰
LLM基础知识(二):从Function Calling到MCP,用TaoToken统一Key打通LangChain工具链
2026/10/2 6:19:55 网站建设 项目流程

1. 从 Function Calling 到 MCP:为什么你的 LangChain 工具链总在“换模型就崩”

如果你正在用 LangChain 搭 Agent,大概率踩过这个坑:本地用 GPT-4 跑得好好的 Function Calling,换成另一个模型后工具调用直接失效,要么不返回tool_calls,要么返回的 JSON 格式对不上,整个链路推倒重来。这不是你的代码问题,而是 Function Calling 本身就是“模型私有方言”——每个厂商对工具调用的训练方式、输出格式、触发时机都不一样。

Function Calling 的本质,是模型在训练阶段被喂了大量“何时调用函数、怎么输出结构化参数”的样本,推理时一旦命中触发条件,就吐出预定义格式的 JSON,比如{"name": "get_weather", "arguments": {"city": "北京"}}。程序解析这段 JSON,去执行真实工具,再把结果塞回上下文让模型生成自然语言回答。问题在于:这套“方言”是模型自带的,换模型就等于换语言,LangChain 里写死的bind_tools逻辑经常要跟着改。

MCP(Model Context Protocol)想解决的就是这个碎片化问题。它把提示词、上下文资源、工具调用统一封装成一套协议,工具以 Server 形式暴露能力(Tools / Resources / Prompts / Sampling / Roots 五类),客户端按标准协议去发现和调用。模型不再需要“天生会调用工具”,而是由 MCP Client 负责把工具列表喂给模型、解析模型输出、执行工具、回传结果。这样一来,工具链和模型解耦了:同一个 MCP Server,GPT、Claude、国产模型都能接。

但现实是,你手头往往同时有好几个模型的 Key,测试阶段来回切换,管理成本极高。我试过把不同厂商的 Key 散落在.env、settings.json、auth.json里,结果一个环境变量名写错,排查半小时。所以这篇的核心思路是:用 TaoToken 的统一 Key 作为模型入口,把 LangChain 的工具链和 MCP 协议串起来,让你换模型时只改一个base_url和model字段,工具定义、MCP Server、Agent 逻辑全部不动。

适合谁看:已经写过基础 LangChain Chain、想搞懂 Function Calling 和 MCP 区别、准备把工具链做成可插拔架构的开发者。读完你能拿到一份可复制的配置片段、一段能跑通的 LangChain 工具调用代码,以及一次真实的验证请求结果。

2. TaoToken 统一 Key 前置准备:一个入口管住所有模型

在动手写 LangChain 之前,先把模型入口统一掉。TaoToken 的作用是提供一个兼容 OpenAI 接口规范的统一入口,你拿一个 Key,就能在同一个base_url下调用不同模型。对 LangChain 来说,这意味着ChatOpenAI这类基于 OpenAI 协议的封装可以直接复用,不用为每个厂商装一套 SDK。

先注册并拿到 Key。访问官网 https://taotoken.net/?utm_source=taotoken_aicg_blog_end&utm_medium=csdn&utm_campaign=rewrite&utm_content= 完成账号注册,然后进控制台创建 API Key。控制台地址是 https://taotoken.net/console?utm_source=taotoken_aicg_blog_end&utm_content=console&utm_campaign=rewrite ,Key 列表在 https://taotoken.net/api-keys?utm_source=taotoken_aicg_blog_end&utm_content=api-keys&utm_campaign=rewrite 。创建时建议给 Key 起个能认出来的名字,比如langchain-tools-dev,方便后面区分测试和生产。

拿到 Key 之后,记住两个地址:

  • API 基地址:https://taotoken.net/api(注意这个不加 UTM 参数,直接用于代码里的base_url)
  • 模型对话入口:https://taotoken.net/models?utm_source=taotoken_aicg_blog_end&utm_content=models&utm_campaign=rewrite ,用来确认当前可用的模型 ID

这里有个关键点:LangChain 的ChatOpenAI默认会往https://api.openai.com/v1发请求,你要做的是把base_url指向 TaoToken 的 API 地址,并把api_key换成 TaoToken 的 Key。因为 TaoToken 兼容 OpenAI 的/v1/chat/completions协议,所以 LangChain 侧几乎零改动。

环境变量建议这样组织,避免 Key 硬编码进代码:

# .env 文件 TAOTOKEN_API_KEY=sk-你的TaoToken密钥 TAOTOKEN_BASE_URL=https://taotoken.net/api

然后在 Python 里用python-dotenv加载。这样做的好处是,后面无论你切到 Claude Code、Cline 还是 Codex,都从同一个环境变量读 Key,不会出现“这个工具配了、那个工具忘了”的情况。

如果你用的是 Claude Code 这类 CLI 工具,配置方式略有不同,它读的是settings.json。但核心三件套是一样的:Base URL、API Key、Model ID。这三样配齐,工具才能正常发起请求。很多人报401或者local proxy failed,八成是这三件套里缺了一个或者写错了。

另外提醒一句:TaoToken 是模型调用入口,不是编辑器替代品,也不要用它去直连生产数据库。工具链里的数据库操作,应该由你自己的 MCP Server 或后端服务去执行,模型只负责决定“调哪个工具、传什么参数”。

3. 可复制配置:LangChain + TaoToken + MCP 工具链最小骨架

这一节给你一份能直接抄的配置和代码。目标是把 LangChain 的ChatOpenAI指向 TaoToken,定义一个工具,跑通一次 Function Calling,并预留 MCP 接入位。

先装依赖:

pip install langchain langchain-openai python-dotenv mcp

然后是核心配置。这里用ChatOpenAI作为模型客户端,base_url指向 TaoToken:

import os import json from dotenv import load_dotenv from langchain_openai import ChatOpenAI from langchain_core.tools import tool load_dotenv() llm = ChatOpenAI( model="gpt-4o-mini", # 换成 TaoToken 模型对话页里可用的模型 ID api_key=os.getenv("TAOTOKEN_API_KEY"), base_url=os.getenv("TAOTOKEN_BASE_URL"), temperature=0, )

注意model字段,它必须和 TaoToken 模型对话页里列出的 ID 一致。写错了会报model not found,而不是401,这两个错误要分清。

接下来定义一个工具。LangChain 用@tool装饰器把普通函数变成模型可调用的工具:

@tool def get_weather(city: str) -> str: """查询指定城市的当前天气。city 参数是城市名称,例如 北京。""" # 这里用模拟数据,真实场景替换成你的 API 调用 fake_db = { "北京": {"temp": 22, "desc": "晴朗"}, "上海": {"temp": 26, "desc": "多云"}, } data = fake_db.get(city, {"temp": 20, "desc": "未知"}) return json.dumps({"city": city, **data}, ensure_ascii=False)

把工具绑定到模型上,这一步就是 Function Calling 的入口:

tools = [get_weather] llm_with_tools = llm.bind_tools(tools) response = llm_with_tools.invoke("北京今天天气怎么样?") print(response.tool_calls)

如果模型支持 Function Calling,response.tool_calls会返回一个列表,里面包含工具名和参数,类似:

[{'name': 'get_weather', 'args': {'city': '北京'}, 'id': 'call_xxx', 'type': 'tool_call'}]

拿到这个之后,LangChain 的 Agent 执行器会自动去调用get_weather,把结果回传。如果你想手动控制,可以自己解析tool_calls并执行。

现在说 MCP 的接入位。MCP 的价值在于把工具从“代码里写死”变成“协议里发现”。一个 MCP Server 启动后,会通过标准协议暴露工具列表,Client 拿到列表后转成 LangChain 的 tool 格式,再bind_tools。这样你新增工具只需要改 MCP Server,不用动 Agent 代码。

一个最小的 MCP Server 配置(以 stdio 方式启动)大概长这样,放在mcp_config.json里:

{ "mcpServers": { "weather-server": { "command": "python", "args": ["weather_mcp_server.py"], "env": { "TAOTOKEN_API_KEY": "sk-你的TaoToken密钥", "TAOTOKEN_BASE_URL": "https://taotoken.net/api" } } } }

注意这里把 TaoToken 的 Key 和 Base URL 通过env传给 MCP Server,这样 Server 内部如果需要调用模型(比如 Sampling 能力),也能走统一入口。三件套 Base URL、Key、Model ID 在 MCP Server 里同样要配齐,缺一个就会在启动时报错。

如果你用的是 Cline 或 Claude Code 这类支持 MCP 的客户端,配置文件的路径和字段名会不同,但结构一致:一个mcpServers对象,里面每个 Server 有command、args、env。Cline 的 MCP 配置在设置面板里,Claude Code 读的是项目根目录的.mcp.json。不管哪个,TaoToken 的 Key 都放在env里,不要写死在代码中。

4. 验证请求:一次真实的工具调用链路跑通

配置写完,必须验证。很多人卡在“代码看起来对,但就是没反应”,所以这一步给你完整的验证动作和预期结果。

先写一个完整的验证脚本verify_tool_chain.py:

import os import json from dotenv import load_dotenv from langchain_openai import ChatOpenAI from langchain_core.tools import tool from langchain_core.messages import HumanMessage, ToolMessage load_dotenv() llm = ChatOpenAI( model="gpt-4o-mini", api_key=os.getenv("TAOTOKEN_API_KEY"), base_url=os.getenv("TAOTOKEN_BASE_URL"), temperature=0, ) @tool def get_weather(city: str) -> str: """查询指定城市的当前天气。city 参数是城市名称。""" fake_db = { "北京": {"temp": 22, "desc": "晴朗"}, "上海": {"temp": 26, "desc": "多云"}, } data = fake_db.get(city, {"temp": 20, "desc": "未知"}) return json.dumps({"city": city, **data}, ensure_ascii=False) tools = [get_weather] llm_with_tools = llm.bind_tools(tools) # 第一轮:模型决定调用工具 messages = [HumanMessage(content="北京今天天气怎么样?")] ai_msg = llm_with_tools.invoke(messages) print("=== 模型返回的 tool_calls ===") print(ai_msg.tool_calls) # 手动执行工具,模拟 Agent 执行器 if ai_msg.tool_calls: messages.append(ai_msg) for tc in ai_msg.tool_calls: if tc["name"] == "get_weather": result = get_weather.invoke(tc["args"]) messages.append(ToolMessage(content=result, tool_call_id=tc["id"])) # 第二轮:把工具结果回传,模型生成最终回答 final_msg = llm_with_tools.invoke(messages) print("=== 模型最终回答 ===") print(final_msg.content) else: print("模型没有触发工具调用,检查模型是否支持 Function Calling")

运行python verify_tool_chain.py,预期看到两段输出。第一段是tool_calls列表,包含get_weather和{"city": "北京"}。第二段是自然语言回答,类似“北京今天晴朗,气温 22 摄氏度”。

如果第一段是空列表[],说明模型没有触发工具调用。可能原因:模型本身不支持 Function Calling,或者bind_tools没生效。这时候去 TaoToken 模型对话页确认你用的模型 ID 是否支持工具调用。有些轻量模型只支持纯对话,不支持 tools 参数。

如果第二段报错reading 'choices'或类似字段缺失,通常是返回结构不符合预期。先打印原始response看看结构,确认 TaoToken 返回的是标准 OpenAI 格式。正常情况下response.choices[0].message里会有content或tool_calls。

验证通过后,你就有了一个最小可复现链路:TaoToken 提供模型入口,LangChain 负责工具绑定和执行,MCP 负责工具的标准化发现。接下来把get_weather换成真实的 MCP Server 工具,链路照样跑通。

5. 常见报错排查:401、local proxy failed、reading choices、OAuth

这一节对照真实报错,给你排查路径。这些错误我在不同项目里都遇到过,按顺序查基本能定位。

401 Unauthorized:最常见。先确认TAOTOKEN_API_KEY环境变量有没有加载成功。在 Python 里打印os.getenv("TAOTOKEN_API_KEY"),如果是None,说明.env没被读到,检查load_dotenv()是否在读取环境变量之前调用。如果 Key 有值但还是 401,去 TaoToken 控制台的 API Keys 页面确认这个 Key 是否被禁用或删除。还有一种情况是 Key 复制时带了空格,strip()一下。

local proxy failed:这个报错通常出现在 CLI 工具(比如 Claude Code、Cline)里,意思是本地代理配置有问题。检查你的settings.json或 MCP 配置里,base_url是不是写成了https://taotoken.net/api,有没有多写/v1或者少写协议头。另外确认没有配置额外的系统代理,TaoToken 的地址应该直连。如果配置里同时存在旧的代理地址和 TaoToken 地址,删掉旧的。

reading 'choices':这个报错说明代码在解析响应时,response.choices是undefined或null。原因通常是返回的不是标准 OpenAI 格式,或者请求根本没成功但被当成功处理了。先打印完整响应体,看error字段。如果返回的是{"error": {"message": "..."}},那真正的问题是请求失败,choices只是表象。常见触发场景是model字段写错,或者base_url指向了一个不兼容 OpenAI 协议的端点。

OAuth 相关报错:如果你用的是 Claude Code 或 Codex 这类工具,它们可能默认走 OAuth 登录流程。当你配置了 TaoToken 的 Key 后,要确保工具走的是 API Key 认证而不是 OAuth。Claude Code 的settings.json里,apiKey字段要填 TaoToken 的 Key,baseUrl填 TaoToken 地址。Codex 的auth.json里,OPENAI_API_KEY换成 TaoToken Key,OPENAI_BASE_URL换成 TaoToken 地址。如果工具同时存在 OAuth 配置和 API Key 配置,优先走 API Key,把 OAuth 相关字段清掉。

模型不触发工具调用:不是报错,但很常见。tool_calls返回空列表,模型直接给了自然语言回答。先确认模型支持 Function Calling,再检查工具描述是否清晰。@tool装饰器里的 docstring 就是给模型看的工具说明,写得太模糊模型不知道什么时候该调。把参数说明、使用场景写清楚,触发率会明显提升。

MCP Server 启动失败:检查mcp_config.json里的command和args路径是否正确。python命令在有些环境里是python3,路径不对会直接报command not found。另外env里的 TaoToken Key 和 Base URL 要确认传进去了,Server 内部如果调模型,缺 Key 会报 401。

排查顺序建议:先确认 Key 和 Base URL 正确,再确认模型 ID 可用,然后确认工具定义清晰,最后看 MCP Server 是否正常启动。大部分问题在前两步就能解决。

6. 把工具链跑成可插拔架构:下一步怎么走

到这里,你已经有了一个能跑通的链路:TaoToken 统一 Key 提供模型入口,LangChain 负责工具绑定和执行,MCP 负责工具的标准化发现。这套结构最大的好处是解耦——换模型只改model字段,加工具只改 MCP Server,Agent 逻辑不动。

如果你要长期做编码类 Agent,建议把模型调用统一走 Coding Plan,地址是 https://taotoken.net/coding-plan?utm_source=taotoken_aicg_blog_end&utm_content=coding-plan&utm_campaign=rewrite ,这样在多个 CLI 工具之间切换时,Key 和额度管理都在一个地方。接入文档在 https://taotoken.net/doc?utm_source=taotoken_aicg_blog_end&utm_content=doc&utm_campaign=rewrite ,里面有各工具的详细配置示例。如果你只是想先验证模型能力,用模型对话入口 https://taotoken.net/models?utm_source=taotoken_aicg_blog_end&utm_content=models&utm_campaign=rewrite 直接试。

一个实用技巧:把 MCP Server 的工具列表缓存到本地,启动时先拉一次,避免每次请求都去发现工具。LangChain 侧可以用ToolNode配合StateGraph做更复杂的多工具编排,但最小链路先用bind_tools跑通就够了。别一上来就上 LangGraph 的 Supervisor 多 Agent,先把单工具调用跑稳,再逐步加工具、加分支。

最后提醒:工具链里的敏感操作(数据库写入、文件删除、外部 API 调用)一定要加确认机制,不要让模型直接执行。MCP 的 Sampling 能力可以让 Server 反向请求模型做决策,但生产环境里,关键操作还是走人工确认或者权限校验。模型负责“决定调什么”,执行层负责“能不能调”,这两层分开,链路才安全。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询