修复不开启mcp工具无法使用预启动工具的bug。

This commit is contained in:
guo zebin
2025-12-30 14:13:39 +08:00
parent 418cc6189b
commit 814f0eabe5
4 changed files with 336 additions and 9 deletions

View File

@@ -0,0 +1,325 @@
# Fay数字人MCP知识库配置指南
> 本文介绍如何在Fay数字人中通过MCP工具配置知识库实现智能问答增强。
## 一、实现效果
### 1. 通过MCP工具灵活配置
Fay采用MCPModel Context Protocol协议实现知识库集成具有以下优势
- **模块化设计**知识库作为独立的MCP服务器运行与Fay主程序解耦
- **灵活扩展**:支持同时接入多个知识库服务,按需启用
- **标准协议**遵循MCP标准可复用社区现有的知识库工具
- **可视化管理**通过Web界面完成全部配置无需修改代码
![MCP工具配置界面](../faymcp/static/images/mcp_config.png)
### 2. 1次LLM请求即可输出
通过**预启动Prestart**机制知识库查询在LLM推理前自动执行
```
用户提问 → 预启动工具执行(知识库检索) → 检索结果注入上下文 → LLM生成回答
```
整个流程只需**1次LLM调用**相比传统RAG方案减少了额外的意图判断步骤响应更快、成本更低。
**工作原理**
- 预启动工具在每次对话时自动触发
- 用户问题通过`{{question}}`占位符传递给知识库查询
- 检索结果作为背景知识注入到LLM的系统提示词中
- LLM基于检索到的知识生成准确回答
### 3. 提供接口可以单独调用
知识库工具支持通过REST API独立调用方便集成到其他系统
**调用接口**
```http
POST http://127.0.0.1:5010/api/mcp/servers/{server_id}/call
Content-Type: application/json
{
"method": "query_yueshen",
"params": {
"query": "",
"top_k": 5
}
}
```
**返回示例**
```json
{
"success": true,
"result": {
"documents": [...],
"distances": [...]
}
}
```
---
## 二、如何配置
### 1. MCP工具配置
#### 步骤一访问MCP管理页面
启动Fay后访问MCP管理界面
```
http://127.0.0.1:5010/Page3
```
#### 步骤二:添加知识库服务器
点击"添加MCP服务器"按钮,配置以下信息:
| 配置项 | 说明 | 示例值 |
|--------|------|--------|
| 服务器名称 | 自定义名称 | `yueshen rag` |
| 传输方式 | 选择STDIO | `stdio` |
| 启动命令 | Python解释器路径 | `python` |
| 启动参数 | 服务器脚本路径 | `mcp_servers/yueshen_rag/server.py` |
| 环境变量 | 配置API密钥等 | 见下方 |
#### 步骤三:配置环境变量
知识库服务需要配置embedding模型的API
```json
{
"YUESHEN_CORPUS_DIR": "新知识库",
"YUESHEN_PERSIST_DIR": "cache_data/chromadb_yueshen",
"YUESHEN_AUTO_INGEST": "1",
"YUESHEN_AUTO_INTERVAL": "300",
"YUESHEN_EMBED_API_KEY": "sk-your-api-key",
"YUESHEN_EMBED_BASE_URL": "https://api.siliconflow.cn/v1",
"YUESHEN_EMBED_MODEL": "Qwen/Qwen3-Embedding-8B"
}
```
**环境变量说明**
| 变量名 | 说明 | 默认值 |
|--------|------|--------|
| `YUESHEN_CORPUS_DIR` | 知识库文档目录 | `新知识库` |
| `YUESHEN_PERSIST_DIR` | 向量数据库存储路径 | `cache_data/chromadb_yueshen` |
| `YUESHEN_AUTO_INGEST` | 是否自动索引新文档 | `1`(启用) |
| `YUESHEN_AUTO_INTERVAL` | 自动索引检查间隔(秒) | `300` |
| `YUESHEN_EMBED_API_KEY` | Embedding API密钥 | - |
| `YUESHEN_EMBED_BASE_URL` | Embedding API地址 | - |
| `YUESHEN_EMBED_MODEL` | Embedding模型名称 | - |
#### 步骤四:连接服务器
保存配置后,点击"连接"按钮启动知识库服务。连接成功后:
- 服务器状态变为绿色"在线"
- 下方显示可用工具列表:`ingest_yueshen``query_yueshen``yueshen_stats`
### 2. 参数配置
#### 配置预启动参数
1. 在工具列表中找到 `query_yueshen` 工具
2. 点击工具右侧的"预启动?"标签
3. 在弹出的对话框中配置参数:
```json
{
"query": "{{question}}",
"top_k": 5,
"where": {}
}
```
**参数说明**
| 参数 | 类型 | 说明 |
|------|------|------|
| `query` | string | 查询文本,`{{question}}`会被替换为用户实际问题 |
| `top_k` | int | 返回最相关的文档数量 |
| `where` | object | 可选的元数据过滤条件 |
#### 配置选项
- **结果保存到记忆**:勾选后,检索结果会保存到对话历史中
- **允许函数调用**是否允许LLM在推理时再次调用此工具
点击"保存预启动"完成配置。
### 3. 启动方式
#### 方式一随Fay自动启动
配置完成后知识库服务会在Fay启动时自动连接。确保
1. MCP服务器已添加并保存
2. 在服务器卡片上启用了自动连接
#### 方式二:手动连接
在MCP管理页面
1. 找到目标服务器卡片
2. 点击"连接"按钮
3. 等待状态变为"在线"
#### 方式三通过API连接
```http
POST http://127.0.0.1:5010/api/mcp/servers/{server_id}/connect
```
#### 验证配置
连接成功后,可以通过以下方式验证:
1. **查看工具列表**:确认`query_yueshen`等工具已显示
2. **测试查询**:在工具面板中手动调用工具测试
3. **对话测试**向Fay提问知识库相关问题观察是否返回准确答案
---
## 三、怎么做到的
### Fay MCP工具的预启动功能
Fay实现了一套独特的**预启动Prestart**机制,使知识库查询能够无缝集成到对话流程中。
#### 核心设计
```
┌─────────────────────────────────────────────────────────┐
│ 用户发送消息 │
└─────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────┐
│ 获取预启动工具配置列表 │
│ GET /api/mcp/prestart/runnable │
└─────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────┐
│ 替换参数中的 {{question}} 占位符 │
│ 将用户问题填充到查询参数中 │
└─────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────┐
│ 并行执行所有预启动工具 │
│ POST /api/mcp/servers/{id}/call │
└─────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────┐
│ 收集检索结果,注入系统提示词 │
│ 作为 <prestart> 标签内容传递给LLM │
└─────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────┐
│ LLM 生成回答 │
│ 基于知识库内容生成准确、相关的回复 │
└─────────────────────────────────────────────────────────┘
```
#### 技术实现要点
**1. 预启动配置独立于工具启用状态**
预启动功能与工具的启用/禁用状态相互独立:
- **启用/禁用**控制LLM是否可以主动调用该工具
- **预启动**:控制工具是否在每次对话前自动执行
这意味着你可以:
- 禁用工具的LLM调用权限但保留预启动功能
- 让知识库查询仅在对话开始时执行避免LLM重复调用
**2. 参数模板与占位符替换**
预启动支持`{{question}}`占位符,在执行时自动替换为用户的实际问题:
```python
# 参数模板
{"query": "{{question}}", "top_k": 5}
# 用户问题:"Fay如何配置语音识别"
# 实际执行参数
{"query": "Fay如何配置语音识别", "top_k": 5}
```
**3. 结果处理与记忆管理**
预启动结果可以选择是否保存到对话记忆:
- `include_history: true` - 结果保存到历史,后续对话可引用
- `include_history: false` - 仅用于当前对话,不污染历史记录
**4. 多知识库并行查询**
支持配置多个预启动工具,它们会并行执行:
```
预启动工具1: 产品知识库查询
预启动工具2: FAQ知识库查询
预启动工具3: 用户手册查询
结果合并后一起注入LLM上下文
```
#### 相关代码位置
| 模块 | 文件 | 说明 |
|------|------|------|
| 预启动注册表 | `faymcp/prestart_registry.py` | 预启动配置的存储与管理 |
| 预启动执行 | `llm/nlp_cognitive_stream.py` | `_run_prestart_tools()` 函数 |
| API路由 | `faymcp/mcp_service.py` | `/api/mcp/prestart/runnable` 接口 |
| 前端配置 | `faymcp/templates/Page3.html` | 预启动配置对话框 |
---
## 常见问题
### Q1: 知识库服务连接失败?
检查以下几点:
1. Python环境是否正确配置
2. 依赖包是否安装完整chromadb, pdfplumber等
3. 环境变量中的API密钥是否正确
4. 知识库文档目录是否存在
### Q2: 检索结果不准确?
优化建议:
1. 调整`top_k`参数,增加返回文档数量
2. 检查文档分块策略是否合理
3. 尝试更换Embedding模型
4. 优化知识库文档的质量和格式
### Q3: 如何添加新文档到知识库?
将文档支持PDF、DOCX、TXT放入`YUESHEN_CORPUS_DIR`配置的目录中:
- 如果启用了`YUESHEN_AUTO_INGEST`,系统会自动索引
- 也可以手动调用`ingest_yueshen`工具触发索引
### Q4: 预启动工具执行超时?
检查:
1. Embedding API服务是否正常
2. 网络连接是否稳定
3. 可适当增加超时时间配置
---
## 总结
Fay数字人通过MCP协议和预启动机制实现了
- **零代码配置**:可视化界面完成全部设置
- **高效查询**1次LLM请求完成知识增强回答
- **灵活扩展**:支持多知识库、多工具并行
- **接口开放**REST API支持外部系统集成
这套方案既保持了系统的简洁性,又提供了强大的知识库集成能力,是构建智能数字人的理想选择。

