RAG 知识问答系统 软件需求规格说明书(SRS)
1. 引言
1.1 目的与范围
本文档定义「RAG 知识问答系统」v1.0 的系统架构、功能需求、界面设计与接口设计,作为前后端开发、联调与验收的依据。
系统定位:面向中小规模私有知识库(个人/团队级,文档总量 ≤ 1000 篇)的检索增强问答系统。用户上传 txt / pdf / docx 文档,系统切块入库,提供基于「BM25 关键词 + 向量语义 → RRF 融合 → Rerank 精排 → LLM 生成」管线的问答服务,回答附带原文引用。
v1.0 不包含:多用户权限体系、公网部署与高可用、对话式多轮上下文追问、模型微调。
1.2 术语表
| 术语 | 说明 |
|---|---|
| Embedding | 将文本映射为稠密向量,语义相近则向量相近(本项目用 bge-small-zh-v1.5,512 维) |
| BM25 | 基于词频(TF)与逆文档频率(IDF)的经典关键词检索算法,中文需先用 jieba 分词 |
| RRF | Reciprocal Rank Fusion,按排名累加 1/(K+rank) 融合多路检索结果,K=60 |
| Rerank / 精排 | Cross-Encoder(bge-reranker-base)将「问题+文档」拼接后精算相关度,对召回的 Top-N 重排序 |
| Chunk / 块 | 文档切块后的最小检索单元 |
| 召回 | 从全量块中粗筛候选集(BM25 一路 + 向量一路) |
| 引用 | 回答中以 [1] [2] 标注结论来源,对应检索命中的原文块 |
2. 总体描述
2.1 系统定位与目标
核心目标:
- 全部参数(LLM、模型路径、检索参数、切块参数)可在界面上配置,改配置不改代码
- 知识库文档通过界面上传、切块、入库、删除,无需手工放文件
- 问答回答带引用来源,可追溯原文
- 检索链路各阶段结果可观测:双路调试视图 + 问答页过程面板(用于调参与排障)
2.2 用户与角色
| 角色 | 说明 | v1.0 权限 |
|---|---|---|
| 普通用户 | 提问、查看回答与引用 | 问答页全部功能 |
| 知识库管理员 | 上传/删除文档、重建索引、向量查询调试 | 知识库页 + 问答页 |
| 系统管理员 | 维护配置参数 | 配置页 + 以上全部 |
v1.0 为单用户模式(无登录鉴权),角色仅用于功能分区;多用户与鉴权列入 v2.0 展望。
2.3 运行环境
| 项 | 要求 |
|---|---|
| 服务端 | Windows / Linux,Python 3.10+,单进程部署 |
| 客户端 | 现代浏览器(Chrome / Edge 最近两个大版本) |
| 模型 | 本地模型目录:bge-small-zh-v1.5(embedding)、bge-reranker-base(精排),手工下载到 backend/models/ |
| LLM | 任意 OpenAI 兼容 Chat Completions 接口(地址、模型名、Key 均可配置) |
| 存储 | SQLite(配置与文档元数据)+ Chroma 落盘(向量)+ 磁盘文件(原始上传文件) |
2.4 约束与假设
- 假设:单机单实例部署;模型加载内存占用约 2~3GB(CPU 推理可用,GPU 可选加速)
- 约束:回答必须严格基于检索命中的内容,无命中时明确告知,禁止模型自由发挥(沿用 rag_core 的系统提示词策略)
- 假设:文档为「段落型」文本资料;扫描版 PDF(纯图片无文字层)解析出的文本为空时应标记失败并提示
[TBD:是否引入 OCR]
3. 技术栈与项目结构
3.1 技术栈
| 层 | 选型 | 说明 |
|---|---|---|
| 前端 | Vue 3 + Vite + Pinia + Vue Router + Element Plus | 选项式 API,Axios 通信 |
| 后端 | Python + FastAPI + Uvicorn | REST + SSE,Pydantic 校验 |
| 检索 | jieba(分词)+ 自研 BM25 + Chroma(向量库) | 复用 rag_core.py 成熟实现 |
| 模型 | sentence-transformers(bge-small-zh-v1.5 / bge-reranker-base) | 本地 models/ 目录加载,离线运行 |
| 生成 | OpenAI 兼容接口(openai SDK) | 模型名 / 地址 / Key 可配置 |
| 文档解析 | pypdf(pdf)、python-docx(docx)、内置读取(txt) | UTF-8 / GBK 自动探测 |
| 元数据存储 | SQLite(sqlite3 标准库) | 零运维 |
3.2 项目结构
rag-demo/
├── frontend/ # Vue3 前端
│ ├── src/
│ │ ├── api/ # Axios 封装(config.js / kb.js / qa.js)
│ │ ├── views/ # 页面:QaChat / KbManage / ConfigManage
│ │ ├── stores/ # Pinia:配置、知识库状态
│ │ ├── components/ # 引用面板、检索过程面板、上传组件等
│ │ └── router.js
│ └── vite.config.js # dev 代理 /ragapi → backend:8088
│
├── backend/ # Python 后端
│ ├── app/
│ │ ├── main.py # FastAPI 入口、CORS、路由挂载
│ │ ├── routers/ # config.py / kb.py / qa.py
│ │ ├── services/
│ │ │ ├── rag_engine.py # 移植 rag_core:模型加载、BM25、RRF、Rerank、生成
│ │ │ ├── ingestion.py # 解析 → 切块 → 向量化 → 入库(含状态机)
│ │ │ └── config_service.py# 配置读写、热更新、校验
│ │ ├── models/ # Pydantic 请求/响应模型
│ │ └── db.py # SQLite 访问层
│ ├── data/
│ │ ├── uploads/ # 用户上传的原始文件
│ │ └── app.db # SQLite(配置 + 文档/块元数据)
│ ├── chroma_db/ # Chroma 向量落盘(自动生成)
│ ├── models/ # 本地模型(bge-small-zh-v1.5、bge-reranker-base)
│ └── requirements.txt
│
└── doc/ # 本文档4. 系统架构
4.1 分层架构
flowchart LR
subgraph 前端 [frontend · Vue3]
UI[页面层<br/>问答 / 知识库 / 配置]
STORE[Pinia 状态]
end
subgraph 后端 [backend · FastAPI]
API[接口层 routers<br/>REST + SSE]
SVC[服务层 services<br/>RagEngine / Ingestion / ConfigService]
REPO[数据层<br/>SQLite + Chroma + 文件]
end
LLM[外部 LLM<br/>OpenAI 兼容接口]
UI -->|HTTP /api| API
API --> SVC --> REPO
SVC -->|Chat Completions| LLM4.2 两条核心数据流
入库流(知识库管理触发)
flowchart LR
A[上传文件<br/>txt/pdf/docx] --> B[解析为纯文本]
B --> C[切块<br/>窗口+重叠, 参数可配]
C --> D[bge-small-zh<br/>批量向量化]
D --> E[(Chroma<br/>embedding+原文+metadata)]
C --> F[BM25 索引<br/>jieba 分词后内存重建]
E --> G[(SQLite<br/>文档/块元数据+状态)]
F --> G查询流(问答触发,v1.0 核心管线)
flowchart LR
Q[用户问题] --> B1[BM25 召回<br/>Top-50]
Q --> B2[向量召回<br/>Chroma Top-50]
B1 --> R["RRF 融合<br/>1/(60+rank) 累加"]
B2 --> R
R --> RR[Rerank 精排<br/>bge-reranker 取 Top-6]
RR --> P[拼装带编号的<br/>参考资料 Prompt]
P --> L[LLM 流式生成<br/>SSE 逐段推送]
L --> A1["回答 + [n] 引用标注"]关键规则:
- BM25 参数 k1=1.5、b=0.75(进配置页可调)
- Chroma 距离度量 cosine,返回距离统一转相似度
1 - distance - 生成系统提示词:严格依据参考资料回答,资料中没有则回答「根据现有资料无法回答」,关键结论后标注来源编号
4.3 配置热更新机制
- 所有配置存 SQLite
sys_config表,启动时加载,替代原.env方案 - 修改保存后:检索类参数(topK、RRF K、切块参数等)即时生效;模型类配置(模型路径、LLM 地址)保存后标记「待重载」,由管理员在配置页点击「重载引擎」触发模型重新加载(避免每次保存都数十秒的加载开销)
LLM_API_KEY属敏感信息:接口返回时脱敏(仅显示末 4 位),前端不可回显完整值
5. 功能需求
5.1 功能模块总览与优先级
| 模块 | 功能点 | 优先级 |
|---|---|---|
| F1 配置管理 | 查看/编辑配置、分组表单、LLM 连通性测试、恢复默认值、重载引擎 | P0 |
| F2 知识库管理 | 文件上传、解析切块入库、文档列表与状态、删除文档、全量重建、双路检索调试 | P0 |
| F3 增强检索问答 | 流式问答、引用来源面板、检索过程可视化、异常兜底 | P0 |
| F4 会话历史 | 本地保存最近 50 条问答记录、完整回放、单条删除与清空 | P0 |
5.2 F1 配置管理
F1.1 配置分组与字段
| 分组 | 字段 | 类型 | 默认值 | 说明 |
|---|---|---|---|---|
| LLM 生成 | llm_model | string | - | 模型名,如 deepseek-chat |
| llm_api_url | string | - | OpenAI 兼容接口地址 | |
| llm_api_key | secret | - | 保存后脱敏显示 | |
| llm_temperature | float | 0.3 | 0~1 | |
| 检索参数 | recall_size | int | 50 | 每路召回条数 |
| final_top_k | int | 6 | 融合精排后送入 LLM 的块数 | |
| rrf_k | int | 60 | RRF 常数 | |
| bm25_k1 / bm25_b | float | 1.5 / 0.75 | BM25 参数 | |
| min_similarity | float | 0.3 | 相似度阈值,低于此值视为无命中 | |
| 切块参数 | chunk_size | int | 300 | 每块目标字符数 |
| chunk_overlap | int | 50 | 相邻块重叠字符数 | |
| 模型路径 | embedding_model_path | string | models/bge-small-zh-v1.5 | 相对 backend/ |
| reranker_model_path | string | models/bge-reranker-base | 同上 |
F1.2 功能规则
| 编号 | 规则 |
|---|---|
| F1-1 | 表单按分组分区展示,保存前做类型与范围校验(非法值行内红字提示,禁止提交) |
| F1-2 | 「测试 LLM 连通性」:后端用当前表单值(未保存也可测)发送一条最小请求,返回 成功/失败+错误详情 |
| F1-3 | 「恢复默认值」:将表单回填为系统默认值(LLM 密钥类不清空),仍需手动保存 |
| F1-4 | 保存成功后提示哪些参数已即时生效、哪些需「重载引擎」,重载期间问答接口返回 503 |
| F1-5 | 模型路径保存时校验目录存在且包含 config.json,否则拒绝保存并提示 |
5.3 F2 知识库管理
F2.1 文件上传与入库
| 编号 | 规则 |
|---|---|
| F2-1 | 支持 .txt / .pdf / .docx,单文件 ≤ 20MB,一次最多 10 个;其余扩展名前端拦截 |
| F2-2 | txt 自动探测编码(UTF-8 优先,失败回退 GBK);pdf 用 pdfplumber 提取文本层;docx 用 python-docx 按段落提取 |
| F2-3 | 解析后正文为空(如扫描版 PDF)→ 该文档状态置「失败」,原因「未解析到文本」,不阻断批次中其他文件 |
| F2-4 | 上传成功即创建文档记录(状态「处理中」),后台异步执行:解析 → 切块(F1 切块参数)→ 批量向量化 → 写入 Chroma → 更新状态「就绪」;任一步异常置「失败」并记录原因 |
| F2-5 | 入库以文件内容 MD5 去重:重复上传返回已有文档记录并提示「已存在」 |
| F2-6 | 新文档入库完成后,BM25 内存索引基于全量「就绪」块增量重建 |
| F2-7 | 删除文档需二次确认;级联删除其全部块(Chroma 按 metadata.doc_id 删除 + SQLite 记录),同步刷新 BM25 索引;原始上传文件一并删除 |
| F2-8 | 「全量重建」:清空 Chroma 集合,按当前切块参数重新处理全部文档(用于改切块参数后重建),执行期间知识库页锁定操作按钮 |
F2.2 文档列表
字段:文件名、类型、大小、块数、状态(处理中/就绪/失败)、失败原因、上传时间、操作(查看块 / 删除)。列表自动轮询刷新(处理中状态时每 3 秒)。
F2.3 双路检索调试(BM25 + 向量 + RRF)
输入任意文本 + topK,并列返回三组结果,用于对比两路召回差异、验证入库质量与调优检索参数:
| 结果组 | 内容 | 分数含义 |
|---|---|---|
| BM25 路 | Top-K 块(文档名、原文摘要) | 词面匹配分(无上界) |
| 向量路 | Top-K 块(文档名、原文摘要) | 语义相似度 0~1 |
| RRF 融合 | 两路融合后 Top-K | 累计 RRF 分,附两路各自名次 |
三列并排展示,同一块横向对齐高亮,直观看到「哪路召回了它、名次多少、融合后排在第几」。
5.4 F3 增强检索问答
| 编号 | 规则 |
|---|---|
| F3-1 | 输入问题提交后,前端清空上一次回答区,进入「思考中」态(阶段提示:检索中 → 重排中 → 生成中) |
| F3-2 | 回答通过 SSE 流式渲染;生成完毕后展示引用来源面板 |
| F3-3 | 引用面板列出 Top-K 块:编号、来源文件名、原文摘要(前 80 字)、相似度;回答中的 [n] 与面板编号一一对应;点击 [n] 高亮定位对应来源条目 |
| F3-4 | 所有候选块相似度低于 min_similarity(F1)→ 不调用 LLM,直接返回「根据现有资料无法回答该问题」并提示去知识库补充资料 |
| F3-5 | LLM 调用失败(超时/鉴权/限流)→ 停止流式,展示错误原因与「重试」按钮;重试复用同一次检索结果,不重复检索 |
| F3-6 | 检索过程可视化:回答完成后可展开「检索过程」折叠面板,按四个阶段展示——① BM25 路 Top-10(词面分)② 向量路 Top-10(相似度)③ RRF 融合排名(累计分)④ Rerank 后 Top-6(精排分);每条含来源文档与块摘要;阶段 ④ 的序号与引用面板 [n] 编号一致,可点击联动 |
5.5 F4 会话历史
| 编号 | 规则 |
|---|---|
| F4-1 | 前端 localStorage 保存最近 50 条完整记录:问题、回答全文、引用列表、检索过程数据、耗时、时间戳 |
| F4-2 | 问答页提供「历史」入口,按时间倒序列出;点击条目在对话区完整回放(含引用与检索过程面板) |
| F4-3 | 支持单条删除与全部清空(清空需二次确认) |
| F4-4 | v1.0 不做服务端持久化:换浏览器或清缓存记录丢失,属可接受范围;服务端持久化列入 v2.0 展望 |
6. 界面设计
6.1 总体布局
左侧固定导航(宽 200px)+ 右侧主区。导航项:问答(默认)、知识库、配置。页头右侧展示知识库状态徽标(就绪块数)。
┌────────┬──────────────────────────────────────────┐
│ ◆ RAG │ 问答 [知识库: 128 块] │
│ ├──────────────────────────────────────────┤
│ 问答 │ │
│ 知识库 │ 主内容区 │
│ 配置 │ (随导航切换页面) │
│ │ │
└────────┴──────────────────────────────────────────┘6.2 问答页
┌─────────────────────────────┬───────────────┐
│ 对话区(滚动) [🕘历史]│ 引用来源面板 │
│ ┌───────────────────────┐ │ [1] 安全规程.txt│
│ │ 用户:井下作业注意什么? │ │ “…必须佩戴…”│
│ └───────────────────────┘ │ [2] 同上 0.82 │
│ ┌───────────────────────┐ │ │
│ │ 助手:…关键结论[1]… │ │ │
│ │ (流式打字渲染) │ │ │
│ └───────────────────────┘ │ │
│ ▸ 检索过程(四阶段,折叠) │ │
├─────────────────────────────┴───────────────┤
│ [ 输入问题… ] [发送] │
└─────────────────────────────────────────────┘交互态:发送后按钮禁用并显示阶段进度;错误时回答气泡内展示原因 + 重试按钮。
6.3 知识库页
┌──────────────────────────────────────────────┐
│ [上传文档] [全量重建] 搜索框: [文件名___] │
├──────┬──────┬──────┬──────┬────────┬────────┤
│ 文件名│ 类型 │ 块数 │ 状态 │ 上传时间 │ 操作 │
│ 安全规程.pdf│ pdf │ 42 │ ●就绪│ 10-22 │ 块/删除 │
│ 井下.docx │ docx│ 18 │ ◐处理中│10-22 │ — │
├──────┴──────┴──────┴──────┴────────┴────────┤
│ [双路检索调试] 输入文本____ [topK:6] [查询] │
│ BM25: 1.安全规程.txt(8.2) 向量: 1.同(0.91) │
│ RRF融合: 1.安全规程.txt 2.井下作业.docx … │
└──────────────────────────────────────────────┘上传组件支持拖拽;「处理中」行状态列带转圈图标,处理完成自动刷新。
6.4 配置页
按 F1.1 四个分组做卡片式表单,每张卡片右上角「恢复默认」。页脚横贯操作条:[保存] [测试 LLM 连通] [重载引擎]。保存后顶部出现提示条:「检索参数已生效;模型路径变更需重载引擎」。
7. 接口设计
约定:统一前缀 /api;响应体 { "code": 0, "msg": "ok", "data": ... },非 0 为业务错误码;SSE 接口例外(见 7.4)。错误码表:1001 参数校验失败、2001 LLM 调用失败、2002 模型未加载/重载中、3001 文档解析失败、3002 文档不存在。
7.1 配置接口
| 方法 | 路径 | 说明 |
|---|---|---|
| GET | /api/config | 读取全部配置(secret 字段脱敏) |
| PUT | /api/config | 保存配置(未传的 secret 字段表示不修改) |
| POST | /api/config/test-llm | 用请求体中的临时配置测试 LLM 连通性 |
| POST | /api/config/reload | 重载模型引擎(阻塞至完成,返回耗时) |
GET /api/config 响应 data 示例:
{
"llm": { "llm_model": "deepseek-chat", "llm_api_url": "https://api.xxx.com/v1",
"llm_api_key": "****abcd", "llm_temperature": 0.3 },
"retrieval": { "recall_size": 50, "final_top_k": 6, "rrf_k": 60,
"bm25_k1": 1.5, "bm25_b": 0.75, "min_similarity": 0.3 },
"chunking": { "chunk_size": 300, "chunk_overlap": 50 },
"models": { "embedding_model_path": "models/bge-small-zh-v1.5",
"reranker_model_path": "models/bge-reranker-base" }
}7.2 知识库接口
| 方法 | 路径 | 说明 |
|---|---|---|
| POST | /api/kb/documents | multipart 上传,file 可重复;立即返回文档记录(状态=处理中) |
| GET | /api/kb/documents?page=&size=&keyword= | 分页文档列表(含块数、状态、失败原因) |
| GET | /api/kb/documents/{doc_id}/chunks | 该文档块列表(序号、原文) |
| DELETE | /api/kb/documents/ | 删除文档及全部块、原始文件 |
| POST | /api/kb/rebuild | 全量重建(按当前切块参数) |
| POST | /api/kb/search | 双路检索调试:{"query": "文本", "top_k": 6},返回 BM25 / 向量 / RRF 三组排名 |
POST /api/kb/search 响应 data 示例:
{
"bm25": [
{ "chunk_id": 12, "doc_name": "安全规程.pdf", "text": "井下作业必须佩戴自救器……", "score": 8.24 }
],
"vector": [
{ "chunk_id": 12, "doc_name": "安全规程.pdf", "text": "井下作业必须佩戴自救器……", "similarity": 0.91 }
],
"rrf": [
{ "chunk_id": 12, "doc_name": "安全规程.pdf", "rrf_score": 0.0317, "bm25_rank": 1, "vector_rank": 2 }
]
}7.3 问答接口(非流式,供集成/调试)
POST /api/qa/ask/sync,请求 {"question": "井下作业注意什么?"},响应:
{
"answer": "井下作业应注意……[1]……[2]。",
"sources": [
{ "no": 1, "doc_name": "安全规程.pdf", "text": "井下作业必须佩戴自救器……", "similarity": 0.91 },
{ "no": 2, "doc_name": "安全规程.pdf", "text": "瓦斯浓度超过1%时……", "similarity": 0.86 }
],
"elapsed_ms": 3120
}7.4 问答接口(SSE 流式,主用)
POST /api/qa/ask,Accept: text/event-stream。事件序列:
| event | data | 说明 |
|---|---|---|
| stage | {"phase": "recall" / "rerank" / "generate"} | 阶段进度提示 |
| trace | {"bm25": [...], "vector": [...], "rrf": [...], "rerank": [...]} | 精排完成后推送检索过程明细(结构同 7.2,规模为各路 Top-10 / 精排 Top-6,供过程可视化面板) |
| delta | {"text": "…"} | 回答增量片段 |
| sources | {"sources": [...]} | 生成完毕推送引用列表(结构同 7.3) |
| done | {"elapsed_ms": 3120} | 结束 |
| error | {"code": 2001, "msg": "…"} | 任一环节失败 |
无命中(F3-4)时:无 delta 事件,直接一个 done,answer 在 done 前以单条 delta 给出固定提示文案。
7.5 系统接口
GET /api/health → {"status": "ok", "chunks": 128, "docs": 6, "engine": "ready"}(重载中 engine=loading)。
8. 数据设计
8.1 SQLite 表
sys_config:key TEXT PRIMARY KEY, value TEXT, updated_at —— 全部配置平铺 KV 存储,服务层按分组装配。
kb_document:
| 字段 | 类型 | 说明 |
|---|---|---|
| doc_id | INTEGER PK | 自增 |
| file_name | TEXT | 原文件名 |
| file_type | TEXT | txt/pdf/docx |
| file_size | INTEGER | 字节 |
| content_md5 | TEXT UNIQUE | 去重依据 |
| chunk_count | INTEGER | 就绪后回填 |
| status | TEXT | processing / ready / failed |
| fail_reason | TEXT | 失败原因 |
| created_at | TEXT | 上传时间 |
kb_chunk:
| 字段 | 类型 | 说明 |
|---|---|---|
| chunk_id | INTEGER PK | 全局自增,同时作为 Chroma 的 id |
| doc_id | INTEGER | 外键 → kb_document |
| chunk_index | INTEGER | 文档内序号 |
| text | TEXT | 块原文 |
8.2 Chroma 集合 rag_docs
- id:
str(chunk_id) - embedding:512 维(bge-small-zh-v1.5,normalize 后)
- document:块原文
- metadata:
{"doc_id": int, "doc_name": str}—— 支持按文档删除、按来源展示 - 距离度量:cosine(
hnsw:space=cosine)
8.3 内存索引
BM25 索引基于全部「就绪」块在内存构建(jieba 分词 + TF/DF/长度统计),文档增删后全量重建(块规模 ≤ 5 万时重建耗时秒级,可接受)。
9. 非功能需求
| 类别 | 要求 |
|---|---|
| 性能 | 检索阶段(召回+融合+精排,CPU)≤ 2s / 次;首 token ≤ 5s;文档入库 ≤ 5s / 百块 [TBD:验收时实测修订] |
| 容量 | 支持文档 1000 篇 / 块 5 万个不降级 |
| 安全 | API Key 脱敏存储与展示;服务默认绑定 127.0.0.1,开放局域网由部署者显式配置;上传文件类型白名单校验 |
| 可维护性 | 检索管线阶段化日志(每个问题记录两路召回与精排耗时);配置变更留审计字段(updated_at)[TBD:是否记录变更人] |
| 可用性 | LLM 失败可重试不丢检索结果;入库失败单文档隔离,不影响批次 |
10. 迭代规划
| 版本 | 范围 |
|---|---|
| v1.0(本文档) | 全部 P0:配置管理、知识库管理(含双路检索调试)、流式问答 + 引用、检索过程可视化、会话历史 |
| v2.0 展望 | 多用户与权限、多知识库空间、OCR、对话多轮上下文、答案反馈闭环、会话服务端持久化 |
11. v1.0 验收标准(P0 摘要)
- 界面修改 LLM 地址/模型名/Key 后,无需重启即可完成问答(必要时仅重载引擎)
- 上传 txt/pdf/docx 各一,全部状态「就绪」,问答可引用其内容;重复上传被去重拦截
- 删除某文档后,其内容不再出现在任何回答与引用中
- 修改 chunk_size 后执行全量重建,块数按新参数变化
- 问一个知识库外的问题,得到「无法回答」类固定答复,且未调用 LLM
- 断开 LLM(错误 Key)提问,得到明确错误提示,恢复后重试成功
- 双路检索调试返回 BM25 / 向量 / RRF 三组结果,同一块在两路中的名次与融合排名可相互核对
- 问答完成后展开「检索过程」面板,四个阶段数据完整,阶段 ④ 序号与回答引用编号一致
- 刷新或重开浏览器后,最近会话历史仍在且可完整回放(含引用与检索过程)