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

资讯详情

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

高级RAG实战:GraphRAG、Agentic RAG与Ollama落地

高级RAG实战:GraphRAG、Agentic RAG与Ollama落地

如果说过去两年大模型应用还有什么绕不开的关键词,那一定是RAG(Retrieval-Augmented Generation,检索增强生成)。从最简单的“把文档切碎丢进向量库”到企业级知识库,RAG已经成了大模型落地最常用的姿势之一。但这章我们不讲入门,我打算直接聊高级RAG技术,也就是当你发现普通RAG项目“回答含糊、知识割裂、hit rate上不去”之后,真正值得折腾的那批方案:本体RAG、GraphRAG、Agentic RAG,以及用Ollama在本地搭一套零基础也能复现的简易RAG知识库。

如果你已经做过一段时间的RAG应用,大概率体会过这样的尴尬:文档明明检索到了,答案却还是错的;常识问题很稳,一旦涉及多跳、对比、总结就崩。这种情况不是模型不够聪明,而是检索管线本身没有跟上问题复杂度。高级RAG技术本质上就是在索引、检索和生成三个环节里各加各的“外挂”,让系统从“查到什么算什么”变成“按需查、查得准、查完会组织”。这篇文章会给你一套从原理到落地的完整参考,适合正在做RAG项目、想突破瓶颈的开发者和产品同学。

1. 先从瓶颈说起:基础RAG到底输在哪里

1.1 不是检索不准,是“碎片化”导致的语义断裂

大多数入门级RAG知识库的流程都很类似:把文档切成文本块,用embedding模型向量化,用户提问后做相似度检索,把Top K片段拼进Prompt让大模型回答。问题恰恰出在“切块”这一步。传统切块方法重格式轻语义,经常把一个完整知识点拦腰截断,于是同一主题的信息散落在多个chunk里。用户问一个需要综合多处信息的问题时,语义检索只返回相似度最高的几个片段,结果往往是每个片段都对,但合起来答不到点子上。

这就像你让一个助手去图书馆查“这家公司为什么能快速增长”,他只给你抄了五段提到“增长”的段落,每段都沾边,但没有一个段落真正回答了因果链。这就是我常说的“检索到了,但知识没接上”。更深层的问题是知识割裂:向量空间里相似片段可能距离很近,但它们在文档逻辑上毫无关联,LLM拿到这样的上下文,只能靠脑补。

我见过不少团队在遇到这类问题后立刻换更大的模型,或者把Prompt写得更长,效果都有限。根本原因在于基础RAG默认“单轮检索就能拿到答案所在的片段”,这个假设对复杂知识场景太理想化。高级RAG技术的第一个价值,就是打破这个假设:要么在检索前先理解问题,要么在索引阶段就把知识之间的结构关系存下来。

1.2 高级RAG到底“高”在哪里

先给一个整体框架,免得你在各种名词里迷路。高级RAG技术通常围绕五个方向展开:

  • 索引增强:不满足于简单切块,而是做文档结构感知、父子分块、知识图谱抽取、多模态内容向量化等。
  • 查询增强:对用户原始问题做改写、分解、扩展,让检索目标更清晰。
  • 检索增强:混合检索、重排序、多路召回,用不同召回策略弥补单一向量检索的盲区。
  • 生成增强:在Prompt组织、引用溯源、答案校验上做文章。
  • 流程增强:也就是Agentic RAG,让LLM自主决定检索计划、调用工具、检查结果,必要时重新检索。

GraphRAG和本体RAG属于索引增强中的结构化路线,它们想解决的是“知识之间关系丢失”的问题。Agentic RAG属于流程增强,更像把RAG从“一次性函数”改造成“会决策的智能体”。而Ollama本地RAG则是典型的轻量落地路线,用最小成本把整条链路跑通。这几条路线并不互斥,实际项目中经常混用。

我个人的建议是:不要一上来就上图谱和智能体,先量化评估现有管线,明确瓶颈在召回、排序还是生成,再选择对应的高级技术。盲目堆复杂度只会让系统变得更难排查。

2. 让机器读懂概念关系:本体RAG与GraphRAG破局“知识割裂”

2.1 本体Ontology到底能做什么

很多读者对“本体RAG”这个名字感到陌生,它不像向量数据库那么流行,但在解决知识割裂问题上它是真有效。本体(Ontology)在信息科学里指的是对某个领域内的概念、实体、属性以及它们之间关系的显式规范描述。放到RAG语境下,本体RAG就是在知识库之外再维护一层“概念地图”,比如“Transformer是一种神经网络架构”,“BERT基于Transformer”,“文本分类依赖BERT”。

