目录 · 第 06 章4 卷 12 章

第 06 章 · 卷二 搞懂 AI 怎么工作

RAG 知识库与检索增强

手册怎么入库、怎么检索、怎么重排、答案怎么带出处。

约 13 分钟9 节
已知事实

平台已有无人机设备、航线、任务、遥测和告警业务能力;技术栈包含 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 文档入库链路

  1. 原始文档从 MinIO 获取 PDF、DOCX、HTML 等文件
  2. 文档解析提取正文、标题、页码、表格和图片位置
  3. 内容清洗去除页眉页脚、重复内容、乱码和无效空白
  4. 结构化分块按章节、段落、表格和流程步骤切分
  5. 元数据绑定绑定文档 ID、版本、设备型号、角色和页码
  6. Embedding将文本块转换为固定维度的向量
  7. 索引写入向 Milvus 写入向量,保存可检索文本与元数据
  8. 发布审核检查解析结果、索引完整性和版本状态

原始文件保存在 MinIO,文档及版本信息保存在 PostgreSQL,向量保存在 Milvus。

这里有一个容易忽略的问题:向量库不是原始文档的唯一存储位置。 向量用于相似度搜索,原文、版本、权限、审核状态和引用位置需要有明确的数据来源。这样即使重建向量索引,也不需要重新整理整套业务元数据。

建议把文档解析、分块、向量化做成可重复执行的入库任务。RocketMQ 可以传递文档处理事件,后台消费者负责解析和索引。重复消费不能产生重复的有效索引记录。

3.2 在线查询链路

  1. 用户提问获取问题、当前用户和业务上下文
  2. 问题理解提取设备型号、业务场景、版本和查询意图
  3. 权限过滤根据用户角色和文档授权范围确定可查集合
  4. 混合召回并行执行向量检索和关键词检索
  5. 结果融合合并候选文档,去重并过滤过期版本
  6. Reranker 重排对候选片段按问题相关性重新排序
  7. 上下文组装截取必要内容,保留页码和文档版本
  8. 大模型生成基于检索证据组织答案
  9. 引用校验将答案引用绑定到真实文档和页码
  10. 返回结果输出答案、引用和必要的证据不足提示

检索链路必须把权限控制放在可信的服务端。不能先把所有文档交给模型,再要求模型自行判断哪些内容不该展示。

4完整执行链路

下面以用户提问“林业巡检发现疑似火点后,应该怎么处理?”为例,说明一次 RAG 问答的执行顺序。

  1. 用户发送问题携带用户身份、当前项目和会话信息
  2. Copilot 编排器识别为业务规程查询,选择 knowledgeSearch 工具
  3. 知识服务鉴权校验用户身份、项目范围和知识库访问权限
  4. 问题改写补充已知场景词,但不擅自改变用户意图
  5. 并行召回Milvus 向量检索与 PostgreSQL 全文关键词检索
  6. 候选融合合并重复片段,过滤不适用的文档版本
  7. 相关性重排选出最能回答当前问题的证据片段
  8. 上下文构建加入片段正文、文档标题、页码及版本
  9. 模型生成要求模型仅依据证据回答,缺少依据时明确说明
  10. 引用校验校验引用 ID 是否来自本次检索结果
  11. 返回前端展示回答、来源链接及对应页面

实际实现时,需要注意四个细节。

第一,问题改写不等于事实补全。 如果用户没有说明无人机型号,系统可以检索通用规程,但不能自行假定用户使用某一型号。

第二,权限过滤必须在召回阶段生效。 对无权访问的文档,不应让它进入重排器或大模型上下文。

第三,模型只能引用本次检索返回的证据。 不允许模型编造文档编号、章节名或页码。

第四,证据不足时允许不回答。 如果检索结果无法覆盖问题中的关键条件,应明确指出缺少哪项依据,而不是让模型补写一套看似合理的操作规程。

5技术选型与原理

5.1 文档解析与分块

不同文件不能一律按固定字符数切开。

文档类型处理方式主要风险
PDF 手册解析正文、标题、页码;扫描件先做 OCR双栏顺序错误、页码丢失
DOCX 规程按标题层级、段落和列表切分步骤编号与正文分离
HTML 文档去除导航、页脚,保留标题和正文结构菜单文字混入正文
表格提取表头、行列关系,按完整语义单元保存参数与对应设备型号分离
流程图解析图中节点、连线和条件,转成有序步骤分支条件、回退路径丢失
扫描件OCR 后保留原页码和识别质量信息数字、单位和型号识别错误

