2026年Agent教程21:知识图谱,让AI?学会联想

Agent教程21:知识图谱,让AI?学会联想这是我的专栏 春哥的 Agent 通关秘籍 系列文章的第 21 篇 希望系统性跟着我一起学 AI Agent 编码的同学可以关注一下我的这个专栏 联想并不是人类独有的高级能力 但它确实更高级 RAG 向量检索 虽然能超越文本进行语义上的模糊搜索 但如果在逻辑上存在超越基础语义的关联式联想 那么 RAG 向量检索可能就力所不及了 让我们思考以下场景 假设 你的 RAG 向量库存了三条向量 小李精通

大家好,我是讯享网,很高兴认识大家。这里提供最前沿的Ai技术和互联网信息。



Agent教程21:知识图谱,让AI?学会联想_后端

这是我的专栏《春哥的Agent通关秘籍》系列文章的第 21 篇。

希望系统性跟着我一起学AI-Agent编码的同学可以关注一下我的这个专栏。


联想并不是人类独有的高级能力。但它确实更高级。

RAG向量检索,虽然能超越文本进行语义上的模糊搜索,但如果在逻辑上存在超越基础语义的关联式联想,那么RAG向量检索可能就力所不及了。

让我们思考以下场景。

假设,你的RAG向量库存了三条向量:

  • “小李精通 Python。”
  • “小李目前在用 n8n 搭建自动化工作流。”
  • “n8n的 Code 节点支持Python 和 JS 脚本”

现在,假设小李提问:“帮我在 n8n 写一段脚本,实现xxxx”

此时,传统的RAG检索思路,要么直接用这句话去检索,要么提前处理一下,用更为精炼的语言去检索。

但,核心内容通常都是“n8n”、“写脚本”、“实现xxx”这些从原问题中提取出来的语义。

检索结果可能会包含:

  • “小李目前在用 n8n 搭建自动化工作流。”
  • “n8n的 Code 节点支持Python 和 JS 脚本”

但几乎很难命中到“小李精通 Python。” 这条记忆信息,从而在给出脚本语言时,可能会错误地选中“JS”作为脚本语言。

Agent教程21:知识图谱,让AI?学会联想_Python_02

而咱们人类实际的记忆方式其实是这样的:

  • 小李要用n8n脚本实现xxx
  • n8n的 Code 节点支持Python 和 JS 脚本
  • 小李擅长Python
  • 那好,我用Python写一段脚本给小李吧

Agent教程21:知识图谱,让AI?学会联想_JavaScript_03

通过代码也能实现这种关联记忆吗?

能的兄弟!包能的。

这就是AI记忆领域最强大的杀手锏之一:知识图谱记忆(Knowledge Graph Memory)。

如上面的例子所说,这个世界上的数据不仅仅是 Excel 表格里冷冰冰的行与列,它们更是错综复杂的关系网。为了处理这种“网状”数据,图数据库(Graph Database) 和它的专属查询语言 Cypher 应运而生。

想象一下,当你在会议室的白板上给同事讲解业务逻辑时,你会怎么画?

你大概率会画几个圆圈(代表实体,比如人、商品、公司),然后用带箭头的线条(代表关系,比如购买、认识、入股)把它们连起来。

这就是图数据库的底层逻辑。它不存表格,它直接把你在白板上画的“圆圈和线条”存进硬盘里。

  • 圆圈 = 节点(Node)
  • 线条 = 关系(Relationship)

图数据库应用而生,相比于传统数据库,它有什么特点?

  • 传统数据库更擅长通过索引搜索具体的数值,而在连表查询Left Join时,在多表关联时极其容易因为笛卡尔积的原因,导致查询时间爆炸。
  • 图数据库恰恰相反,它非善于善于从一个实体关联到另外的实体,速度极快,在多层实体关联场景下,对传统数据库进行降维打击。

列举几个最常见的例子:

  • 社交网络与推荐:从海量数据里找到你的3度好友(朋友的朋友的朋友),放到【你可能认识的人】里。
  • 金融侦察与反诈骗:从资金海量的转移过程中,它善于顺着各种资金流向,找到诈骗集团真正的账户。
  • 各类拓扑结构评估,比如信息系统的架构等影响评估等。

Agent教程21:知识图谱,让AI?学会联想_后端_04

因而,也衍生出了许多种能支持各类场景的图数据库出来,比如:Neo4jMemgraphKùzuFalkorDB 等。

其中在各类图数据库中,使用最广的一种查询语法,名为:Cypher

