☰
RAGFlow 系列教程 第18课:工具系统与 MCP 集成——从 Function Calling 到动态工具扩展的 TaoToken 配置骨架
2026/9/28 18:16:19 网站建设 项目流程

1. 为什么工具系统总在“最后一公里”掉链子

RAGFlow 的工具系统与 MCP 集成,说白了就是让大模型从“只会聊天”变成“能动手干活”。Function Calling 负责让模型表达“我想调用哪个工具、传什么参数”,MCP 负责把外部工具服务器动态挂进来,而工具系统本身负责注册、校验、执行、回传结果。三者串起来,才是一条完整的动态工具扩展链路。

但真正动手时,问题往往不在架构图,而在配置。RAGFlow 的 Agent 画布能识别工具,可模型请求要发出去、工具调用要收回来,中间必须有一条稳定的 API 通道。很多同学卡在这里:本地工具能跑,一接远程模型就报 401;MCP 服务器连上了,工具列表却拉不下来;config.toml 和 settings.json 两个文件到底谁管谁,改错一个就整条链路失效。

这篇是 RAGFlow 系列教程第 18 课的实操版,聚焦工具系统与 MCP 集成场景,把 Function Calling 到动态工具扩展的链路拆开。我会给出 TaoToken 统一 Key/API 通道在 config.toml 与 settings.json 中的可复制配置骨架,再演示一次工具注册与调用验证动作。适合已经在用 RAGFlow Agent、想接 MCP 做动态工具扩展、但被配置和报错卡住的开发者。读完你能跑通一条最小可用的动态工具扩展流程,而不是只停留在看架构图。

2. TaoToken 在工具链路里扮演什么角色

RAGFlow 的工具调用链路里,模型是决策者,工具是执行者,而模型请求必须走一个兼容 OpenAI Function Calling 格式的 API 端点。TaoToken 在这里提供的就是这条统一通道:一个 Key、一个 API 地址,同时覆盖模型对话、Coding Plan、控制台和 API Keys 管理。对 RAGFlow 来说,它就是一个标准的 OpenAI 兼容端点,工具系统生成的 function 定义能直接被模型消费。

先把入口理清楚,后面配置才不会乱:

  • 官网入口:https://taotoken.net/?utm_source=taotoken_aicg_blog_end&utm_medium=csdn&utm_campaign=rewrite&utm_content=
  • API 基址:https://taotoken.net/api (这个不加 UTM,直接填进配置)
  • 模型对话:https://taotoken.net/models?utm_source=taotoken_aicg_blog_end&utm_campaign=rewrite
  • Coding Plan:https://taotoken.net/coding-plan?utm_source=taotoken_aicg_blog_end&utm_campaign=rewrite
  • 控制台:https://taotoken.net/console?utm_source=taotoken_aicg_blog_end&utm_campaign=rewrite
  • API Keys:https://taotoken.net/api-keys?utm_source=taotoken_aicg_blog_end&utm_campaign=rewrite
  • 接入文档:https://taotoken.net/doc?utm_source=taotoken_aicg_blog_end&utm_campaign=rewrite
  • ClaudeCodeAnthropic:https://taotoken.net/claude-code-anthropic?utm_source=taotoken_aicg_blog_end&utm_campaign=rewrite

注意:RAGFlow 里模型配置和工具配置是两套东西。模型走的是 LLM API,工具走的是工具自身的 API Key(比如 Tavily)或 MCP 服务器地址。TaoToken 解决的是前者,别把两者混在一个字段里。

我试过把 TaoToken 的 Key 同时用在模型对话和 Coding Plan 场景,RAGFlow 侧只需要保证 base_url 指向https://taotoken.net/api,模型名填控制台里可用的即可。工具系统那边,Function Calling 的格式转换由 RAGFlow 的get_meta()自动完成,你不需要手写 OpenAI 的 function schema。

3. config.toml 与 settings.json 的可复制配置骨架

RAGFlow 的配置分两层:config.toml管服务级参数,settings.json管运行时模型和工具相关设置。工具系统与 MCP 集成要动的主要是这两处。下面给的是骨架,字段名以你本地版本为准,重点是结构和位置。

3.1 config.toml 里的模型与沙箱段