有了这层关系,系统在回答问题“为什么BERT适合做文本分类?”时,不再只是从文本块里找“BERT”和“分类”的相似段落,而是可以沿着本体关系从BERT走到Transformer、注意力机制、分类头,把一整条逻辑链组织出来。这就是对抗知识割裂的核心思路:在chunk之外另建一张关系网,作为检索的路标。

你可能会担心维护本体太费人力。确实,手工构建代价不小,所以实践中有两条路:一是利用LLM从文档中自动抽取实体和关系,生成轻量本体;二是在已有Wiki、词典、结构化数据库的基础上对齐。最近很多RAG和LLM Wiki结合的趋势,本质就是让Wiki的条目结构充当半自动本体。即使是自动抽取出来的噪声关系,只要在检索时做约束和过滤,也比完全没有关系可用要好得多。

这里顺便回答一个我常被问到的问题:“RAG知识库能存储图片吗?”可以,但图片通常不走同一条纯文本链路。常规做法是把图片的OCR文本、标题、周围上下文一起向量化,或者用多模态模型直接生成图像描述向量。本体层也可以描述“图片在文档中解释了哪个概念”,让检索端更准确地找到图。不过大多数项目并不需要一开始就做多模态,先解决文本关系,收益更高。

2.2 GraphRAG的实现思路与落地路径

GraphRAG可以看作本体RAG的一种工程实现:先用LLM抽取文档中的实体和关系,构建知识图谱,再通过图算法把信息聚合成社区摘要,最后结合向量检索和图的局部游走找到答案。它的名字来自微软那篇GraphRAG论文,但现在已经发展成一类技术路线。

我在实际项目里推荐的落地路径是四层:

  1. 文档结构化拆分:保留标题、段落关系,先让抽取阶段有干净的输入。
  2. 实体与关系抽取:用LLM对每个chunk抽取三元组(头实体、关系、尾实体),整合时做实体对齐,把相同实体合并。
  3. 存入图库或图结构内存:简单项目可以直接用NetworkX,重一点的项目用Neo4j;关系少时甚至可以直接存JSON。
  4. 检索阶段组合:用户问题先识别实体,查图得到相关实体和关系路径;同时做向量检索补充细节,最后把两路结果融合给LLM。

为什么说它能破局?因为纯向量检索是“相似性匹配”,不是“逻辑推导”。比如“A公司收购了B公司,B公司推出了C产品,C产品最新的版本是什么”这种多跳问题,向量检索很难一次命中。但在图里,从A走到B再找到C是一条明确的路径。高级RAG的价值就在这种场景体现得非常明显。

工具选型方面,如果你想快速验证思路,不必一上来就上Neo4j。可以用LightRAG或nano-graphrag这类以LLM为中心的开源实现,它们能自动完成抽取和存储,几百行代码就能跑通。我的体会是:先小范围试,确认图谱召回带来的提升,再决定要不要投资重型图数据库。

2.3 一个小型本体RAG设计示例

用一个我做过的小项目举例,场景是企业内部技术博客知识库。我没有构建庞大本体,只定了四类实体:技术概念、框架工具、项目、作者;四类关系:实现、依赖、对比、维护。文档切块后,我抽取出类似这样的三元组:

  • “LangChain” —实现—> “RAG流程”
  • “LangChain4j” —依赖—> “LangChain”
  • “GraphRAG” —对比—> “向量检索RAG”

用户提问“LangChain4j的Easy RAG怎么用”时,检索流程变成:先识别问题实体“LangChain4j”和“Easy RAG”,进入图谱查到它属于Java生态,依赖LangChain思想;再以这些实体为线索,定位到相关博客段落;最后把图谱关系文本和向量片段一起给LLM。整体效果是,答案不再是孤立的步骤说明,而会带出这个工具在整个生态里的位置。

这个设计的经验是:本体不是越全越好。一开始就定义几十种实体类型、上百种关系,会让抽取阶段难以收敛,还容易产生大量错误关系。宁可先定义五类核心关系,把准确率做高,再逐步扩展。你看,高级RAG里真正难的不是图算法,而是“如何选择值得建模的关系”。

3. Agentic RAG:让大模型自己决定怎么查

3.1 从“一次检索”到“多轮决策”