你可以把它为理解为 图库里的 SQL

Cypher 语法的核心是两个概念:

  1. 节点(Node)。使用小括号包裹,写法如下:
(p:Person {name: “小李”})

数据库就知道你要找一个类型是 Person,且名字叫“小李”的节点。

  1. 关系(Relationship)。使用如下结构:-[]->
-[:KNOWS]->

当你写下 -[:KNOWS]->,数据库就知道这是一条名叫“认识”的带方向的线。

通过这两个概念,就能够拼凑出一条具备语义的查询语句:

MATCH (p1:Person {name: “小李”})-[:KNOWS]->(friend:Person)-[:KNOWS]->(fof:Person) RETURN fof.name

翻译一下这段代码:

“请帮我匹配这样一个图案:从小李 (p1) 出发,顺着认识的线 -[:KNOWS]-> 找到朋友 (friend),再顺着认识的线 -[:KNOWS]-> 找到朋友的朋友 (fof)。最后把这个人的名字给我。”

也就完成了“二度好友”的迅速查询。

是不是还挺好理解的?

这就是 Cypher 的魅力。

你不需要告诉数据库“怎么找”,你只需要向数据库“描述那个图案的长相”,底层的图引擎会自动为你规划最优的寻路路线。

了解基础 Cypher 语法是必要的,这样才能更准确的要求LLM构建合适的JSON结构,以便完成日常的增删改查操作。

Cypher // 语义:图里有叫$name的 Person 就不管,没有就新建一个。 MERGE (n:Person {name: $name}) 
”`Cypher MERGE (n:Person {name: $name}) // 如果是全新创建的节点,打上出生时间戳,初始化提及次数为 1 ON CREATE SET

n.created_at = $current_time, n.mention_count = 1 

// 如果是已经存在的节点,更新最后活跃时间,提及次数 +1 ON MATCH SET

n.last_seen = $current_time, n.mention_count = coalesce(n.mention_count, 0) + 1 

”`

注意:在 Cypher 中,节点类型(Label)不能作为变量传递,必须用 Python 字符串拼接(f-string);而属性值必须作为参数(Parameters)传递,防注入且提升性能。

entity_label = “Language” # 从大模型提取的 JSON 中获取 entity_name = “Python”

1. 构建 Cypher 模板

cypher_node = f”“”

MERGE (n:{entity_label} {{name: $name}}) ON CREATE SET n.weight = 1 ON MATCH SET n.weight = n.weight + 1 

”“”

2. 传参执行

conn.execute(cypher_node, parameters={“name”: entity_name})

核心原则:

  • 连线必须建立在已有的实体之上;
  • 连线本身不能重复生成;
  • 能够通过权重(Weight)体现关系的强弱。

绝对不要直接 MERGE 整个带两头节点的关系链,这在 Cypher 中是极其危险的,极易导致意想不到的节点重复。

正确做法:先把两头“锚定”(MATCH),再在它们之间“拉线”(MERGE)。

// ✅ 推荐的写法:先 MATCH,后 MERGE MATCH (source:Person {name: ‘小李’}), (target:Language {name: ‘Python’}) MERGE (source)-[r:KNOWS]->(target)

注意:如果不 MATCH 直接 MERGE,可能会导致创建多个【小李】节点和【Python】节点。

// ❌ 危险的写法:直接 MERGE 整个模式 MERGE (p:Person {name: ‘小李’})-[:KNOWS]->(l:Language {name: ‘Python’})

如果用户在对话中反复强调过两百多次:“我喜欢孙燕姿”,那么和他只提过一次的“最近喜欢二手玫瑰”。

那么,在记忆中这里可能需要一些区分。

这个区分就是“权重”,我们可以再更新时,给权重属性+1。

实际上,就是把【我】【喜欢】【孙燕姿】中的【喜欢】这条线上的一个属性值不断递增。

MATCH (source:Person {name: \(s_name}), (target:Tool {name: \)t_name}) MERGE (source)-[r:USES]->(target) // 第一次连线 ON CREATE SET

r.weight = 1, r.established_at = $current_time 

// 再次听到同样的连线 ON MATCH SET

r.weight = r.weight + 1, r.last_confirmed_at = $current_time

有了这个 weight 属性,未来 Agent 检索时就可以加上 WHERE r.weight > 3,自动过滤掉那些只提过一次的噪音干扰。

source_label = "Person" 

source_name = “小李” target_label = “Tool” target_name = “n8n” relation_type = “USES”

cypher_rel = f”“”