# config.toml 片段:模型通道 + 沙箱执行 [llm] base_url = "https://taotoken.net/api" api_key = "sk-你的TaoTokenKey" model = "你的可用模型名" timeout = 120 [sandbox] # CodeExec 工具依赖沙箱,默认走自管理 Docker host = "127.0.0.1" port = 9385 provider = "self_managed" exec_timeout = 600 [mcp] # MCP 会话相关,SSE 与 Streamable HTTP 双传输 enable = true default_timeout = 10 max_sessions = 8

这里[llm]段是工具调用能发出去的前提。base_url必须是https://taotoken.net/api,不要带尾部斜杠,也不要带 UTM 参数。api_key从 API Keys 页面拿。[sandbox]段对应 CodeExec 工具,如果你暂时不跑代码执行,可以先不启用,但 MCP 工具里如果有代码类工具,沙箱必须通。

3.2 settings.json 里的工具与 MCP 注册

{ "llm": { "base_url": "https://taotoken.net/api", "api_key": "sk-你的TaoTokenKey", "model": "你的可用模型名" }, "tools": { "enabled": ["Retrieval", "TavilySearch", "DuckDuckGo", "CodeExec"], "tavily": { "api_key": "tvly-你的TavilyKey", "search_depth": "basic", "max_results": 6 } }, "mcp_servers": [ { "name": "local-tools", "server_type": "streamable_http", "url": "http://127.0.0.1:8000/mcp", "headers": {}, "variables": {} } ] }

tools.enabled决定哪些内置工具参与 Function Calling 格式转换。mcp_servers数组里每一项对应一个 MCP 服务器,server_type支持sse和streamable_http两种。variables用于 URL 或 header 里的变量模板替换,比如把 token 抽出来。

提示:config.toml和settings.json里如果都写了base_url,以运行时加载的settings.json为准。改完记得重启 RAGFlow 服务,热加载不一定生效。

3.3 工具注册的自动发现机制

RAGFlow 的工具注册靠agent/tools/__init__.py的动态导入:扫描目录下所有.py文件,排除__开头和base.py,用inspect.getmembers()提取公开类注册进__all_classes。这意味着你新增一个工具文件,只要继承ToolBase并定义好ToolParamBase,放进目录就会被发现,不需要手动注册。

# agent/tools/my_tool.py 最小骨架 from abc import ABC from agent.tools.base import ToolMeta, ToolParamBase, ToolBase from common.connection_utils import timeout class MyToolParam(ToolParamBase): def __init__(self): self.meta: ToolMeta = { "name": "my_tool_name", "description": "工具功能描述,LLM 据此决定是否调用", "parameters": { "param1": { "type": "string", "description": "参数说明", "required": True, }, }, } super().__init__() self.custom_config = "default_value" def check(self): self.check_empty(self.custom_config, "Custom Config") class MyTool(ToolBase, ABC): component_name = "MyTool" @timeout(60) def _invoke(self, **kwargs): query = kwargs.get("param1", self._param.param1) result = do_something(query) self.set_output("content", str(result)) return self.output()

get_meta()会把ToolMeta转成 OpenAI Function Calling 格式,MCP 工具则通过mcp_tool_metadata_to_openai_tool()做同样的转换。两条路径最终都汇到LLMToolPluginCallSession的tools_map里,本地工具和 MCP 会话共存,靠isinstance区分调用方式。

4. 一次工具注册与调用验证动作

配置写完,得验证链路真的通。下面这套动作从工具列表拉取到实际调用,覆盖本地工具和 MCP 工具两条路径。

4.1 验证模型通道与 Function Calling 格式

先确认模型能正常返回 tool_calls。用 curl 直接打 TaoToken 的 API,带上一个简单的 function 定义:

curl -s https://taotoken.net/api/chat/completions \ -H "Authorization: Bearer sk-你的TaoTokenKey" \ -H "Content-Type: application/json" \ -d '{ "model": "你的可用模型名", "messages": [{"role": "user", "content": "北京天气怎么样"}], "tools": [{ "type": "function", "function": { "name": "get_weather", "description": "查询指定城市天气", "parameters": { "type": "object", "properties": {"city": {"type": "string"}}, "required": ["city"] } } }], "tool_choice": "auto" }'

如果返回体里出现tool_calls字段,且function.name是get_weather,说明模型通道和 Function Calling 格式都没问题。这一步不通,后面工具系统再对也没用。

4.2 验证 MCP 工具列表拉取

MCP 会话通过get_tools()同步拉取工具列表,底层是asyncio.run_coroutine_threadsafe()桥接到独立事件循环。你可以在 RAGFlow 的 Python 环境里跑一段验证:

