1. Langgraph 多智能体编排遇上亮数据 MCP:真实开发场景拆解

如果你正在用 Langgraph 搭多智能体系统,大概率会遇到一个很现实的问题:模型调用通道和工具调用通道是两套东西。模型这边你可能用 OpenAI 兼容接口,工具这边又要单独接一个 MCP Server,两边的鉴权、超时、重试策略各写一套,调试的时候日志散落在不同地方,排查一个 401 要翻三个配置文件。

Langgraph 本身是一个状态图驱动的编排框架,它把智能体的执行过程抽象成节点和边,每个节点可以是一个模型调用、一个工具执行、或者一段纯逻辑。亮数据 MCP 提供的是网页数据采集与结构化提取能力,通过 MCP 协议暴露成标准工具,让智能体可以像调用本地函数一样去抓取网页内容。把这两者结合起来,理论上能做出「规划—采集—分析—再规划」的闭环智能体。

但实际落地时,问题往往不在编排逻辑,而在通道管理。Langgraph 的节点里要调模型,模型请求要带 Key;MCP 工具注册后要调远程服务,远程服务也要鉴权。如果每个环节都单独配一套凭证,代码里就会散落各种 os.environ 读取和硬编码,换一个环境就要改一遍。

我试过的一种做法是:把模型调用统一收敛到一个兼容 OpenAI 协议的网关,MCP 工具调用则通过 Langgraph 的 ToolNode 注册,两者共用同一套 Base URL 和 Key 管理策略。这样 Langgraph 图里只需要关心「什么时候调模型、什么时候调工具」,不需要关心「这个请求走哪个通道、带哪个 Key」。

这篇要交付的就是这样一套可跟做的方案:用 TaoToken 作为统一 Key 接入层,Langgraph 负责多智能体编排,亮数据 MCP 作为工具提供方,最后跑通一个端到端的本地验证。适合已经了解 Langgraph 基本概念、正在找统一通道管理方案的开发者。下面从环境准备开始,一步步把配置、代码、验证和排障都过一遍。

2. TaoToken 统一 Key 前置准备:Base URL 与模型通道配置

在动手写 Langgraph 代码之前,先把模型通道的事情理清楚。Langgraph 的节点里调模型,底层通常走 OpenAI 兼容的 ChatOpenAI 或 ChatAnthropic 这类封装。这些封装都支持自定义 base_url 和 api_key,所以只要有一个兼容 OpenAI 协议的网关,就能把模型调用统一收口。

TaoToken 提供的就是这样一个入口。它的 API 地址是 https://taotoken.net/api,兼容 OpenAI 的 /v1/chat/completions 和 Anthropic 的 /v1/messages 两种协议。你需要在控制台创建一个 API Key,然后把它配到环境变量里,Langgraph 节点读取环境变量即可。

具体操作路径:打开 https://taotoken.net/console,登录后在 API Keys 页面创建一个新 Key。创建时注意选择权限范围,如果只是本地验证,给最小权限即可。创建完成后复制 Key,它只会显示一次。

拿到 Key 之后,在项目根目录建一个 .env 文件,写入两行:

TAOTOKEN_API_KEY=sk-你的实际Key
TAOTOKEN_BASE_URL=https://taotoken.net/api

然后在 Python 代码里用 python-dotenv 加载。这里有个细节:Langgraph 的 ChatOpenAI 封装默认会读 OPENAI_API_KEY 和 OPENAI_BASE_URL,但为了避免和本地其他项目冲突,建议显式传参,不要依赖默认环境变量名。

模型 ID 的选择上,TaoToken 的模型列表可以在 https://taotoken.net/models 查看。本地验证阶段建议选一个响应快、成本低的模型,比如 gpt-4o-mini 或 claude-3-5-haiku 这类。把模型 ID 也写进 .env:

TAOTOKEN_MODEL_ID=gpt-4o-mini

这样模型通道的三要素就齐了:Base URL、Key、Model ID。后面 Langgraph 节点里统一从这三个变量构造模型实例,换模型或换 Key 只改 .env,不动代码。

有一点要注意:TaoToken 是合规的 API 接入服务,不要把它和任何非正规通道混为一谈。它的定位就是统一管理模型 Key 和调用通道,让你在 Langgraph 里不用为每个模型单独配一套凭证。如果你需要长期跑编码类 Agent,可以了解下 Coding Plan,它在长会话场景下有更稳定的通道策略。

