向量数据库不该成为新孤岛:KingbaseES 多模融合架构如何减少数据搬运
向量数据库项目最容易在演示环境里显得简单:把一批文档切成段,调用模型生成向量,写入向量库,再用相似度检索返回几条结果。真正接入业务后,问题很快变成另一副样子。用户权限在业务库里,文档正文在文件系统或文档库里,向量检索在第三套服务里,订单、组织、区域和时间条件又分散在别处。回答一次问题,需要先查权限,再查文档,再查向量结果,最后把几份结果拼在一起。
只要其中一处更新没有及时同步,检索结果就可能落后于业务状态。文档已经撤回,向量索引还留着;客户已经变更所属机构,旧的权限标签仍然出现在召回结果中;一条知识被重新分段,旧向量和新向量同时存在,排查时很难判断问题出在模型、同步任务还是数据库查询。
这也是“向量数据库”不应被简单理解成又一套独立存储的原因。对于需要事务数据、文档属性、空间位置、时间状态和语义向量一起参与检索的系统,更合理的方向是让不同数据模型在同一套数据库架构中协同管理。KingbaseES 的融合数据库定位,正是把关系、文档、向量、空间和时序等数据能力放到统一的数据底座中,再由业务按场景选择模型,而不是为了每一种字段单独搭一套数据库。
从三套系统拼结果,到一条可解释的查询
以企业制度问答为例,资料管理员把制度文件上传到知识库,应用需要完成四件事:确认提问者能看到哪些制度;从授权范围内的文本片段中做语义召回;根据制度的生效时间排除过期资料;最后把文件版本、部门和密级信息一起返回给上层应用。
在分散架构里,流程大致是“业务库查权限 -> 文档库查正文 -> 向量库查相似度 -> 应用层过滤和拼接”。这条链路每增加一个过滤条件,就多一次接口交互和一次字段映射。权限标签、文件版本和向量记录也分别有自己的更新事务,任何一个步骤失败都可能产生半成功状态。
融合架构并不要求把正文、属性和向量塞进一列,而是允许它们在同一套数据库管理范围内保持清晰的表结构。正文可以放在文档字段或对象存储引用中,元数据放在关系表,向量放在向量列,权限通过关系表和角色控制;查询时通过同一条 SQL 把这些条件组合起来。
图里的变化不是把所有数据“揉成一种格式”,而是把数据的归属、权限和事务边界放到同一个可管理的系统里。关系表仍然负责明确的业务约束,文档数据保留原有的层次,向量字段服务于相似度检索,时间和空间字段则继续按各自的查询规律使用。应用面对的是统一的连接和权限体系,数据库内部仍按数据模型选择合适的存储与索引方式。
关系数据和向量数据要一起更新
向量检索最容易被忽略的字段不是向量本身,而是它对应的业务状态。一个制度片段至少需要记录来源文件、版本号、部门、密级、生效时间和是否有效。向量生成模型发生变化时,模型版本也要写进记录,否则同一张表里混合了不同模型的向量,召回效果发生波动后没有办法回放。
CREATE TABLE knowledge_chunk (
chunk_id bigint GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY,
document_id bigint NOT NULL,
version_no integer NOT NULL,
chunk_no integer NOT NULL,
title varchar(300) NOT NULL,
content text NOT NULL,
department_code varchar(32) NOT NULL,
security_level varchar(16) NOT NULL,
effective_from timestamp NOT NULL,
effective_to timestamp,
is_enabled boolean NOT NULL DEFAULT true,
model_name varchar(80) NOT NULL,
embedding vector(768),
updated_at timestamp NOT NULL DEFAULT current_timestamp,
UNIQUE (document_id, version_no, chunk_no)
);
vector(768) 表示一个固定维度的向量列,维度必须和实际使用的模型一致。模型更换时,不应该直接覆盖旧值;先增加模型版本或新批次,完成召回回归后再切换 is_enabled。这样做会多保存一段时间的数据,却能把“模型变化”和“业务资料变化”区分开。
文档发布和向量写入应处在同一个业务事务里,至少要保证发布状态、版本号和向量记录不会只成功一半。一个简化的事务片段如下:
BEGIN;
UPDATE knowledge_document
SET current_version = 8,
status = 'PUBLISHED',
updated_at = current_timestamp
WHERE document_id = 10086
AND status = 'READY';
UPDATE knowledge_chunk
SET is_enabled = false
WHERE document_id = 10086
AND version_no = 7;
UPDATE knowledge_chunk
SET is_enabled = true
WHERE document_id = 10086
AND version_no = 8
AND model_name = 'embedding-v3';
COMMIT;
向量是否已经生成完成,需要由应用的状态字段或任务表确认。不能把“文件发布成功”当成“语义检索已经可用”,也不能把向量生成失败的记录标记为有效。统一数据库能提供事务边界,但不会替业务决定模型生成是否成功。
语义相似度和业务条件要在一条 SQL 里完成
仅按向量距离取前几条,容易把不属于当前部门、已经失效或密级不匹配的内容召回。真正可用的检索需要先把业务范围写进过滤条件,再按向量距离排序。金仓公开资料给出的向量字段、相似度运算符和索引写法,可以作为同类场景的 SQL 参考;具体维度、索引类型和参数仍需按目标版本的向量组件确认。
CREATE INDEX idx_knowledge_chunk_embedding
ON knowledge_chunk
USING hnsw (embedding vector_cosine_ops);
用户提问经模型转换得到 :query_embedding 后,混合查询可以写成:
SELECT chunk_id,
document_id,
version_no,
title,
content,
department_code,
security_level,
effective_from,
embedding <-> CAST(:query_embedding AS vector(768)) AS distance
FROM knowledge_chunk
WHERE is_enabled = true
AND department_code IN ('FINANCE', 'RISK')
AND security_level <= :user_security_level
AND effective_from <= current_timestamp
AND (effective_to IS NULL OR effective_to > current_timestamp)
ORDER BY embedding <-> CAST(:query_embedding AS vector(768))
LIMIT 8;
这条 SQL 的结果可以直接交给上层的重排序或生成服务使用。权限、版本和有效期已经在数据库条件中完成,应用不需要拿回几十条候选记录后再逐条过滤。相似度排序仍然只是召回手段,最终答案还应保留文件编号、版本和引用片段,方便业务人员追溯原始资料。
向量检索也可以与普通关键词结合。标题、制度编号和部门代码属于明确字段,适合使用等值或模糊条件;语义向量适合处理同义表达。两类条件分开写在 SQL 中,结果的来源和过滤理由会更清楚:
SELECT chunk_id, title, content
FROM knowledge_chunk
WHERE is_enabled = true
AND department_code = 'RISK'
AND (title LIKE '%' || :keyword || '%'
OR content LIKE '%' || :keyword || '%')
ORDER BY updated_at DESC
LIMIT 20;
关键词查询和向量查询不一定要互相替代。制度编号、设备型号、合同编号等精确字段仍然应当优先过滤;当用户说法与原文用词不一致时,再让向量相似度承担补充召回。把两类检索放进统一的数据模型中,应用可以按场景组合,而不用为每一种检索方式建立一条完全不同的数据同步链路。
从用户权限到文件版本,再到向量距离,条件都能在数据库侧留下可审计的查询记录。出现“召回了不该出现的材料”时,可以依次检查权限表、有效期条件、向量批次和查询参数,而不是先在三个系统里分别导出结果再人工对照。
检索结果还要能回放
企业知识检索不能只记录最终生成的答案。一次召回至少应保存查询时间、调用账号、使用的模型版本、向量批次、业务过滤条件和返回片段编号。用户反馈答案错误时,才能用同一组条件重跑,确认是资料版本变化、权限规则变化,还是向量模型变化。
审计表不必保存完整提问和完整文档,可以记录脱敏后的查询标识与结果引用:
CREATE TABLE retrieval_audit (
request_id varchar(64) PRIMARY KEY,
user_code varchar(64) NOT NULL,
model_name varchar(80) NOT NULL,
query_hash varchar(128) NOT NULL,
filter_snapshot text NOT NULL,
result_chunk_ids text NOT NULL,
created_at timestamp NOT NULL DEFAULT current_timestamp
);
filter_snapshot 保存当时使用的部门、密级和有效期条件,result_chunk_ids 保存召回片段编号。业务系统需要限制这张表的查询权限,并按审计周期清理;查询哈希也不能被当成永久匿名化手段。对于高风险业务,还应保存最终引用的文件版本和人工反馈结论,让检索回归从“感觉变准了”变成可以比较的结果集合。
召回阈值也要通过业务样本确定。固定返回前 8 条并不保证 8 条都相关,距离值在不同模型之间也不能直接横向比较。模型升级时,应使用同一批问题对比命中片段、错误召回、权限拦截和无答案场景,再决定是否切换向量批次。统一存储让这类回放更容易执行,但判断检索质量仍然需要业务标注和稳定的测试集。
多模融合不是无条件合并
统一底座解决的是数据管理边界,不代表所有负载都应该放在同一个实例、同一张表或同一个索引里。向量索引构建会占用内存和 CPU,批量导入文档会产生写入峰值,空间数据和时序数据又有各自的访问规律。资源隔离、表空间规划和备份策略仍然要按工作负载拆开设计。
数据安全也要跟着模型变化。向量本身可能包含个人信息、合同内容或医疗影像的特征,不能因为它不是可读文本就降低访问级别。应用账号只读取经过授权的视图,生成向量的任务账号只写入指定列,运维账号负责索引和容量管理;原始文档和向量索引的保留周期也要同步纳入数据治理。
模型更新是另一个需要留痕的动作。一次 Embedding 模型升级,可能影响召回顺序、阈值和结果数量。model_name、维度、生成时间和批次号都应该记录在表里,回归测试至少覆盖热门问题、权限边界、失效文档和重复片段。没有这些信息,向量结果变了只能凭感觉猜原因。
统一管理的价值要落到运维动作
多模融合架构最先减少的是重复搬运。业务状态更新时,权限标签和向量记录可以在同一事务边界内处理;文档下线时,不必等待另一套系统的同步任务完成;查询时,结构化条件和相似度排序可以由同一条 SQL 表达。运维人员关注的对象从多个同步队列、多个账号和多份字段映射,收敛为数据模型、索引、权限和资源四类问题。
它也让迁移和扩展更容易分阶段推进。先把关系表和文档元数据纳入统一管理,再按业务优先级增加向量字段;先让关键词检索稳定运行,再接入语义召回。每一步都能用结果集、权限验证和回归问题集证明,而不是一次性替换所有存储组件。
向量数据库真正进入企业系统后,评价标准不应只看相似度查询能否返回几条结果。更关键的是:文档版本是否和向量批次一致,权限是否在召回前生效,业务事务失败后是否会留下孤立向量,模型升级后能否重现历史结果。KingbaseES 的多模融合架构为这些数据放在同一套管理边界内提供了路径,剩下的工作仍然是把字段、索引、权限和回归规则设计扎实。