向量数据库与图数据库混合检索架构:大模型知识问答系统实战

发布时间:2026/10/11 11:05:24
向量数据库与图数据库混合检索架构:大模型知识问答系统实战 1. 项目缘起与整体架构思路1.1 为什么单靠向量库或图库都不够用做过大模型应用的人多半踩过这个坑用户问“A公司的核心供应商有哪些这些供应商之间有没有共同的股东”纯向量检索能召回一堆语义相近的文档片段但它答不出“共同股东”这种需要多跳关系推导的问题反过来纯图数据库能精准遍历关系可用户要是问“最近关于供应链风险的讨论集中在哪些方面”图库就抓瞎了因为它不擅长处理模糊语义。这个项目的出发点就是把这两类数据库捏在一起用。向量数据库负责“语义召回”把用户问题映射到高维空间找出语义最接近的文本块、实体描述、事件摘要图数据库负责“关系推理”把这些召回结果作为入口节点沿着预定义的边做多跳遍历把散落在不同文档里的关联信息串成一条完整的证据链。大模型在中间扮演两个角色一是把用户自然语言问题翻译成检索指令包括向量查询语句和图查询语句二是把检索回来的结构化非结构化混合上下文组织成最终答案。我个人的判断是2024年下半年到2025年这类“向量图”的混合检索架构会逐渐成为知识密集型问答系统的标配。原因很简单企业内部的文档、工单、邮件、会议纪要里既有大量非结构化的语义信息又有明确的组织关系、流程关系、因果关系单靠一种存储和检索范式覆盖不了。1.2 整体数据流与组件选型整个系统的数据流可以拆成四条链路写入链路原始文档经过解析、分块、实体抽取、关系抽取后分别写入向量库和图库。向量库存文本块的embedding和元数据图库存实体节点、关系边以及指向向量库中对应文本块的引用ID。查询理解链路用户问题进入大模型做意图分类和查询改写输出两类指令——向量检索指令查询文本、topK、过滤条件和图查询指令起始节点类型、关系路径、跳数限制。混合检索链路向量库返回语义相关的文本块和实体候选图库从这些实体出发做邻域扩展返回关联实体、关系路径和属性。两路结果在应用层做融合排序。答案生成链路融合后的上下文文本块三元组路径描述拼装成prompt交给大模型生成最终回答同时附上引用来源。组件选型上向量库我试过几种主流方案最终倾向选择支持元数据过滤和混合检索稠密稀疏的引擎因为纯稠密向量在专有名词、编号、代码等场景下召回不稳定加上BM25之类的稀疏检索能明显提升鲁棒性。图库方面如果团队已经有Neo4j的运维经验继续用Neo4j是最省事的如果追求分布式写入和水平扩展可以看看JanusGraph或NebulaGraph。大模型这块查询理解和答案生成可以用同一个模型但如果成本敏感查询理解用7B级别的小模型微调答案生成用更大的模型这样整体推理成本能降不少。注意向量库和图库之间的数据一致性是个容易被忽视的问题。文档更新时如果只更新了向量库而忘了同步图库的实体关系就会出现“检索得到文本但图查询找不到对应节点”的尴尬情况。我的做法是在应用层维护一个统一的文档ID映射表任何写入操作都通过这个映射表协调两个库的更新并且定期跑一致性校验任务。1.3 适用场景与不适用场景这套架构最适合的场景有几类企业知识库问答尤其是涉及组织架构、产品关系、流程依赖的、金融风控中的关联方识别、医疗领域的症状-药物-疾病关联推理、法律领域的法条-案例-判决关联检索。共同特征是数据既有丰富的文本语义又有明确的结构化关系且用户问题往往需要跨文档、多跳推理。不适合的场景也很明确如果数据完全是结构化表格直接用SQL图查询就够了没必要上向量库如果数据完全是自由文本且几乎没有实体关系那纯向量检索大模型就够了图库反而是过度设计。我见过一些团队为了“技术先进性”硬上图谱结果实体抽取准确率不到70%图里全是噪声反而拖累了整体效果。2. 核心细节解析与实操要点2.1 实体抽取与关系抽取的工程化处理实体抽取是整个系统的地基。我的经验是不要指望一个通用NER模型能搞定所有领域实体。通用模型在人物、地点、机构上表现还行但到了“产品型号”“合同条款编号”“工艺参数”这些领域实体上召回率会断崖式下跌。实操上我采用“通用模型规则小样本微调”的三层策略。第一层用通用NER模型做粗筛召回高置信度的通用实体第二层用正则和词典匹配领域专有实体比如用正则匹配“XX-1234”这种编号格式用词典匹配已知的产品名、项目名第三层针对前两层漏掉的难例标注几百条数据微调一个小模型专门补召回。关系抽取更麻烦。我试过纯LLM抽取效果不稳定同一段文本跑两次可能抽出不同的关系。后来改成“LLM生成候选规则校验”的方式先用LLM从文本中抽取候选三元组然后用预定义的关系schema做校验过滤掉不在schema中的关系类型再对实体做归一化比如“A公司”“A有限公司”“A集团”统一到一个实体ID。# 关系抽取后的归一化示例伪代码 def normalize_triple(triple, entity_alias_map, relation_schema): head entity_alias_map.get(triple.head, triple.head) tail entity_alias_map.get(triple.tail, triple.tail) if triple.relation not in relation_schema: return None return (head, triple.relation, tail)实操心得实体归一化一定要在写入图库之前做否则图里会出现大量“同义不同名”的节点导致图查询时漏掉关联。我一般会维护一个别名表新实体入库时先查别名表命中就复用已有节点ID没命中才创建新节点。2.2 向量库的索引设计与检索策略向量库的索引设计直接影响检索速度和召回质量。以我用的引擎为例核心参数是M每个节点的最大连接数和efConstruction构建时的候选队列大小。M越大索引越稠密召回越高但内存占用越大efConstruction越大构建越慢但索引质量越好。我的经验值是数据量在百万级以下时M16、efConstruction200是个不错的起点数据量上千万后考虑用量化索引如PQ来压缩内存但会损失一些精度。检索策略上我强烈建议开启混合检索。纯稠密向量在以下场景会翻车用户查询包含精确的编号、代码、人名或者查询词与文档用词差异很大但语义相同。混合检索把稠密向量得分和稀疏检索BM25/SPLADE得分加权融合权重可以通过A/B测试调。我的默认配置是稠密权重0.7、稀疏权重0.3但在代码检索场景下会反过来。分块策略也值得细说。固定长度分块比如512 token简单但容易切断语义按段落分块保留了语义完整性但块大小不均我最终采用的是“语义分块重叠窗口”先用句子边界检测把文档切成句子再用滑动窗口把相邻句子合并成块块之间保留20%的重叠。这样既保证了块内语义连贯又避免了边界信息丢失。2.3 图schema设计与多跳查询优化图schema的设计要平衡表达力和查询效率。我见过两种极端一种是过度设计把什么属性都建成节点结果图里节点数量爆炸查询慢得没法用另一种是过度简化所有关系都塞成一种边类型导致查询时无法区分关系语义。我的做法是核心实体建成节点核心关系建成边边的属性存关系强度、时间戳、来源文档ID。非核心的属性直接存在节点属性里不单独建节点。比如“供应商”是节点“供应”是边边的属性包括供应金额、供应开始时间、供应品类而供应商的“注册资本”就直接存在供应商节点的属性里。多跳查询的性能是图库应用的关键瓶颈。三跳以上的查询如果不加限制很容易在图里“爆炸”。我的优化手段有几个一是限制跳数默认最多三跳超过三跳的查询走预计算路径二是限制每跳的扇出比如每跳最多取50个邻居三是用图算法预计算一些常用路径比如用PageRank找出重要节点用社区发现算法预计算社区结构查询时直接命中预计算结果。// 三跳查询示例找出与某公司相关的供应商及其共同股东 MATCH (c:Company {name: 某公司})-[:SUPPLIES_FROM]-(s:Supplier) MATCH (s)-[:HAS_SHAREHOLDER]-(sh:Shareholder) MATCH (sh)-[:HAS_SHAREHOLDER]-(other:Supplier) WHERE other s RETURN s.name, sh.name, collect(other.name) AS co_suppliers LIMIT 50注意图查询一定要加LIMIT否则在稠密图上很容易返回海量结果拖垮应用层。另外对于频繁执行的查询模式可以在图库中建立物化视图或预计算索引把查询时间从秒级降到毫秒级。3. 实操过程与核心环节实现3.1 环境搭建与数据准备环境搭建这块我建议用容器化方式部署方便版本管理和迁移。向量库和图库各起一个容器应用层用Python或Java写大模型推理可以用本地部署的推理服务也可以调用云端API根据数据敏感度决定。数据准备是最耗时的环节。我的一般流程是先做数据清洗去重、去噪、格式统一再做分块和元数据标注然后跑实体关系抽取最后分别写入两个库。这里有个细节写入向量库的文本块要带上实体ID列表作为元数据这样向量检索返回文本块时应用层能直接拿到关联的实体ID去图库做邻域扩展省去了一次额外的实体链接步骤。# 写入向量库时携带实体元数据 metadata { doc_id: doc_001, chunk_id: chunk_003, entities: [entity_101, entity_205, entity_310], source: 内部知识库, timestamp: 2024-06-01 } vector_store.upsert(embeddingemb, metadatametadata)3.2 查询理解与路由实现查询理解模块的核心任务是把用户问题分类到不同的检索路径。我把它分成三类纯语义查询只需要向量检索比如“最近关于供应链风险的讨论有哪些”。纯关系查询只需要图查询比如“A公司的母公司是谁”。混合查询两者都需要比如“A公司的供应商中哪些最近有负面新闻”。分类用一个小模型做意图识别就够了准确率能到90%以上。关键是分类后的查询改写对于混合查询大模型需要同时生成向量检索的查询文本和图查询的起始节点及路径模式。这里我踩过一个坑大模型生成的图查询语句经常有语法错误或引用了不存在的节点类型。后来我加了一层校验用图schema做白名单过滤只允许schema中定义过的节点类型和关系类型出现在查询中。# 查询路由与校验示例 def route_query(user_query): intent intent_classifier(user_query) if intent semantic: return {vector_query: rewrite_for_vector(user_query)} elif intent relational: graph_query llm_generate_cypher(user_query) if validate_cypher(graph_query, schema): return {graph_query: graph_query} else: return {vector_query: rewrite_for_vector(user_query)} # 降级 else: return { vector_query: rewrite_for_vector(user_query), graph_query: validate_cypher(llm_generate_cypher(user_query), schema) }3.3 混合检索结果融合与排序两路检索返回的结果需要融合排序。我的做法是向量检索结果按相似度得分排序图检索结果按路径长度和关系强度排序然后做加权融合。权重可以通过学习得到也可以用简单的规则——比如向量得分归一化后乘以0.6图得分归一化后乘以0.4具体权重根据业务场景调。融合后的上下文拼装也有讲究。我一般按“先图后文”的顺序组织先放图查询返回的三元组和路径描述再放向量检索返回的文本块。这样大模型在生成答案时先看到结构化的关系事实再看到支撑这些事实的原文片段生成的答案既有逻辑性又有依据。实操心得融合排序时如果两路结果都命中了同一个实体或同一篇文档应该给这个结果加分。我实现了一个简单的“交叉验证加分”机制如果某个实体同时出现在向量检索的元数据和图检索的节点中它的排序权重乘以1.5。这个技巧在实测中能把答案准确率提升10%左右。3.4 答案生成与引用溯源答案生成环节prompt的设计很关键。我的模板大致是这样的你是一个知识助手。请根据以下检索结果回答用户问题。 检索结果包括两部分 1. 关系事实来自图数据库 {graph_context} 2. 相关文档片段来自向量数据库 {vector_context} 用户问题{user_query} 要求 - 答案必须基于检索结果不要编造。 - 如果检索结果不足以回答请明确说明。 - 在答案末尾列出引用的文档ID和关系路径。引用溯源是这套系统相比纯向量检索的一大优势。因为图查询返回的路径本身就带有来源文档ID向量检索返回的文本块也有doc_id所以最终答案可以精确到“这句话来自哪篇文档的哪个段落以及哪条关系路径”。这在企业知识库场景下非常重要用户需要知道答案的依据是什么。4. 常见问题与排查技巧实录4.1 检索召回不准的排查思路召回不准是最常见的问题表现是“答案明明在库里但就是检索不到”。我的排查顺序是检查分块是否合理把用户问题对应的原文找出来看它被分到了哪个块块的大小和边界是否合理。如果答案被切成了两半分别落在两个块里那召回就会出问题。检查embedding模型是否匹配如果文档用的是中文embedding模型查询却用了英文模型或者模型版本不一致召回会大幅下降。我一般会在写入和查询时用同一个模型并且记录模型版本。检查元数据过滤条件有时候是过滤条件太严把正确结果过滤掉了。可以临时去掉过滤条件看召回是否恢复。检查图查询的起始节点如果向量检索返回的实体ID在图库中不存在比如实体归一化时ID变了图查询就会返回空。这时候要检查实体ID映射表是否同步。4.2 图查询性能瓶颈的优化图查询慢通常有三个原因跳数太多、扇出太大、图太大。对应的优化手段问题表现可能原因优化手段三跳查询超过5秒扇出太大限制每跳邻居数加LIMIT特定节点查询慢超级节点对超级节点做拆分或预计算全图遍历慢图太大用社区发现预计算分区查询时先定位分区并发查询慢连接池不足增大连接池加缓存超级节点是图库应用的一个经典难题。比如“某公司”这个节点可能连接了上万个供应商每次查询都要遍历这么多边性能必然差。我的做法是对超级节点做“边采样”或“边聚合”查询时只取权重最高的前N条边或者预先按关系类型聚合查询时直接读聚合结果。4.3 大模型生成答案不稳定的应对大模型生成答案不稳定表现为同一问题两次回答不一致或者答案中混入了检索结果之外的信息。我的应对策略降低temperature答案生成时temperature设为0.1以下减少随机性。加约束prompt明确要求“只基于检索结果回答”并在prompt中给出反例。后校验生成答案后用一个小模型或规则做校验检查答案中的实体是否都在检索结果中出现过如果出现未检索到的实体标记为“可能幻觉”并重新生成。缓存对于高频问题缓存答案避免重复生成导致的不一致。踩过的坑有一次线上出现答案中混入了“训练数据中的知识”用户问的是内部文档里的流程模型却答了一个通用流程。后来在prompt里加了“如果检索结果中没有明确说明请回答‘根据现有资料无法确定’”这个问题才解决。4.4 数据一致性与更新策略向量库和图库的数据一致性是运维中的一大痛点。我的做法是统一写入入口所有数据更新都通过一个统一的写入服务这个服务负责同时更新两个库并记录更新日志。最终一致性不追求强一致性允许两个库之间有秒级的延迟但通过定期校验任务来发现和修复不一致。版本管理每次更新给文档打上版本号查询时默认查最新版本也支持查历史版本。回滚机制如果更新后发现效果变差可以按版本号回滚。校验任务的实现思路是定期从向量库中抽样一批文本块提取其中的实体ID去图库中检查这些实体是否存在反过来从图库中抽样一批节点检查其关联的文本块ID是否在向量库中存在。发现不一致时以图库为准还是以向量库为准取决于业务场景——如果图库是人工审核过的就以图库为准如果图库是自动抽取的就以向量库为准。4.5 成本控制与资源规划这套系统的成本主要来自三块向量库的内存、图库的存储和计算、大模型的推理。向量库的内存占用与数据量和索引参数正相关百万级文本块大约需要几十GB内存图库的存储相对小但多跳查询的CPU消耗不低大模型推理是大头尤其是答案生成环节。我的成本控制经验向量库用量化索引压缩内存但要注意量化后的召回损失可以通过增加topK来补偿。图库对不常查询的边做冷热分离热数据放内存冷数据放磁盘。大模型查询理解用小模型答案生成用大模型高频问题缓存答案批量查询合并请求。整体监控各环节的延迟和成本找出瓶颈环节重点优化。实测下来一个中等规模的知识库十万级文档、百万级文本块、千万级边用这套架构单次查询的端到端延迟可以控制在2秒以内其中向量检索200毫秒、图查询500毫秒、大模型生成1秒左右。成本方面如果答案生成用云端API单次查询成本大约几分钱如果本地部署主要是GPU折旧和电费。这个项目后续还可以往几个方向扩展一是加入时序维度支持“某时间段内的关系变化”查询二是加入多模态检索支持图片、表格的语义检索和图关联三是做主动学习把用户反馈自动转化为训练数据持续优化实体抽取和查询理解模型。我在实际使用中发现用户反馈是提升系统效果最宝贵的资源一定要在设计之初就埋好反馈收集的入口。

关于本文作者

来自尧图内容编辑团队

尧图内容编辑团队 内容团队

尧图内容编辑团队

本文由尧图网络内容编辑团队执笔。团队由资深项目经理、前端工程师与设计师组成,所有内容均来自亲手交付的真实项目,先讲清问题、再给出可落地的解法。尧图深耕北京网站建设十年,服务过京华建材集团、智造科技等各行业客户,把一线经验沉淀为可复用的行业观察。

  • 十年建站经验,覆盖建材、制造、服务、文创等
  • 项目经理把关选题与事实准确性
  • 工程师与设计师联合撰写专业细节
  • 统一编辑规范,保证文风与排版一致
  • 每月复盘转化数据,迭代选题方向

延伸阅读

相关资讯与近期热门内容

深度阅读推荐

建站决策前值得细读的三篇

网站改版的5个关键决策
2024-08-12

网站改版的5个关键决策

什么时候该改版、改到什么程度、如何避免流量掉光,京华建材集团改版复盘给出答案。

获取专属建站方案

看完文章,把您的行业与预算告诉我们,免费获取一份量身定制的官网建设方案与报价。

立即免费咨询