MATCH (source:{source_label} {{name: $s_name}}), (target: {{name: $t_name}}) MERGE (source)-[r:{relation_type}]->(target) ON CREATE SET r.weight = 1 ON MATCH SET r.weight = r.weight + 1 

”“”

conn.execute(cypher_rel, parameters=)

了解了图的概念,我们就需要开始设计,如何在Agent中合理地使用图数据库了。

那么就涉及到两个核心问题要处理:

  • 如何从用户的对话里解析出图结构
  • 如何结合上下文,从图数据库里查询出有用的图结构

一般来说,流程如下图所示:

Agent教程21:知识图谱,让AI?学会联想_图数据库_05

  • 定期对聊天历史进行消息提取,生成三元组,插入图数据库,形成【知识图谱】
  • 当用户与LLM交互时,如需要查询知识图谱,则由另一子LLM生成Cypher查询语句,将查到的信息返回主LLM进行解答。

因此,此时我们其实由三个LLM Client:

  • Client 1: 和用户交互的Client
  • Client 2: 提取三元组知识
  • Client 3: 根据诉求生成Cypher查询语句

这两个实现其实不复杂,无非就是SystemPrompt,输出结构设置好,条件配好,通过LLM就能完成提取。

相信看文章的你也可以轻松做到。

需要注意的是,至少需要在提示词里给好以下提示:

  • 你有哪些实体类型需要提取
  • 你有哪些关系类型需要提取
  • 输出的JSON格式/Cypher格式如何,给好定义和示例

这里就不放具体实现了,不然又是几百字的提示词,有灌水嫌疑,需要的同学可以在这里查看demo源码:

github.com/zhangshichu…

以我们上面的例子为例,加入用户输入:“”

LLM帮我们生成了如下Cypher查询语句:

MATCH (n8n:Entity {name: “n8n”}) OPTIONAL MATCH (n8n)-[:SUPPORTS]->(language:Entity) OPTIONAL MATCH (n8n)-[:USES]->(tool:Entity) OPTIONAL MATCH (person:Entity {entity_type: “Person”})-[:USES]->(n8n) OPTIONAL MATCH (person)-[:KNOWS]->(person_language:Entity) OPTIONAL MATCH (person)-[:LEARNS]->(person_learns:Entity) OPTIONAL MATCH (person)-[:INTERESTED_IN]->(person_interest:Entity) OPTIONAL MATCH (person)-[:WORKS_AT]->(company:Entity) OPTIONAL MATCH (company)-[:USES]->(company_tool:Entity) OPTIONAL MATCH (web_scraping:Entity {name: “网页抓取”}) OPTIONAL MATCH (script_writing:Entity {name: “脚本编写”}) OPTIONAL MATCH (tech_solution:Entity {name: “技术方案”}) OPTIONAL MATCH (web_scraping)-[:BUILDS_WITH]->(scraping_component:Entity) OPTIONAL MATCH (script_writing)-[:BUILDS_WITH]->(scripting_component:Entity) OPTIONAL MATCH (tech_solution)-[:BUILDS_WITH]->(solution_component:Entity) RETURN 
n8n, collect(DISTINCT language) AS n8n_supported_languages, collect(DISTINCT tool) AS n8n_used_tools, collect(DISTINCT person) AS n8n_users, collect(DISTINCT person_language) AS user_known_languages, collect(DISTINCT person_learns) AS user_learning_topics, collect(DISTINCT person_interest) AS user_interests, collect(DISTINCT company) AS user_companies, collect(DISTINCT company_tool) AS company_tools, web_scraping, collect(DISTINCT scraping_component) AS web_scraping_components, script_writing, collect(DISTINCT scripting_component) AS script_writing_components, tech_solution, collect(DISTINCT solution_component) AS tech_solution_components

这个查询语句的核心逻辑在于:

  • MATCH 严格经过节点
  • MATCH (n8n:Entity {name: "n8n"}): 必须经过n8n节点
  • OPTION MATCH 可选经过节点
OPTIONAL MATCH (n8n)-[:SUPPORTS]->(language:Entity) 

OPTIONAL MATCH (n8n)-[:USES]->(tool:Entity) OPTIONAL MATCH (person:Entity {entity_type: “Person”})-[:USES]->(n8n) OPTIONAL MATCH (person)-[:KNOWS]->(person_language:Entity)

  • 上面的语句的意思是:“去打听下 n8n 支持啥语言、依赖啥工具;然后再顺藤摸瓜揪出是谁在用它,以及这人自己会啥编程语言。”
  • OPTION 的意思是:有符合的就查,没符合的也没关系,不严格

