mirror of
https://github.com/xszyou/Fay.git
synced 2026-03-12 17:51:28 +08:00
修复不开启mcp工具无法使用预启动工具的bug。
This commit is contained in:
325
docs/Fay数字人MCP知识库配置指南.md
Normal file
325
docs/Fay数字人MCP知识库配置指南.md
Normal file
@@ -0,0 +1,325 @@
|
||||
# Fay数字人MCP知识库配置指南
|
||||
|
||||
> 本文介绍如何在Fay数字人中通过MCP工具配置知识库,实现智能问答增强。
|
||||
|
||||
## 一、实现效果
|
||||
|
||||
### 1. 通过MCP工具灵活配置
|
||||
|
||||
Fay采用MCP(Model Context Protocol)协议实现知识库集成,具有以下优势:
|
||||
|
||||
- **模块化设计**:知识库作为独立的MCP服务器运行,与Fay主程序解耦
|
||||
- **灵活扩展**:支持同时接入多个知识库服务,按需启用
|
||||
- **标准协议**:遵循MCP标准,可复用社区现有的知识库工具
|
||||
- **可视化管理**:通过Web界面完成全部配置,无需修改代码
|
||||
|
||||

|
||||
|
||||
### 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支持外部系统集成
|
||||
|
||||
这套方案既保持了系统的简洁性,又提供了强大的知识库集成能力,是构建智能数字人的理想选择。
|
||||
BIN
docs/images/fay_yueshen_rag.png
Normal file
BIN
docs/images/fay_yueshen_rag.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 113 KiB |
@@ -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:
|
||||
# 处理结果,确保它是可序列化的
|
||||
|
||||
@@ -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()
|
||||
|
||||
Reference in New Issue
Block a user