Agentic RAG最近是热词,也是RAG智能体的核心写法。基础RAG是一次函数调用:进去问题,出来答案。Agentic RAG则把一个查询拆成可迭代的决策循环。Agent先理解用户的问题复杂度,决定是否需要检索、检索哪类工具、要不要先查一次再细化,甚至答案生成后还自我校验一遍。

最经典的例子是“这几篇论文里,哪篇提出的方法在推理任务上效果最好”这类比较型问题。基础RAG会检索“论文”“推理”“最好”相关片段,结果往往是把几篇论文的关键词混在一起。Agentic RAG则会规划:先检索候选论文列表,再针对每篇论文分别检索“方法”和“效果指标”,最后汇总比较。这个过程中LLM不是单纯回答,而是在做信息获取的“项目经理”。

回头看你为什么需要它,根本原因是用户问题的意图和复杂度不可预知。你不可能针对每种提问模式手写一套检索逻辑,但Agent可以用思维链自己判断。这也是为什么很多RAG瓶颈出现在问题环节,而不是检索环节。把“查什么”交给一个能推理的LLM,往往比堆更多向量库更有效。

3.2 用LangChain4j Easy RAG快速实现Agentic工作流

LangChain4j是Java生态里比较友好的LangChain移植版本,它的Easy RAG模块封装了文档解析、切分、向量化和检索的基本路径,同时保留了工具调用能力。相比Python生态,Java项目接入时少踩很多环境坑。如果你是Python玩家,也可以照着同样思路用LangChain或自建函数实现。

下面这个伪代码展示Agentic RAG的核心思想,不依赖具体框架:

public class RagAgent { private final ChatLanguageModel chatModel; private final Retriever retriever; private final ToolRouter router; public Answer answer(String userQuery) { // 1. 判断查询是否需要检索,还是可以直接回答 Plan plan = planner.plan(userQuery); // 2. 根据计划决定检索工具:向量库、图查询、Web搜索、文档问答 List<Tool> tools = router.selectTools(plan); // 3. 执行检索并收集结果 List<Content> contents = tools.execute(userQuery); // 4. 让LLM基于结果生成答案,并判断是否足够 Answer draft = chatModel.answer(userQuery, contents); if (draft.isConfident()) { return draft; } // 5. 不自信则重新分析缺失信息,生成补充查询后再次检索 String refinedQuery = draft.suggestRefinedQuery(); return answer(refinedQuery); } }

这段代码看着简单,但已经把Agentic RAG最重要的两个机制体现出来了:路由和自检。路由让Agent选择最合适的检索工具,自检让Agent发现“第一次检索的信息不够”。实际项目中还有更细的设计:Query Rewriting把模糊提问“LangChain4j怎么用”改写成“LangChain4j Easy RAG 的依赖配置与示例”;HyDE先让LLM生成一个假设答案,再用假设答案去检索,提高召回率。

从工作流角度,我建议Agentic RAG的每个工具都要返回来源信息。这样最后生成答案时能附带引用,同时Agent在做自检时也能知道信息来自哪里。没有来源的工具调用,在调试时是个无底洞,你会分不清答案是检索得来的还是模型幻觉出来的。

3.3 Agent的路线选择与成功率优化

说点Agentic RAG的坑。第一是死循环,Agent反复生成补查询,查了一次又一次,始终觉得信息不够。必须设定最大迭代次数,比如默认三到五次,达到上限就让Agent基于已有信息作答,不要无限转圈。

第二是上下文膨胀。每一轮检索结果都拼在历史里,Prompt越来越长,模型注意力被稀释。我的做法是只保留“上一轮结论”和“新增检索片段”,把早期的原始片段压缩成摘要再放入上下文。

第三是工具调用幻觉。模型可能想象出一个不存在的工具名,或者给检索器传入不合理参数。在LangChain4j里可以通过限制工具列表、强制JSON格式输出、增加参数校验来缓解。别指望Agent总是聪明,你要用工程手段保证它“蠢”得可控。

这里想分享一个很实用的判断标准:如果你发现用户的提问中超过30%都需要多跳推理,或者问题类型非常多样,那值得上Agentic RAG。如果绝大多数是“某某功能怎么配”这类单跳问题,普通RAG加一个查询改写器就够用了。高级技术是用来解决真实痛点的,不是用来炫的。

4. 零基础也能上手的本地RAG知识库:Ollama实战

4.1 环境准备与工具选型

高级RAG讨论得再多,最终都要落到能跑起来的系统上。很多读者私信问有没有零基础可复制的本地RAG教程,我推荐一条轻量路线:Ollama跑大模型,本地向量库用Chroma或LanceDB,文本拆解先用递归切分,后面再按需升级。整条链路完全离线,不依赖外部接口,适合学习和小规模场景。

先安装Ollama,这是目前体验最顺的本地模型运行工具。装好后在终端执行:

ollama pull qwen2.5:7b ollama pull nomic-embed-text

第一句拉取生成模型,第二句拉取embedding模型。如果你机器只有16G内存,建议用4b或3b级别的模型;32G以上再考虑7b。embedding模型维度会影响后续向量库字段,注意保持一致。Chroma这类向量库能存metadata,但不要期待它替你解决全部语义问题。

硬性要求很低,CPU也能跑,只是慢。我推荐至少8G内存,能在纯CPU机器上处理几百个文档。想快一些,有NVIDIA显卡最好;没有显卡就控制文档总量。

4.2 标准流程:加载、拆解、向量化、检索、回答

搭建零基础RAG知识库,标准流程五步:

