1. 为什么 Doris MCP + LangChain 值得你花一个下午跑通
如果你手上已经有一套 Apache Doris 集群,TPC-H 或者业务表都躺在里面,但每次取数还得写 SQL、找字段注释、跟业务方来回确认口径,那 Doris MCP + LangChain 这套组合就是为你准备的。它要做的事情很直接:把「自然语言 → Doris SQL → 执行 → 带业务解读的结果」这条链路串起来,让你用一句话就能问出「哪个客户下单最多」这种问题,而不是先翻三张表的 schema。
Doris 本身是 MPP 架构的实时分析数据库,向量化执行引擎在 PB 级数据上也能做到秒级响应,这是它能扛住 AI 问数背后高频查询的前提。LangChain 负责的是 Agent 编排:把大模型、工具调用、提示词模板拼成一个可执行链路。而 MCP(Model Context Protocol)是中间那层标准化接口,让 LangChain 不用为 Doris 单独写一堆 Connector,直接通过 MCP Server 暴露的工具就能拿到库表信息、执行 SQL。
这套方案适合谁?三类人最合适:一是已有 Doris 数据源、想快速验证 AI 问数可行性的数据开发;二是正在学 LangChain Agent、想找一个真实数据库场景练手的工程师;三是团队里负责数据平台、想给业务方做一个「能对话的取数入口」的人。整条链路跑通不需要你改 Doris 源码,也不需要自己维护元数据映射,配置量集中在两个文件和一个 Key 上。
我试过把这套流程从零搭一遍,卡点基本都在 Key 配置和 MCP 连通性上,所以下面会把 TaoToken 统一 Key 的配置骨架、三步验证动作写清楚,你照着复制就能复现。
2. TaoToken 统一 Key:一处配置,LangChain 与 MCP 共用
在原始方案里,LangChain 侧要配 DeepSeek 或其它模型的 API Key,MCP Server 侧要配 Doris 的连接信息,两边 Key 管理是分开的。如果你后面还要接 Claude Code、Cursor 或者别的 Agent 工具,Key 会散落在多个配置文件里,换一次 Key 要改一圈。
TaoToken 在这里的角色是统一入口:它提供兼容 OpenAI 协议的 API 端点,LangChain 的init_chat_model可以直接指向它,MCP 侧如果涉及模型调用也能复用同一个 Key。这样你只需要维护一份 Key,配置集中在config.toml和settings.json两个文件里。
先拿 Key。访问控制台创建 API Key:
https://taotoken.net/console?utm_source=taotoken_aicg_blog_end&utm_medium=csdn&utm_campaign=rewrite&utm_content=console创建后在 API Keys 页面复制,格式通常是sk-开头的一串。这个 Key 同时用于 LangChain 的模型调用和后续 MCP 工具链里的模型请求。
接入文档在这里,配置项含义可以对照查:
https://taotoken.net/doc?utm_source=taotoken_aicg_blog_end&utm_medium=csdn&utm_campaign=rewrite&utm_content=docAPI 基础地址是:
https://taotoken.net/api注意这个地址不加 UTM 参数,直接作为base_url使用。LangChain 的 OpenAI 兼容接口会在这个地址后面拼/v1/chat/completions,所以你在配置里填https://taotoken.net/api即可,不要手动加/v1。
2.1 config.toml 配置骨架
config.toml放在项目根目录,用于 LangChain 侧读取模型配置:
[llm] provider = "openai" model = "claude-3-5-sonnet" base_url = "https://taotoken.net/api" api_key = "sk-你的TaoTokenKey" temperature = 0.2 max_tokens = 4096 [mcp] server_name = "doris_mcp_server" transport = "streamable_http" url = "http://localhost:3000/mcp" timeout = 30 [doris] host = "127.0.0.1" port = 9030 user = "root" password = "你的Doris密码" database = "tpch"temperature设 0.2 是为了让 SQL 生成更稳定,问数场景不需要太高的创造性。max_tokens给 4096 是因为 Doris 表结构信息加上查询结果可能比较长。
2.2 settings.json 配置骨架
settings.json用于 MCP Server 侧和部分工具链读取,字段和config.toml对应但格式是 JSON:
{ "llm": { "provider": "openai", "model": "claude-3-5-sonnet", "base_url": "https://taotoken.net/api", "api_key": "sk-你的TaoTokenKey" }, "mcp": { "server_name": "doris_mcp_server", "transport": "streamable_http", "url": "http://localhost:3000/mcp" }, "doris": { "host": "127.0.0.1", "port": 9030, "user": "root", "password": "你的Doris密码", "database": "tpch" } }两个文件里的api_key填同一个 TaoToken Key。如果你用环境变量管理,可以把 Key 写成${TAOTOKEN_API_KEY},然后在.env里定义,避免明文提交到仓库。
注意:
base_url只填到https://taotoken.net/api,不要写成https://taotoken.net/api/v1,否则 LangChain 会拼出/api/v1/v1/chat/completions导致 404。
3. 可复制配置:Doris MCP Server 与 LangChain 链路搭建
配置骨架有了,接下来把 MCP Server 跑起来,再写 LangChain 侧的调用代码。这一步的目标是让 MCP 工具能被 LangChain 发现并调用。
3.1 启动 Doris MCP Server
先把 MCP Server 克隆到本地并安装依赖:
git clone https://github.com/apache/doris-mcp-server.git cd doris-mcp-server pip install -r requirements.txt配置 Doris 连接信息,编辑.env:
cp .env.example .env vim .env填入:
DORIS_HOST=127.0.0.1 DORIS_PORT=9030 DORIS_USER=root DORIS_PASSWORD=你的Doris密码 DORIS_DATABASE=tpch启动服务:
./start_server.sh &看到Uvicorn running on http://0.0.0.0:3000就说明 MCP Server 起来了。这个 3000 端口就是config.toml里mcp.url对应的地址。
3.2 LangChain 侧读取配置并初始化 Agent
Python 版本需要 >= 3.12。依赖装这些:
pip install langchain langchain-community langchain-openai langchain-mcp-adapters python-dotenv aiohttp aiofiles tomli下面是读取config.toml并初始化 Agent 的核心代码:
import asyncio import tomli from langchain.agents import AgentExecutor, create_openai_tools_agent from langchain.chat_models import init_chat_model from langchain.prompts import ChatPromptTemplate from langchain_mcp_adapters.client import MultiServerMCPClient def load_config(path="config.toml"): with open(path, "rb") as f: return tomli.load(f) async def build_agent(): cfg = load_config() llm_cfg = cfg["llm"] mcp_cfg = cfg["mcp"] mcp_client = MultiServerMCPClient({ mcp_cfg["server_name"]: { "transport": mcp_cfg["transport"], "url": mcp_cfg["url"], } }) tools = await mcp_client.get_tools() if not tools: raise RuntimeError("MCP 工具加载为空,检查 MCP Server 是否启动") llm = init_chat_model( model=llm_cfg["model"], model_provider=llm_cfg["provider"], api_key=llm_cfg["api_key"], base_url=llm_cfg["base_url"], temperature=llm_cfg["temperature"], ) prompt = ChatPromptTemplate.from_messages([ ("system", "你是 Doris 问数助手,先调用工具获取库表信息,再生成 SQL 并执行,最后给出业务解读。"), ("human", "{input}"), ("placeholder", "{agent_scratchpad}"), ]) agent = create_openai_tools_agent(llm, tools, prompt) return AgentExecutor(agent=agent, tools=tools, verbose=True, max_iterations=3) async def main(): executor = await build_agent() result = await executor.ainvoke({"input": "当前 Doris 有哪些库表?"}) print(result["output"]) if __name__ == "__main__": asyncio.run(main())这段代码和原始方案的区别在于:模型配置从config.toml读取,base_url指向 TaoToken,Key 只维护一份。max_iterations=3是防止 Agent 在工具调用上死循环,问数场景一般两轮内就能出结果。
3.3 关键参数对照
| 参数 | 作用 | 建议值 |
|---|---|---|
transport | MCP 通信方式 | streamable_http |
url | MCP Server 地址 | http://localhost:3000/mcp |
temperature | 模型随机性 | 0.2 |
max_iterations | Agent 最大工具调用轮数 | 3 |
base_url | TaoToken API 地址 | https://taotoken.net/api |
4. 三步验证:从 MCP 连通性到问数结果比对
配置写完不代表链路通了,按下面三步验证,每步都有明确的成功标志。
4.1 第一步:MCP 工具连通性检查
先单独验证 MCP Server 是否暴露了工具。写一个最小脚本:
import asyncio from langchain_mcp_adapters.client import MultiServerMCPClient async def check(): client = MultiServerMCPClient({ "doris_mcp_server": { "transport": "streamable_http", "url": "http://localhost:3000/mcp", } }) tools = await client.get_tools() print(f"发现 {len(tools)} 个工具") for t in tools: print("-", t.name) asyncio.run(check())成功标志:输出工具数量大于 0,且能看到类似get_db_list、execute_sql这样的工具名。如果输出 0 个工具,先检查 MCP Server 日志里有没有报 Doris 连接失败。
4.2 第二步:LangChain 链路调用
用 3.2 的代码跑一次当前 Doris 有哪些库表?。成功标志:控制台打印出库表列表,且verbose=True下能看到 Agent 调用了 MCP 工具。这一步验证的是 LangChain → TaoToken → 模型 → MCP 工具这条完整链路。
如果报401,检查api_key是否填对;如果报404,检查base_url是否多写了/v1;如果报Connection refused,检查 MCP Server 是否还在运行。
4.3 第三步:问数结果比对
最后用一句自然语言查询验证端到端效果:
result = await executor.ainvoke({ "input": "请切换到 tpch 库,分析哪个客户下单最多" }) print(result["output"])成功标志:Agent 自动生成 Doris SQL、执行查询、返回客户名称和订单数,并附带业务解读。为了确认结果可信,你可以手动在 Doris 里跑一遍对应的 SQL 比对:
SELECT c_name, COUNT(*) AS order_count FROM tpch.orders o JOIN tpch.customer c ON o.o_custkey = c.c_custkey GROUP BY c_name ORDER BY order_count DESC LIMIT 1;两边结果一致,说明问数链路从配置到出数全程可复现。
5. 本篇常见错排查
5.1 MCP Server 启动后工具列表为空
最常见的原因是.env里 Doris 连接信息不对。MCP Server 启动时如果连不上 Doris,工具注册会失败但进程不一定退出。检查DORIS_HOST、DORIS_PORT、DORIS_USER、DORIS_PASSWORD四项,确认 Doris FE 的 9030 端口可以从本机访问。
5.2 LangChain 报 base_url 相关 404
TaoToken 的 API 地址是https://taotoken.net/api,LangChain 的 OpenAI 兼容层会自动拼/v1/chat/completions。如果你在config.toml里写成https://taotoken.net/api/v1,最终请求路径会变成/api/v1/v1/chat/completions,返回 404。改回不带/v1的地址即可。
5.3 Agent 不调用工具直接回答
如果模型没有调用 MCP 工具,而是直接编造了一个答案,通常是 system prompt 不够明确。把 system prompt 改成「必须先调用工具获取库表信息,再生成 SQL,禁止凭记忆回答」,并把temperature降到 0.1。另外确认tools列表非空,空工具列表下 Agent 只能靠模型自身知识回答。
5.4 查询结果与手动 SQL 不一致
先确认 Agent 生成的 SQL 里库名和表名是否正确。Doris 里跨库查询需要写全库名.表名,如果 Agent 只写了表名,可能查到了默认库。可以在 system prompt 里加上「生成 SQL 时必须带库名前缀」。另外检查tpch数据是否完整导入,TPC-H 的orders和customer表数据量对不上会导致结果偏差。
5.5 长时间无响应或超时
MCP 的timeout默认 30 秒,如果 Doris 查询本身较慢,可以调到 60。LangChain 侧如果max_iterations设得过大,Agent 可能反复调用工具,建议保持 3。TaoToken 侧如果模型响应慢,可以在config.toml里换一个更轻量的模型做问数场景。
6. 继续往下走:从跑通到日常使用
三步验证跑通之后,这套系统就可以进入日常使用了。如果你主要用它做交互式问数,可以直接在模型对话页面测试不同问法,观察 Agent 的工具调用策略:
https://taotoken.net/model-chat?utm_source=taotoken_aicg_blog_end&utm_medium=csdn&utm_campaign=rewrite&utm_content=model-chat如果你打算把问数能力接到长期运行的编码或 Agent 工作流里,比如让 Claude Code 通过 MCP 直接查 Doris,那 Key 的稳定性和额度管理就比单次调用更重要,可以看 Coding Plan:
https://taotoken.net/coding-plan?utm_source=taotoken_aicg_blog_end&utm_medium=csdn&utm_campaign=rewrite&utm_content=coding-planKey 管理和新建入口在控制台:
https://taotoken.net/console?utm_source=taotoken_aicg_blog_end&utm_medium=csdn&utm_campaign=rewrite&utm_content=consoleAPI Keys 页面:
https://taotoken.net/api-keys?utm_source=taotoken_aicg_blog_end&utm_medium=csdn&utm_campaign=rewrite&utm_content=api-keys接入文档:
https://taotoken.net/doc?utm_source=taotoken_aicg_blog_end&utm_medium=csdn&utm_campaign=rewrite&utm_content=docClaude Code 接入说明:
https://taotoken.net/ClaudeCodeAnthropic?utm_source=taotoken_aicg_blog_end&utm_medium=csdn&utm_campaign=rewrite&utm_content=ClaudeCodeAnthropic最后留一个实操建议:把config.toml和settings.json里的 Key 换成环境变量引用,然后在.gitignore里加上.env。问数系统跑通只是第一步,Key 不泄露、配置可复现,才能让这套链路在团队里真正用起来。