Binary file not shown.

After

Width:  |  Height:  |  Size: 113 KiB

View File

@@ -331,24 +331,25 @@ def disconnect_all_mcp_servers():
util.log(1, f'成功断开 {disconnected_count} 个MCP服务连接资源已清理')
# 调用MCP服务器工具
def call_mcp_tool(server_id, method, params=None):
def call_mcp_tool(server_id, method, params=None, skip_enabled_check=False):
"""
调用MCP服务器工具
:param server_id: 服务器ID
:param method: 方法名
:param params: 参数字典
:param skip_enabled_check: 是否跳过启用状态检查(用于预启动调用)
:return: (是否成功, 结果或错误信息)
"""
try:
# 检查工具是否被启用
if not get_tool_state(server_id, method):
# 检查工具是否被启用(预启动调用跳过此检查)
if not skip_enabled_check and not get_tool_state(server_id, method):
return False, f"工具 '{method}' 已被禁用"
# 获取客户端对象
client = get_mcp_client(server_id)
if not client:
return False, "未找到服务器连接"
# 调用工具
return client.call_tool(method, params)
except Exception as e:
@@ -724,11 +725,12 @@ def call_server_tool(server_id):
data = request.json
method = data.get('method')
params = data.get('params', {})
is_prestart = data.get('is_prestart', False) # 预启动调用跳过启用状态检查
if not method:
return jsonify({"error": "缺少方法名"}), 400
success, result = call_mcp_tool(server_id, method, params)
success, result = call_mcp_tool(server_id, method, params, skip_enabled_check=is_prestart)
if success:
# 处理结果,确保它是可序列化的

View File

@@ -336,7 +336,7 @@ def _run_prestart_tools(user_question: str) -> List[Dict[str, Any]]:
try:
resp = requests.post(
f"http://127.0.0.1:5010/api/mcp/servers/{server_id}/call",
json={"method": tool_name, "params": filled_params},
json={"method": tool_name, "params": filled_params, "is_prestart": True},
timeout=120,
)
resp.raise_for_status()