28 RAG 第一版交付:从功能拼接到可演示系统
RAG 第一版交付:从功能拼接到可演示系统
RAG 第一版交付的目标不是加入所有高级能力,而是把文档入库、问答、引用、权限和异常处理组成一条稳定、可重复演示、可以验收的完整链路。
[TOC]
1. 第一版交付范围
第一版必须完成:
上传文档
查看文档处理状态
解析和清洗文本
生成并保存chunks
生成并保存embeddings
提出知识库问题
返回基于资料的答案
展示引用来源
执行知识库和文档权限过滤
资料不足时明确拒答
保存基础对话历史
提供健康检查和错误响应
第一版暂不强求:
复杂混合检索
Rerank模型
高级评测平台
多Agent协作
自动规划
大规模分布式向量库
复杂工作流审批
先完成稳定闭环,再逐步增强。
2. 系统全景
graph TD;
A["用户上传文档"] --> B["文件存储"];
A --> C["文档元数据"];
C --> D["解析文本"];
D --> E["文本清洗"];
E --> F["文档切片"];
F --> G["Embedding"]; G --> H["PostgreSQL + pgvector"]; I["用户提问"] --> J["问题向量化"];
J --> K["带权限条件检索"];
H --> K; K --> L["组装上下文和来源"];
L --> M["qwen3.5-flash 生成答案"];
M --> N["返回答案、引用和 traceId"];
第一版可以采用:
Java:业务接口、状态编排、数据库、权限
Python:解析、清洗、切片、Embedding等AI能力
PostgreSQL + pgvector:业务数据和向量
文件系统或MinIO:原始文件
qwen3.5-flash:答案生成
text-embedding-v4:文本向量化
3. 交付接口清单
3.1 文档接口
POST /knowledge-bases/{kbId}/documents
GET /knowledge-bases/{kbId}/documents
GET /documents/{documentId}
DELETE /documents/{documentId}
GET /documents/{documentId}/status
3.2 处理接口
可以提供独立学习接口:
POST /documents/{documentId}/parse
POST /documents/{documentId}/clean
POST /documents/{documentId}/chunk
POST /documents/{documentId}/embed
正式体验也可以增加一键处理:
POST /documents/{documentId}/ingest
一键处理内部依次执行:
parse -> clean -> chunk -> embed
3.3 问答接口
POST /knowledge-bases/{kbId}/chat
3.4 会话和来源接口
POST /conversations
GET /conversations/{conversationId}
POST /conversations/{conversationId}/messages
GET /documents/{documentId}/chunks/{chunkId}
3.5 运维接口
GET /health
GET /ready
生产环境不要暴露包含敏感配置的内部诊断信息。
4. 文档状态机
graph LR;
A["UPLOADED"] --> B["PARSING"]; B --> C["PARSED"]; C --> D["CLEANED"]; D --> E["CHUNKED"]; E --> F["EMBEDDING"]; F --> G["EMBEDDED"]; B -- "失败" --> H["FAILED"];
D -- "失败" --> H;
E -- "失败" --> H;
F -- "失败" --> H;
H -- "重试" --> B;
状态必须能够回答:
文档当前处理到哪一步
是否可以被检索
失败发生在哪一步
能否安全重试
只有完整完成向量化的文档参与检索:
WHERE document.status = 'EMBEDDED'
AND chunk.embedding IS NOT NULL
5. 上传验收
上传时检查:
文件是否为空
文件大小是否超限
文件类型是否允许
文件名是否安全
知识库是否存在
用户是否有上传权限
是否需要SHA-256去重
成功响应:
{
"documentId": "doc_001", "originalName": "产品手册.pdf",
"status": "UPLOADED", "traceId": "trace_xxx"}
验收点:
原始文件可读取
数据库存在文档元数据
文件大小与Hash正确
跨租户不能查询该文档
非法文件名不能逃逸上传目录
6. 入库处理验收
每个阶段应保存中间结果。
6.1 解析
raw_text非空
页码或段落定位可追踪
解析器名称和版本可记录
6.2 清洗
cleaned_text非空
页眉页脚和噪声得到处理
标题结构没有丢失
原始文本仍可回看
6.3 切片
chunk数量大于0
chunkIndex连续且唯一
content不为空
titlePath和页码尽量保留
6.4 向量化
embeddedChunkCount = totalChunkCount
所有向量维度为1024
模型记录为text-embedding-v4
文档状态为EMBEDDED
7. 问答验收
请求:
{
"question": "单个上传文件最大是多少?",
"topK": 5}
成功响应:
{
"answer": "单个上传文件最大为 20MB [C1]。",
"answered": true, "sources": [ { "sourceId": "C1", "documentName": "产品手册.pdf",
"titlePath": "文件管理 > 上传限制",
"pageStart": 8, "snippet": "单个上传文件最大为20MB。"
} ], "traceId": "trace_xxx"}
验收点:
正确chunk进入TopK
答案中的数字与原文一致
引用编号合法
来源可以定位到真实文档
回答不包含资料外补充
8. 拒答验收
问题:
公司明年的营收目标是多少?
知识库没有相关资料时:
{
"answer": "根据当前知识库资料无法确定。",
"answered": false, "sources": [], "traceId": "trace_xxx"}
以下情况都不能退化成模型自由回答:
检索结果为空
最高相关度过低
Embedding服务失败
向量数据库失败
所有候选被权限过滤
系统异常和正常拒答要使用不同错误码或状态字段。
9. 权限验收
至少测试:
用户只能访问被授权知识库
跨租户documentId返回403或404
无权chunk不会进入检索结果
无权正文不会进入Prompt和日志
来源点击会重新鉴权
权限撤销后旧来源不能继续打开
不能只验证页面上“看不见文档”,还要验证直接调用接口也无法访问。
10. 对话验收
第一轮:
用户:上传文件最大是多少?
第二轮:
用户:那超过后返回什么错误码?
系统应改写为:
上传文件超过大小限制后返回什么错误码?
验收点:
原问题和改写问题都保存
检索使用改写问题
回答仍基于知识库
会话只能由所属用户读取
11. 页面与交互
第一版至少需要三个页面或视图。
11.1 文档管理
上传文件
查看文件名、大小和状态
查看失败原因
重新处理失败文档
删除文档
11.2 知识库问答
选择知识库
输入问题
展示流式或同步答案
展示引用来源
点击来源查看证据
11.3 会话历史
显示会话列表
打开历史消息
继续追问
删除会话
不要把开发调试信息默认显示给普通用户。
12. 统一错误响应
{
"code": "DOCUMENT_NOT_READY", "message": "文档尚未完成向量化。",
"traceId": "trace_xxx", "details": null}
建议错误码:
VALIDATION_FAILED
UNAUTHORIZED
FORBIDDEN
KNOWLEDGE_BASE_NOT_FOUND
DOCUMENT_NOT_FOUND
DOCUMENT_NOT_READY
PARSER_FAILED
CHUNKING_FAILED
EMBEDDING_FAILED
RETRIEVAL_FAILED
MODEL_UNAVAILABLE
RATE_LIMITED
外部响应不要返回内部堆栈、SQL、服务器路径和密钥。
13. 数据一致性检查
文档状态与数据应满足:
| 状态 | 期望数据 |
|---|---|
UPLOADED |
文档元数据和原文件存在 |
PARSED |
raw_text 存在 |
CLEANED |
cleaned_text 存在 |
CHUNKED |
至少一个 chunk |
EMBEDDED |
所有 chunk 均有向量 |
FAILED |
error_message 非空 |
可以定期检查异常状态:
EMBEDDED但存在空向量
CHUNKED但chunk数量为0
FAILED但没有错误信息
数据库有文档记录但原文件丢失
长期停留在处理中状态
14. 健康检查
14.1 Liveness
回答:应用进程是否活着。
GET /health
不要依赖所有外部服务,否则外部故障可能导致容器被不断重启。
14.2 Readiness
回答:应用是否可以处理真实请求。
检查:
PostgreSQL连接
vector扩展和关键表
必要的Python服务
模型配置是否存在
GET /ready
返回中不要泄露连接密码和内部地址。
15. 配置管理
环境变量示例:
DASHSCOPE_API_KEY
DASHSCOPE_BASE_URL
QWEN_MODEL=qwen3.5-flash
EMBEDDING_MODEL=text-embedding-v4
EMBEDDING_DIMENSION=1024
DATABASE_URL
DATABASE_USERNAME
DATABASE_PASSWORD
UPLOAD_ROOT
要求:
密钥不提交Git
启动时校验必要配置
不同环境使用不同配置
日志不打印密码和API Key
16. 演示数据
准备一组稳定的公开演示文档:
产品手册.pdf
接口说明.md
常见问题.txt
准备问题:
单个上传文件最大是多少?
超过限制返回什么错误码?
支持哪些文件类型?
资料中没有答案的问题
需要连续追问的问题
不要用包含真实客户、员工或生产数据的文档演示。
17. 演示脚本
推荐演示顺序:
1. 创建或选择知识库
2. 上传一份文档
3. 展示文档状态从UPLOADED到EMBEDDED
4. 打开chunk或向量状态摘要
5. 提出资料内问题
6. 展示答案和引用来源
7. 点击来源查看原文
8. 提出资料外问题,展示拒答
9. 连续追问,展示问题改写
10. 使用无权限账号验证隔离
演示不要依赖临时手工改数据库。
18. 第一版验收表
| 模块 | 验收标准 | 结果 |
|---|---|---|
| 上传 | 合法文件成功、非法文件拒绝 | 待验收 |
| 解析 | 文本和定位信息可查看 | 待验收 |
| 清洗 | 正文保留、噪声减少 | 待验收 |
| 切片 | chunk非空且顺序正确 | 待验收 |
| Embedding | 数量和维度一致 | 待验收 |
| 检索 | 典型问题命中正确chunk | 待验收 |
| 问答 | 仅依据资料回答 | 待验收 |
| 引用 | 来源真实可访问 | 待验收 |
| 拒答 | 无资料时不编造 | 待验收 |
| 权限 | 无跨租户和越权检索 | 待验收 |
| 历史 | 追问能够正确改写 | 待验收 |
| 异常 | 返回统一错误和traceId | 待验收 |
19. Definition of Done
第一版完成标准:
代码可从干净环境启动
数据库脚本可重复执行
README包含启动步骤
至少一套演示数据可复现
核心接口有请求响应示例
主链路有自动化或手工验收记录
无明文密钥
没有已知跨租户漏洞
能完成10分钟以内稳定演示
不是“代码写完”就算交付。
20. 常见问题
20.1 第一版要不要加入混合检索和 Rerank
不必。
先用向量检索证明主链路可靠,后续再通过评测增加增强能力。
20.2 第一版可以只做后端吗
可以,但至少要提供 Swagger、接口示例或简单演示页面,让别人能够验证完整流程。
20.3 是否需要生产级高可用
第一版不要求完整高可用,但要明确哪些部分仍是学习配置,不能把 Demo 当作生产完成。
20.4 文档处理可以同步吗
小文件学习阶段可以。正式系统更适合异步任务,并提供状态查询和重试。
21. 练习清单
整理第一版功能范围
列出文档、处理、问答、会话和健康接口
完成一份文档从上传到EMBEDDED
完成资料内问题和资料外问题测试
完成来源点击和权限测试
准备稳定演示数据和问题
编写统一错误响应
建立第一版验收表
从干净环境重新启动并演示
22. 小结
第一版交付链路:
upload
-> ingest -> embedded -> retrieve -> answer -> citation -> authorization -> conversation
本节最重要的结论:
第一版交付的价值是证明完整链路稳定可用。功能可以少,但上传、检索、回答、引用、拒答和权限必须能够被重复验证。