3. 可复制配置:Langgraph 节点与亮数据 MCP 服务注册

这一节是核心,直接给可复制的代码和配置。先看项目依赖,建一个 requirements.txt:

langgraph>=0.2.0
langchain-openai>=0.2.0
langchain-core>=0.3.0
mcp>=1.0.0
langchain-mcp-adapters>=0.1.0
python-dotenv>=1.0.0
httpx>=0.27.0

安装命令:

pip install -r requirements.txt

接下来是 MCP 服务注册。亮数据 MCP 通过标准 MCP 协议暴露工具,Langgraph 这边用 langchain-mcp-adapters 把 MCP 工具转成 LangChain Tool。先写一个 mcp_config.json,路径放在项目根目录:

{
  "mcpServers": {
    "brightdata": {
      "command": "npx",
      "args": [
        "-y",
        "@brightdata/mcp-server",
        "--api-key",
        "${BRIGHTDATA_API_KEY}"
      ],
      "env": {
        "BRIGHTDATA_API_KEY": "你的亮数据APIKey"
      }
    }
  }
}

注意这里 BRIGHTDATA_API_KEY 是亮数据侧的凭证,和 TaoToken 的 Key 是两回事。亮数据负责网页采集,TaoToken 负责模型调用,两者各管各的鉴权,但在 Langgraph 图里统一编排。

然后是 Langgraph 的节点配置。建一个 agent_graph.py:

import os
from dotenv import load_dotenv
from langchain_openai import ChatOpenAI
from langchain_mcp_adapters.client import MultiServerMCPClient
from langgraph.prebuilt import create_react_agent
from langgraph.graph import StateGraph, END
from typing import TypedDict, Annotated
import operator

load_dotenv()

TAOTOKEN_API_KEY = os.getenv("TAOTOKEN_API_KEY")
TAOTOKEN_BASE_URL = os.getenv("TAOTOKEN_BASE_URL")
TAOTOKEN_MODEL_ID = os.getenv("TAOTOKEN_MODEL_ID")

def build_model():
    return ChatOpenAI(
        model=TAOTOKEN_MODEL_ID,
        api_key=TAOTOKEN_API_KEY,
        base_url=TAOTOKEN_BASE_URL,
        temperature=0,
        timeout=60,
        max_retries=2,
    )

class AgentState(TypedDict):
    messages: Annotated[list, operator.add]

async def build_graph():
    client = MultiServerMCPClient({
        "brightdata": {
            "command": "npx",
            "args": ["-y", "@brightdata/mcp-server"],
            "env": {"BRIGHTDATA_API_KEY": os.getenv("BRIGHTDATA_API_KEY")},
            "transport": "stdio",
        }
    })
    tools = await client.get_tools()
    model = build_model()
    agent = create_react_agent(model, tools)

    graph = StateGraph(AgentState)
    graph.add_node("agent", agent)
    graph.set_entry_point("agent")
    graph.add_edge("agent", END)
    return graph.compile()

这段代码的关键点:ChatOpenAI 显式传 base_url 和 api_key,指向 TaoToken;MCP 工具通过 MultiServerMCPClient 注册,transport 用 stdio 本地拉起;create_react_agent 把模型和工具绑在一起,形成 ReAct 循环。

如果你用的是 Claude Code 或 Cline 这类工具做本地调试,它们的 MCP 配置格式和上面类似,但要注意 settings.json 里的字段名可能不同。Claude Code 的 MCP 配置通常写在 ~/.claude/settings.json,Cline 写在 VS Code 的 settings.json 里,核心三件套还是 Base URL、Key、Model ID,只是外层包装不一样。

4. 端到端验证请求:从 Langgraph 调用到亮数据采集结果

配置写完后,跑一个最小验证脚本 run_agent.py:

import asyncio
from agent_graph import build_graph

async def main():
    graph = await build_graph()
    result = await graph.ainvoke({
        "messages": [
            ("user", "请用亮数据工具抓取 https://example.com 的标题,并总结成一句话。")
        ]
    })
    for msg in result["messages"]:
        print(type(msg).__name__, ":", msg.content)

if __name__ == "__main__":
    asyncio.run(main())

运行:

python run_agent.py

预期输出会分几段:先是 AIMessage 带 tool_calls,表示模型决定调用亮数据工具;然后是 ToolMessage,内容是亮数据返回的网页结构化数据;最后是 AIMessage,内容是模型基于工具结果生成的总结。

