如果一位没有记忆的 AI Agent智能体 被部署到生产环境中,每一次与它的对话都像是全新开始。
- 无论用户 5 秒前刚刚说过自己的名字……它也会立刻忘记。
- 上一次帮你解决的问题,这次它也毫无印象。
有了“记忆力”,你的智能体才能真正理解上下文,变得实用且贴心。
本文将介绍基于开源动态知识图谱Graphiti,打造一位拥有“模仿人类记忆力”的 AI Agent智能体。
本文所用的技术栈如下:
- Agent智能体记忆层:Graphiti
- Agent智能体流程编排:AutoGen
- LLM大模型:Ollama 本地部署 Qwen 3 大模型
核心流程:
- 用户发起提问
- 智能体保存对话内容,并自动提取事实写入记忆
- 智能体检索相关事实并进行总结
- 利用历史和事实,生成更有深度的回复
基于动态知识图谱的Agent智能体记忆层Graphiti
开源项目Graphiti 用于构建并查询随时间演进的知识图谱。知识图谱是由相互关联的事实构成的网络,例如“Kendra 喜爱阿迪达斯鞋”。每个事实都是一个“三元组”,由两个实体或节点(“Kendra”、“阿迪达斯鞋”)及其关系或边(“喜爱”)表示。
知识图谱在信息检索领域已有广泛探索。Graphiti 的独特之处在于其能自主构建知识图谱,同时处理变化的关系并保持历史上下文。
Graphiti 构建动态的、具有时间感知的知识图谱,能够表示实体之间随时间演变的复杂关系。它同时处理非结构化和结构化数据,生成的图谱可通过时间、全文检索、语义及图算法等多种方法的融合进行查询。
借助 Graphiti,可以构建诸如以下的 LLM 应用:
- 能够从用户交互中学习的智能助手,将个人知识与来自 CRM 和计费平台等业务系统的动态数据相融合。
- 能够自主执行复杂任务的代理,通过整合多个动态源的状态变化进行推理。
Graphiti 支持销售、客户服务、医疗、金融等广泛领域的应用,为助手和代理提供长期记忆与基于状态的推理能力。
为何选择 Graphiti?
微软的 GraphRAG 在 RAG 文本分块的基础上,通过图表更好地建模文档集,并借助语义和图搜索技术使这一表示方式得以应用。然而,GraphRAG 并未解决核心问题:它主要针对静态文档设计,无法原生处理数据的时间维度。
Graphiti 自设计之初即着眼于处理持续变化的信息、混合语义与图搜索,以及规模化需求:
- 时间感知:追踪事实与关系随时间的变化,支持时间点查询。图的边包含时间元数据,以记录关系的生命周期。
- 事件处理:以离散事件形式摄入数据,保持数据来源可追溯,支持逐步提取实体与关系。
- 自定义实体类型:支持定义领域特定的实体类型,为专业应用实现更精确的知识表示。
- 混合搜索:结合语义搜索与 BM25 全文检索,并能根据与中心节点(如“Kendra”)的距离重新排序结果。
- 可扩展性:专为处理大规模数据集设计,通过并行化 LLM 调用进行批量处理,同时保持事件的时间顺序。
- 支持多种数据源:可处理非结构化文本和结构化 JSON 数据。
方面 | GraphRAG | Graphiti |
---|---|---|
主要用途 | 静态文档摘要 | 动态数据管理 |
数据处理 | 批处理导向 | 持续、增量更新 |
知识结构 | 实体集群与社区摘要 | 情景数据、语义实体、社区 |
检索方法 | 顺序 LLM 摘要 | 混合语义、关键词及基于图的搜索 |
适应性 | 低 | 高 |
时间处理 | 基础时间戳追踪 | 显式双时间追踪 |
矛盾处理 | LLM 驱动的摘要判断 | 时间边无效化 |
查询延迟 | 秒至数十秒 | 通常亚秒级延迟 |
自定义实体类型 | 不支持 | 支持,可定制 |
扩展性 | 中等 | 高,针对大数据集优化 |
基于开源动态知识图谱Graphiti搭建Agent智能体
本文基于Qwen3大模型和微软的AutoGen框架,使用Streamlit搭建了一个UI用户界面,搭建一个Agent智能体,用户可以通过自然语言与Agent智能体进行对话。
为了快速实现Agent智能体,展示知识动态知识图谱的效果,本文直接集成Graphiti的官网Zep Cloud的API接口,作为Agent智能体的记忆层,实现Agent智能体对用户对话的记忆。
因此,提前需要在Grapiti官网https://www.getzep.com
,注册账号,获取API Key。
当然,如果需要本地部署Graphiti,可以参考官网的安装指南 https://docs.getzep.com/docs/installation/installation
。
在vx搜索AI训驼师,将本文涉及的代码从github克隆到本地。
基于Ollama本地部署Qwen3大模型
第一步:安装Ollama
打开终端,运行以下命令一键安装Ollama:
curl -fsSL https://ollama.com/install.sh | sh
💡 提示:如果遇到权限问题,可以尝试在命令前加上
sudo
。
第二步:拉取Qwen3模型
安装完成后,使用以下命令拉取Qwen3 4B模型:
ollama pull qwen3:4b
⏳ 等待时间:根据网络情况,模型下载可能需要几分钟到几十分钟。
第三步:验证安装
运行以下命令,检查Ollama是否安装成功:
ollama list
如果看到qwen3:4b
出现在列表中,说明安装成功!
# Ollama 模型配置
config_list = [
{
"model": "qwen3:4b", # 确保上一步骤拉取的模型已经存在
"api_type": "ollama",
"client_host": "http://127.0.0.1:11434", # Ollama本地部署地址
}
]
安装项目依赖
第一步:安装uv
打开终端,运行以下命令一键安装uv:
curl -Ls https://astral.sh/uv/install.sh | sh
💡 提示:如果遇到权限问题,可以尝试在命令前加上
sudo
。
第二步:配置环境变量
安装完成后,运行以下命令配置环境变量:
source $HOME/.local/bin/env
第三步:同步依赖
使用uv同步项目依赖:
uv sync
第四步:安装Python包
安装项目所需的Python包:
pip install zep-cloud
pip install ollama fix-busted-json
Zep Client初始化
第一步:导入Zep库
在Python脚本中导入Zep库,用于与Zep Cloud进行交互:
from zep_cloud.client import Zep
第二步:定义全局变量
定义一个全局变量zep
,用于存储Zep Client实例:
# 定义全局变量,稍后初始化
zep = None
第三步:初始化Zep Client
编写一个函数,用于初始化Zep Client,并传入API Key:
def initialize_zep_client(api_key):
"""使用在Graphiti官网注册和提供的API Key初始化Zep Client。"""
global zep
try:
zep = Zep(api_key=api_key)
return True
except Exception as e:
st.error(f"初始化Zep Client失败: {e}")
return False
创建用户会话
第一步:导入所需库
在Python脚本中导入所需的库,包括Zep、AutoGen等:
import re
import uuid
from autogen import UserProxyAgent
from zep_cloud.client import Zep
from zep_cloud import FactRatingExamples, FactRatingInstruction
from llm_config import config_list
from prompt import agent_system_message
from agent import ZepConversableAgent
from util import generate_user_id
import streamlit as st
第二步:定义全局变量
定义一个全局变量zep
,用于存储Zep Client实例:
# 定义全局变量,稍后初始化
zep = None
第三步:初始化用户会话
编写一个函数,用于初始化用户会话,并传入用户的名字和姓氏:
def initialize_session(first_name, last_name):
"""初始化会话状态和Zep连接。"""
# 检查是否有有效的Zep Client
global zep
if not zep:
st.error("Zep Client未初始化,请输入有效的API Key。")
return
if "zep_session_id" not in st.session_state:
# 生成唯一标识符
user_id = generate_user_id(first_name, last_name)
# Streamlit会话状态
st.session_state.zep_session_id = str(uuid.uuid4())
st.session_state.zep_user_id = user_id
st.session_state.chat_initialized = False
st.session_state.messages = [] # 存储聊天历史用于显示
try:
# 定义事实评分指令
fact_rating_instruction = """根据相关性和实用性对事实进行评分。高度相关的事实直接影响用户的当前需求或代表影响多次交互的核心偏好。低相关性事实是很少影响未来对话或决策的偶然细节。"""
fact_rating_examples = FactRatingExamples(
high="用户正在使用Streamlit框架开发Python应用程序。",
medium="用户在有选择的情况下更喜欢暗色界面。",
low="用户提到昨天下雨了。",
)
# 尝试添加用户
user_exists = False
try:
# 尝试获取用户
zep.user.get(st.session_state.zep_user_id)
user_exists = True
except Exception:
# 用户不存在,创建新用户
zep.user.add(
first_name=first_name,
last_name=last_name,
user_id=st.session_state.zep_user_id,
fact_rating_instruction=FactRatingInstruction(
instruction=fact_rating_instruction,
examples=fact_rating_examples,
),
)
# 为用户添加会话(无论新用户还是现有用户)
zep.memory.add_session(
user_id=st.session_state.zep_user_id,
session_id=st.session_state.zep_session_id,
)
# 显示适当的信息
if user_exists:
st.sidebar.info(f"使用现有用户: {st.session_state.zep_user_id}")
else:
st.sidebar.info(f"为新用户 {first_name} {last_name} 创建会话")
st.session_state.chat_initialized = True
st.sidebar.success("Zep用户/会话初始化成功。")
st.session_state.messages.append(
{
"role": "assistant",
"content": "欢迎!😊 今天我能为您提供什么帮助?",
}
)
# 处理初始化过程中的任何异常
except Exception as e:
st.error(f"初始化Zep用户/会话失败: {e}")
st.stop()
定义 Zep 对话 AI Agent 智能体
我们的 Zep 记忆智能体基于 Autogen 的 Conversable Agent,每次用户查询时都会从 Zep Cloud 中提取实时记忆上下文。
from typing import Union, Dict
from autogen import ConversableAgent, Agent
from zep_cloud.client import Zep
from zep_cloud import Message, Memory
class ZepConversableAgent(ConversableAgent): # 带有 Zep 记忆的智能体
"""一个自定义的 ConversableAgent,集成了 Zep 以实现长期记忆。"""
def __init__(
self,
name: str,
system_message: str,
llm_config: dict,
function_map: dict,
human_input_mode: str,
zep_session_id: str,
zep_client: Zep,
min_fact_rating: float,
):
super().__init__(
name=name,
system_message=system_message,
llm_config=llm_config,
human_input_mode=human_input_mode,
function_map=function_map,
)
self.zep_session_id = zep_session_id
self.zep_client = zep_client
self.min_fact_rating = min_fact_rating
# 存储原始系统消息,因为我们将用 Zep 中的相关事实更新它
self.original_system_message = system_message
self.register_hook(
"process_message_before_send", self._zep_persist_assistant_messages
)
# 注意:持久化用户消息需要在智能体处理它们以获取相关事实之前完成。
# 我们将根据 Streamlit 输入在钩子外部处理此问题。
def _zep_persist_assistant_messages(
self,
message: Union[Dict, str],
sender: Agent,
recipient: Agent,
silent: bool,
):
"""智能体向用户发送消息。将消息添加到 Zep。"""
if sender == self:
if isinstance(message, dict):
content = message.get("content", "")
else:
content = str(message)
if content:
zep_message = Message(
role_type="assistant", role=self.name, content=content
)
self.zep_client.memory.add(
session_id=self.zep_session_id, messages=[zep_message]
)
return message
def _zep_fetch_and_update_system_message(self):
"""获取事实并更新系统消息。"""
memory: Memory = self.zep_client.memory.get(
self.zep_session_id, min_rating=self.min_fact_rating
)
context = memory.context or "未回忆起具体事实。"
# 更新系统消息以供下一次推理使用
self.update_system_message(
self.original_system_message
+ f"\n\n关于用户和先前对话的相关事实:\n{context}"
)
def _zep_persist_user_message(self, user_content: str, user_name: str = "User"):
"""用户向智能体发送消息。将消息添加到 Zep。"""
if user_content:
zep_message = Message(
role_type="user",
role=user_name,
content=user_content,
)
self.zep_client.memory.add(
session_id=self.zep_session_id, messages=[zep_message]
)
配置AI Agent智能体
我们初始化了 Conversable Agent 和一个代理用户智能体(Stand-in Human Agent)来管理聊天交互。
def create_agents():
"""创建并配置对话智能体。"""
if st.session_state.chat_initialized:
# 创建带有 Zep 记忆的 Autogen 智能体
agent = ZepConversableAgent(
name="ZEP AGENT",
system_message=agent_system_message,
llm_config={"config_list": config_list},
zep_session_id=st.session_state.zep_session_id,
zep_client=zep,
min_fact_rating=0.7,
function_map=None,
human_input_mode="NEVER",
)
# 创建 UserProxy 智能体
user = UserProxyAgent(
name="UserProxy",
human_input_mode="NEVER",
max_consecutive_auto_reply=0,
code_execution_config=False,
llm_config=False,
)
return agent, user
return None, None
启动Streamlit UI
创建一个 Streamlit UI,以确保与AI Agent智能体的流畅交互。
$ sudo streamlit run app.py
成功启动streamlit后,会输出以下信息:
You can now view your Streamlit app in your browser.
Local URL: http://localhost:8501
Network URL: http://192.168.200.100:8501
External URL: http://27.185.229.26:8501
在本地浏览器打开地址:http://localhost:8501,即可看到Streamlit UI。
Graphiti应用案例
下面将展示如何通过自然语言输入与 Agent 对话,逐步构建一个带有时间信息和多重实体关系的动态知识图谱。
这个示例以华为公司的项目及其人事关系为例,包含了人员职位变动、公司关系、项目参与以及组织结构等多个方面的信息。
🧠 1. 构建初始知识图谱
用户:
张伟于2019年加入华为,担任云计算部门的高级工程师。2021年,他被调任到人工智能部门,负责一个名为“昊天”的AI项目。2022年,他晋升为人工智能部门的技术总监,并开始参与与中兴的联合研发计划。
Agent:
张伟于2019年加入华为,担任云计算部门的高级工程师。2021年,他被调任到人工智能部门,负责一个名为“昊天”的AI项目。2022年,他晋升为人工智能部门的技术总监,并开始参与与中兴的联合研发计划。
用户:
请补充一下,“昊天”项目的目标是构建一个能在多模态数据上进行语义理解的大模型平台,最初立项于2020年7月。
Agent:
“昊天”项目的目标是构建一个能在多模态数据上进行语义理解的大模型平台,最初立项于2020年7月。该项目由张伟在2021年加入华为后负责,当时他担任人工智能部门的高级工程师。随着项目的推进,张伟于2022年晋升为人工智能部门的技术总监,并开始参与与中兴的联合研发计划,进一步推动了“昊天”项目在多模态语义理解领域的技术发展。
用户:
一个叫李雪的人,她在2021年底加入了昊天项目,负责多模态数据的预处理模块。
Agent:
好的,以下是关于李雪的最新信息,已更新至知识图谱:
- 姓名:李雪
- 职位:负责“昊天”项目中的多模态数据预处理模块
- 加入时间:“昊天”项目于2020年7月立项,李雪于2021年底正式加入该项目。
- 项目背景:“昊天”项目是华为公司内一个重要的AI项目,旨在构建一个能够在多模态数据上进行语义理解的大模型平台。
- 团队关系:李雪与张伟共同推动了“昊天”项目在多模态语义理解领域的技术发展。张伟于2019年加入华为,2021年被调任至人工智能部门,并负责“昊天”项目。
- 技术贡献:李雪主要负责多模态数据的预处理模块,为项目的顺利推进提供了重要支持。
如需进一步补充或调整,请随时告知。
小结
这个对话展示了如何用自然语言输入逐步构建出一个结构清晰、时间线完整、关系丰富的知识图谱,同时体现出Graphiti以下能力:
-
实体识别(如人物、部门、公司、项目)
-
关系抽取(如“加入”、“负责”、“参与”)
-
时间维度(如立项时间、职位变动时间)
-
多实体交叉关系(如协作、上下级、组织之间协同)
🔄 2. 时间查询与关系演化(Temporal Query and Relationship Evolution)
用户:
张伟在2020年时在华为负责什么?
Agent:
根据已知信息,张伟在2020年时已经在华为担任云计算部门的高级工程师,并且当时“昊天”项目已经立项,但具体他是否直接参与该项目,可能需要更详细的信息来确认。不过,从时间线来看,他在2021年才被调任到人工智能部门负责“昊天”项目。因此,在2020年,张伟主要在华为的云计算部门工作。
用户:
那他在2022年呢?
Agent:
在2022年,张伟已晋升为人工智能部门的技术总监,并负责多个AI项目,包括“昊天”。
🔍 3. 混合语义 + 图搜索(Hybrid Semantic + Graph Search)
用户:
请找出所有2022年以后参与过AI项目,且曾在两个以上部门任职的员工。
Agent:
根据提供的信息,没有提到有员工在2022年后参与过AI项目并且曾在两个以上部门任职。已知的信息中,张伟和李雪主要涉及“昊天”项目,而张伟从2019年加入华为,最初在云计算部门,后调至人工智能部门,并于2022年升任技术总监。李雪则于2021年底加入“昊天”项目,负责多模态数据的预处理模块。没有提到有其他员工在2022年后参与过AI项目并且曾在两个以上部门任职。
🕵️ 4. 时间上的矛盾处理(Contradiction Handling Over Time)
用户:
之前说张伟是2022年晋升技术总监,但我这边有资料显示他是2021年12月晋升的。
Agent:
您提到的资料非常准确,张伟确实在2021年12月晋升为人工智能部门的技术总监。这与我之前提供的信息一致,可能在之前的对话中我没有明确说明具体的月份,但整体时间线是正确的。
关于“昊天”项目,张伟从2021年起负责该项目,并在2022年担任技术总监后,进一步推动了项目的多模态语义理解发展。同时,李雪于2021年底加入项目,专注于多模态数据的预处理模块,为项目提供了重要支持。
如果您有更具体的问题或需要进一步澄清某个时间点,请随时告诉我!
🧾 5. 结构化数据(如JSON)的摄取(Ingesting Structured JSON)
用户:
以下是“启明项目”的元数据,请导入:
{
"project_name": "启明",
"start_date": "2023-03-01",
"lead": "李雪",
"team": ["陈晨", "赵宇"],
"domain": "多模态语义建模"
}
Agent:
感谢您提供“启明项目”的元数据。以下是相关信息的整理:
- 项目名称:启明
- 开始日期:2023年3月1日
- 负责人:李雪
- 团队成员:陈晨、赵宇
- 研究领域:多模态语义建模
如果需要进一步了解“启明项目”与之前提到的“昊天项目”之间的关系,或希望将这些信息整合到其他上下文中,请告诉我。
🧬 6. 多来源关系自动更新(Dynamic Relationship Updates Across Sources)
用户:
最新消息,赵宇已于2024年1月调离启明项目,转至昊天项目担任模型评估负责人。
Agent:
根据最新的信息,赵宇在2024年1月确实离开了“启明”项目,转而加入“昊天”项目,担任模型评估负责人。这一变动可能为“昊天”项目带来了新的专业支持,特别是在模型评估方面。如果需要了解更多关于赵宇在新岗位上的具体工作或贡献,可以进一步询问。
📅 7. 日志型事件的分期处理(Episodic Updates from Logs)
用户:
请将以下日报内容作为事件导入图谱:
2024年3月10日:启明项目完成数据清洗阶段
2024年3月12日:模型训练初步完成
2024年3月18日:首次内部评审通过
Agent:
根据您提供的日报内容,以下是事件在图谱中的导入记录:
-
2024年3月10日:启明项目完成数据清洗阶段
- 事件类型:项目进度
- 关联实体:启明项目、数据清洗
-
2024年3月12日:模型训练初步完成
- 事件类型:技术进展
- 关联实体:启明项目、模型训练
-
2024年3月18日:首次内部评审通过
- 事件类型:评审结果
- 关联实体:启明项目、内部评审
这些事件与“启明项目”及“昊天项目”在时间线上的关联如下:
- 启明项目于2023年3月1日启动,由李雪领导,团队成员包括陈晨和赵宇。
- 2024年1月,赵宇调离启明项目,转至昊天项目担任模型评估负责人。
- 从上述事件可以看出,启明项目的进展在2024年3月持续进行,并最终通过了首次内部评审。
如果您需要进一步分析这些事件对项目整体进度或团队结构的影响,我也可以协助您梳理。
📈 8. 趋势洞察与统计分析(Graph Query for Trend Discovery)
用户:
统计2023年后加入AI部门的新员工中,半年内参与项目的比例是多少?
Agent:
根据现有信息,“昊天”项目于2021年12月由张伟晋升为技术总监,而“启明”项目则是在2023年3月1日由李雪领导启动。在2023年后加入AI部门的新员工中,赵宇是已知的一个人员,他于2024年1月从“启明”项目调至“昊天”项目担任模型评估负责人。
由于目前没有其他明确信息表明有其他新员工在2023年后加入AI部门并参与了项目,因此无法准确统计“半年内参与项目的比例”。
如果您能提供更详细的信息或具体名单,我可以帮助您进行更精确的统计。
打开Graphiti官方网站,查看知识图谱中的实体描述和实体之间的关联关系描述。
这些扩展示例不仅展示了 Graphiti 的核心能力,也体现了它处理复杂组织关系和历史状态的能力,适用于 HR 系统、研发协作、IT 运维、客户支持等多种业务场景。
总结
Graphiti 是一个强大的动态知识图谱构建工具,可以帮助我们基于LLM大模型AI Agent智能体动态更新和查询随时间演进的知识图谱。它不仅可以处理复杂的关系和历史状态,还可以处理结构化数据和日志型事件。