# 验证 MCP 工具列表 from common.mcp_tool_call_conn import MCPToolCallSession from common.mcp_tool_call_conn import mcp_tool_metadata_to_openai_tool session = MCPToolCallSession( mcp_server=type("S", (), { "url": "http://127.0.0.1:8000/mcp", "server_type": "streamable_http", "headers": {} })() ) tools = session.get_tools(timeout=10) print("MCP 工具数量:", len(tools)) for t in tools: openai_tool = mcp_tool_metadata_to_openai_tool(t) print(openai_tool["function"]["name"], "->", openai_tool["function"]["description"])

正常输出会列出 MCP 服务器暴露的所有工具名和描述。如果这里报ValueError或超时,先查 MCP 服务器本身是否在跑,再查server_type是否和服务器实现匹配。

4.3 验证一次完整工具调用

工具列表拿到后,走一次tool_call:

# 验证 MCP 工具调用 result = session.tool_call( name="your_tool_name", arguments={"param1": "test_value"}, timeout=10 ) print("调用结果:", result)

本地工具的验证更直接,在 Agent 画布上挂一个Retrieval或DuckDuckGo,发一条会触发工具的消息,看画布引用区是否出现 chunk。_retrieve_chunks()会把搜索结果统一格式化并注入画布引用,这是判断工具是否真正执行成功的直观信号。

4.4 成功结果的判断标准

一次成功的动态工具扩展,应该同时满足:模型返回了正确的tool_calls;LLMToolPluginCallSession.tool_call()没有抛assert name in self.tools_map;工具执行结果通过callback记录到了工具名、参数、结果和耗时;画布引用区或对话上下文里出现了工具返回的内容。四个都满足,链路才算通。

5. 本篇常见错排查

5.1 401 或模型不可用

最常见的是base_url写错。必须是https://taotoken.net/api,不能带/v1后缀,也不能带 UTM 参数。api_key确认从 API Keys 页面复制完整,没有多余空格。如果config.toml和settings.json都配了,检查运行时实际加载的是哪个。

5.2 MCP 工具列表为空

先确认 MCP 服务器进程在跑,端口对得上。server_type填sse但服务器只支持streamable_http,或者反过来,都会导致initialize()超时。headers里如果需要鉴权,确认变量模板替换后的值正确。max_sessions太小、并发拉取时也会失败。

5.3 工具调用报 name does not exist

LLMToolPluginCallSession的tools_map里没有这个工具名。可能是工具没被自动发现(文件名以__开头或叫base.py),也可能是 MCP 工具列表没拉取成功。检查agent/tools/目录下的文件命名,以及 MCP 会话是否在 Agent 加载时完成了get_tools()。

5.4 CodeExec 沙箱超时

CodeExec默认超时是COMPONENT_EXEC_TIMEOUT,默认 10 分钟。如果沙箱 Provider 不可用,会回退到 HTTP 请求http://SANDBOX_HOST:9385/run。确认config.toml里[sandbox]的 host 和 port 正确,Docker 沙箱容器在运行。自管理 Provider 需要本地 Docker 环境。

5.5 工具执行结果没进上下文

工具执行了但模型没用到结果,通常是callback没正确把结果附加到对话上下文。检查 Agent 组件的max_rounds,默认 5 轮,轮次用完就停了。另外确认工具返回格式符合预期,_retrieve_chunks()之外的工具有没有正确set_output()。

6. 把链路跑通之后

工具系统与 MCP 集成的核心,是把 Function Calling 的格式转换、MCP 的动态发现、以及统一调度这三段接起来。TaoToken 在这条链路里的位置很明确:提供模型请求的统一 Key 和 API 通道,让get_meta()生成的 function 定义能被模型正确消费。配置骨架给的是结构,真正跑通靠的是逐段验证——先确认模型通道,再确认 MCP 工具列表,最后确认一次完整调用。

如果你还在接入阶段,建议先把 API Keys 和接入文档过一遍,把 Key 和 base_url 固定下来。验证模型是否支持 Function Calling,可以直接用模型对话页面发一条带 tools 的请求试。长期做编码和 Agent 扩展的话,Coding Plan 那条线也值得看,它和工具系统的调用场景是打通的。链路跑通一次之后,后面加工具就是往目录里放文件、往mcp_servers里加一项的事。

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

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

立即咨询