尧图建网站 尧图建网站 YAOTU WEB BUILD 免费咨询
ARTICLE DETAIL

资讯详情

深耕网站建设与建站编程的一线实战洞察。

LLM+本体论+知识图谱:构建Graph RAG问答系统实战

LLM+本体论+知识图谱:构建Graph RAG问答系统实战 LLM、Ontologies、Knowledge Graphs 这三个词放在一起容易被理解成三种各自独立的技术。但在知识密集型应用里它们恰好组成一条完整的增强链路本体论负责定义语义边界知识图谱负责存储结构化事实LLM 负责处理非结构化输入并生成最终回答。这个组合在英文里常被叫作 Triple Threat意思是三个方面都能独立发挥作用组合在一起能解决单靠 LLM 很难解决的准确性问题。本文会把这套组合拆成一个可以复现的工程流程先用一个最小图书本体定义图谱的 Schema再用 LLM 从图书简介中抽取实体和关系把结果写入 Neo4j最后通过 Graph RAG 的方式回答自然语言问题。适合刚接触 RAG、知识图谱或者正在做企业知识库问答的开发者。读完这篇内容你能得到一个可运行的问答闭环也能知道不同环节出错时应该从哪里排查。1. 先理解“Triple Threat”LLM、本体论和知识图谱为什么必须组合1.1 三个技术概念分别解决什么问题LLM 最擅长的是自然语言理解和生成。它能读懂一段文字抽取关键信息也能根据上下文生成流畅回答。但 LLM 的知识来自训练数据而训练数据存在截止时间同时模型对事实记忆并不精确这就导致它会在不确定的时候“编造”看似合理的内容。知识图谱是以节点和边表示实体与关系的数据结构。比如“刘慈欣”是一个 Author 节点“《三体》”是一个 Book 节点两者之间有一条 AUTHORED_BY 的关系。知识图谱把事实显式存储下来查询结果就是确定的事实不依赖模型记忆。本体论在计算机领域指的是一套显式的、共享的概念模型用来描述某个领域的类、属性、关系和约束。通俗地说本体就是“规矩”有哪些实体类型、允许哪些关系、哪些属性是必填的。知识图谱是本体实例化之后的数据载体而 LLM 负责把非结构化文本变成符合本体的实例数据。三者其实是一条流水线本体定义图纸知识图谱存放数据LLM 处理自然语言输入并生成回答。1.2 单独使用LLM时最容易出现的四类问题第一类问题是幻觉。比如问“《三体》是哪年出版的”模型如果记得不准确会给出一个结构完整但年份错误的答案。这个问题在垂直领域更加严重因为训练数据中关于企业内部产品、历史记录和专有术语的内容非常少。第二类是知识陈旧。模型训练完成后不会自动获得新数据。今天新建的某个项目、昨晚发布的版本、一个刚刚更名的机构模型可能完全不知道。第三类是推理不可控。复杂问题需要多跳推理时比如“刘慈欣写的书里哪一本是重庆出版社出版的”模型可能跳跃式推理跳过关键证据最终给出一个无法验证的结论。第四类是难以溯源。即便答案正确也很难知道答案来自哪一条事实。实际业务中用户会追问“你怎么知道的”“数据来源是什么”没有知识图谱支撑的纯 LLM 系统很难回答这类问题。这些问题不意味着 LLM 没有用而是意味着需要外部知识源来约束模型。知识图谱和本体论就是这种外部知识源的载体。1.3 本体论落到工程里就是一套语义约束很多人听到 Ontology 会觉得是哲学概念工程上没有必要。实际上在知识图谱项目中本体就是数据建模规范。以一个图书领域的最小本体为例实体类型类Book、Author、Publisher、Category。属性Book 有 title、publishYear、isbnAuthor 有 namePublisher 有 nameCategory 有 name。关系Book 通过 AUTHORED_BY 指向 AuthorBook 通过 PUBLISHED_BY 指向 PublisherBook 通过 BELONGS_TO 指向 Category。约束Book 的 title 不能为空Author 的 name 唯一一本书至少有一个作者一本书只能属于一个分类。有了这套约束LLM 抽取结果就不是“随意的节点和边”而是必须落在这些类型和关系里的合法数据。这样后续查询才有稳定预期也才能对数据质量做自动校验。1.4 Triple Threat 的协作链路组合使用时的完整链路如下非结构化文本进入系统例如一段图书简介。LLM 按本体定义的 Schema 从中抽取实体和关系输出 JSON。校验程序检查 JSON 是否符合本体的类和关系约束。合法数据写入知识图谱。用户提出自然语言问题。系统从问题中识别实体在图谱中定位节点。沿关系扩展子图把子图序列化为文本。文本作为上下文和用户问题一起提交给 LLMLLM 最终生成答案。这个链路里LLM 出现在两个位置知识抽取阶段和最终回答阶段。本体和知识图谱在中间提供事实约束避免模型在两个阶段里自由发挥。2. 技术底座先建模再选存储否则图谱会越做越乱2.1 最小图书本体实体、属性、关系与约束在写代码之前先把本体设计清楚。下面这个最小图书本体足够演示完整流程也能直接扩展到其他领域。实体类型关键属性说明Booktitle, publishYear, isbn一本书Authorname作者Publishername出版社Categoryname分类关系起始节点结束节点语义AUTHORED_BYBookAuthor这本书由该作者创作PUBLISHED_BYBookPublisher这本书由该出版社出版BELONGS_TOBookCategory这本书属于该分类约束包括Book.title 必须唯一。Author.name 必须唯一。Publisher.name 必须唯一。Category.name 必须唯一。关系只能出现一次比如同一对 Book 和 Author 之间不能有两条 AUTHORED_BY。这套约束在后面的 Neo4j 配置里会变成唯一约束和索引。先建模的好处是LLM 抽取时不会产生偏离方向的关系比如“书 A 喜欢作者 B”这种无意义关系。2.2 图存储选型Neo4j、RDF三元组库和内存图实际项目选型时常见选择有下面几种方案适合场景优点缺点Neo4j应用开发、Graph RAG、文本问答Cypher 查询语言成熟事务能力强社区支持多本体推理能力不如 RDF 标准RDF 三元组库如 Jena GraphDB标准语义网、企业知识中台支持 OWL、SHACL 等本体标准学习成本高存储和查询方式与普通开发者习惯不同内存图如 NetworkX学习原型、小规模测试安装简单无外部依赖不适合生产不支持复杂查询和并发关系数据库加递归查询实体关系模式非常固定的场景不引入新组件多跳查询性能差建模不够灵活对于本文的图书问答示例推荐使用 Neo4j。Neo4j 的 Cypher 查询非常直观社区版可以在本地运行也方便后续扩展到生产项目。如果只是为了快速理解流程可以用 Neo4j Aura 或者本地 Docker 启动一个实例。需要注意的是如果业务本身需要标准本体推理比如子类自动推导、属性传递等应该考虑 RDF 三元组库。属性图数据库也能做一部分推理但标准和能力不如 RDF 体系完整。2.3 环境准备依赖安装与Neo4j启动以 Python 3.10 环境为例需要安装以下依赖pip install neo4j openai python-dotenv其中neo4j是官方 Python 驱动openai是调用兼容 OpenAI 接口的大模型服务的 SDKpython-dotenv用来管理环境变量。启动 Neo4j 最简单的方式是使用 Docker 命令docker run -d \ --name neo4j-graphrag \ -p 7474:7474 -p 7687:7687 \ -e NEO4J_AUTHneo4j/yourpassword \ neo4j:5这条命令会启动一个 Neo4j 5.x 容器7474 端口是浏览器管理界面7687 端口是驱动连接端口。生产环境不要使用这种明文密码方式学习环境可以接受。启动后访问http://localhost:7474使用neo4j和yourpassword登录执行RETURN 1;如果返回 1说明数据库已经正常启动。2.4 创建约束和索引让重复写入不再产生脏数据先用 Cypher 创建唯一约束。比如 Book 的 title、Author 的 name 都应该是唯一的CREATE CONSTRAINT book_title_unique IF NOT EXISTS FOR (b:Book) REQUIRE b.title IS UNIQUE; CREATE CONSTRAINT author_name_unique IF NOT EXISTS FOR (a:Author) REQUIRE a.name IS UNIQUE; CREATE CONSTRAINT publisher_name_unique IF NOT EXISTS FOR (p:Publisher) REQUIRE p.name IS UNIQUE; CREATE CONSTRAINT category_name_unique IF NOT EXISTS FOR (c:Category) REQUIRE c.name IS UNIQUE;这些约束保证同一个书名、同一个作者名不会在图谱里出现多个节点。后续使用MERGE写入数据时会依赖这些约束做到“有则更新无则创建”。这里要注意 Neo4j 版本差异。Neo4j 5.x 使用REQUIRE语法旧版本使用ON (b:Book) ASSERT b.title IS UNIQUE。如果语法报错需要根据实际版本调整。3. 用LLM做知识抽取把非结构化文本变成图谱数据3.1 人工建图为什么不可持续如果只有几本书人工录入没有问题。但真实场景中图书简介可能有几百万条还有大量新增内容。人工建图速度慢而且不同人对同一实体的命名方式不一样会产生大量重复节点。LLM 知识抽取能自动完成实体识别和关系抽取尤其擅长处理自然语言中隐含的关系。比如“《三体》的作者在 2015 年获得雨果奖”这句话模型需要同时抽取“刘慈欣”这个 Person 实体和“获得”这个关系。传统 NLP 流水线需要多个模型串联LLM 用一个 Prompt 就能完成。但 LLM 抽取不是无约束的。必须让它按本体输出否则它会自己发明实体类型和关系类型导致图谱结构失控。3.2 设计抽取Prompt角色、输出格式和字段约束一个好的抽取 Prompt 至少包含五个部分角色定义、实体类型、关系类型、输出格式、反例说明。下面是一个示例EXTRACTION_PROMPT 你是知识抽取引擎负责从图书简介中抽取结构化知识。 允许的实体类型 - Book: title, publishYear, isbn - Author: name - Publisher: name - Category: name 允许的关系类型 - {bookTitle: Book.title, relation: AUTHORED_BY, authorName: Author.name} - {bookTitle: Book.title, relation: PUBLISHED_BY, publisherName: Publisher.name} - {bookTitle: Book.title, relation: BELONGS_TO, categoryName: Category.name} 输出要求 1. 只输出 JSON 对象key 为 entities 和 relations。 2. 如果文本里没有明确提到某个信息不要编造。 3. 实体名称使用完整表达例如不要写“刘慈欣作家”只写“刘慈欣”。 4. 关系方向不能反。 用户输入 {text} 把这个 Prompt 和输入文本一起提交给 LLM模型会返回符合字段定义的 JSON。Prompt 里明确“不要编造”是为了减少模型在缺失信息时自行补全的情况。3.3 调用大模型并解析JSON下面是一个最小调用代码使用兼容 OpenAI SDK 的服务import json import os from openai import OpenAI client OpenAI( base_urlos.getenv(LLM_BASE_URL), api_keyos.getenv(LLM_API_KEY), ) def extract_knowledge(text): prompt EXTRACTION_PROMPT.format(texttext) resp client.chat.completions.create( modelos.getenv(LLM_MODEL, your-model-name), messages[{role: user, content: prompt}], temperature0, response_format{type: json_object}, ) content resp.choices[0].message.content return json.loads(content)这里有几个关键点temperature0降低输出随机性知识抽取场景要求稳定格式。response_format{type: json_object}要求模型输出 JSON 对象但不是所有服务都支持这个参数。如果服务不支持需要在 Prompt 里更严格地限制输出格式并在解析时做兜底。LLM_BASE_URL、LLM_API_KEY、LLM_MODEL通过环境变量注入避免把密钥写进代码。实际项目中建议先打印一次模型返回值确认它能稳定输出 JSON。很多问题都出在模型返回了 Markdown 代码块导致json.loads失败。3.4 抽取后的校验与实体标准化LLM 即使输出了合法 JSON也不代表数据一定合法。需要按本体约束做二次校验。校验逻辑包括entities里的每个实体类型是否允许列表中的类型。relations里的relation字段是否属于允许的关系集合。关系两端的实体是否存在于entities列表中。必填属性是否有值例如Book.title不能为空。下面是一个简化校验函数ALLOWED_RELATIONS {AUTHORED_BY, PUBLISHED_BY, BELONGS_TO} def validate_extraction(data): entities {item[name]: item[type] for item in data[entities]} relation_count 0 for rel in data[relations]: if rel[relation] not in ALLOWED_RELATIONS: raise ValueError(f非法关系类型: {rel[relation]}) if rel[bookTitle] not in entities: raise ValueError(f关系中引用了不存在的实体: {rel[bookTitle]}) relation_count 1 return relation_count 0实体标准化也是一个常见问题。比如“刘慈欣”与“刘慈欣中国作家”可能是同一个实体但 LLM 在不同样本里可能输出不同写法。解决办法是在 Prompt 里要求使用规范名称并在写入前做一层清洗映射例如去除括号注释、统一全半角、统一大小写。4. 用知识图谱增强LLM从传统RAG到Graph RAG4.1 传统向量RAG的边界在哪里传统 RAG 流程是把文档切分成块向量化之后放入向量数据库。用户提问时检索出语义最相似的文档块再把这些块作为上下文交给 LLM。这种方式对“问题答案集中在同一段文本”的场景效果好但在多跳推理和精确事实查询上不够可靠。比如“刘慈欣写的书里哪一本是重庆出版社出版的”正确做法是先找到刘慈欣再沿 AUTHORED_BY 找到他的所有书再沿 PUBLISHED_BY 过滤出重庆出版社。向量检索很难准确完成这种跨实体、跨关系的推理。知识图谱能够精确表达这种路径。通过图查询可以沿着关系一步一步走不会因为词面相似而召回错误信息。4.2 Graph RAG的完整查询链路Graph RAG 不是完全替代向量 RAG而是与向量检索组合使用。一个典型流程是用户提问。使用实体识别提取问题中的实体名比如“刘慈欣”。在图谱中找到实体节点。沿关系扩展 1 到 2 跳获取子图。把子图序列化为自然语言文本。将文本作为上下文和原始问题一起提交给 LLM。其中第 3 步和第 4 步是核心。实体链接如果失败后续查询都会失败。子图扩展深度如果太浅上下文缺少关键关系如果太深上下文又会被无关信息淹没。4.3 让LLM生成CypherNL2Cypher的最小实现在图书问答示例里可以把“自然语言转 Cypher”这一步也交给 LLM。前提是让模型知道图谱的 Schema。下面是一个最小实现思路def generate_cypher(question): schema_text 节点类型 - Book(title, publishYear, isbn) - Author(name) - Publisher(name) - Category(name) 关系类型 - (Book)-[:AUTHORED_BY]-(Author) - (Book)-[:PUBLISHED_BY]-(Publisher) - (Book)-[:BELONGS_TO]-(Category) prompt f 你是 Neo4j Cypher 生成器。根据下面的图谱 Schema把用户问题转成只读 Cypher 查询。 Schema: {schema_text} 要求 1. 只输出 Cypher不要 Markdown 代码块。 2. 查询必须是只读禁止 CREATE、MERGE、DELETE。 3. 如果问题没有明确条件使用 RETURN 返回所有可用的属性。 用户问题: {question} resp client.chat.completions.create( modelos.getenv(LLM_MODEL), messages[{role: user, content: prompt}], temperature0, ) return resp.choices[0].message.content.strip()模型生成的 Cypher 必须先检查再执行。简单的检查包括是否以MATCH或RETURN开头是否包含CREATE、MERGE、DELETE、DROP等关键字。生产环境应该使用只读数据库账号并且限制连接权限。使用 NL2Cypher 的确能提高灵活性但稳定性取决于 Schema 是否清晰。上面这段 Prompt 里把节点和关系都列出来了模型不容易生成不存在的属性名。4.4 把子图序列化成高质量上下文Neo4j 查询返回的是节点和关系不能直接塞给 LLM。需要把它们转换成自然语言。比如查询返回(Book {title: 三体, publishYear: 2008}) -[:AUTHORED_BY]- (Author {name: 刘慈欣})可以序列化成“《三体》发布于 2008 年作者是刘慈欣。”也可以在查询阶段直接使用 Cypher 返回聚合文本。比如MATCH (b:Book {title: $title})-[:AUTHORED_BY]-(a:Author) RETURN b.title AS bookTitle, b.publishYear AS publishYear, a.name AS authorName然后在 Python 里拼成句子rows session.run(cypher, titlebook_title) for row in rows: context.append(f《{row[bookTitle]}》发布于 {row[publishYear]}作者是 {row[authorName]}。)上下文拼接完成后再组装最终 Promptprompt f 你是一位图书问答助手。只能根据下面的知识图谱上下文回答问题。 如果上下文里没有足够信息直接说“知识库里没有相关信息”不要编造。 上下文 {chr(10).join(context)} 问题{question} 这里“只能根据上下文回答”是一条关键约束能显著降低幻觉。5. 最小闭环搭建一个图书问答系统5.1 准备测试数据三段图书简介为了方便演示准备三条简短、无版权风险的图书信息描述。下面是示例文本《三体》是刘慈欣创作的科幻小说由重庆出版社出版首次出版于2008年讲 述地球文明与三体文明的信息交流与宇宙博弈。 《球状闪电》是刘慈欣的科幻作品由四川科学技术出版社出版描述一种神秘的 自然现象及其背后的军事应用。 《活着》是余华创作的小说由作家出版社出版讲述一个普通农民在大时代中 的人生起伏。这里只做事实性描述不复制原文。实际项目里你可以替换成自己的文档、商品描述或内部资料。5.2 抽取并写入Neo4j把抽取函数和写入函数串起来from neo4j import GraphDatabase driver GraphDatabase.driver( os.getenv(NEO4J_URI, bolt://localhost:7687), auth(os.getenv(NEO4J_USER, neo4j), os.getenv(NEO4J_PASSWORD, yourpassword)), ) def write_book_subgraph(data): with driver.session() as session: for item in data.get(entities, []): if item[type] Book: session.run( MERGE (b:Book {title: $title}) SET b.publishYear $publishYear, b.isbn $isbn , titleitem[name], publishYearitem.get(publishYear), isbnitem.get(isbn), ) # Author、Publisher、Category 类似这里省略 for rel in data.get(relations, []): session.run( f MATCH (b:Book {{title: $bookTitle}}) MATCH (a:{rel[relation].split(_)[0]} {{name: $targetName}}) MERGE (b)-[:{rel[relation]}]-(a) , bookTitlerel[bookTitle], targetNamerel[authorName], )这段代码只是一个示意框架。更完整的写法应该是把每种实体和关系分别处理避免把动态关系名拼接进 Cypher。这里展示的是思路实际项目里建议把书写成更清晰的函数并且对 Cypher 中的动态标签做白名单校验。关键点在于MERGE。MERGE会先查找匹配节点不存在才创建配合第 2 章创建的唯一约束可以避免重复写入。5.3 实现问答函数问答函数需要完成实体提取、图谱查询、上下文组装和最终回答四步def answer_question(question): # 第一步从问题里提取书名这里用简单规则实际项目可以用 LLM # 例如支持 “刘慈欣写过哪些书”“《三体》是什么类型” entity extract_entity(question) # 第二步根据实体类型查询图谱 with driver.session() as session: cypher MATCH (b:Book)-[:AUTHORED_BY]-(a:Author) WHERE a.name $name RETURN b.title AS bookTitle, b.publishYear AS publishYear result session.run(cypher, nameentity) rows [dict(r) for r in result] # 第三步序列化上下文 context \n.join( f《{r[bookTitle]}》出版于 {r[publishYear]}。 for r in rows ) # 第四步交给 LLM 生成答案 prompt f 根据知识图谱上下文回答问题。不要编造知识库以外的信息。 上下文 {context} 问题{question} resp client.chat.completions.create( modelos.getenv(LLM_MODEL), messages[{role: user, content: prompt}], temperature0, ) return resp.choices[0].message.contentextract_entity函数可以先用简单规则处理比如检测问题里是否包含书名号或者匹配图谱里已有的实体名。生产环境建议使用 LLM 实体识别或者用一个小的 NER 模型。5.4 运行结果与预期输出运行三个问题python answer.py 刘慈欣写过哪些书预期输出类似刘慈欣在知识库中的作品包括《三体》和《球状闪电》。再问python answer.py 《三体》是哪家出版社出版的预期输出《三体》由重庆出版社出版。第三个测试可以故意问知识库里没有的信息python answer.py 莫言获得诺贝尔文学奖的作品是什么预期输出知识库里没有相关信息。这一步验证的是“不知道就说不知道”。如果系统此时强行编造说明最终 Prompt 的约束不够强或者上下文里有无关信息被模型利用了。6. 高频问题与排错链路6.1 抽取结果不是合法JSON现象json.loads抛出JSONDecodeError或者返回结果里只有 Markdown 代码块。常见原因模型输出与 Prompt 要求不一致某些服务不支持response_formattemperature设置过高。处理方式先打印resp.choices[0].message.content看看模型到底返回了什么。如果返回了json可以在解析前用正则提取代码块内容。如果服务不支持 JSON mode去掉response_format参数并加强 Prompt 中的输出说明。将temperature设置为 0。预防建议先单独跑 3 到 5 条文本确认输出格式稳定后再接入完整流程。6.2 图里能查到数据问答却查不到现象在 Neo4j Browser 里MATCH (n:Author) RETURN n能看到作者节点但问答系统返回“没有信息”。常见原因连接的不是同一个数据库实体名匹配失败查询条件写错字段名。处理方式检查问答系统的NEO4J_URI是否指向本地启动的实例。打印extract_entity提取出来的实体名对比图谱里的Author.name。确认 Cypher 查询里使用的属性名与写入时一致比如写入的是publishYear查询时却写成了publishedYear。预防建议在问答函数中打印查询参数和返回行数形成带日志的排查习惯。6.3 LLM生成的Cypher不可用现象执行时报语法错或者返回空结果。常见原因模型生成了不存在的属性名关系类型写错查询条件顺序错误。处理方式把生成的 Cypher 打印出来在 Neo4j Browser 里手动执行。在 NL2Cypher 的 Prompt 里把 Schema 列得更全最好附上一个正确示例。做一次安全校验禁止包含CREATE、MERGE、DELETE、DROP等关键字。预防建议不要直接执行模型输出的 Cypher先做规则检查再执行。对于高频问题可以直接写固定的查询模板只有当模板覆盖不了时才走 NL2Cypher。6.4 回答出现幻觉或答非所问现象最终回答里有知识图谱中没有的信息。常见原因上下文序列化后信息被截断Prompt 没有强制要求基于上下文子图扩展范围太广模型被无关信息干扰。处理方式在 Prompt 中明确写“只能根据上下文回答上下文没有的信息不要补充。”检查返回的上下文是否包含问题所需的实体。限制子图扩展深度为 1 到 2 跳避免引入过多无关节点。预防建议准备一个包含已知答案的评测集每次调整 Prompt 或查询逻辑后重新评测不要只靠印象判断效果。6.5 推荐一条排查顺序按照下面顺序排查能覆盖大多数问题检查输入文本是否被正确读取。检查 LLM 抽取结果格式和内容是否正确。检查图谱中是否存在对应节点和关系。检查查询 Cypher 能否在 Browser 中返回结果。检查上下文序列化后的文本是否包含关键事实。检查最终 Prompt 是否清楚约束模型只能基于上下文回答。每一步都可以打印中间结果。建议把抽取结果、Cypher、上下文、最终答案都记录到日志里方便以后回溯。7. 生产环境落地建议与扩展方向7.1 本体演化与数据版本管理知识图谱的 Schema 不是永远不变的。当业务增加“改编电影”关系时必须同步更新本体、LLM 抽取 Prompt、Cypher 查询模板和校验规则。建议把本体定义放在版本管理系统中例如用一个 YAML 或 JSON 文件描述实体、关系和约束。每次修改都走评审并且准备迁移脚本把旧数据迁移到新 Schema。不要直接在数据库里改约束因为存量数据可能不符合新规则。7.2 数据质量校验流水线LLM 抽取的结果要经过校验才能入库。生产环境可以建一条校验流水线必填字段检查。实体类型白名单检查。关系方向检查。重复实体检查。抽样人工审核。抽样人工审核非常关键。LLM 抽取的错误往往是系统性的比如某个特定表达方式总是把作者名和书名搞反。定期抽检能及时发现这些问题。7.3 权限、审计与安全使用 LLM API 时密钥要放在环境变量或密钥管理系统中不要提交到代码仓库。图谱数据库账号要遵循最小权限原则服务账号只读写入任务用单独的账号。日志中不要打印完整的 API Key也不要打印完整的 Prompt 和答案。如果内容涉及客户隐私还要做脱敏处理。生产环境要记录谁在什么时候修改了图谱数据方便追溯。7.4 从RAG走向Agent与MCP等工具集成当系统需要支持多轮对话、工具调用和自主规划时知识图谱可以作为 Agent 的外部工具。当前主流的 Agent 框架里可以通过标准的工具协议暴露图谱查询能力例如把“查询图书信息”“查询作者关联作品”注册成 Agent 可调用的工具。MCPModel Context Protocol这类基于工具上下文的方案也值得关注。把知识图谱封装成一个 MCP 工具后LLM 可以在对话过程中自主决定何时查询图谱、查询什么内容。这样比简单的问答链路更加灵活但也会引入 Agent 规划失败、工具调用超时等新问题。建议从小范围场景开始先保留固定链路再把“是否查询图谱”的判断交给 Agent最后才尝试让 Agent 动态编排多个工具。7.5 给初学者的练习清单如果想系统掌握这套组合可以按顺序完成以下练习用 NetworkX 在内存里手动创建图书图谱忽略外部依赖先理解节点和边的概念。用 Neo4j 手动写入 10 本书练习MERGE和唯一约束。手写 5 条 Cypher 查询覆盖单跳、双跳和属性过滤。使用 LLM 从 10 条文本中抽取知识对比人工抽取结果统计准确率。实现一个最简单问答函数不生成 Cypher直接根据固定模板查询。引入 NL2Cypher尝试让模型自动生成查询并加上安全校验。准备 20 个测试问题建立评测集每次改动后重新跑一遍。这套练习路径会把“会调用 API”升级成“能构建可靠的知识增强系统”。核心收获不是某个具体库的用法而是理解本体、数据和生成模型之间如何互相约束。实际项目里不要把知识图谱和 LLM 当作二选一的方案。本体约束数据数据约束生成生成结果再反过来帮助完善本体。三者的组合才是 Triple Threat 的真正含义。
返回列表