多库检索与存储修复: - RRF 融合去重改用 (collection, chunk_id) 复合键,修复同名文件结果被吞 - DocStore 存储路径加 collection 前缀,修复跨库同名切片数据覆盖 - search_multiple 去重改用复合键 - chunk_id 解析改用 rsplit 兼容下划线文件名 上传与版本管理修复: - 同名文件上传改为覆盖模式,自动清理旧切片 - 修复首次上传不创建版本记录 - 修复覆盖上传版本号回退到 v1 - sync ADDED 分支改用动态版本号生成 - _generate_version_id 改为基于全部版本递增 - 废止/恢复操作同步 SQLite 版本记录 - mark_document_as_superseded 改为仅更新 SQLite 删除清理修复: - 删除文档时同步清理 SQLite 版本记录和变更日志 - 删除向量库时同步清理该库所有版本记录 - cleanup 改为清理 SQLite 记录而非 ChromaDB 测试: - test_version_management.py: 27 条版本管理单元测试 - test_edge_cases.py: 28 条边界用例测试 - test_upload_dedup.py: 5 条上传去重测试 - e2e_risk_test.py: 27 条端到端风险测试 文档: - 新增风险边界问题修复注意事项.md(面向后端的对接文档) - 新增向量库边界风险分析.md - 更新多篇现有文档
1947 lines
43 KiB
Markdown
1947 lines
43 KiB
Markdown
# RAG API curl 测试手册
|
||
|
||
> 基于 `后端对接规范.md`,所有 curl 命令均在生产模式 (`APP_ENV=prod`) 下验证通过。
|
||
>
|
||
> 测试日期:2026-06-04 | 生产服务器:`47.116.16.222` | 服务地址:`http://127.0.0.1:5001`
|
||
>
|
||
> 当前部署模型:`qwen-plus`(DashScope)| 嵌入模型:`bge-base-zh-v1.5`(本地 CPU)| Rerank:`qwen3-rerank`(DashScope 云端 API)
|
||
|
||
## 目录
|
||
|
||
- [1. 基础信息](#1-基础信息)
|
||
- [2. 健康检查](#2-健康检查)
|
||
- [3. 问答接口](#3-问答接口)
|
||
- [4. 检索接口](#4-检索接口)
|
||
- [5. 向量库管理](#5-向量库管理)
|
||
- [6. 文档管理](#6-文档管理)
|
||
- [7. 切片管理](#7-切片管理)
|
||
- [8. 同步服务](#8-同步服务)
|
||
- [9. 反馈系统](#9-反馈系统)
|
||
- [10. FAQ 管理](#10-faq-管理)
|
||
- [11. 出题系统](#11-出题系统)
|
||
- [12. 图片服务](#12-图片服务)
|
||
- [13. 报告服务](#13-报告服务)
|
||
- [14. 知识库路由](#14-知识库路由)
|
||
- [附录. 已知问题](#附录-已知问题)
|
||
|
||
---
|
||
|
||
## 1. 基础信息
|
||
|
||
### 认证方式
|
||
|
||
生产模式 (`APP_ENV=prod`) 下无需认证 Header,直接放行。用户信息使用默认值:
|
||
|
||
```json
|
||
{"user_id": "backend-caller", "username": "后端调用", "role": "user", "department": ""}
|
||
```
|
||
|
||
### 中文编码注意
|
||
|
||
Windows bash 中 curl 传递中文 JSON 需使用文件方式:
|
||
|
||
```bash
|
||
# 方式一:使用临时文件(推荐)
|
||
echo '{"query":"中文内容"}' > /tmp/test.json
|
||
curl -s -X POST http://localhost:5001/search -H "Content-Type: application/json" -d @/tmp/test.json
|
||
|
||
# 方式二:英文可直接传递
|
||
curl -s -X POST http://localhost:5001/search -H "Content-Type: application/json" -d '{"query":"hello"}'
|
||
```
|
||
|
||
### 通用响应格式
|
||
|
||
所有接口返回 JSON,成功时 HTTP 200,错误时返回对应 HTTP 状态码。
|
||
|
||
---
|
||
|
||
## 2. 健康检查
|
||
|
||
### GET /health
|
||
|
||
检查服务运行状态。
|
||
|
||
```bash
|
||
curl -s http://localhost:5001/health
|
||
```
|
||
|
||
**响应示例**:
|
||
```json
|
||
{
|
||
"bm25_index": "动态按需加载",
|
||
"knowledge_base": "多向量库模式 (按集合提供服务)",
|
||
"mode": "Agentic RAG",
|
||
"status": "ok"
|
||
}
|
||
```
|
||
|
||
**验证结果**:✅ 通过
|
||
|
||
---
|
||
|
||
## 3. 问答接口
|
||
|
||
### POST /rag
|
||
|
||
知识库问答(SSE 流式返回)。
|
||
|
||
```bash
|
||
echo '{"message":"三峡工程","chat_history":[]}' > /tmp/rag.json
|
||
curl -s -X POST http://localhost:5001/rag \
|
||
-H "Content-Type: application/json" \
|
||
-d @/tmp/rag.json
|
||
```
|
||
|
||
**请求体**:
|
||
| 字段 | 类型 | 必需 | 说明 |
|
||
|------|------|------|------|
|
||
| `message` | string | ✅ | 用户消息 |
|
||
| `chat_history` | array | ✅(生产模式) | 对话历史 |
|
||
| `collections` | string[] | ❌ | 知识库列表,默认 `["public_kb"]` |
|
||
| `session_id` | string | ❌ | 会话 ID |
|
||
|
||
**chat_history 格式**:
|
||
```json
|
||
[
|
||
{"role": "user", "content": "之前的问题"},
|
||
{"role": "assistant", "content": "之前的回答"}
|
||
]
|
||
```
|
||
|
||
**SSE 事件序列**:
|
||
```
|
||
data: {"type": "start", "message": "正在检索知识库..."}
|
||
data: {"type": "sources", "sources": [...]}
|
||
data: {"type": "chunk", "content": "每个token"}
|
||
data: {"type": "finish", "answer": "完整回答[ref:chunk_id]", "sources": [...], "citations": [...]}
|
||
```
|
||
|
||
**finish 事件中 citations 结构**(引用溯源,用于前端跳转定位):
|
||
```json
|
||
{
|
||
"citations": [
|
||
{
|
||
"chunk_id": "3.docx_33",
|
||
"chunk_index": 33,
|
||
"source": "3.docx",
|
||
"collection": "public_kb",
|
||
"doc_type": "word",
|
||
"section": "第五篇 投入管理 > 一、零售终端建设投入标准",
|
||
"preview": "内容摘要...",
|
||
"content": "切片内容(截断 300 字)",
|
||
"chunk_type": "text",
|
||
"page": null,
|
||
"page_end": null
|
||
}
|
||
]
|
||
}
|
||
```
|
||
|
||
| citations 字段 | 说明 |
|
||
|------|------|
|
||
| `chunk_id` | 切片唯一标识,格式 `{文件名}_{序号}` |
|
||
| `chunk_index` | 全局切片序号(从 chunk_id 提取),用于文档预览跳转 |
|
||
| `source` | 来源文件名 |
|
||
| `collection` | 所属向量库名称,用于定位文档所在知识库 |
|
||
| `doc_type` | 文档类型:`pdf`、`word`、`excel` |
|
||
| `section` | 章节路径(已清洗,过滤掉正文内容) |
|
||
| `page` / `page_end` | 页码(仅 PDF) |
|
||
| `bbox` / `bbox_mode` | 坐标定位(仅 PDF) |
|
||
| `section_chunk_id` | 章节内段落序号(仅 Word) |
|
||
|
||
**带 collections 参数**:
|
||
```bash
|
||
echo '{"message":"三峡工程","chat_history":[],"collections":["public_kb"]}' > /tmp/rag.json
|
||
curl -s -X POST http://localhost:5001/rag \
|
||
-H "Content-Type: application/json" \
|
||
-d @/tmp/rag.json
|
||
```
|
||
|
||
> **⚠️ 重要**:指定知识库必须使用 `collections` 数组参数(如 `["dept_tech"]`),而非 `collection` 单数参数。
|
||
> 使用单数 `collection` 参数会被忽略,导致默认检索 `public_kb`。
|
||
|
||
**多向量库同时查询**:
|
||
```bash
|
||
# 同时检索多个知识库
|
||
echo '{"message":"信息安全","collections":["dept_tech","public_kb"],"chat_history":[]}' > /tmp/rag.json
|
||
curl -s -X POST http://localhost:5001/rag \
|
||
-H "Content-Type: application/json" \
|
||
-d @/tmp/rag.json
|
||
```
|
||
|
||
**验证结果**:✅ 通过
|
||
|
||
---
|
||
|
||
### POST /chat
|
||
|
||
普通聊天模式(非知识库)。
|
||
|
||
```bash
|
||
echo '{"message":"你好","chat_history":[]}' > /tmp/chat.json
|
||
curl -s -X POST http://localhost:5001/chat \
|
||
-H "Content-Type: application/json" \
|
||
-d @/tmp/chat.json
|
||
```
|
||
|
||
**请求体**:
|
||
| 字段 | 类型 | 必需 | 说明 |
|
||
|------|------|------|------|
|
||
| `message` | string | ✅ | 用户消息 |
|
||
| `chat_history` | array | ❌ | 对话历史 |
|
||
|
||
**响应示例**:
|
||
```json
|
||
{
|
||
"answer": "你好!很高兴见到你~",
|
||
"mode": "chat",
|
||
"sources": [],
|
||
"web_searched": false
|
||
}
|
||
```
|
||
|
||
**验证结果**:✅ 通过
|
||
|
||
---
|
||
|
||
## 4. 检索接口
|
||
|
||
### POST /search
|
||
|
||
混合检索(向量 + BM25),供 Dify 工作流调用。
|
||
|
||
```bash
|
||
echo '{"query":"三峡工程","top_k":3}' > /tmp/search.json
|
||
curl -s -X POST http://localhost:5001/search \
|
||
-H "Content-Type: application/json" \
|
||
-d @/tmp/search.json
|
||
```
|
||
|
||
**请求体**:
|
||
| 字段 | 类型 | 必需 | 说明 |
|
||
|------|------|------|------|
|
||
| `query` | string | ✅ | 查询文本 |
|
||
| `top_k` | int | ❌ | 返回数量,默认 5 |
|
||
| `collections` | string[] | ❌ | 知识库列表,默认 `["public_kb"]` |
|
||
|
||
**响应示例**:
|
||
```json
|
||
{
|
||
"contexts": ["综述\n三峡工程是国之重器..."],
|
||
"metadatas": [
|
||
{
|
||
"_collection": "public_kb",
|
||
"chunk_id": "三峡公报_1-15页.pdf_text_8",
|
||
"chunk_type": "text",
|
||
"collection": "public_kb",
|
||
"doc_type": "pdf",
|
||
"page": 5,
|
||
"page_end": 6,
|
||
"section": "三峡工程公报 > 综述",
|
||
"source": "三峡公报_1-15页.pdf",
|
||
"status": "active",
|
||
"version": "v1"
|
||
}
|
||
],
|
||
"scores": [0.9975]
|
||
}
|
||
```
|
||
|
||
**scores 说明**:相似度分数,范围 0-1,越高越相关(已从距离转换)。
|
||
|
||
**验证结果**:✅ 通过
|
||
|
||
---
|
||
|
||
## 5. 向量库管理
|
||
|
||
### GET /collections
|
||
|
||
获取向量库列表。
|
||
|
||
```bash
|
||
curl -s http://localhost:5001/collections
|
||
```
|
||
|
||
**响应示例**:
|
||
```json
|
||
{
|
||
"collections": [
|
||
{
|
||
"created_at": "2026-06-02T21:35:43.839864",
|
||
"department": "",
|
||
"description": "所有人可访问的公开文档",
|
||
"display_name": "公开知识库",
|
||
"document_count": 824,
|
||
"name": "public_kb"
|
||
},
|
||
{
|
||
"created_at": "2026-06-04T06:15:52.556940",
|
||
"department": "",
|
||
"description": "",
|
||
"display_name": "dept_1_kb",
|
||
"document_count": 800,
|
||
"name": "dept_1_kb"
|
||
}
|
||
],
|
||
"total": 9
|
||
}
|
||
```
|
||
|
||
**验证结果**:✅ 通过
|
||
|
||
---
|
||
|
||
### POST /collections
|
||
|
||
创建新向量库。
|
||
|
||
```bash
|
||
echo '{"name":"test_kb","display_name":"测试库","department":"测试部","description":"测试描述"}' > /tmp/create.json
|
||
curl -s -X POST http://localhost:5001/collections \
|
||
-H "Content-Type: application/json" \
|
||
-d @/tmp/create.json
|
||
```
|
||
|
||
**请求体**:
|
||
| 字段 | 类型 | 必需 | 说明 |
|
||
|------|------|------|------|
|
||
| `name` | string | ✅ | 向量库名称(字母、数字、下划线、连字符) |
|
||
| `display_name` | string | ❌ | 显示名称 |
|
||
| `department` | string | ❌ | 所属部门 |
|
||
| `description` | string | ❌ | 描述 |
|
||
|
||
**响应示例**:
|
||
```json
|
||
{
|
||
"message": "向量库 'test_kb' 创建成功",
|
||
"name": "test_kb",
|
||
"success": true
|
||
}
|
||
```
|
||
|
||
**验证结果**:✅ 通过
|
||
|
||
---
|
||
|
||
### PUT /collections/\<name\>
|
||
|
||
修改向量库信息。
|
||
|
||
```bash
|
||
echo '{"display_name":"新名称","description":"新描述"}' > /tmp/update.json
|
||
curl -s -X PUT http://localhost:5001/collections/test_kb \
|
||
-H "Content-Type: application/json" \
|
||
-d @/tmp/update.json
|
||
```
|
||
|
||
**请求体**:
|
||
| 字段 | 类型 | 必需 | 说明 |
|
||
|------|------|------|------|
|
||
| `display_name` | string | ❌ | 显示名称 |
|
||
| `description` | string | ❌ | 描述 |
|
||
|
||
**验证结果**:✅ 通过
|
||
|
||
---
|
||
|
||
### DELETE /collections/\<name\>
|
||
|
||
删除向量库。
|
||
|
||
```bash
|
||
curl -s -X DELETE http://localhost:5001/collections/test_kb
|
||
```
|
||
|
||
**查询参数**:
|
||
| 参数 | 类型 | 必需 | 说明 |
|
||
|------|------|------|------|
|
||
| `delete_documents` | boolean | ❌ | 是否删除文档源文件,默认 false |
|
||
|
||
**带参数示例**:
|
||
```bash
|
||
curl -s -X DELETE "http://localhost:5001/collections/test_kb?delete_documents=true"
|
||
```
|
||
|
||
**验证结果**:✅ 通过
|
||
|
||
---
|
||
|
||
### GET /collections/\<kb_name\>/documents
|
||
|
||
获取向量库内的文档列表。
|
||
|
||
```bash
|
||
curl -s "http://localhost:5001/collections/public_kb/documents"
|
||
```
|
||
|
||
**响应示例**:
|
||
```json
|
||
{
|
||
"collection": "public_kb",
|
||
"documents": [
|
||
{
|
||
"chunks": 105,
|
||
"source": "1.docx"
|
||
},
|
||
{
|
||
"chunks": 39,
|
||
"source": "三峡公报_1-15页.pdf"
|
||
}
|
||
],
|
||
"total": 9
|
||
}
|
||
```
|
||
|
||
**验证结果**:✅ 通过
|
||
|
||
---
|
||
|
||
### GET /collections/\<kb_name\>/chunks
|
||
|
||
获取向量库切片列表。
|
||
|
||
```bash
|
||
curl -s "http://localhost:5001/collections/public_kb/chunks?limit=2&offset=0"
|
||
```
|
||
|
||
**查询参数**:
|
||
| 参数 | 类型 | 必需 | 说明 |
|
||
|------|------|------|------|
|
||
| `document_id` | string | ❌ | 过滤指定文档的切片 |
|
||
| `limit` | int | ❌ | 返回数量,默认 100 |
|
||
| `offset` | int | ❌ | 偏移量,默认 0 |
|
||
|
||
**响应示例**:
|
||
```json
|
||
{
|
||
"collection": "public_kb",
|
||
"chunks": [
|
||
{
|
||
"id": "三峡公报_1-15页.pdf_text_0",
|
||
"document": "三峡公报_1-15页.pdf",
|
||
"content": "切片内容...",
|
||
"metadata": {
|
||
"chunk_id": "三峡公报_1-15页.pdf_text_0",
|
||
"chunk_type": "text",
|
||
"collection": "public_kb",
|
||
"page": 1,
|
||
"source": "三峡公报_1-15页.pdf",
|
||
"status": "active",
|
||
"version": "v1"
|
||
},
|
||
"score": null
|
||
}
|
||
],
|
||
"total": 150
|
||
}
|
||
```
|
||
|
||
**验证结果**:✅ 通过
|
||
|
||
---
|
||
|
||
### GET /collections/\<kb_name\>/documents/\<filename\>/versions
|
||
|
||
获取文档版本历史。
|
||
|
||
```bash
|
||
# URL 编码文件名中的特殊字符
|
||
curl -s "http://localhost:5001/collections/public_kb/documents/%E4%B8%89%E5%B3%A1%E5%85%AC%E6%8A%A5_1-15%E9%A1%B5.pdf/versions?limit=5"
|
||
```
|
||
|
||
**查询参数**:
|
||
| 参数 | 类型 | 必需 | 说明 |
|
||
|------|------|------|------|
|
||
| `limit` | int | ❌ | 返回数量,默认 10 |
|
||
|
||
**响应示例**:
|
||
```json
|
||
{
|
||
"success": true,
|
||
"document_id": "三峡公报_1-15页.pdf",
|
||
"collection": "public_kb",
|
||
"versions": [
|
||
{
|
||
"version": "v1",
|
||
"status": "active",
|
||
"effective_date": "2026-04-14T21:03:06",
|
||
"deprecated_date": null,
|
||
"chunk_count": 120
|
||
}
|
||
],
|
||
"total": 1
|
||
}
|
||
```
|
||
|
||
**验证结果**:✅ 通过
|
||
|
||
---
|
||
|
||
### POST /collections/\<kb_name\>/update-image-descriptions
|
||
|
||
更新图片切片描述(重新生成)。
|
||
|
||
```bash
|
||
curl -s -X POST "http://localhost:5001/collections/public_kb/update-image-descriptions"
|
||
```
|
||
|
||
**响应示例**:
|
||
```json
|
||
{
|
||
"success": true,
|
||
"message": "图片描述更新完成",
|
||
"updated": 5
|
||
}
|
||
```
|
||
|
||
**验证结果**:✅ 通过
|
||
|
||
---
|
||
|
||
## 6. 文档管理
|
||
|
||
### GET /documents/list
|
||
|
||
获取文档列表。
|
||
|
||
```bash
|
||
curl -s "http://localhost:5001/documents/list?collection=public_kb"
|
||
```
|
||
|
||
**查询参数**:
|
||
| 参数 | 类型 | 必需 | 说明 |
|
||
|------|------|------|------|
|
||
| `collection` | string | ❌ | 知识库名称(也可用 `kb_name`),默认返回全部 |
|
||
|
||
> **注意**:该接口不支持分页,返回指定知识库的全部文档列表。
|
||
|
||
**响应示例**:
|
||
```json
|
||
{
|
||
"documents": [
|
||
{
|
||
"collection": "public_kb",
|
||
"filename": "三峡公报_1-15页.pdf",
|
||
"last_modified": "2026-04-14T21:03:06",
|
||
"path": "public_kb/三峡公报_1-15页.pdf",
|
||
"size": 2773520
|
||
}
|
||
],
|
||
"total": 8
|
||
}
|
||
```
|
||
|
||
**验证结果**:✅ 通过
|
||
|
||
---
|
||
|
||
### GET /documents/\<path\>/status
|
||
|
||
获取文档处理状态。
|
||
|
||
```bash
|
||
# URL 编码路径中的斜杠
|
||
curl -s "http://localhost:5001/documents/public_kb%2Ftest.txt/status"
|
||
```
|
||
|
||
**响应示例**:
|
||
```json
|
||
{
|
||
"success": true,
|
||
"status": "active",
|
||
"chunk_count": 105,
|
||
"last_processed": null
|
||
}
|
||
```
|
||
|
||
**验证结果**:✅ 通过
|
||
|
||
---
|
||
|
||
### POST /documents/upload
|
||
|
||
上传单个文件。
|
||
|
||
```bash
|
||
echo "测试文档内容" > /tmp/test.txt
|
||
curl -s -X POST http://localhost:5001/documents/upload \
|
||
-F "file=@/tmp/test.txt" \
|
||
-F "collection=public_kb"
|
||
```
|
||
|
||
**表单字段**:
|
||
| 字段 | 类型 | 必需 | 说明 |
|
||
|------|------|------|------|
|
||
| `file` | file | ✅ | 上传文件 |
|
||
| `collection` | string | ✅ | 目标知识库(也可用 `kb_name`) |
|
||
|
||
**响应示例**:
|
||
```json
|
||
{
|
||
"data": {
|
||
"file": {
|
||
"collection": "public_kb",
|
||
"filename": "test.txt",
|
||
"path": "public_kb/test.txt",
|
||
"size": 18,
|
||
"replaced": false
|
||
},
|
||
"sync_status": "已保存并添加到向量库"
|
||
},
|
||
"message": "文件上传成功,已保存并添加到向量库",
|
||
"status": "success",
|
||
"status_code": 2002,
|
||
"success": true
|
||
}
|
||
```
|
||
|
||
> **同名文件处理**:上传同名文件时,旧版本的切片会被自动清理后覆盖(`replaced: true`),不会生成时间戳后缀文件。
|
||
|
||
**验证结果**:✅ 通过
|
||
|
||
---
|
||
|
||
### POST /documents/batch-upload
|
||
|
||
批量上传文件。
|
||
|
||
```bash
|
||
echo "文件1内容" > /tmp/file1.txt
|
||
echo "文件2内容" > /tmp/file2.txt
|
||
curl -s -X POST http://localhost:5001/documents/batch-upload \
|
||
-F "files=@/tmp/file1.txt" \
|
||
-F "files=@/tmp/file2.txt" \
|
||
-F "collection=public_kb"
|
||
```
|
||
|
||
**响应示例**:
|
||
```json
|
||
{
|
||
"data": {
|
||
"results": [
|
||
{"filename": "file1.txt", "path": "public_kb/file1.txt", "status": "success", "replaced": false},
|
||
{"filename": "file2.txt", "path": "public_kb/file2.txt", "status": "success", "replaced": false}
|
||
],
|
||
"success_count": 2,
|
||
"total": 2
|
||
},
|
||
"message": "批量上传完成,成功 2/2 个文件",
|
||
"status": "success",
|
||
"status_code": 2003,
|
||
"success": true
|
||
}
|
||
```
|
||
|
||
> **同名文件处理**:与单文件上传相同,批量上传中遇到同名文件也会自动覆盖旧版本(`replaced: true`)。
|
||
|
||
**验证结果**:✅ 通过
|
||
|
||
---
|
||
|
||
### PUT /documents/\<path\>
|
||
|
||
更新/替换文档。
|
||
|
||
```bash
|
||
echo "更新后的文档内容" > /tmp/updated.txt
|
||
curl -s -X PUT "http://localhost:5001/documents/public_kb%2Ftest.txt" \
|
||
-F "file=@/tmp/updated.txt"
|
||
```
|
||
|
||
**表单字段**:
|
||
| 字段 | 类型 | 必需 | 说明 |
|
||
|------|------|------|------|
|
||
| `file` | file | ✅ | 替换的文件 |
|
||
|
||
**响应示例**:
|
||
```json
|
||
{
|
||
"success": true,
|
||
"message": "文件已更新"
|
||
}
|
||
```
|
||
|
||
**验证结果**:✅ 通过
|
||
|
||
---
|
||
|
||
### DELETE /documents/\<path\>
|
||
|
||
删除文档。
|
||
|
||
```bash
|
||
# URL 编码路径中的斜杠
|
||
curl -s -X DELETE "http://localhost:5001/documents/public_kb%2Ftest.txt"
|
||
```
|
||
|
||
**响应示例**:
|
||
```json
|
||
{
|
||
"message": "文档已删除",
|
||
"success": true
|
||
}
|
||
```
|
||
|
||
**验证结果**:✅ 通过
|
||
|
||
---
|
||
|
||
### POST /collections/\<kb_name\>/documents/\<filename\>/deprecate
|
||
|
||
废弃文档版本。
|
||
|
||
```bash
|
||
curl -s -X POST "http://localhost:5001/collections/public_kb/documents/test.txt/deprecate"
|
||
```
|
||
|
||
**验证结果**:✅ 通过(接口存在)
|
||
|
||
---
|
||
|
||
### POST /collections/\<kb_name\>/documents/\<filename\>/restore
|
||
|
||
恢复文档版本。
|
||
|
||
```bash
|
||
curl -s -X POST "http://localhost:5001/collections/public_kb/documents/test.txt/restore"
|
||
```
|
||
|
||
**验证结果**:✅ 通过(接口存在)
|
||
|
||
---
|
||
|
||
### 🛠️ DEV GET /documents/\<path\>/preview
|
||
|
||
> **开发环境自用接口,后端组无需调用。**
|
||
> 仅供 dev-ui 内部前端实现引用溯源跳转使用。后端组可根据 `/rag` 返回的 `citations` 中的 `chunk_index`、`page`、`bbox` 等字段自行实现文档定位。
|
||
|
||
文档预览(支持按切片序号跳转),用于引用溯源点击后定位到文档中的具体位置。
|
||
|
||
```bash
|
||
# 跳转到指定切片(前后各取 2 个上下文切片)
|
||
curl -s "http://localhost:5001/documents/public_kb%2F1.docx/preview?chunk_index=33&context=2"
|
||
|
||
# 不指定 chunk_index,返回前 5 个切片作为概览
|
||
curl -s "http://localhost:5001/documents/public_kb%2F1.docx/preview"
|
||
```
|
||
|
||
**查询参数**:
|
||
| 参数 | 类型 | 必需 | 说明 |
|
||
|------|------|------|------|
|
||
| `chunk_index` | int | ✅ | 目标切片序号(来自 citations 的 `chunk_index` 字段) |
|
||
| `context` | int | ✅ | 上下文切片数,默认 2(前后各取 2 个) |
|
||
|
||
**响应示例**:
|
||
```json
|
||
{
|
||
"success": true,
|
||
"collection": "public_kb",
|
||
"source": "1.docx",
|
||
"total_chunks": 105,
|
||
"target_index": 33,
|
||
"chunks": [
|
||
{"id": "1.docx_31", "content": "...", "metadata": {...}, "is_target": false},
|
||
{"id": "1.docx_32", "content": "...", "metadata": {...}, "is_target": false},
|
||
{"id": "1.docx_33", "content": "...", "metadata": {...}, "is_target": true},
|
||
{"id": "1.docx_34", "content": "...", "metadata": {...}, "is_target": false},
|
||
{"id": "1.docx_35", "content": "...", "metadata": {...}, "is_target": false}
|
||
]
|
||
}
|
||
```
|
||
|
||
> **说明**:`is_target: true` 的切片即为引用定位目标,前端可高亮显示并滚动到该位置。
|
||
|
||
---
|
||
|
||
## 7. 切片管理
|
||
|
||
### GET /documents/\<path\>/chunks
|
||
|
||
获取文档切片列表。
|
||
|
||
```bash
|
||
# URL 编码路径
|
||
curl -s "http://localhost:5001/documents/dept_hr%2F%E4%BA%BA%E5%91%98%E5%90%8D%E5%86%8C.txt/chunks"
|
||
```
|
||
|
||
> **注意**:该接口不支持分页或过滤参数,返回指定文档的全部切片。
|
||
|
||
**响应示例**:
|
||
```json
|
||
{
|
||
"chunks": [
|
||
{
|
||
"document": "# 智启科技有限公司人员名册\n\n**更新日期**:2024年6月...",
|
||
"id": "人员名册.txt_text_0",
|
||
"metadata": {
|
||
"chunk_id": "人员名册.txt_text_0",
|
||
"chunk_index": 0,
|
||
"chunk_type": "text",
|
||
"collection": "dept_hr",
|
||
"doc_type": "other",
|
||
"page": 1,
|
||
"page_end": 1,
|
||
"preview": "# 智启科技有限公司人员名册...",
|
||
"section": "人员名册",
|
||
"source": "人员名册.txt",
|
||
"has_table": false,
|
||
"status": "active",
|
||
"version": "v1"
|
||
},
|
||
"status": "active",
|
||
"version": "v1"
|
||
}
|
||
],
|
||
"collection": "dept_hr",
|
||
"document_id": "dept_hr/人员名册.txt",
|
||
"success": true,
|
||
"total": 4
|
||
}
|
||
```
|
||
|
||
**切片字段说明**:
|
||
|
||
| 字段 | 说明 |
|
||
|------|------|
|
||
| `id` / `chunk_id` | 切片唯一标识,格式:`{文件名}_{类型}_{序号}` |
|
||
| `document` | **切片完整内容**(重要:用于增删改查) |
|
||
| `chunk_type` | 切片类型:`text`(文本)、`table`(表格)、`image`(图片) |
|
||
| `source` | 来源文件名 |
|
||
| `page` / `page_end` | 起止页码 |
|
||
| `section` | 所属章节路径 |
|
||
| `preview` | 内容预览(截断版,用于列表展示) |
|
||
| `has_table` | 是否包含表格 |
|
||
|
||
**验证结果**:✅ 通过
|
||
|
||
---
|
||
|
||
### POST /chunks
|
||
|
||
新增切片。
|
||
|
||
```bash
|
||
echo '{"collection":"public_kb","content":"测试切片内容","metadata":{"section":"测试章节"}}' > /tmp/chunk.json
|
||
curl -s -X POST http://localhost:5001/chunks \
|
||
-H "Content-Type: application/json" \
|
||
-d @/tmp/chunk.json
|
||
```
|
||
|
||
**请求体**:
|
||
| 字段 | 类型 | 必需 | 说明 |
|
||
|------|------|------|------|
|
||
| `collection` | string | ✅ | 向量库名称 |
|
||
| `content` | string | ✅ | 切片内容 |
|
||
| `metadata` | object | ❌ | 元数据 |
|
||
|
||
**验证结果**:✅ 通过
|
||
|
||
---
|
||
|
||
### PUT /chunks/\<id\>
|
||
|
||
修改切片。
|
||
|
||
```bash
|
||
echo '{"collection":"dept_hr","content":"更新后的内容"}' > /tmp/update_chunk.json
|
||
curl -s -X PUT "http://localhost:5001/chunks/人员名册.txt_text_0" \
|
||
-H "Content-Type: application/json" \
|
||
-d @/tmp/update_chunk.json
|
||
```
|
||
|
||
**请求体**:
|
||
| 字段 | 类型 | 必需 | 说明 |
|
||
|------|------|------|------|
|
||
| `collection` | string | ✅ | 向量库名称 |
|
||
| `content` | string | ❌ | 新内容 |
|
||
| `metadata` | object | ❌ | 新元数据 |
|
||
|
||
**验证结果**:✅ 通过
|
||
|
||
---
|
||
|
||
### DELETE /chunks/\<id\>
|
||
|
||
删除切片。
|
||
|
||
```bash
|
||
curl -s -X DELETE "http://localhost:5001/chunks/人员名册.txt_text_0?collection=dept_hr"
|
||
```
|
||
|
||
**查询参数**:
|
||
| 参数 | 类型 | 必需 | 说明 |
|
||
|------|------|------|------|
|
||
| `collection` | string | ✅ | 向量库名称 |
|
||
|
||
**验证结果**:✅ 通过
|
||
|
||
---
|
||
|
||
## 8. 同步服务
|
||
|
||
### POST /sync
|
||
|
||
触发文档同步。
|
||
|
||
```bash
|
||
curl -s -X POST http://localhost:5001/sync \
|
||
-H "Content-Type: application/json"
|
||
```
|
||
|
||
**响应示例**:
|
||
```json
|
||
{
|
||
"data": {
|
||
"result": {
|
||
"documents_added": 1,
|
||
"documents_deleted": 1,
|
||
"documents_modified": 0,
|
||
"documents_processed": 2,
|
||
"end_time": "2026-05-04T01:45:42",
|
||
"errors": [],
|
||
"start_time": "2026-05-04T01:45:41",
|
||
"status": "completed"
|
||
}
|
||
},
|
||
"message": "同步完成",
|
||
"status": "success",
|
||
"status_code": 2010,
|
||
"success": true
|
||
}
|
||
```
|
||
|
||
**验证结果**:✅ 通过
|
||
|
||
---
|
||
|
||
### GET /sync/status
|
||
|
||
获取同步状态。
|
||
|
||
```bash
|
||
curl -s http://localhost:5001/sync/status
|
||
```
|
||
|
||
**响应示例**:
|
||
```json
|
||
{
|
||
"documents_tracked": 0,
|
||
"enabled": true,
|
||
"last_sync": null,
|
||
"monitoring": false
|
||
}
|
||
```
|
||
|
||
**验证结果**:✅ 通过
|
||
|
||
---
|
||
|
||
### GET /sync/history
|
||
|
||
获取同步历史。
|
||
|
||
```bash
|
||
curl -s http://localhost:5001/sync/history
|
||
```
|
||
|
||
**响应示例**:
|
||
```json
|
||
{
|
||
"history": []
|
||
}
|
||
```
|
||
|
||
**验证结果**:✅ 通过
|
||
|
||
---
|
||
|
||
### GET /sync/changes
|
||
|
||
获取待同步变更。
|
||
|
||
```bash
|
||
curl -s http://localhost:5001/sync/changes
|
||
```
|
||
|
||
**响应示例**:
|
||
```json
|
||
{
|
||
"changes": []
|
||
}
|
||
```
|
||
|
||
**验证结果**:✅ 通过
|
||
|
||
---
|
||
|
||
### POST /sync/start
|
||
|
||
启动文件监控。
|
||
|
||
```bash
|
||
curl -s -X POST http://localhost:5001/sync/start
|
||
```
|
||
|
||
**响应示例**:
|
||
```json
|
||
{
|
||
"message": "文件监控已启动",
|
||
"status": "success",
|
||
"status_code": 2010
|
||
}
|
||
```
|
||
|
||
**验证结果**:✅ 通过
|
||
|
||
---
|
||
|
||
### POST /sync/stop
|
||
|
||
停止文件监控。
|
||
|
||
```bash
|
||
curl -s -X POST http://localhost:5001/sync/stop
|
||
```
|
||
|
||
**响应示例**:
|
||
```json
|
||
{
|
||
"message": "文件监控已停止",
|
||
"status": "success",
|
||
"status_code": 2010
|
||
}
|
||
```
|
||
|
||
**验证结果**:✅ 通过
|
||
|
||
---
|
||
|
||
## 9. 反馈系统
|
||
|
||
### POST /feedback
|
||
|
||
提交反馈。
|
||
|
||
```bash
|
||
echo '{"session_id":"test-session","query":"测试问题","answer":"测试回答","rating":1,"reason":"测试原因"}' > /tmp/feedback.json
|
||
curl -s -X POST http://localhost:5001/feedback \
|
||
-H "Content-Type: application/json" \
|
||
-d @/tmp/feedback.json
|
||
```
|
||
|
||
**请求体**:
|
||
| 字段 | 类型 | 必需 | 说明 |
|
||
|------|------|------|------|
|
||
| `session_id` | string | ✅ | 会话 ID |
|
||
| `query` | string | ✅ | 用户问题 |
|
||
| `answer` | string | ❌ | 系统回答(可为空) |
|
||
| `rating` | int | ✅ | 评分(1=赞,-1=踩) |
|
||
| `reason` | string | ❌ | 原因 |
|
||
|
||
**响应示例**:
|
||
```json
|
||
{
|
||
"faq_suggested": true,
|
||
"feedback_id": 7,
|
||
"success": true,
|
||
"suggestion_id": 6
|
||
}
|
||
```
|
||
|
||
**验证结果**:✅ 通过
|
||
|
||
---
|
||
|
||
### GET /feedback/list
|
||
|
||
获取反馈列表。
|
||
|
||
```bash
|
||
curl -s "http://localhost:5001/feedback/list?limit=5"
|
||
```
|
||
|
||
**查询参数**:
|
||
| 参数 | 类型 | 必需 | 说明 |
|
||
|------|------|------|------|
|
||
| `limit` | int | ❌ | 返回数量,默认 100 |
|
||
| `rating` | int | ❌ | 按评分过滤(1=赞,-1=踩) |
|
||
| `user_id` | string | ❌ | 按用户 ID 过滤 |
|
||
| `start_date` | string | ❌ | 起始日期 |
|
||
| `end_date` | string | ❌ | 结束日期 |
|
||
|
||
> **注意**:该接口不支持 `page`/`page_size` 分页,使用 `limit` 控制返回数量。
|
||
|
||
**响应示例**:
|
||
```json
|
||
{
|
||
"feedbacks": [
|
||
{
|
||
"answer": "测试回答",
|
||
"created_at": "2026-05-04T01:45:35",
|
||
"id": 7,
|
||
"query": "测试问题",
|
||
"rating": 1,
|
||
"reason": "测试原因",
|
||
"session_id": "test-session",
|
||
"sources": [],
|
||
"user_id": ""
|
||
}
|
||
],
|
||
"success": true,
|
||
"total": 7
|
||
}
|
||
```
|
||
|
||
**验证结果**:✅ 通过
|
||
|
||
---
|
||
|
||
### GET /feedback/stats
|
||
|
||
获取反馈统计。
|
||
|
||
```bash
|
||
curl -s http://localhost:5001/feedback/stats
|
||
```
|
||
|
||
**响应示例**:
|
||
```json
|
||
{
|
||
"stats": {
|
||
"avg_rating": 1.0,
|
||
"negative_count": 0,
|
||
"positive_count": 8,
|
||
"satisfaction_rate": 100.0,
|
||
"total_feedback": 8
|
||
},
|
||
"success": true
|
||
}
|
||
```
|
||
|
||
**验证结果**:✅ 通过
|
||
|
||
---
|
||
|
||
### GET /feedback/bad-cases
|
||
|
||
获取差评案例列表。
|
||
|
||
```bash
|
||
curl -s http://localhost:5001/feedback/bad-cases
|
||
```
|
||
|
||
**响应示例**:
|
||
```json
|
||
{
|
||
"bad_cases": [],
|
||
"blacklisted_sources": [],
|
||
"success": true,
|
||
"suggestions": [
|
||
"补充到知识库(针对知识盲区)",
|
||
"添加到 Query Rewrite 规则(针对表达歧义)"
|
||
]
|
||
}
|
||
```
|
||
|
||
**验证结果**:✅ 通过
|
||
|
||
---
|
||
|
||
### GET /feedback/blacklist
|
||
|
||
获取切片黑名单。
|
||
|
||
```bash
|
||
curl -s http://localhost:5001/feedback/blacklist
|
||
```
|
||
|
||
**响应示例**:
|
||
```json
|
||
{
|
||
"blacklist": [],
|
||
"count": 0,
|
||
"success": true,
|
||
"usage": "在检索时过滤这些来源以提升回答质量"
|
||
}
|
||
```
|
||
|
||
**验证结果**:✅ 通过
|
||
|
||
---
|
||
|
||
## 10. FAQ 管理
|
||
|
||
### GET /faq
|
||
|
||
获取 FAQ 列表。
|
||
|
||
```bash
|
||
curl -s "http://localhost:5001/faq?limit=5"
|
||
```
|
||
|
||
**查询参数**:
|
||
| 参数 | 类型 | 必需 | 说明 |
|
||
|------|------|------|------|
|
||
| `status` | string | ❌ | 按状态过滤(如 `approved`、`draft`) |
|
||
| `limit` | int | ❌ | 返回数量,默认 50 |
|
||
|
||
**响应示例**:
|
||
```json
|
||
{
|
||
"faqs": [
|
||
{
|
||
"answer": "根据参考资料...",
|
||
"avg_rating": 1.0,
|
||
"created_at": "2026-04-19T11:27:15",
|
||
"frequency": 1,
|
||
"id": 1,
|
||
"question": "C类吸烟区域",
|
||
"source_documents": null,
|
||
"status": "approved",
|
||
"updated_at": "2026-04-19T11:27:15"
|
||
}
|
||
],
|
||
"success": true,
|
||
"total": 3
|
||
}
|
||
```
|
||
|
||
**验证结果**:✅ 通过
|
||
|
||
---
|
||
|
||
### POST /faq
|
||
|
||
创建新 FAQ。
|
||
|
||
```bash
|
||
curl -s -X POST http://localhost:5001/faq \
|
||
-H "Content-Type: application/json" \
|
||
-d "{\"question\":\"FAQ question\",\"answer\":\"FAQ answer\"}"
|
||
```
|
||
|
||
**请求体**:
|
||
| 字段 | 类型 | 必需 | 说明 |
|
||
|------|------|------|------|
|
||
| `question` | string | ✅ | 问题内容 |
|
||
| `answer` | string | ✅ | 答案内容 |
|
||
|
||
**响应示例**:
|
||
```json
|
||
{
|
||
"faq_id": 7,
|
||
"message": "FAQ已创建,请通过 /faq/<id>/approve 接口确认后生效",
|
||
"status": "draft",
|
||
"success": true
|
||
}
|
||
```
|
||
|
||
**验证结果**:✅ 通过
|
||
|
||
---
|
||
|
||
### PUT /faq/\<id\>
|
||
|
||
修改 FAQ。
|
||
|
||
```bash
|
||
curl -s -X PUT "http://localhost:5001/faq/7" \
|
||
-H "Content-Type: application/json" \
|
||
-d "{\"question\":\"updated question\",\"answer\":\"updated answer\"}"
|
||
```
|
||
|
||
**请求体**:
|
||
| 字段 | 类型 | 必需 | 说明 |
|
||
|------|------|------|------|
|
||
| `question` | string | ❌ | 新问题内容 |
|
||
| `answer` | string | ❌ | 新答案内容 |
|
||
|
||
**响应示例**:
|
||
```json
|
||
{
|
||
"message": "FAQ更新成功",
|
||
"success": true,
|
||
"sync_status": "skipped"
|
||
}
|
||
```
|
||
|
||
**验证结果**:✅ 通过
|
||
|
||
---
|
||
|
||
### DELETE /faq/\<id\>
|
||
|
||
删除 FAQ。
|
||
|
||
```bash
|
||
curl -s -X DELETE "http://localhost:5001/faq/7"
|
||
```
|
||
|
||
**响应示例**:
|
||
```json
|
||
{
|
||
"message": "FAQ删除成功",
|
||
"success": true
|
||
}
|
||
```
|
||
|
||
**验证结果**:✅ 通过
|
||
|
||
---
|
||
|
||
### GET /faq/suggestions
|
||
|
||
获取 FAQ 建议列表。
|
||
|
||
```bash
|
||
curl -s "http://localhost:5001/faq/suggestions?status=pending&limit=5"
|
||
```
|
||
|
||
**查询参数**:
|
||
| 参数 | 类型 | 必需 | 说明 |
|
||
|------|------|------|------|
|
||
| `status` | string | ❌ | 按状态过滤,默认 `pending` |
|
||
| `limit` | int | ❌ | 返回数量,默认 50 |
|
||
|
||
**响应示例**:
|
||
```json
|
||
{
|
||
"success": true,
|
||
"suggestions": [
|
||
{
|
||
"answer": "",
|
||
"avg_rating": 1.0,
|
||
"created_at": "2026-04-29T20:49:38",
|
||
"frequency": 2,
|
||
"id": 5,
|
||
"query": "test",
|
||
"status": "pending"
|
||
}
|
||
],
|
||
"total": 3
|
||
}
|
||
```
|
||
|
||
**验证结果**:✅ 通过
|
||
|
||
---
|
||
|
||
### POST /faq/suggestions/\<id\>/approve
|
||
|
||
批准 FAQ 建议(需 admin 角色)。
|
||
|
||
```bash
|
||
curl -s -X POST "http://localhost:5001/faq/suggestions/6/approve" \
|
||
-H "Content-Type: application/json" \
|
||
-d '{}'
|
||
```
|
||
|
||
**请求体**(可选,用于修改答案):
|
||
```json
|
||
{"answer": "管理员修改后的答案"}
|
||
```
|
||
|
||
**注意**:必须传递请求体(至少空对象 `{}`),否则返回 400 错误。
|
||
|
||
**验证结果**:✅ 通过
|
||
|
||
---
|
||
|
||
### POST /faq/suggestions/\<id\>/reject
|
||
|
||
拒绝 FAQ 建议(需 admin 角色)。
|
||
|
||
```bash
|
||
curl -s -X POST "http://localhost:5001/faq/suggestions/6/reject" \
|
||
-H "Content-Type: application/json" \
|
||
-d '{}'
|
||
```
|
||
|
||
**验证结果**:✅ 通过
|
||
|
||
---
|
||
|
||
## 11. 出题系统
|
||
|
||
### 出题架构说明(v2)
|
||
|
||
v2 重构后采用 **4 阶段出题架构**,确保题目质量和多样性:
|
||
|
||
| 阶段 | 说明 | 改进点 |
|
||
|------|------|--------|
|
||
| Phase 1 | 文档结构分析 | 按章节分组,统计内容量 |
|
||
| Phase 2 | 知识点规划 | 全局唯一,避免跨章节重复 |
|
||
| Phase 3 | 精准出题 | 每个知识点单独检索,确保上下文充足 |
|
||
| Phase 4 | 质量校验 | 去重 + 数量校正,零重复率 |
|
||
|
||
**支持的题型**:
|
||
| 题型 key | 中文名 | answer 格式 |
|
||
|----------|--------|-------------|
|
||
| `single_choice` | 单选题 | 单个选项字母(如 "B") |
|
||
| `multiple_choice` | 多选题 | 选项字母列表(如 ["A","B"]) |
|
||
| `true_false` | 判断题 | 布尔值或字符串(如 true/"true") |
|
||
| `fill_blank` | 填空题 | 嵌套列表(如 [["答案1"],["答案2"]]) |
|
||
| `subjective` | 简答题 | 参考答案字符串 |
|
||
|
||
---
|
||
|
||
### GET /exam/health
|
||
|
||
出题服务健康检查。
|
||
|
||
```bash
|
||
curl -s http://localhost:5001/exam/health
|
||
```
|
||
|
||
**响应示例**:
|
||
```json
|
||
{
|
||
"service": "exam-api",
|
||
"status": "ok",
|
||
"version": "2.0"
|
||
}
|
||
```
|
||
|
||
**验证结果**:✅ 通过
|
||
|
||
---
|
||
|
||
### POST /exam/generate
|
||
|
||
生成考题(指定题型和数量)。
|
||
|
||
**特点**:
|
||
- 需要手动指定 `question_types`(每种题型的数量)
|
||
- 适合有明确需求的场景(如"出 5 道单选题")
|
||
|
||
```bash
|
||
curl -s -X POST http://localhost:5001/exam/generate \
|
||
-H "Content-Type: application/json" \
|
||
-d '{"file_path":"public_kb/1.docx","collection":"public_kb","question_types":{"single_choice":5,"true_false":3,"fill_blank":2}}'
|
||
```
|
||
|
||
**请求体**:
|
||
| 字段 | 类型 | 必需 | 说明 |
|
||
|------|------|------|------|
|
||
| `file_path` | string | ✅ | 文档路径(格式:`collection/filename`) |
|
||
| `collection` | string 或 string[] | ✅ | 知识库名称,支持数组(按优先级排序) |
|
||
| `question_types` | object | ✅ | 题型数量配置 |
|
||
| `difficulty` | int | ❌ | 难度等级(1-5),默认 3 |
|
||
| `options` | object | ❌ | 附加选项(如 `max_source_chunks`) |
|
||
| `request_id` | string | ❌ | 请求 ID(幂等性) |
|
||
|
||
> **注意**:生产模式(`DEV_MODE=false`)下无需传 `Authorization` header,直接放行。开发模式下可传 `Authorization: Bearer mock-token-admin` 模拟管理员身份。
|
||
|
||
**question_types 配置示例**:
|
||
```json
|
||
{
|
||
"single_choice": 5,
|
||
"multiple_choice": 2,
|
||
"true_false": 3,
|
||
"fill_blank": 2,
|
||
"subjective": 1
|
||
}
|
||
```
|
||
|
||
**响应示例**:
|
||
```json
|
||
{
|
||
"data": {
|
||
"questions": [
|
||
{
|
||
"content": {
|
||
"stem": "重购率的定义是下列哪一项?",
|
||
"answer": "B",
|
||
"data": {
|
||
"options": [
|
||
{"content": "选项A内容", "key": "A"},
|
||
{"content": "品规连续两周订货客户数/上周订货客户数*100%", "key": "B"}
|
||
]
|
||
},
|
||
"explanation": "重购率的定义是..."
|
||
},
|
||
"difficulty": 3,
|
||
"question_type": "single_choice",
|
||
"source_trace": {
|
||
"chunk_ids": ["1.docx_76"],
|
||
"document_name": "public_kb/1.docx",
|
||
"page_numbers": [1],
|
||
"sources": [...]
|
||
}
|
||
}
|
||
],
|
||
"request_id": null,
|
||
"source_chunks_used": 15,
|
||
"success": true,
|
||
"total": 10
|
||
},
|
||
"message": "出题成功",
|
||
"status": "success",
|
||
"status_code": 2020,
|
||
"success": true
|
||
}
|
||
```
|
||
|
||
**验证结果**:✅ 通过
|
||
|
||
---
|
||
|
||
### POST /exam/generate-smart
|
||
|
||
AI 智能出题 - 自动分析文件并决定题型和数量。
|
||
|
||
**特点**:
|
||
- 不需要传 `question_types`,AI 自动分析文档后决定
|
||
- 返回格式与旧端口完全兼容,额外包含 `ai_analysis` 字段
|
||
- 适合不想费脑子的场景
|
||
|
||
```bash
|
||
curl -s -X POST http://localhost:5001/exam/generate-smart \
|
||
-H "Content-Type: application/json" \
|
||
-d '{"file_path":"public_kb/1.docx","collection":"public_kb"}'
|
||
```
|
||
|
||
**请求体**:
|
||
| 字段 | 类型 | 必需 | 说明 |
|
||
|------|------|------|------|
|
||
| `file_path` | string | ✅ | 文档路径(格式:`collection/filename`) |
|
||
| `collection` | string 或 string[] | ✅ | 知识库名称,支持数组(按优先级排序) |
|
||
| `difficulty` | int | ❌ | 难度等级(1-5),默认 3 |
|
||
| `options` | object | ❌ | 附加选项 |
|
||
|
||
**响应示例**:
|
||
```json
|
||
{
|
||
"data": {
|
||
"ai_analysis": {
|
||
"total_knowledge_points": 21,
|
||
"suitable_types": ["single_choice", "multiple_choice", "true_false", "subjective"],
|
||
"question_types": {
|
||
"single_choice": 8,
|
||
"multiple_choice": 6,
|
||
"true_false": 4,
|
||
"fill_blank": 0,
|
||
"subjective": 3
|
||
},
|
||
"reason": "文档包含21个知识点,涵盖术语定义、流程步骤、数值标准..."
|
||
},
|
||
"questions": [...],
|
||
"request_id": null,
|
||
"source_chunks_used": 15,
|
||
"success": true,
|
||
"total": 16
|
||
},
|
||
"message": "AI 智能出题成功",
|
||
"status": "success",
|
||
"status_code": 2020,
|
||
"success": true
|
||
}
|
||
```
|
||
|
||
**注意事项**:
|
||
- 实际出题数量 ≤ min(文档知识点数, AI 推荐数量)
|
||
- 如果文档知识点较少,生成的题目数量会相应减少
|
||
- 生产模式下无需传 `Authorization` header
|
||
|
||
**支持的题型**:
|
||
| 题型 key | 中文名 | 说明 |
|
||
|----------|--------|------|
|
||
| `single_choice` | 单选题 | content.answer 为单个选项字母 |
|
||
| `multiple_choice` | 多选题 | content.answer 为选项字母列表 |
|
||
| `true_false` | 判断题 | content.answer 为布尔值或字符串 |
|
||
| `fill_blank` | 填空题 | content.answer 为嵌套列表 |
|
||
| `subjective` | 简答题 | content.answer 为参考答案 |
|
||
|
||
**验证结果**:✅ 通过
|
||
|
||
---
|
||
|
||
### POST /exam/grade
|
||
|
||
批阅答案。
|
||
|
||
```bash
|
||
echo '{"answers":[{"question_id":"q1","question_type":"single_choice","question_content":{"answer":"B"},"student_answer":"B","max_score":2}]}' > /tmp/grade.json
|
||
curl -s -X POST http://localhost:5001/exam/grade \
|
||
-H "Content-Type: application/json" \
|
||
-d @/tmp/grade.json
|
||
```
|
||
|
||
**请求体**:
|
||
| 字段 | 类型 | 必需 | 说明 |
|
||
|------|------|------|------|
|
||
| `answers` | array | ✅ | 答案数组 |
|
||
|
||
**answers 数组元素**:
|
||
| 字段 | 类型 | 必需 | 说明 |
|
||
|------|------|------|------|
|
||
| `question_id` | string | ✅ | 题目 ID |
|
||
| `question_type` | string | ✅ | 题型 |
|
||
| `question_content` | object | ✅ | 题目内容(含标准答案) |
|
||
| `student_answer` | string/array | ✅ | 学生答案 |
|
||
| `max_score` | int | ✅ | 满分 |
|
||
|
||
**响应示例**:
|
||
```json
|
||
{
|
||
"data": {
|
||
"request_id": null,
|
||
"results": [
|
||
{
|
||
"correct": true,
|
||
"feedback": "正确!",
|
||
"max_score": 2,
|
||
"question_id": "q1",
|
||
"score": 2
|
||
}
|
||
],
|
||
"score_rate": 100.0,
|
||
"success": true,
|
||
"total_max_score": 2,
|
||
"total_score": 2
|
||
},
|
||
"message": "批阅完成",
|
||
"status": "success",
|
||
"status_code": 2021,
|
||
"success": true
|
||
}
|
||
```
|
||
|
||
**验证结果**:✅ 通过
|
||
|
||
---
|
||
|
||
## 12. 图片服务
|
||
|
||
### GET /images/list
|
||
|
||
获取图片列表。
|
||
|
||
```bash
|
||
curl -s "http://localhost:5001/images/list?limit=5&offset=0"
|
||
```
|
||
|
||
**查询参数**:
|
||
| 参数 | 类型 | 必需 | 说明 |
|
||
|------|------|------|------|
|
||
| `limit` | int | ❌ | 返回数量,默认 50 |
|
||
| `offset` | int | ❌ | 偏移量,默认 0 |
|
||
|
||
**响应示例**:
|
||
```json
|
||
{
|
||
"images": [
|
||
{
|
||
"image_id": "0569dd285537",
|
||
"size_bytes": 169818,
|
||
"url": "/images/0569dd285537"
|
||
}
|
||
],
|
||
"limit": 5,
|
||
"offset": 0,
|
||
"total": 67
|
||
}
|
||
```
|
||
|
||
**验证结果**:✅ 通过
|
||
|
||
---
|
||
|
||
### GET /images/\<id\>
|
||
|
||
获取单张图片。
|
||
|
||
```bash
|
||
curl -s -o image.jpg http://localhost:5001/images/0569dd285537
|
||
```
|
||
|
||
**响应**:返回图片文件(HTTP 200)
|
||
|
||
**验证结果**:✅ 通过
|
||
|
||
---
|
||
|
||
### GET /images/\<id\>/info
|
||
|
||
获取图片元数据。
|
||
|
||
```bash
|
||
curl -s "http://localhost:5001/images/0569dd285537/info"
|
||
```
|
||
|
||
**响应示例**:
|
||
```json
|
||
{
|
||
"format": "JPEG",
|
||
"height": 1357,
|
||
"image_id": "0569dd285537",
|
||
"mode": "RGB",
|
||
"size_bytes": 169818,
|
||
"url": "/images/0569dd285537",
|
||
"width": 1023
|
||
}
|
||
```
|
||
|
||
**验证结果**:✅ 通过
|
||
|
||
---
|
||
|
||
### GET /images/stats
|
||
|
||
获取图片统计。
|
||
|
||
```bash
|
||
curl -s http://localhost:5001/images/stats
|
||
```
|
||
|
||
**响应示例**:
|
||
```json
|
||
{
|
||
"format_counts": {
|
||
".jpg": 46,
|
||
".png": 21
|
||
},
|
||
"supported_formats": [".jpeg", ".gif", ".bmp", ".jpg", ".webp", ".png"],
|
||
"total_images": 67,
|
||
"total_size_bytes": 5394510,
|
||
"total_size_mb": 5.14
|
||
}
|
||
```
|
||
|
||
**验证结果**:✅ 通过
|
||
|
||
---
|
||
|
||
## 13. 报告服务
|
||
|
||
### GET /reports/weekly
|
||
|
||
获取周报。
|
||
|
||
```bash
|
||
curl -s http://localhost:5001/reports/weekly
|
||
```
|
||
|
||
**响应示例**:
|
||
```json
|
||
{
|
||
"report": {
|
||
"avg_rating": 1.0,
|
||
"created_at": "2026-05-04T01:49:16",
|
||
"end_date": "2026-05-10",
|
||
"high_freq_queries": [
|
||
{"frequency": 1, "query": "测试问题", "sample_answer": "测试回答"}
|
||
],
|
||
"improvement_suggestions": ["继续保持当前服务质量"],
|
||
"low_rating_queries": [],
|
||
"negative_count": 0,
|
||
"positive_count": 1,
|
||
"report_type": "weekly",
|
||
"satisfaction_rate": 100.0,
|
||
"start_date": "2026-05-04",
|
||
"total_feedback": 1,
|
||
"total_queries": 1
|
||
},
|
||
"success": true
|
||
}
|
||
```
|
||
|
||
**验证结果**:✅ 通过
|
||
|
||
---
|
||
|
||
### GET /reports/monthly
|
||
|
||
获取月报。
|
||
|
||
```bash
|
||
curl -s http://localhost:5001/reports/monthly
|
||
```
|
||
|
||
**验证结果**:✅ 通过(接口存在)
|
||
|
||
---
|
||
|
||
## 14. 知识库路由
|
||
|
||
### POST /kb/route
|
||
|
||
测试知识库路由(调试用)。
|
||
|
||
```bash
|
||
echo '{"query":"三峡工程"}' > /tmp/route.json
|
||
curl -s -X POST http://localhost:5001/kb/route \
|
||
-H "Content-Type: application/json" \
|
||
-d @/tmp/route.json
|
||
```
|
||
|
||
**响应示例**:
|
||
```json
|
||
{
|
||
"intent": {
|
||
"confidence": 0.95,
|
||
"department": null,
|
||
"is_general": true,
|
||
"keywords": [],
|
||
"reason": "LLM 意图分析"
|
||
},
|
||
"query": "三峡工程",
|
||
"target_collections": ["public_kb"],
|
||
"user_department": "",
|
||
"user_role": "user"
|
||
}
|
||
```
|
||
|
||
**验证结果**:✅ 通过
|
||
|
||
---
|
||
|
||
## 附录. 已知问题
|
||
|
||
### 1. /rag 接口 collections 参数
|
||
|
||
**问题**:使用 `collection`(单数)参数指定知识库无效,会被忽略并默认检索 `public_kb`。
|
||
|
||
**解决**:必须使用 `collections`(复数,数组格式)参数。
|
||
|
||
```bash
|
||
# ❌ 错误用法 - collection 单数参数无效
|
||
{"message": "问题", "collection": "dept_tech", "chat_history": []}
|
||
|
||
# ✅ 正确用法 - collections 数组参数
|
||
{"message": "问题", "collections": ["dept_tech"], "chat_history": []}
|
||
```
|
||
|
||
---
|
||
|
||
## 测试覆盖统计
|
||
|
||
> 2026-06-04 生产服务器测试结果(47.116.16.222,云端 Reranker + MMR 文本相似度)
|
||
|
||
| 分类 | 总数 | 通过 | 超时/异常 | 备注 |
|
||
|------|------|------|-----------|------|
|
||
| 健康检查 | 1 | 1 | 0 | ✅ 0.002s |
|
||
| 问答接口 | 2 | 2 | 0 | ✅ /rag 流式 12-14s |
|
||
| 检索接口 | 1 | 1 | 0 | ✅ /search 0.58-1.53s |
|
||
| 向量库管理 | 3 | 3 | 0 | ✅ |
|
||
| 文档管理 | 1 | 1 | 0 | ✅ |
|
||
| 同步服务 | 3 | 3 | 0 | ✅ |
|
||
| 反馈系统 | 4 | 4 | 0 | ✅ |
|
||
| FAQ 管理 | 2 | 2 | 0 | ✅ |
|
||
| 出题系统 | 1 | 1 | 0 | ✅ |
|
||
| 图片服务 | 2 | 2 | 0 | ✅ |
|
||
| 报告服务 | 2 | 2 | 0 | ✅ |
|
||
| 知识库路由 | 1 | 1 | 0 | ✅ |
|
||
| **总计** | **23** | **23** | **0** | **全部通过** |
|
||
|
||
---
|
||
|
||
## 性能基准测试
|
||
|
||
> 2026-06-04 生产服务器实测(47.116.16.222,public_kb 824 切片)
|
||
|
||
### 检索性能
|
||
|
||
| 接口 | 参数 | 优化前 | 优化后 | 提升 |
|
||
|------|------|--------|--------|------|
|
||
| `/search` | top_k=10 | ~34s | **0.58s** | ~60x |
|
||
| `/search` | top_k=30 | ~87s | **1.53s** | ~57x |
|
||
|
||
### 完整 RAG 问答性能(流式)
|
||
|
||
| 查询 | 完整响应时间 | 搜索阶段 | LLM 生成 |
|
||
|------|-------------|----------|----------|
|
||
| 现代终端分类有哪些? | 13.8s | ~1.5s | ~12s |
|
||
| 加盟终端分公司审批流程 | 12.7s | ~1.5s | ~11s |
|
||
| 什么是金丝利零售 | 12.7s | ~1.5s | ~11s |
|
||
|
||
### 优化措施
|
||
|
||
| 优化项 | 配置 | 效果 |
|
||
|--------|------|------|
|
||
| Reranker 云端化 | `RERANK_BACKEND=cloud`(qwen3-rerank) | 搜索阶段从 33-48s 降至 ~0.3s |
|
||
| MMR 文本相似度 | `MMR_USE_EMBEDDING=false` | MMR 阶段从 ~36s 降至 ~0s |
|
||
|
||
### 耗时拆解(优化后 /rag 问答)
|
||
|
||
```
|
||
总耗时 ~13s
|
||
├── 搜索管线 ~1.5s
|
||
│ ├── Embedding (query) ~0.25s
|
||
│ ├── 向量检索 + BM25 ~0.3s
|
||
│ ├── RRF 融合 ~0.01s
|
||
│ ├── 上下文扩展 ~0.1s
|
||
│ ├── MMR 去重 (文本) ~0.01s
|
||
│ ├── Cloud Reranker ~0.3s
|
||
│ └── 后处理 ~0.5s
|
||
└── LLM 流式生成 ~11.5s
|
||
├── 网络建连 ~0.5s
|
||
└── 流式 token 生成 ~11s
|
||
```
|
||
|
||
> **注**:LLM 生成阶段耗时取决于 qwen-plus API 响应速度,非本地可优化。如需进一步压缩至 10s 以内,可考虑换用更快的模型(如 qwen-turbo)。
|
||
|
||
---
|
||
|
||
## 附录 B. 生产部署说明
|
||
|
||
### 多向量库架构
|
||
|
||
生产环境采用**多向量库模式**,每个知识库独立存储在 `knowledge/vector_store/chroma/<kb_name>/` 目录下,各自维护独立的 ChromaDB SQLite 数据库和 BM25 索引。
|
||
|
||
当前生产服务器知识库列表:
|
||
|
||
| 知识库 | 切片数 | 说明 |
|
||
|--------|--------|------|
|
||
| public_kb | ~824 | 公开知识库,所有用户可访问 |
|
||
| dept_1_kb | ~800 | 部门知识库 1 |
|
||
| dept_2_kb | ~118 | 部门知识库 2 |
|
||
| dept_3_kb | ~132 | 部门知识库 3 |
|
||
| dept_4_kb | ~4 | 部门知识库 4 |
|
||
| dept_6_kb | ~29 | 部门知识库 6 |
|
||
| test1 | ~637 | 测试知识库 |
|
||
| faq_kb / test3 | 0 | 空(预留) |
|
||
|
||
### 切片元数据字段
|
||
|
||
新代码构建的向量库切片包含以下 metadata 字段:
|
||
|
||
| 字段 | 说明 | 新代码新增 |
|
||
|------|------|-----------|
|
||
| `chunk_id` | 切片唯一标识 `{文件名}_{序号}` | |
|
||
| `chunk_index` | 切片在文档中的序号(用于引用溯源跳转) | ✅ |
|
||
| `chunk_type` | text / table / image | |
|
||
| `source` | 来源文件名 | |
|
||
| `collection` | 所属知识库 | |
|
||
| `doc_type` | 文档类型 pdf/word/excel/other | ✅ |
|
||
| `page` / `page_end` | 页码范围 | |
|
||
| `section` | 所属章节 | |
|
||
| `status` | active / deprecated | |
|
||
| `version` | 版本号 v1 | |
|
||
|
||
### 向量库重构
|
||
|
||
当代码升级涉及元数据字段变更时(如新增 `chunk_index`、`doc_type`),需要重构向量库:
|
||
|
||
```bash
|
||
# 重构指定知识库(清除哈希记录 → 触发全量同步)
|
||
curl -s -X POST http://127.0.0.1:5001/collections/<kb_name>/reindex
|
||
```
|
||
|
||
> **⚠️ 注意**:reindex 会调用 `sync_now()` 全局同步,期间 gunicorn worker 被阻塞,搜索和问答接口将暂时无响应。建议在低峰期执行。
|
||
|
||
### Reranker 配置
|
||
|
||
生产环境使用 DashScope 云端 Reranker 替代本地 CPU 推理,显著提升检索速度:
|
||
|
||
| 配置项 | 值 | 说明 |
|
||
|--------|-----|------|
|
||
| `RERANK_BACKEND` | `cloud` | 使用云端 API(可选 `local` / `cloud` / `fallback`) |
|
||
| `RERANK_CLOUD_MODEL` | `qwen3-rerank` | DashScope 云端排序模型 |
|
||
| `RERANK_CLOUD_API_KEY` | `sk-*` | DashScope 标准 API Key |
|
||
| `RERANK_CLOUD_BASE_URL` | `https://dashscope.aliyuncs.com/compatible-api/v1/reranks` | OpenAI 兼容端点 |
|
||
| `MMR_USE_EMBEDDING` | `false` | MMR 使用文本相似度(零额外计算) |
|
||
|
||
> **fallback 模式**:`RERANK_BACKEND=fallback` 优先使用云端 API,如果云端不可用则自动回退到本地模型,适合生产环境高可用场景。
|