VeapAI 自然语言操作实战|第 05 篇:向量与召回——从知识条目到可检索资产

> 系列:VeapAI 自然语言操作实战(全体系架构专题)

> 本文要点:声明式资产 · 写入三表台账 · 就绪检查 · 固定顺序的过滤链

条目写完,为什么还搜不到

知识库里明明有一条"第三十条",问答却召回不到。这类"搜不到"的问题,排查下来通常有三层原因:没向量化、索引没就绪、被过滤链挡掉。

这就是向量层的全部工作量。它不是"接一个 Milvus 就完事",而是一段有状态、有台账、有边界的工程链路。本文按两段来看:先看写入,再看召回。

!向量化作业与运行记录:写入链的每一批都有统计与明细

资产先声明,再同步

!向量资产生命周期:声明式资产(实例 → 集合 → 字段 → 索引)与写入链(作业 → 批次 → 逐条 → 台账)

平台对 Milvus 资产采用声明式管理:先在平台侧把资产定义清楚,再同步到远端。资产有五层:

  • 实例:`endpoint`、认证(token / 用户密码,密钥加密存储)、TLS 与健康检查;

  • 集合:`primary_field`(主键字段名)、`vector_field`、`vector_dim`、`metric_type`(L2 / IP / COSINE)四个字段必须显式声明;集合绑定知识主题;

  • 字段定义:Schema 权威在平台侧,每个字段可以从元数据标准的字段里选择性创建;

  • 索引:类型(HNSW / IVF_FLAT / AUTOINDEX 等)与构建状态(`build_state`);

  • 别名与分区:可选,用于平滑切换与数据组织。

声明与远端之间可能出现差异,所以集合上有一列 `sync_state`:unknown、in_sync、out_of_sync、pending、error。改完声明后同步一次,状态归位;出问题时有据可查。

写入:三张表记账,外加一本台账

一次向量化写入,本地会留下四份记录,各管一段:

| 表 | 角色 | 关键字段(注释原文节选) |

| --- | --- | --- |

| `ai_vector_ingest_job` | 作业定义(业务数据向量化 → Milvus) | `source_type`:knowledge_entry 等;`embed_model_id`:Embedding模型ID;`upsert_mode`:insert_only / upsert / replace |

| `ai_vector_ingest_run` | 运行批次 | `run_status`:running / success / fail / canceled;total / success / fail 计数 |

| `ai_vector_ingest_item` | 运行明细(失败定位) | `item_status`:success / fail / skip;`milvus_pk`:写入成功后回填 |

| `ai_vector_object_map` | 向量对象映射(业务对象 ↔ Milvus主键) | `milvus_pk`:字符串化,兼容 Int64 / UUID;`etag`:内容hash(判断是否需重算向量) |

四份记录的分工很清楚:job 说"要做什么",run 说"这一批做得怎么样",item 说"哪一条出错了",object_map 说"这个对象现在对应哪个向量"。

台账里的 `etag` 是个细节亮点:它是内容的指纹。内容没变,向量就不用重算;内容变了,etag 变化触发重写。没有这列,每次执行都得全量重算。

就绪检查与两条数据契约

检索之前有一道硬门禁,叫就绪检查。规则只有两条:集合里有数据时,必须存在且仅存在一个启用的向量字段索引,且 `build_state=ready`,才允许加载集合并检索;集合没有数据时,直接返回空结果,不做任何尝试。

这个检查防的是最常见的"搜不到":索引还在构建中,检索请求打过去,表面没有报错,结果却是空的。与其让用户猜,不如把门禁前置。

另外两条数据契约,是踩过坑之后写死的:

  • `primary_field` 只表示 Milvus 的物理主键;业务侧反查知识条目,必须用独立的 `object_id` 字段。两者不是一回事,混用会在某些主键模式下直接查错;

  • 召回返回 `object_id` 后,如果回查知识条目为空,必须显式报"知识召回数据不一致",禁止静默输出空列表。查不到就是有问题,问题要报出来。

召回:固定顺序的过滤链

!召回过滤链:检索、融合、发布态、权限、ACL、重排、加权,每一步顺序固定

召回的执行从"解析"开始:先定召回目标,再定参数。目标是链路解析出来的------从应用服务的 `topic_id` 出发,经过应用绑定、知识主题、标准,最终落到向量化作业。

检索行为的配置收在检索模板 `ai_vector_search_template` 里,四组要素:

  • `strategy_type`:vector(缺省)、bm25(全文)、hybrid_rrf(向量 + 全文 RRF 融合);

  • `query_rewrite_config`:查询改写(hyde / multi_query),可关闭;

  • `rerank_config`:重排配置(供应商与 topN);

  • `top_k`、`score_threshold`、`filter_expr`、`output_fields`:常规检索参数。

多主题召回是批量执行的。按"集合 + 嵌入模型"分组,每组一次 inspect / embed / search,过滤表达式形如 `topic_id in ...`。多个知识主题因此不会退化成多次往返。