  1. 加载文档,支持PDF、Markdown、TXT。
  2. 文本拆解,先按段落分割,再按固定长度切片。
  3. 生成向量并存储。
  4. 用户提问时把问题转成向量,检索相似片段。
  5. 将片段拼入Prompt,交给Ollama模型生成答案。

下面是一段可直接运行的Python示例,依赖chromadb和ollama客户端。为了让零基础读者看懂,我没有用复杂框架,只用标准接口:

import os import chromadb from ollama import Client client = Client(host="http://localhost:11434") chroma = chromadb.PersistentClient(path="./rag_demo") collection = chroma.get_or_create_collection(name="docs") def embed_text(text: str) -> list: return client.embeddings(model="nomic-embed-text", prompt=text)["embedding"] def ingest(doc_id: str, chunks: list[str]): vectors = [embed_text(c) for c in chunks] collection.add( ids=[f"{doc_id}_{i}" for i in range(len(chunks))], documents=chunks, embeddings=vectors, metadatas=[{"doc_id": doc_id} for _ in chunks] ) def retrieve(query: str, top_k: int = 5): q_vec = embed_text(query) return collection.query(query_embeddings=[q_vec], n_results=top_k) def generate_answer(query: str, top_k: int = 5): hits = retrieve(query, top_k)["documents"][0] context = "\n---\n".join(hits) prompt = f"基于以下资料回答问题,如果资料不足就明确说明。\n资料:\n{context}\n问题:{query}\n" resp = client.chat(model="qwen2.5:7b", messages=[{"role": "user", "content": prompt}]) return resp["message"]["content"]

注意,上面对话messages可以再加一条system prompt,让模型聚焦知识库内容,减少瞎编。文本拆解我强烈建议先做一次“结构感知切分”:Markdown按标题切,PDF按段落切。用unstructured或docling这类工具可以保留标题层级,比无脑按字符串切半个字符强得多。这也是“有没有本地的RAG文本拆解工具”的答案:本地可用unstructured、marker、docling,它们都是可独立运行的开源工具。

4.3 零基础最容易踩的坑

我帮人排查过不少本地RAG项目,问题高度集中。第一个是embedding模型不一致,索引时用了一个embedding模型,查询时换了另一个,导致检索结果完全不可用。向量本身没有语义,维度对上了也不代表空间一致。解决方案很简单,全局固定一个embedding模型。

第二个是文本拆解粗细不当。切得太碎,单块语义不完整;切得太长,检索出的大块文本塞进Prompt容易超长,而且注意力被稀释。我的经验是中文文档先按标题分块,再用200到400个字符作为窗口大小,重叠30到50个字符,能把绝大多数内容处理得比较干净。

第三个是问答时直接把检索结果按原序拼进Prompt,没有重排。向量检索返回的顺序不一定符合阅读逻辑,LLM拿到一段跳跃的上下文会困惑。可以先对检索结果做一次简单重排,比如用关键词覆盖率或Rerank模型,把真正相关的内容放前面。

最后提醒一点:本地RAG在大模型选择上不要贪大。7b模型在知识问答上已经够用,但推理能力有限。如果你发现答案总是漏点,先调整检索质量,再考虑升级模型。跑通了,后续再加GraphRAG或者Agent逻辑,才是更稳的路径。

5. 检索质量怎么量化:Hit Rate评测与工程化避坑

5.1 什么是Hit Rate,以及为什么你的RAG总是答非所问

聊RAG工程就绕不开Hit Rate,它衡量的是:对于一个评测问题,正确答案是否出现在系统召回的Top K结果里。如果100个测试问题里有70个的正确答案被召回,Hit Rate@5就是70%。它是RAG检索阶段的北极星指标。生成模型再强,如果Hit Rate低,它就只能靠幻觉续命。

很多RAG项目“答非所问”不是模型问题,而是Hit Rate低。你问“如何配置并发参数”,正确答案在文档第100页,但Top K返回的是第3页的概览,模型自然答不准。所以做高级RAG的第一步,先构建一个小评测集,里面至少包含三类问题:单点事实、多跳逻辑、对比分析。然后统计当前系统在这三类上的Hit Rate差异。

一个好的评测集不光是问题和标准答案,还要标注“答案所依赖的文档来源”。这样当Hit Rate不达标时,你能立刻知道是召回环节把正确来源丢掉了,还是排序把正确来源放到了后面。我见过团队反复调Prompt,最后发现是embedding模型本身对领域术语区分度不够,换一个微调过的embedding模型,Hit Rate立刻涨了十几个点。这就是量化带来的价值。

5.2 提升Hit Rate的实战手段

提升Hit Rate不是靠单一魔法,而是一组检索策略的组合。我按性价比从高到低排一下:

