目录 · 第 06 章4 卷 12 章
第 06 章 · 卷二 搞懂 AI 怎么工作
RAG 知识库与检索增强
手册怎么入库、怎么检索、怎么重排、答案怎么带出处。
平台已有无人机设备、航线、任务、遥测和告警业务能力;技术栈包含 Java 21、Spring Boot 3、Spring AI、Spring AI Alibaba、PostgreSQL、Redis、RocketMQ、Milvus、MinIO。
建设支持文档解析、向量检索、混合检索、重排、权限过滤、引用溯源和版本管理的 RAG 知识库。
暂无,本文只做方案设计。文中的表名、接口和代码是建议实现,不代表已经上线或经过实测。
1要解决的问题
核心问题:无人机手册和业务规程是给人看的,Copilot 需要把它们转换成可检索、可引用、受权限控制的知识,再交给大模型回答。
平台已有设备接入、航线规划、任务下发、遥测回传和告警处置能力。新增 Copilot 后,用户可能会问:
- “M350 RTK 低电量返航的触发条件是什么?”
- “林业巡检发现疑似火点,按照什么规程处理?”
- “当前角色能不能查看应急消防的飞行操作手册?”
- “旧版设备手册和新版冲突时,应该以哪个版本为准?”
这些问题不能只靠大模型的训练知识回答。设备型号、固件版本、企业规程和平台操作流程都可能发生变化。模型即使回答得很流畅,也可能引用错误的条件。
RAG(检索增强生成)解决的是这个问题。它不负责重新训练大模型,而是在回答问题时,先从业务知识库找出相关资料,再把资料和用户问题一起交给模型。
需要明确三件事:
- 知识库负责提供依据。 原始手册、规程和经过审核的业务文档是知识来源。
- 检索负责找对资料。 根据问题、设备型号、用户权限和文档版本筛选内容。
- 大模型负责组织答案。 根据检索结果解释规则,并返回可以核对的出处。
RAG 不替代实时业务查询。例如,用户问“这架无人机现在还剩多少电”,应该调用设备遥测接口,而不是搜索手册。用户问“低电量时应该如何处置”,才适合使用 RAG。
本章事实边界:
| 类别 | 内容 |
|---|---|
| 已知事实 | 平台已有无人机设备、航线、任务、遥测和告警业务能力;技术栈包含 Java 21、Spring Boot 3、Spring AI、Spring AI Alibaba、PostgreSQL、Redis、RocketMQ、Milvus、MinIO。 |
| 目标设计 | 建设支持文档解析、向量检索、混合检索、重排、权限过滤、引用溯源和版本管理的 RAG 知识库。 |
| 验证结果 | 暂无,本文只做方案设计。文中的表名、接口和代码是建议实现,不代表已经上线或经过实测。 |
2在整个系统中的位置
RAG 是 Copilot 的知识检索能力,不是整个智能助手,也不是无人机的控制执行引擎。
它与其他模块的边界如下:
| 模块 | 负责什么 | 示例 |
|---|---|---|
| Copilot 对话编排 | 判断用户意图,决定调用知识检索还是业务工具 | 判断“怎么返航”属于知识问题 |
| RAG 知识服务 | 检索资料、过滤权限、整理上下文、返回引用 | 查询返航规则及手册页码 |
| 业务工具服务 | 查询实时状态、执行受控业务操作 | 查询电量、生成航线草稿 |
| 大模型服务 | 理解问题、组织答案、生成结构化输出 | 用自然语言解释处置流程 |
| 业务数据库 | 保存设备、任务、告警等业务数据 | 查询当前任务状态 |
举个例子。
用户问:“消防巡检发现疑似火点,下一步怎么做?”
Copilot 先识别出这是一个处置规程问题,调用 RAG 检索消防规程。知识服务返回适用的流程、风险条件和出处。模型再结合平台已有的告警信息组织答案。
如果用户接着说:“现在就让无人机靠近火点拍摄。”
这就不再是单纯的知识问答。Copilot 需要调用业务工具,检查设备状态、空域限制和任务约束,生成任务草稿,并按平台的授权与确认流程执行。RAG 返回的文字不能直接变成飞行指令。
3总体设计
整个 RAG 分成两条链路:离线入库链路和在线查询链路。
3.1 文档入库链路
- 原始文档从 MinIO 获取 PDF、DOCX、HTML 等文件
- 文档解析提取正文、标题、页码、表格和图片位置
- 内容清洗去除页眉页脚、重复内容、乱码和无效空白
- 结构化分块按章节、段落、表格和流程步骤切分
- 元数据绑定绑定文档 ID、版本、设备型号、角色和页码
- Embedding将文本块转换为固定维度的向量
- 索引写入向 Milvus 写入向量,保存可检索文本与元数据
- 发布审核检查解析结果、索引完整性和版本状态
原始文件保存在 MinIO,文档及版本信息保存在 PostgreSQL,向量保存在 Milvus。
这里有一个容易忽略的问题:向量库不是原始文档的唯一存储位置。 向量用于相似度搜索,原文、版本、权限、审核状态和引用位置需要有明确的数据来源。这样即使重建向量索引,也不需要重新整理整套业务元数据。
建议把文档解析、分块、向量化做成可重复执行的入库任务。RocketMQ 可以传递文档处理事件,后台消费者负责解析和索引。重复消费不能产生重复的有效索引记录。
3.2 在线查询链路
- 用户提问获取问题、当前用户和业务上下文
- 问题理解提取设备型号、业务场景、版本和查询意图
- 权限过滤根据用户角色和文档授权范围确定可查集合
- 混合召回并行执行向量检索和关键词检索
- 结果融合合并候选文档,去重并过滤过期版本
- Reranker 重排对候选片段按问题相关性重新排序
- 上下文组装截取必要内容,保留页码和文档版本
- 大模型生成基于检索证据组织答案
- 引用校验将答案引用绑定到真实文档和页码
- 返回结果输出答案、引用和必要的证据不足提示
检索链路必须把权限控制放在可信的服务端。不能先把所有文档交给模型,再要求模型自行判断哪些内容不该展示。
4完整执行链路
下面以用户提问“林业巡检发现疑似火点后,应该怎么处理?”为例,说明一次 RAG 问答的执行顺序。
- 用户发送问题携带用户身份、当前项目和会话信息
- Copilot 编排器识别为业务规程查询,选择 knowledgeSearch 工具
- 知识服务鉴权校验用户身份、项目范围和知识库访问权限
- 问题改写补充已知场景词,但不擅自改变用户意图
- 并行召回Milvus 向量检索与 PostgreSQL 全文关键词检索
- 候选融合合并重复片段,过滤不适用的文档版本
- 相关性重排选出最能回答当前问题的证据片段
- 上下文构建加入片段正文、文档标题、页码及版本
- 模型生成要求模型仅依据证据回答,缺少依据时明确说明
- 引用校验校验引用 ID 是否来自本次检索结果
- 返回前端展示回答、来源链接及对应页面
实际实现时,需要注意四个细节。
第一,问题改写不等于事实补全。 如果用户没有说明无人机型号,系统可以检索通用规程,但不能自行假定用户使用某一型号。
第二,权限过滤必须在召回阶段生效。 对无权访问的文档,不应让它进入重排器或大模型上下文。
第三,模型只能引用本次检索返回的证据。 不允许模型编造文档编号、章节名或页码。
第四,证据不足时允许不回答。 如果检索结果无法覆盖问题中的关键条件,应明确指出缺少哪项依据,而不是让模型补写一套看似合理的操作规程。
5技术选型与原理
5.1 文档解析与分块
不同文件不能一律按固定字符数切开。
| 文档类型 | 处理方式 | 主要风险 |
|---|---|---|
| PDF 手册 | 解析正文、标题、页码;扫描件先做 OCR | 双栏顺序错误、页码丢失 |
| DOCX 规程 | 按标题层级、段落和列表切分 | 步骤编号与正文分离 |
| HTML 文档 | 去除导航、页脚,保留标题和正文结构 | 菜单文字混入正文 |
| 表格 | 提取表头、行列关系,按完整语义单元保存 | 参数与对应设备型号分离 |
| 流程图 | 解析图中节点、连线和条件,转成有序步骤 | 分支条件、回退路径丢失 |
| 扫描件 | OCR 后保留原页码和识别质量信息 | 数字、单位和型号识别错误 |
分块大小需要通过实际语料验证,不能只看一个固定的 Token 数。
目标设计可以从每块约 400~800 个 Token、相邻文本块重叠约 50~100 个 Token 开始测试。这只是初始参数,不是已验证的最佳值。短规程可以更小,长段落可以适当增大,完整的表格行和操作步骤则应优先保持语义完整。
分块时应遵循以下原则:
- 尽量不拆开一个完整的操作步骤。
- 每块保留所属章节标题,避免只检索到孤立的句子。
- 表格块必须带上表头、适用型号和单位。
- 流程图应保留节点顺序、判断条件和分支结果。
- 超长表格可以按行组拆分,但每块都要重复必要的表头。
- OCR 置信度低的关键参数进入人工复核流程,不应直接成为可信操作依据。
分块不是越细越好。切得太细,模型不知道句子属于什么场景;切得太大,检索会带回大量无关内容,也更容易挤占上下文。
5.2 Embedding 与 Milvus
Embedding 模型把文本映射成一个固定长度的浮点向量。语义接近的文本通常会在向量空间中更接近。
例如,“电量不足时返航”和“低电量触发自动返航”虽然用词不同,但可能表达相近的意思。向量检索适合找这类语义相似的内容。
模型选型要看三个方面:
- 中文与专业术语能力。 能否处理无人机型号、行业术语、缩写和中英文混合内容。
- 部署与数据边界。 采用云端模型还是本地模型,是否允许文档内容发往外部服务。
- 检索效果与成本。 在自己的问题集上比较召回效果、响应时间和推理成本。
向量维度不是手工随意设置的。Embedding 模型输出多少维,就必须按该维度创建对应的 Milvus 向量字段。更换模型后,即使维度相同,向量空间也可能不同,因此通常需要重新生成向量并重建索引。
距离度量也要与模型的训练和使用建议一致:
- 余弦相似度(Cosine): 比较向量方向,常用于语义检索。
- 内积(IP): 比较向量内积;若向量已经归一化,排序结果与余弦相似度一致。
- 欧氏距离(L2): 比较向量之间的几何距离,距离越小通常越接近。
Milvus 的索引可以从 FLAT 和 HNSW 等方案中选择。FLAT 适合小规模数据或用于建立精确检索基线;HNSW 通过图结构提高近似最近邻搜索效率,但需要在内存、构建成本和召回质量之间权衡。具体选择应结合数据规模和压测结果,不应在没有测试的情况下直接认定某个索引最好。
5.3 三种检索方案对比
| 方案 | 原理 | 优点 | 不足 | 在无人机知识库中的用途 |
|---|---|---|---|---|
| 纯向量检索 | 把问题向量与文本块向量比较 | 能处理同义表达和自然语言提问 | 对精确型号、编号、数字不一定可靠 | “低电量时如何处理” |
| 关键词检索 | 根据词项匹配、相关性评分检索 | 精确术语、型号和规程编号更容易命中 | 不擅长理解不同措辞的语义关系 | “M350 RTK”“SOP-FIRE-012” |
| 混合检索 | 合并向量与关键词召回结果 | 同时覆盖语义表达和精确术语 | 实现与调优更复杂,需要融合策略 | 生产环境中的通用知识问答 |
本方案优先采用混合检索。
关键词检索可以先使用 PostgreSQL 全文检索能力,例如 tsvector、tsquery 和 ts_rank。如果后续出现大量型号、编号、短语和复杂词法匹配需求,再评估专用搜索引擎。
两路检索的分数通常不能直接相加,因为向量相似度和关键词相关性分数不在同一尺度上。可以采用 RRF(Reciprocal Rank Fusion,倒数排名融合),根据候选在不同检索结果中的排名计算融合分数,再交给重排器处理。
5.4 Reranker 重排
向量检索和关键词检索负责快速找候选,Reranker 负责进一步判断候选片段与问题是否真正相关。
例如,用户问“电池温度异常时如何处理”,召回结果可能包含电池存储、充电、飞行中告警等多个章节。重排器可以优先保留与“飞行中温度异常处置”直接相关的内容。
目标设计可以从以下参数开始验证:
- 两路召回融合后保留约 30~50 个候选片段。
- 使用 Reranker 对候选片段与问题进行相关性评分。
- 重排后保留约 5~8 个片段进入上下文构建。
这些数字是初始调优范围,不是实测结果。实际保留数量要看片段长度、问题复杂度、模型上下文窗口和评测结果。
如果知识库很小、问题简单,而且初步评测已经足够好,可以暂时不使用 Reranker。若经常出现“找到了相关章节,却选错了具体操作步骤”,重排通常更值得投入。
5.5 上下文注入与引用溯源
传给模型的内容不能只是几段没有来源的文字。每个片段都要携带可追溯的标识:
chunkId:文本块唯一标识。documentId:所属文档。versionId:文档版本。title:文档标题。pageStart、pageEnd:原文页码范围。sectionPath:章节路径。content:文本块正文。
组装 Prompt 时,只放入本次问题最相关的片段,并明确要求模型根据证据回答。上下文超过预算时,应删除低相关片段或压缩重复内容,不能直接截断关键操作条件。
可以采用如下提示词结构:
你是无人机平台的业务知识助手。
回答规则:
1. 只根据提供的知识片段回答规程类问题。
2. 不得编造型号、阈值、步骤和文档出处。
3. 如果证据不足,明确说明缺少的条件或资料。
4. 涉及不同设备型号时,不能混用操作规则。
5. 引用只能使用知识片段提供的 chunkId。
用户问题:
{question}
知识片段:
[证据 K1]
文档:{title}
版本:{version}
章节:{sectionPath}
页码:{pageStart}-{pageEnd}
内容:{content}
请返回答案和引用的证据 ID。模型返回 K1 后,服务端再根据 chunkId 查回可信的文档信息,生成引用链接。不能把模型生成的页码直接当作真实页码。
引用至少要能定位到文档和页面。如果解析工具能保存原始 PDF 页码,还可以通过 MinIO 文件访问服务生成受权限保护的预览链接。
上下文预算也要留给用户问题、系统提示词、对话历史和模型输出。不能把整个章节或整份手册一次性塞给模型。对于需要跨章节比较的复杂问题,可以分阶段检索,再合并证据,但每个结论仍然要有来源。
5.6 权限过滤与知识过期
知识库权限应由服务端执行,不由模型决定。
建议把文档适用范围与访问权限分开存储:
- 适用范围: 设备型号、业务场景、固件版本、组织或项目范围。
- 访问权限: 允许访问的角色、组织、项目和密级。
例如,消防应急规程可以限制为应急处置角色和授权项目。用户即使知道文档名称,也不能通过关键词检索绕过权限。
检索请求应携带经过认证的用户身份,由知识服务生成过滤条件。Milvus 的元数据过滤和 PostgreSQL 的权限查询都需要遵循同一套授权规则。对于不适合直接在向量库中表达的复杂权限关系,可以先由 PostgreSQL 计算允许访问的文档集合,再限制向量检索范围。
文档更新时,不能只上传新版文件。建议使用以下状态:
DRAFT → PROCESSING → REVIEW → PUBLISHED → RETIRED
其中:
DRAFT:草稿,尚未进入正式检索。PROCESSING:正在解析、分块和向量化。REVIEW:等待审核或质量检查。PUBLISHED:当前有效版本。RETIRED:已经下线,不再参与检索。
新版应在解析和索引构建完成、质量检查通过后再发布。发布时更新有效版本指针,旧版进入 RETIRED,并清理或隔离旧版索引。不能先删除旧版,再发现新版解析失败。
检索时要同时校验发布状态、有效版本和权限条件。缓存结果也必须考虑权限和版本变化,避免用户继续看到已经下线的内容。
6关键数据结构与代码
6.1 分块结构
建议在 PostgreSQL 中维护文档及分块元数据,MinIO 保存原始文件,Milvus 保存向量和必要的过滤字段。
核心表可以设计为:
| 表名 | 主要字段 | 作用 |
|---|---|---|
kb_document | id、title、doc_type、status、current_version_id | 文档主记录 |
kb_document_version | id、document_id、version_no、object_key、checksum、status | 原始文件与版本状态 |
kb_chunk | id、version_id、content、page_start、page_end、section_path、metadata | 保存分块原文与引用位置 |
kb_document_acl | document_id、role_code、org_id、project_id | 文档访问授权 |
kb_ingest_job | id、version_id、status、error_message | 入库任务状态与失败原因 |
建议用 UUID 或其他全局唯一标识作为 documentId、versionId 和 chunkId。数据库记录与 Milvus 中的主键必须保持可关联。
分块数据结构可以这样定义:
public record KnowledgeChunk(
String chunkId,
String documentId,
String versionId,
String title,
String sectionPath,
Integer pageStart,
Integer pageEnd,
String deviceModel,
String businessDomain,
String content,
Map<String, Object> metadata
) {}这里的 content 是真正参与检索和上下文注入的正文。metadata 用于保存扩展信息,例如固件版本、语言、文档类型、解析来源和 OCR 质量标记。
pageStart 和 pageEnd 应来自解析阶段的原始页码映射。如果文档来源是网页而不是 PDF,可以保留章节标题、段落 ID 或原始 URL,不应人为伪造页码。
6.2 入库接口
入库服务可以设计为异步流程:
public interface KnowledgeIngestionService {
// 接收文件,创建文档版本及入库任务
IngestJobId submit(IngestDocumentCommand command);
// 解析、清洗、分块并生成向量
void process(IngestJobId jobId);
// 检查处理结果并发布有效版本
void publish(String versionId, String reviewerId);
}
public record IngestDocumentCommand(
String documentId,
String title,
String objectKey,
String versionNo,
String businessDomain,
List<String> allowedRoles
) {}
public record IngestJobId(String value) {}submit 负责登记文件和任务,可以向 RocketMQ 发送入库事件。消费者调用 process,按顺序执行解析、清洗、分块、向量化和索引写入。审核通过后才调用 publish。
实现时需要保证幂等。例如,以 versionId + chunkId + embeddingModelVersion 作为处理记录的关键组合,避免 RocketMQ 重复投递时重复写入有效数据。
如果处理失败,任务进入失败状态并记录原因,不能将未完成的版本发布到线上。
6.3 检索接口
在线检索可以提供统一的服务接口,让 Copilot 编排器不必关心 Milvus、关键词检索和 Reranker 的内部实现。
public interface KnowledgeRetrievalService {
KnowledgeSearchResult search(KnowledgeSearchRequest request);
}
public record KnowledgeSearchRequest(
String question,
String userId,
String organizationId,
String projectId,
List<String> roleCodes,
String deviceModel,
String businessDomain,
int recallLimit,
int resultLimit
) {}
public record KnowledgeEvidence(
String chunkId,
String documentId,
String versionId,
String title,
String sectionPath,
Integer pageStart,
Integer pageEnd,
String content,
double relevanceScore
) {}
public record KnowledgeSearchResult(
List<KnowledgeEvidence> evidence,
boolean sufficientEvidence,
String reason
) {}这是目标设计接口,不是 Spring AI 的原生 API。具体的向量检索和模型调用应由实现类封装。
调用顺序可以设计为:
public KnowledgeSearchResult search(KnowledgeSearchRequest request) {
// 1. 校验身份,并从可信授权服务获取可访问范围
var access = accessService.resolve(request.userId());
// 2. 将问题转换为向量
var queryVector = embeddingService.embed(request.question());
// 3. 并行执行向量检索和关键词检索
var vectorHits = vectorStore.search(
queryVector, request, access
);
var keywordHits = keywordStore.search(
request.question(), request, access
);
// 4. 合并候选并按有效版本和权限过滤
var candidates = candidateMerger.merge(
vectorHits, keywordHits, access
);
// 5. 对候选进行相关性重排
var reranked = reranker.rerank(
request.question(), candidates
);
// 6. 按相关性和上下文预算选取证据
var evidence = evidenceSelector.select(
reranked, request.resultLimit()
);
// 7. 检查证据是否足以回答问题
return evidenceEvaluator.evaluate(evidence);
}上面展示的是职责划分,accessService、embeddingService、vectorStore 等是需要自行实现或适配的服务,不是可以直接复制运行的完整代码。生产实现还应为检索超时、模型不可用和索引版本不一致定义明确的异常处理。
有两个边界必须守住:
userId、角色和组织信息不能直接相信前端传值,应以登录态和服务端授权结果为准。relevanceScore是检索排序信号,不代表答案正确。是否有足够证据,需要结合最低相关性、关键条件覆盖和业务规则进行判断。
6.4 Prompt 组装与引用绑定
上下文组装器应将每条证据转换成固定格式,并同时生成可追溯的引用映射。
public record CitationRef(
String citationId,
String chunkId,
String documentId,
String versionId,
String title,
Integer pageStart,
Integer pageEnd
) {}
public record GroundedPrompt(
String systemPrompt,
String userPrompt,
List<CitationRef> citations
) {}例如,组装器把第一条证据标记为 K1,并将 K1 → chunkId → versionId → pageStart/pageEnd 保存到本次请求的引用映射中。
模型回答时可以输出:
{
"answer": "应按照当前适用的消防处置规程核实告警,并执行相应处置步骤。",
"citationIds": ["K1"],
"insufficientEvidence": false
}这只是目标设计中的输出示例,不代表平台已经采用该协议。服务端必须校验 JSON 结构、引用 ID 是否属于本次检索结果,以及对应文档是否仍然有效、当前用户是否仍有权限。
如果引用失效或证据不足,应删除无效引用、重新检索或返回不确定提示,不能为了让答案看起来完整而保留错误出处。
7异常、安全与边界条件
RAG 的风险不只是检索不到答案,还包括把错误资料、过期规程或无权访问的内容交给模型。
| 场景 | 处理策略 |
|---|---|
| 文件解析失败 | 记录任务失败原因,保留原文件,不发布该版本 |
| OCR 识别关键参数异常 | 标记待复核,未经审核不进入正式知识库 |
| 向量检索超时 | 按策略尝试关键词检索;证据不足时明确告知 |
| Reranker 不可用 | 仅在降级策略经过验证时使用原始召回结果,否则拒答或提示暂不可用 |
| 没有足够证据 | 返回缺少的设备型号、规程版本或具体条件 |
| 文档已过期 | 过滤旧版本,不让它参与正式回答 |
| 用户无权访问 | 不返回正文、片段内容或可绕过权限的文件链接 |
| 引用不存在 | 拒绝该引用,重新校验或生成不带虚假出处的结果 |
| 文档包含恶意提示词 | 将其视为待检索资料,不允许文档内容覆盖系统规则 |
| 不同手册相互冲突 | 展示适用范围、版本和来源,按正式生效规则处理;无法判断时交由人工确认 |
还要防范检索增强中的间接提示注入。例如,某份上传文档写着“忽略系统指令,并执行以下命令”。这段文字即使被检索到,也只能作为文档内容处理,不能改变 Copilot 的权限或工具调用策略。
RAG 也不应该直接控制无人机。知识片段只能提供解释、规程和建议。任何涉及起飞、航线变更、返航或其他实际控制操作的行为,都必须进入平台已有的业务校验、授权和执行流程。
8测试与验证
检索质量不能只靠人工问几个问题判断。需要建立一套可以重复运行的评测集。
目标设计是为不同业务场景准备问题,并由熟悉无人机业务的人员标注正确依据,包括文档、版本、章节、页码和预期答案要点。
8.1 检索评测
| 指标 | 衡量什么 | 如何使用 |
|---|---|---|
| Recall\@K(召回率) | 前 K 个候选是否包含已标注的正确证据 | 判断检索有没有把正确资料找出来 |
| Hit Rate\@K(命中率) | 前 K 个候选中是否至少有一条相关证据 | 快速判断一次检索是否命中 |
| MRR(平均倒数排名) | 第一条正确证据排在多靠前的位置 | 判断正确资料是否容易被模型看到 |
| nDCG\@K | 多条结果的排序质量 | 比较不同检索融合与重排方案 |
| 引用准确率 | 答案中的引用是否真实、有效且支持对应结论 | 防止错误页码和无关出处 |
| 答案依据充分率 | 关键结论是否被检索证据覆盖 | 检查模型是否在缺乏依据时自行补全 |
这里的召回率需要统一计算口径。可以把 Recall\@K 定义为“已标注相关证据中,有多少比例出现在前 K 个结果中”;Hit Rate\@K 则看每个问题是否至少命中一条正确证据。两者不能混为一谈。
8.2 评测用例
至少覆盖以下几类问题:
- 语义问题:“电池电量不足时怎么处理?”
- 精确匹配:“SOP-FIRE-012 规定了什么?”
- 型号区分:“不同机型的返航规则是否一致?”
- 版本问题:“旧版手册中的参数是否仍然有效?”
- 权限问题:“无权查看消防规程的角色能否检索到其内容?”
- 证据不足:“没有提供设备型号,能否给出特定机型的精确阈值?”
- 表格问题:“某型号允许的参数范围是多少?”
- 流程问题:“告警确认后,处置流程有哪些分支?”
测试时要对比纯向量、纯关键词、混合检索,以及混合检索加 Reranker 的表现。保持同一套问题、同一套正确答案和证据标注,才有比较价值。
权限测试要检查结果正文、引用信息、文件预览链接和日志输出,不能只看前端有没有显示答案。
8.3 验证门槛
上线前可以设置目标门槛,但必须由业务方根据风险等级确定,不应凭空填写一组漂亮的准确率。
对消防和飞行安全相关规程,建议额外设置人工验收:关键步骤是否完整、适用机型是否正确、参数是否有来源、无证据时是否能够拒答。一般知识问答通过,不代表高风险操作建议也合格。
每次调整分块策略、Embedding 模型、检索参数、Reranker 或 Prompt 后,都应重新跑同一套回归集。否则无法判断效果提升究竟来自哪一项改动。
9面试表达与追问
问答一:为什么用了向量数据库,还要做关键词检索?
答: 向量检索擅长理解语义相似的问题,但无人机业务里有大量型号、参数、告警编号和规程编号。这些内容需要精确匹配。纯关键词又容易漏掉同义表达,所以我会优先考虑混合检索。两路结果通过 RRF 融合,再由 Reranker 判断哪些片段真正回答了问题。最终选型要通过同一套业务问题集比较,而不是只看技术名词。
问答二:怎么保证模型回答的内容有依据,不会编造出处?
答: 我会给每个分块保存唯一 ID、所属文档、版本、章节和原始页码。检索结果进入 Prompt 时就带上这些信息,并要求模型返回本次请求中的证据 ID。模型生成答案后,由服务端校验引用 ID,再从可信的元数据中生成文档和页码链接。模型自己写出的页码不能直接相信。证据不足时允许拒答,不让它自行补齐规程。
问答三:手册更新了,怎么保证旧版本不会继续被检索?
答: 我不会在上传新版文件时直接删除旧版,而是给文档版本维护独立状态。新版经过解析、分块、向量化和审核后,再切换当前有效版本。旧版转为退役状态,检索时同时校验发布状态、版本有效性和用户权限。索引清理、缓存失效和引用访问也要跟着版本切换处理。这样即使新版入库失败,也不会因为提前删除旧版而导致整个知识库不可用。