通过这种语句,能形成非常广泛且发散的联想联调。

查询结果如下:

[, ‘_label’: ‘Entity’, ‘name’: ‘n8n’, ‘entity_type’: ‘Tool’, ‘properties’: None}, [, ‘_label’: ‘Entity’, ‘name’: ‘JavaScript’, ‘entity_type’: ‘Language’, ‘properties’: None}, , ‘_label’: ‘Entity’, ‘name’: ‘Python’, ‘entity_type’: ‘Language’, ‘properties’: None}], None, [, ‘_label’: ‘Entity’, ‘name’: ‘小李’, ‘entity_type’: ‘Person’, ‘properties’: ‘{}’}], [, ‘_label’: ‘Entity’, ‘name’: ‘Python’, ‘entity_type’: ‘Language’, ‘properties’: None}], [, ‘_label’: ‘Entity’, ‘name’: ‘Rust’, ‘entity_type’: ‘Language’, ‘properties’: ‘{}’}], None, None, None, None, None, None, None, None, None]

这一大串JSON什么鬼?其实翻译一下很简单:

“图谱查明是 小李 正在使用 n8n(该工具支持 JS 和 Python),并且他本人刚好懂 Python(最近还在学 Rust)。”

咦?通过联想,小李在当前场景更适合Python的联想居然就有了,再把这些信息给主LLM做参考,整个记忆联调就通顺了!

如果三元组知识图谱的关联能力那么强,为什么它在大家讨论记忆方案时,并不是最热门最常见的技术呢?

任何技术都有它的优势与劣势,上面我们谈到了知识图谱的优势。

下面我们也有必要了解它的缺陷,让它流行程度上不那么高。

相比于前面两节提到的“事实”和“摘要”,图谱的入库必要要求以下几点:

  • 节点识别是准确的
  • 关系识别是准确的

这种准确甚至包含到大小写,Pythonpython 不做好准确区分的话,甚至都会导致入库两个实体。

更遑论,用户可能在沟通时使用类似 Py 这样的简称,一不小心就实体重复。

关系也是:LikeLIKE_USES一不小心,会产生两个关系。

而准不准确这点,非常看LLM的脸色,不稳定。

因此显然不如“事实”和“摘要”皮实可靠。

Agent教程21:知识图谱,让AI?学会联想_JavaScript_06

还记得我们在向量库(RAG)里是怎么做记忆更新的吗?

  • 把旧的 Chunk 删掉,塞一个新的 Chunk 进去就行了。

但在图谱里,修改一个事实牵一发而动全身:

假设小李说:“我不用 Python 了,我现在全栈转 Node.js。” 在图谱里更新这个动作需要:

  • 查找到 (小李) 节点。
  • 查找到它和 (Python) 节点之间的所有关系线。
  • 删除 [CURRENTLY_USING] 连线(但还要考虑是否保留 [USED_IN_PAST] 连线作为历史经验)。
  • 创建新的 (Node.js) 节点。
  • 建立新的连线。

如果涉及复杂的层级关系,这种图结构的级联更新(Cascading Updates)在工程代码里写起来非常容易出 Bug。

让我们理解向量与图谱两种记忆方式,不难发现:

  • 纯图谱太“轴”(容错率极低,构建成本极高)
  • 纯向量太“傻”(没有逻辑观,容易产生幻觉)

所以最新的趋势中,是把它们缝合起来:

  • 用图谱做骨架:约束核心的业务逻辑、技术栈拓扑。
  • 用向量做血肉:把大段的文本、模糊的表述转化为 Embedding,挂载在图节点上。
  • 检索时:先用向量的“模糊匹配”搞定实体消歧(查找到正确的入口节点),然后再顺着图谱的“精确连线”进行逻辑推理。

demo中用到的Kuzu其实就支持这种方式,不过非常可惜的是Kuzu已经归档不再维护了。

但还有很多选择,如 FalkorDBLiteCogDB 等。

这一节我们学习【知识图谱】这种可以给AI赋能联想能力的记忆结构。

demo地址在这里:github.com/zhangshichu…

Agent教程21:知识图谱,让AI?学会联想_前端_07

小讯
上一篇 2026-04-08 18:16
下一篇 2026-04-08 18:14

相关推荐

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容,请联系我们,一经查实,本站将立刻删除。
如需转载请保留出处:https://51itzy.com/kjqy/251837.html