检索拿到候选之后,还有一条固定顺序的过滤链,一步都不能省:

  1. 发布态:审核、开放、状态三个闸门都过的条目才可召回;

  2. 权限系数:条目公开级别低于配置系数的直接过滤;

  3. ACL:按 allow / deny 矩阵判定主体可见性;

  4. 重排:按配置的供应商对候选重新打分;

  5. 加权排序:按知识配置的权重系数与原始分加权,稳定降序。

顺序即契约。先做发布态与权限、再做重排、最后加权,任何一步换顺序,结果的解释都会变。

过程全程留痕:`ai_vector_search_audit` 记录查询文本、`top_k`、过滤表达式、结果数量、耗时与状态。向量本身只留 hash,不落库。

!检索调试台:dense / sparse / 融合三路结果并排,便于对比策略效果

!检索模板:策略、改写与重排配置的可视化维护入口

源码走读

  • 资产与写入:`veap-cloud/veap-modules/veap-milvus`------`AiMilvusCollectionController`、`AiVectorIngestJobController` 与写入执行器;

  • 召回执行:`AiKnowledgeEntryVectorQueryAppService`(单主题与批量两条路径);内网入口 `InnerMilvusVectorQueryController`(`/milvus/inner/knowledgeEntry/vectorQueryHitsBatch`);

  • 嵌入调用:`EmbeddingFacade`------兼容 openai_compat 协议(`/api/embed`)与既有直连两种模式;

  • 检索模板:`ai_vector_search_template` 的 `strategy_type`、`rerank_config`、`query_rewrite_config` 三列,由可视化页面维护;

  • SDK:Milvus SDK(2.6.x),客户端按连接键复用。

较真:两次"信任"引发的返工

向量层最贵的教训,都与"信任"有关。

第一次是信任本地台账。旧的跳过逻辑是:台账里有记录、本轮就跳过写入。上线后遇到一次远端集合被清空的情况,台账还在,数据已经没了,于是所有条目都被跳过,知识全丢但没有任何报错。修复后的契约很简单:远端集合 `rowCount=0` 时不得信任台账,必须重新写入;并且只有本轮发生了实际写入,才允许刷新台账。

第二次是信任"已经写好的方法"。批量召回上线后,结果恒为空。排查到根因:单主题与批量两条路径的 `output_fields` 传参不同。批量路径仍然只传 `object_id` 一个字段,而结果分发逻辑要按 `topic_id` 分组。字段缺失导致每条记录都被判定为无效并丢弃。解法其实早就在代码里------一个定义好但没被用上的批量字段集。

教训写在规范里:**新增一个执行参数,必须把全部调用点的语义差异重新核对一遍。**单主题路径的方案,不能默认搬进批量路径。

复现与验证

  1. 看写入链:`SELECT run_status, total_count, success_count, fail_count FROM ai_vector_ingest_run WHERE job_id = <作业id> ORDER BY id DESC LIMIT 5;`

  2. 看台账:`SELECT object_type, object_id, milvus_pk, last_upsert_status FROM ai_vector_object_map WHERE collection_id = <集合id> LIMIT 20;`

  3. 看审计:`SELECT result_count, latency_ms, status FROM ai_vector_search_audit ORDER BY id DESC LIMIT 10;`

这一层的边界:它只负责"条目进、证据出",不负责改写业务口径,也不承担知识质量。条目本身准不准,是前两层的事------向量层只保证"查得到"。

到这里,知识侧的链路已经完整:附件与系统数据进来,加工成条目,向量化后可以被召回。接下来换个视角,看这些能力是怎么被装配进同一个前端运行时的。

相关推荐
mingbaiceping1 小时前
复旦-华盛顿大学EMBA:2026年AI课程矩阵解析
人工智能
李福春1 小时前
技术思考问题17:上了LangChain框架就等于AI-Agent工程化吗?
大数据·人工智能·langchain·深圳同盟·腾讯云架构师技术同盟·llm应用架构·编排抽象
揽秀亭长1 小时前
AIGC 检测原理拆解与论文降 AI 率的可复现处理流程(2026版)
人工智能·aigc
羞儿1 小时前
【DSH】为什么需要-Harness
人工智能·大模型·harness·认知构建
JackLam3 小时前
AI-安装ChatGpt Codex
人工智能
强哥聊算力4 小时前
《算力江湖·英伟达传奇》第七集:ChatGPT出现前夜,英伟达发生了什么?
服务器·人工智能·算法·ai·chatgpt·gpu算力
吴佳浩4 小时前
Run:ai 开源了,我把 GPU 编排摆回 AI 栈里看了一遍
人工智能
IT_Octopus6 小时前
【零基础入门 LLM 开发 · Day 13】:LangChain 的对话记忆——Message 对象版
人工智能·python·langchain
一只鹿鹿鹿6 小时前
政务外网整体设计方案(PPT)
大数据·数据库·web安全·系统安全·流程图·政务