如果一切正常,你会看到类似这样的输出:

AIMessage : [tool_call: brightdata_scrape(url='https://example.com')]
ToolMessage : {"title": "Example Domain", "content": "..."}
AIMessage : 该页面标题为 Example Domain,是一个用于示例的保留域名。

这个过程验证了三件事:TaoToken 的模型通道通了,亮数据 MCP 工具注册成功了,Langgraph 的 ReAct 循环能正常调度模型和工具。

如果你想单独验证模型通道,不经过 MCP,可以直接用 curl 打 TaoToken 的接口:

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": "ping"}]
  }'

返回 200 且带 choices 字段,说明 Key 和 Base URL 没问题。这一步能快速区分是模型通道的问题还是 MCP 工具的问题。

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

实际跑的时候,报错基本集中在几个地方。下面按真实报错对照排查。

401 Unauthorized:最常见。先检查 .env 里的 TAOTOKEN_API_KEY 有没有多余空格或换行。然后确认 base_url 是 https://taotoken.net/api,不要漏掉 /api,也不要多加 /v1(ChatOpenAI 会自动拼 /v1/chat/completions)。如果 Key 是在控制台刚创建的,确认没有复制错行。用上面的 curl 单独测一下,能快速定位是 Key 问题还是代码问题。

local proxy failed / connection refused:这个通常出在 MCP 服务拉起阶段。npx -y @brightdata/mcp-server 第一次运行会下载包,如果网络环境导致 npm 拉取失败,就会报连接错误。解决方法是先手动跑一次 npx -y @brightdata/mcp-server --help,确认包能正常下载。另外检查 mcp_config.json 里的 env 字段,BRIGHTDATA_API_KEY 要填真实值,不能留占位符。

reading 'choices' of undefined:这个报错说明请求发出去了,但返回体里没有 choices 字段。常见原因是模型 ID 写错了,或者 Base URL 指向了一个不兼容 OpenAI 协议的端点。检查 TAOTOKEN_MODEL_ID 是否在 TaoToken 的模型列表里,以及 base_url 是否以 /api 结尾。如果返回体是 {"error": ...},把完整错误打出来看。

OAuth 相关报错:如果你在 Claude Code 或 Cline 里配 MCP,可能会遇到 OAuth token 过期或 scope 不足的提示。这类问题不在 TaoToken 侧,而在 MCP 客户端侧。检查 settings.json 里的 MCP server 配置,确认 command 和 args 路径正确,env 里的 Key 没有过期。Claude Code 的配置里如果同时有 baseUrl 和 apiKey,确认它们指向的是 TaoToken 而不是其他地址。

工具调用死循环:Langgraph 的 ReAct agent 有时会反复调同一个工具。这通常是模型对工具返回结果不满意,或者工具返回格式不符合预期。可以在 create_react_agent 里加 max_iterations 限制,或者在 prompt 里明确告诉模型「如果工具返回结果已足够,直接总结,不要重复调用」。

排查顺序建议:先 curl 测模型通道,再单独测 MCP 工具,最后跑 Langgraph 全链路。这样能把问题范围快速缩小到某一层。

6. 语义一致 CTA:统一 Key 接入与后续调试入口

模型通道和 MCP 工具都跑通之后,日常调试主要围绕两件事:换模型和加工具。换模型只改 .env 里的 TAOTOKEN_MODEL_ID,Langgraph 代码不动。加工具则在 mcp_config.json 里追加一个 server 配置,MultiServerMCPClient 会自动把新工具注册进来。

如果你在排障阶段需要反复验证 Key 和通道,可以直接用模型对话页面发一条测试消息,比跑完整 Langgraph 图快很多。接入文档里有各语言 SDK 的配置示例,包括 Python、Node.js 和 curl,对照着改 base_url 和 api_key 就行。

长期跑编码类 Agent 的话,Coding Plan 在长会话和工具调用密集场景下有更稳的通道策略,适合把 Langgraph 图跑在生产环境。API Keys 页面可以管理多个 Key,按项目或环境分开,避免一个 Key 泄露影响所有服务。

最后留一个实用技巧:在 Langgraph 的 AgentState 里加一个 debug 字段,把每次模型请求的 model 和 base_url 记下来,出问题时直接看日志,不用猜请求走了哪个通道。这个字段不影响图逻辑,但排障时能省很多时间。

Logo

更多推荐