十年匠心定制 · 商业建站与技术教学双线并行 咨询热线:400-886-1026 service@lmnt.cn
ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

向量数据库RAG落地——先把权限和版本写进表里

向量数据库RAG落地——先把权限和版本写进表里 文章目录先看传统架构为什么会变复杂设计一张可追溯的知识表查询不能只有 top k增量更新要保证幂等关系、文档、GIS 和时序数据如何一起参与检索MCP 接入让 AI 有工具但不要给它万能钥匙结尾向量只是能力不是答案让检索结果可解释而不是只给一个分数模型升级也要有迁移方案平时我们看很多 RAG 的演示啊其实往往仅仅只是三步。切一下文档然后生成向量接着做相似度搜索。但是呢你真正把企业层级里的资料接进去之后问题马上就变了。变成了另外一组问题。比如说这段内容到底发布没有这个用户有没有权限去看原文更新了那旧的向量什么时候让它失效还有啊你检索出来的设备故障记录它现在还符不符合当前的实际状态如果要去做向量数据库的实验的话我其实更愿意从一张表开始。而不是说一上来就去搭一套很复杂的平台。为什么呢因为你一旦把文档、版本、权限、模型还有向量这些东西都放在一块儿了。RAG 的边界就很清楚了。也就是说向量它就是负责把候选内容给召回来。结构化字段呢负责做过滤和治理。大模型负责把答案组织好。但是大模型不能替数据库去做决定也不能替用户去越权。先看传统架构为什么会变复杂传统的 AI 系统里面常见的组合是什么呢就是有关系库、文档库还有一个单独的向量数据库再加上缓存和好几个 ETL 任务。每一套组件啊它可能确实有它合理的用途。问题出在哪里呢问题在于业务发来一个请求的时候它需要同时去访问这些组件。同步重新向量化用户问题应用编排层关系库文档库向量数据库应用层拼接大模型权限/版本遗漏风险用户问题KingbaseES融合数据底座关系/文档/向量/GIS/时序库内过滤与混合检索大模型上下文这里说的这个“融合”啊其实不是说一句“一个数据库把所有问题都解决掉”就完事了。它的意思是什么呢是减少那些没必要的搬数据的过程。让关系的属性、文档的内容、向量的索引还有访问的条件能够更容易地放在同一条可以审计的链路里面。至于说模型推理嘛依然可以交给专门的 AI 服务去跑。设计一张可追溯的知识表我会先把知识块设计成下面这样。维度和索引只是示意真正执行前要核对 KES 版本支持的向量类型、距离操作符和索引语法。CREATETABLEknowledge_chunk(chunk_idBIGINTPRIMARYKEY,document_idBIGINTNOTNULL,document_versionINTEGERNOTNULL,contentTEXTNOTNULL,embedding_modelVARCHAR(128)NOTNULL,embedding_dimINTEGERNOTNULL,embedding VECTOR(768),tenant_idBIGINTNOTNULL,department_idBIGINT,access_levelINTEGERNOTNULL,lifecycle_statusVARCHAR(16)NOTNULL,source_uriVARCHAR(512),updated_at TIMESTAMPTZNOTNULL,created_at TIMESTAMPTZNOTNULLDEFAULTCURRENT_TIMESTAMP,UNIQUE(document_id,document_version,chunk_id));CREATEINDEXknowledge_chunk_filter_idxONknowledge_chunk(tenant_id,department_id,lifecycle_status,access_level);CREATEINDEXknowledge_chunk_embedding_idxONknowledge_chunkUSINGhnsw(embedding);在这张表里面其实最重要的字段并不是embedding。而是document_version还有lifecycle_status再加上访问的范围。如果缺了这些东西的话系统就很容易把旧版本给回答出来。或者说把用户根本没有权限看到的内容直接塞进上下文里面去了。字段组作用丢失后的问题文档和版本回到原文判断新旧无法去重和撤回旧知识租户和部门做结构化过滤可能跨租户召回权限等级进入上下文前拦截可能发生越权回答模型和维度区分向量来源模型升级后无法重建来源和时间解释答案来源无法审计和追责查询不能只有 top k纯相似度查询很容易写出来但企业查询通常还带租户、部门、状态和时间条件SELECTchunk_id,document_id,document_version,content,source_uri,1-(embedding:query_embedding)ASsimilarityFROMknowledge_chunkWHEREtenant_id:tenant_idAND(department_id:department_idORdepartment_idISNULL)ANDaccess_level:user_access_levelANDlifecycle_statuspublishedANDupdated_at:knowledge_cutoffORDERBYembedding:query_embeddingLIMIT8;这里面的VECTOR(768)啊还有 HNSW 以及其实仅仅只是用来做个说明的例子。它们是跟版本相关的一些示例。向量的类型、维度、索引还有距离的度量这些必须得跟你用的 Embedding 模型保持一致才行。你不能先随便定一个维度然后反过来让模型去适配它。精确检索还有近似检索呢也要看指标来选。IVFFlat 的话它更适合在资源不够用的时候去控制索引的结构。HNSW 往往更关注检索的速度还有召回率。但是它的内存占用还有构建的成本你得拿自己的数据去测一下才行。指标适合回答的问题测试方法RecallK相关片段是否被召回标注问题-文档对统计命中P95 延迟高峰期用户是否等得起并发压测不只测平均值更新可见时间文档改了多久能搜到从发布事件到首次召回计时权限误召回是否召回不该看的内容构造跨部门和跨租户用例重复/过期率结果是否被旧版本污染按文档 ID 和版本统计增量更新要保证幂等知识库里面最常见的那种故障啊其实并不是“向量生成不出来”。而是同一篇文档你更新了好几次之后旧版本的向量还在结果里面待着。或者说任务重试了之后产生了一堆重复的块。那我会怎么干呢我会把版本号还有幂等键都写进处理的流程里面去。失败文档发布事件生成document_idversion清洗与切分批量生成embedding按文档版本幂等写入抽样检查向量维度权限与召回回归发布新版本保留旧版本/重试队列旧版本标记retired下面这个呢是一个偏工程化一点的 Python 处理骨架。它没有绑定到某一个具体的 Embedding 服务上面。它仅仅只是强调了一下事务的边界还有幂等的逻辑defindex_document(event,db,embedder):document_idevent[document_id]versionevent[version]chunkssplit_text(event[content],max_tokens500,overlap80)rows[]forordinal,textinenumerate(chunks):vectorembedder.encode(text)iflen(vector)!event[embedding_dim]:raiseValueError(embedding dimension mismatch)rows.append({chunk_id:make_chunk_id(document_id,version,ordinal),document_id:document_id,document_version:version,content:text,embedding:vector,lifecycle_status:staging,})withdb.transaction():db.upsert_chunks(rows,keychunk_id)db.assert_chunk_count(document_id,version,len(rows))db.mark_version(document_id,version,published)db.retire_older_versions(document_id,keepversion)先把完整的新版本写进去接着再去发布然后再把旧版本给下线。这样的话就算向量服务或者是索引任务暂时挂了旧的知识还是能用的。就不会出现那种情况就是文档已经发布了但是你一检索却返回一个空结果。关系、文档、GIS 和时序数据如何一起参与检索在企业里面遇到的问题啊往往不仅仅只是“哪篇文档最相似”这么简单。打个比方搞运维的人可能会这么问“过去一个星期里面出现类似振动曲线的设备有哪些它们是不是在同一个园区里面最近三个月有没有维修的记录”这个问题要回答的话就需要向量相似度、设备的关系、空间的范围、时序的窗口还有维修的文档一起参与进来。KingbaseES 的融合数据架构呢它其实是给了一个方向。就是把这几种数据模型放在一个统一的底座里面去做管理和关联分析。它的价值在于什么呢在于减少好几套系统之间那种重复的同步。但是具体的查询到底适不适合在库里面直接完成这个还是得根据你的数据量、访问的模式还有权限的要求来决定。SELECTd.device_id,d.site_code,r.repair_count,v.similarityFROMdevice_profileASdJOINrecent_repairsASrONr.device_idd.device_idJOINvector_candidatesASvONv.device_idd.device_idWHEREd.site_codeIN(SELECTsite_codeFROMsite_boundaryWHEREST_Contains(geometry,:query_point))ANDr.last_repair_atCURRENT_DATE-INTERVAL3 monthsORDERBYv.similarityDESCFETCHFIRST20ROWSONLY;这段 SQL 啊它其实是一个融合查询的结构示意。它并不是说每个项目都得把复杂的逻辑直接塞到一条语句里面去写。它展示的是一个判断的顺序。也就是说先拿业务和权限的条件把范围给缩小。接着再做向量的召回或者重排。这样就能减少那些没意义的数据搬来搬去。MCP 接入让 AI 有工具但不要给它万能钥匙参考资料里面提到的那个 KES MCP Server 啊它提供了一些标准的工具。比如探索数据库结构、查 SQL、看执行计划还有检查状态什么的。这些可以在支持 MCP 的开发工具里面去用。对开发者来说的话你去问一句“这张表有没有合适的索引”这比你自己手动去复制好几个查询结果要快得多。但是对于生产环境来说呢AI 生成了 SQL这并不代表 AI 就可以无限制地去写库了。gitclone https://gitee.com/king-db/kingbase-mcpcdkingbase-mcp uv run kingbase-mcp --access-mode restricted那我一般会按三层权限去接入层级权限可以做什么不能做什么探索只读元数据看表、列、索引、约束读取敏感字段值分析限制查询看执行计划、慢查询、质量问题长时间全表扫描变更显式审批建索引、调参数、执行变更无审批直接改生产资料里面给的体验环境的要求啊包括了 KES V8R6 还有更高的版本然后是 Python 3.12 到 3.13再加上支持 MCP 的客户端。但是你要真正接到生产环境里面去的话还得加上超时的设置、返回行数的限制、SQL 的审计、账号的最小权限还有回退的窗口。结尾向量只是能力不是答案向量数据库的底层能力确实很重要。但是呢它没法替你去把数据治理的工作给做了。金仓向量组件把向量的存储、计算还有检索都放到了 KES 的能力体系里面去。而且它还能支持跟关系、文档、GIS、时序这些模型去做关联。这其实给减少 ETL 还有统一运维提供了一条能走得通的路。那对我自己来说的话我要去判断一个向量数据库的方案到底能不能落地。我主要就看五件事。能不能追溯到原文能不能把权限过滤掉能不能把版本管理好召回率和延迟能不能测量出来还有失败的时候能不能回退代码你可以继续往上加索引你也可以继续去调优。但是这五件事你要是没做好那 RAG 也就仅仅只是一个看起来挺聪明的搜索框而已。让检索结果可解释而不是只给一个分数我在做 RAG 项目的时候啊最不放心看到的一种界面就是什么样呢就是它只给你显示一段回答。但是却不告诉你这个回答到底是引用了哪些资料。相似度的分数看着好像挺科学的。但是它并不等于事实就是正确的。真正能用的系统啊至少得把文档的标题、版本、来源的链接、更新的时间还有片段的编号留给调用方。必要的时候呢还得把结构化的过滤条件写进审计的记录里面去。这样做其实有两个好处。第一个好处是业务那边的人可以马上判断出来这个答案有没有引用过期的制度或者是错误的版本。而不是说直接把模型吐出来的东西当成最后的结论。第二个好处是系统要是出现争议了。团队可以把当时的查询向量、过滤条件、召回的结果还有模型的提示词都给回放出来。这样就能定位问题到底出在哪了。是切分的时候出的错还是向量化的时候或者是检索、重排、又或者是生成的时候如果没有这条证据链在那摆着的话那向量数据库的调优往往就只能是靠猜了。我一般会把评估的集合分成两种。一种是“常规问题”另一种是“边界问题”。常规问题呢就是用来测 RecallK 还有延迟的。比如问“某个制度应该怎么去申请”。边界问题的话它专门就是用来测权限和时效的。比如问“同一个标题下面旧版和新版能不能被正确地选出来”“不同部门的用户是不是只能看到授权给他们的内容”“已经撤销掉的文档是不是还能被召回”边界问题的数量其实不用很多。但是呢每次你的模型变了或者索引变了又或者是切分的策略变了你都必须要重新跑一遍。索引的选择呢也得跟更新的频率放在一起看。HNSW 还有 IVFFlat 以及精确检索它们都有各自的取舍。你不能光挑一个在小样本数据上面跑得最快的。如果你的文档每天都变来变去的那索引的维护成本还有新向量可见的时间往往就比单次查询的延迟更重要了。那如果你的知识库比较稳定而且你需要更高的召回率这时候你就可以多投点资源去构建索引。所有的结论啊都应该来自你自己的数据量、维度、并发还有召回的标准。而不是说直接把演示用的参数照抄过来。最后呢就是得把失败的方式给设计好。Embedding 服务超时了怎么办单批向量的维度报错了怎么办索引构建失败了怎么办还有 MCP 工具返回了太多的数据怎么办这些情况啊都不应该直接让线上的问答给崩掉。你可以把上一版已经发布好的索引给保留着。然后给失败的事件做一个可以重试的队列。再限制一下单次返回的大小。并且在回答里面明确地提示一句“没有找到已经授权而且有效的资料”。比起模型去编造一个看起来很流畅的答案这种失败的方式其实更符合企业层级里的系统的那个可信边界。模型升级也要有迁移方案当 Embedding 模型从一个版本往另一个版本升级的时候啊你不能把新的向量和旧的向量直接混在同一个检索空间里面去比。为什么呢因为维度啊、归一化的方式啊还有语义的分布这些一旦变了。那相似度它就不再是拿同一把尺子去量的了。更稳妥的一个做法是什么呢就是给模型的版本还有维度打上标签。然后先在一个影子索引里面去把新版本给构建出来。接着用同一套评估的集合去比较一下召回、延迟还有权限的过滤情况。都确认没问题了再一步一步地去把读取的流量给切过去。在切换的这段时间里面呢你还得考虑回退的事情。旧的索引要保留多久新加进来的文档要不要同时去写两套向量失败了的话由哪个版本来回答这些安排啊确实会增加一点短期的成本。但是呢它比你在线上突然发现“同一个问题怎么突然搜不到资料了”这种情况要可控得多。向量数据库的演进啊其实跟普通的数据库迁移是一样的。它都需要版本、验证、观察还有回退这四个步骤。
返回列表