  • 查询改写:把模糊提问变成能命中的关键词组合,比如“怎么让搜索更快”改写成“缓存策略 性能优化 搜索延迟”,成本最低,收益明显。
  • 混合检索:把向量相似度和BM25关键词匹配结果合并,再统一去重重排。代码、专有名词、ID类查询用BM25更强,语义匹配用向量更强。
  • 小文档块检索,大文档块生成:检索时用细粒度chunk,找到具体位置;生成时把该chunk所属的完整章节或更大上下文放进去。这个方法叫Small-to-Big,能同时兼顾精度和上下文完整度。
  • 重排序:第一轮用宽召回(Top 50),再用交叉编码器或Rerank模型精排,取Top 5。成本增加不多,效果立竿见影。
  • 元数据过滤:在向量库里存章节、作者、日期、标签,查询时先按元数据缩小范围,再向量检索,能显著减少噪声。

还有一个容易被忽略的细节:Chunk之间要保留来源引用。生成答案时LLM需要知道这段话来自哪份文档,否则引用溯源无法做。即使不做展示,调试时也能快速定位错误检索片段。

5.3 典型问题排查速查表

实际项目中,我总结出一张问题排查表,遇到RAG表现异常可以按图索骥:

现象可能原因解决办法
答案明显与资料矛盾Hit Rate低,相关片段未召回检查召回Top K是否包含正确来源;尝试混合检索
回答车轱辘话,没有细节检索到的是概述片段改用Small-to-Big,检索细粒度片段,生成用完整章节
相似问题结果反复横跳embedding模型不稳定或查询改写不一致固定模型,确保每次查询同参数
经常漏掉一个重要实体实体不在文本块边界内增加实体级索引或依赖图谱检索
中文专有名词检索不准切词问题或向量模型未适配领域引入关键词扩展,或换领域微调embedding模型
多跳问题总答错单轮检索无法覆盖完整路径将问题拆解为多个子查询,或上Agentic RAG
答案太长、重点被淹没上下文塞了太多无关片段收紧Top K,增加重排,限制Prompt内资料长度

定位问题时我建议每次只改一个变量。比如先固定Prompt,只改检索策略;再固定检索策略,只改chunk大小。很多人混淆变量,最后根本不知道是哪一步救了效果。

5.4 工程化避坑与我的个人体会

做高级RAG越久,越发现“高级”不等于“复杂”。我自己的体会是,先把Hit Rate评估跑起来,哪怕只有五十条测试题,也比闷头加模块好。因为评估能告诉你改进方向,而这些方向往往出人意料。比如有个金融知识库项目,卡了很久的瓶颈其实是PDF表格解析乱码,不是检索策略问题。你堆一堆图谱和Agent,不如先换个好的文本拆解工具。

最后再分享一个小技巧:在Agentic RAG和GraphRAG这类复杂系统里,给每个环节加上“可观测性”,把检索到的片段ID、重排分数、Agent每一步的思考过程都记录一遍。排查问题时再也不用两眼一抹黑。高级RAG技术本义是让系统更聪明,不是你生产事故的源头。记住这一点,你就能在正确的地方画重点,而不是把系统越做越重。

返回列表