分块大小需要通过实际语料验证,不能只看一个固定的 Token 数。

目标设计可以从每块约 400~800 个 Token、相邻文本块重叠约 50~100 个 Token 开始测试。这只是初始参数,不是已验证的最佳值。短规程可以更小,长段落可以适当增大,完整的表格行和操作步骤则应优先保持语义完整。

分块时应遵循以下原则:

  • 尽量不拆开一个完整的操作步骤。
  • 每块保留所属章节标题,避免只检索到孤立的句子。
  • 表格块必须带上表头、适用型号和单位。
  • 流程图应保留节点顺序、判断条件和分支结果。
  • 超长表格可以按行组拆分,但每块都要重复必要的表头。
  • OCR 置信度低的关键参数进入人工复核流程,不应直接成为可信操作依据。

分块不是越细越好。切得太细,模型不知道句子属于什么场景;切得太大,检索会带回大量无关内容,也更容易挤占上下文。

5.2 Embedding 与 Milvus

Embedding 模型把文本映射成一个固定长度的浮点向量。语义接近的文本通常会在向量空间中更接近。

例如,“电量不足时返航”和“低电量触发自动返航”虽然用词不同,但可能表达相近的意思。向量检索适合找这类语义相似的内容。

模型选型要看三个方面:

  1. 中文与专业术语能力。 能否处理无人机型号、行业术语、缩写和中英文混合内容。
  2. 部署与数据边界。 采用云端模型还是本地模型,是否允许文档内容发往外部服务。
  3. 检索效果与成本。 在自己的问题集上比较召回效果、响应时间和推理成本。

向量维度不是手工随意设置的。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 时,只放入本次问题最相关的片段,并明确要求模型根据证据回答。上下文超过预算时,应删除低相关片段或压缩重复内容,不能直接截断关键操作条件。

可以采用如下提示词结构:

text
你是无人机平台的业务知识助手。

回答规则:
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_documentid、title、doc_type、status、current_version_id文档主记录
kb_document_versionid、document_id、version_no、object_key、checksum、status原始文件与版本状态
kb_chunkid、version_id、content、page_start、page_end、section_path、metadata保存分块原文与引用位置
kb_document_acldocument_id、role_code、org_id、project_id文档访问授权
kb_ingest_jobid、version_id、status、error_message入库任务状态与失败原因

建议用 UUID 或其他全局唯一标识作为 documentId、versionId 和 chunkId。数据库记录与 Milvus 中的主键必须保持可关联。

分块数据结构可以这样定义:

java
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 入库接口

入库服务可以设计为异步流程:

java
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 的内部实现。

java
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。具体的向量检索和模型调用应由实现类封装。

调用顺序可以设计为:

java
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 等是需要自行实现或适配的服务,不是可以直接复制运行的完整代码。生产实现还应为检索超时、模型不可用和索引版本不一致定义明确的异常处理。

有两个边界必须守住:

  1. userId、角色和组织信息不能直接相信前端传值,应以登录态和服务端授权结果为准。
  2. relevanceScore 是检索排序信号,不代表答案正确。是否有足够证据,需要结合最低相关性、关键条件覆盖和业务规则进行判断。

6.4 Prompt 组装与引用绑定

上下文组装器应将每条证据转换成固定格式,并同时生成可追溯的引用映射。

java
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 保存到本次请求的引用映射中。

模型回答时可以输出:

json
{
  "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,再从可信的元数据中生成文档和页码链接。模型自己写出的页码不能直接相信。证据不足时允许拒答,不让它自行补齐规程。

问答三:手册更新了,怎么保证旧版本不会继续被检索?

答: 我不会在上传新版文件时直接删除旧版,而是给文档版本维护独立状态。新版经过解析、分块、向量化和审核后,再切换当前有效版本。旧版转为退役状态,检索时同时校验发布状态、版本有效性和用户权限。索引清理、缓存失效和引用访问也要跟着版本切换处理。这样即使新版入库失败,也不会因为提前删除旧版而导致整个知识库不可用。