发布时间:2026/8/30 2:34:06
从Context到Long-term Me:企业级Agent记忆系统实战 最近在给一个企业级 Agent 项目做记忆系统改造时踩了不少坑也把“记忆”这件事从最初理解的“把历史消息塞进 Prompt”慢慢梳理成了分层、持久化、有治理策略的完整架构。这篇文章就围绕“从 Context 到 Long-term Me”这条主线结合 LangChain、LangGraph 和 DeepAgent 框架完整拆解企业级 Agent 记忆系统的设计思路、落地代码和工程治理方案。不管你是准备入门 Agent 开发还是已经在做多轮对话、智能客服、Copilot 类应用这篇文章都值得收藏。我会尽量用工程化的语言把概念、代码、坑点一次讲透。1. Agent 记忆系统背景与核心概念1.1 一次真实的“失忆”事故先看一个很常见的场景。用户在第一轮对话里说我是上海的后端开发主要用 Java 和 Kubernetes 部署。Agent 也正常回复了。但用户第二天再开一个会话问帮我看看这段 Deployment 配置有什么问题Agent 完全不记得用户的技术背景给了通用答案。用户只能重新解释一遍。这只是“失忆”的初级版本。更严重的是会话历史越来越长每次都把全部消息塞进 PromptToken 成本线性增长。多用户共用一套 Agent记忆没有隔离A 用户的偏好被 B 用户的会话检索到。用户明确表达过“不要用 xx 方案”Agent 却在后续对话里反复推荐。这些问题本质上都是同一个大模型本身是无状态的但业务要求 Agent 在长生命周期内保持身份和上下文的一致性。1.2 什么是 Agent 记忆系统Agent 记忆系统可以理解为给 Agent 装载一套跨请求、跨会话的信息基础设施。它负责存储、更新、检索和淘汰与用户、任务、环境相关的信息让 Agent 从“一次性问答工具”进化成“越来越懂用户的长期助手”。从工程角度我们可以把记忆分成几个层次记忆类型生命周期典型载体核心问题Context单次请求Prompt 窗口容量有限、成本高、随用随丢Working Memory单次会话内State Checkpointer需要持久化、需要控制长度Long-term Memory跨会话向量库 / 数据库写入、检索、去重、更新User Profile持续演进画像服务闭环更新、权限控制这里要特别区分两个概念Context是“窗口式的记忆”它只存在于一次请求中模型看完就丢。Long-term Me是“身份式的记忆”它跨越会话存在是 Agent 在时间维度上对用户持续建模的结果。如果一个 Agent 只能靠 Context 工作那它本质上只是“一个没有记忆的函数”。而“Long-term Me”的下一层意思是Agent 不仅要记住用户说了什么还要能整理出用户的身份、偏好、决策和里程碑形成可复用的长期记忆。1.3 从 Context 到 Long-term Me 的演进路线我习惯把记忆系统分成四个演进阶段阶段一纯 Context所有信息都塞进系统提示词或用户消息简单直接但受限于 Token 上限也无法跨会话。阶段二会话级 Message HistoryLangChain 中的ChatMessageHistory、InMemoryChatMessageHistory可以保存消息记录解决单次会话内的连续性。阶段三持久化工作记忆用 LangGraph 的 State 和 Checkpointer 把会话状态持久化到 SQLite、Postgres会话中断后可以恢复。阶段四长期记忆 用户画像从对话中抽取关键事实写入 Long-term Memory 存储并在下一次会话中检索注入 Prompt。此时 Agent 才真正开始形成“Long-term Me”。这篇文章的核心实战案例就是带你从阶段三走向阶段四。2. 环境准备与依赖选型2.1 运行环境本文示例代码使用 Python 3.10建议使用 3.11 或 3.12。操作系统不限Windows、macOS、Linux 都可以。你需要准备一个可以访问的大模型 API本文以 OpenAI 兼容接口为例。如果没有 OpenAI Key也可以使用国内支持 OpenAI 协议的大模型服务只需要修改base_url和model即可。一个虚拟环境推荐使用venv或conda创建隔离环境。2.2 安装依赖pip install langchain langchain-openai langgraph langgraph-checkpoint-sqlite openai简单说明每个包的作用langchain提供模型封装、消息抽象、Prompt 模板等基础组件。langchain-openaiLangChain 对 OpenAI 兼容接口的适配器。langgraph本文的核心编排框架负责状态管理和流程控制。langgraph-checkpoint-sqliteLangGraph 的 SQLite 持久化后端用于保存会话状态。openaiOpenAI 官方 Python SDK作为底层调用依赖。版本方面建议安装当前 PyPI 的最新稳定版本。LangChain 和 LangGraph 迭代较快不同小版本接口可能会有微调但本文使用的核心 API 在 0.2 和 0.3 版本下都可以运行。2.3 项目结构我们用一个最小但完整的工程来演示agent_memory/ ├── main.py # LangGraph 图定义与运行入口 ├── memory_store.py # 长期记忆存储层 ├── memory_extract.py # 记忆抽取与检索 └── requirements.txt这个结构划分得很干净图编排、存储、抽取逻辑各自独立方便后续扩展。2.4 LangChain 和 LangGraph 到底有什么区别这是很多新手常问的问题。简单来说LangChain 更像是一个“零件库”提供模型封装、消息抽象、文档加载、Prompt 模板、输出解析器。LangGraph 更像是一个“流水线引擎”它基于状态图模型允许你定义节点、边、条件路由、循环、持久化状态。如果你的需求是“调用一次 LLM 并处理结果”用 LangChain 就够了。但如果你需要多轮对话、条件分支、循环、人工审批、中断恢复、跨会话状态LangGraph 是更合适的编排层。有人担心 LangChain 过时了其实并没有。LangGraph 仍然依赖 LangChain 提供的基础组件两者是互补关系。在记忆系统场景里LangChain 提供模型调用和消息抽象LangGraph 负责状态流转和持久化配合很自然。3. LangChain 与 LangGraph 的记忆机制拆解3.1 LangChain 中的消息历史LangChain 提供了多种消息历史实现例如InMemoryChatMessageHistory、FileChatMessageHistory、RedisChatMessageHistory等。先看一个最简单的内存版本from langchain_core.chat_history import InMemoryChatMessageHistory history InMemoryChatMessageHistory() history.add_user_message(你好我是上海的后端开发) history.add_ai_message(你好我记住了) print(history.messages)输出[HumanMessage(content你好我是上海的后端开发), AIMessage(content你好我记住了)]这种方式适合聊天机器人简单的会话保存但有几个问题它只是保存在内存中重启进程就丢失。它是“平铺”的消息列表没有做消息摘要、裁剪和重要性评估。它无法区分哪些信息值得长期保存哪些只是寒暄。所以在企业级 Agent 记忆系统里Message History 只能作为最底层的“会话日志”而不是完整的记忆方案。3.2 LangGraph 的 State 与 ReducerLangGraph 的核心是StateGraph。它维护一个全局状态对象每个节点都可以读取状态并返回状态更新。记忆的本质其实就藏在 State 的设计里。看一个典型的状态定义from typing import Annotated, TypedDict from langgraph.graph.message import add_messages class AgentState(TypedDict): messages: Annotated[list, add_messages] user_id: str retrieved_memories: list这里有两个关键点messages是一个列表通过add_messages这个 reducer 做更新。默认情况下节点返回一个字典时LangGraph 会用新值覆盖旧字段。但messages字段使用add_messagesreducer 后新消息会被追加到旧消息列表后面而不是直接覆盖。也就是说LangGraph 的 State 天然就是一个“短期工作记忆”。每一轮对话产生的消息都会累积在 State 中这就是 Agent 在单次会话中的上下文来源。3.3 Checkpointer把工作记忆持久化State 默认保存在内存中进程重启后就会丢失。要让工作记忆持久化我们需要使用 Checkpointer。SQLite 版本的使用方式如下from langgraph.checkpoint.sqlite import SqliteSaver checkpointer SqliteSaver.from_conn_string(langgraph_checkpoint.db) graph builder.compile(checkpointercheckpointer)在调用图时通过thread_id区分不同的会话config {configurable: {thread_id: session_xxx}} result graph.invoke(input_data, configconfig)同一个thread_id的多次invoke会共享同一个 State也就是说会话历史不会丢。这就是 LangGraph 对工作记忆的持久化方案。3.4 为什么纯 Context 拼接不可持续很多初学 Agent 的人会把“记忆”等同于“把历史消息全部塞进 Prompt”。小规模 Demo 可以跑通但一旦进入生产环境问题会逐渐暴露对话轮数多了以后Context 长度受限。所有历史消息都消耗 Token成本随对话轮数线性增长。无关的历史信息会干扰模型判断降低回答质量。所以记忆系统必须做分层尽量用“结构化的长期记忆”替代“无差别的历史消息”让模型每次只读取最相关的少量信息而不是把所有历史都搬进上下文。4. 完整实战用 LangGraph 构建带长期记忆的 Agent这一节是全文核心。我们将实现一个带长期记忆的 Agent它的流程如下用户输入retrieve节点按user_id和当前问题检索长期记忆。agent节点把长期记忆注入 System Prompt和历史消息一起交给模型。extract节点从最新对话中抽取值得长期记忆的事实写入记忆库。这样的设计可以保证同一会话内Converation History 由 LangGraph 的 State 管理跨会话后Agent 靠长期记忆库重新“想起”用户。4.1 长期记忆存储层 memory_store.py我们使用 SQLite 作为长期记忆的落库方式。每一个记忆条目都包含user_id用户隔离维度。content记忆内容。kind类型比如fact、preference、decision、milestone。importance重要性分数影响检索排序。created_at/updated_at时间戳用于生命周期管理。# 文件路径agent_memory/memory_store.py import os import sqlite3 from datetime import datetime DB_PATH os.path.join(os.path.dirname(__file__), agent_memory.db) def get_connection(): conn sqlite3.connect(DB_PATH) conn.row_factory sqlite3.Row conn.execute( CREATE TABLE IF NOT EXISTS long_term_memory ( id INTEGER PRIMARY KEY AUTOINCREMENT, user_id TEXT NOT NULL, content TEXT NOT NULL, kind TEXT DEFAULT fact, importance REAL DEFAULT 0.5, created_at TEXT DEFAULT (datetime(now)), updated_at TEXT DEFAULT (datetime(now)) ) ) conn.commit() return conn def add_memory(user_id: str, content: str, kind: str fact, importance: float 0.5): conn get_connection() conn.execute( INSERT INTO long_term_memory(user_id, content, kind, importance) VALUES (?, ?, ?, ?) , (user_id, content, kind, importance), ) conn.commit() conn.close() def get_user_memories(user_id: str): conn get_connection() rows conn.execute( SELECT * FROM long_term_memory WHERE user_id ? ORDER BY updated_at DESC LIMIT 200 , (user_id,), ).fetchall() conn.close() return [dict(row) for row in rows] def search_memories(user_id: str, query: str, limit: int 5): 先用 user_id 过滤再做简单的关键词评分。 生产环境建议替换为向量检索 Rerank。 memories get_user_memories(user_id) if not memories: return [] if not query: return memories[:limit] scored [] query_tokens query.lower().split() for m in memories: content_lower m[content].lower() score 0.0 for token in query_tokens: if token in content_lower: score 1.0 final_score score * m[importance] scored.append((final_score, m)) scored.sort(keylambda x: x[0], reverseTrue) matched [m for s, m in scored if s 0] if matched: return matched[:limit] # 兜底没有匹配时返回最新记忆避免长期记忆被“遗忘” return memories[:limit]这段代码有几个设计点值得注意使用user_id过滤是记忆隔离的基础。search_memories先用关键词评分再用重要性加权。这是最简单的检索策略便于理解。生产环境可以替换为 Embedding 向量检索。查询结果限制为 5 条控制注入 Prompt 的 Token 开销。4.2 记忆抽取与检索 memory_extract.py为了让 Agent 能“记住”用户我们需要从对话中抽取结构化记忆。这里使用 LLM 作为抽取引擎让模型把一段对话转成 JSON 记忆条目。# 文件路径agent_memory/memory_extract.py import json import os from langchain_core.messages import AIMessage, HumanMessage from langchain_openai import ChatOpenAI from memory_store import add_memory EXTRACT_PROMPT 你是长期记忆抽取器。请从下面的对话中提取值得长期记住的信息例如 - 用户的身份背景、职业、所在城市 - 用户的技术栈、项目偏好、工作习惯 - 用户明确表达过的偏好、禁忌、目标 - 用户提到的关键日期、约定、决策 只输出 JSON 数组不要输出任何解释。每个元素包含以下字段 - content: 记忆内容 - kind: fact / preference / decision / milestone - importance: 0.0 到 1.0 的浮点数 对话内容 {dialogues} def _format_recent_messages(messages, n: int 6) - str: lines [] for m in messages[-n:]: role User if isinstance(m, HumanMessage) else Assistant text getattr(m, content, ) or lines.append(f{role}: {text}) return \n.join(lines) def extract_memories_from_state(user_id: str, messages, llmNone, min_importance: float 0.6): if not messages: return llm llm or ChatOpenAI( modelos.getenv(OPENAI_MODEL, gpt-4o-mini), temperature0, ) dialogues _format_recent_messages(messages, 6) try: resp llm.invoke(EXTRACT_PROMPT.format(dialoguesdialogues)) items json.loads(resp.content.strip()) if not isinstance(items, list): return except Exception: return for item in items: content (item.get(content) or ).strip() if not content: continue importance float(item.get(importance, 0.5)) if importance min_importance: continue add_memory( user_iduser_id, contentcontent, kinditem.get(kind, fact), importanceimportance, )这里的抽取逻辑并不复杂关键是两点只抽取最近 6 条消息避免每轮都重复处理全部历史。设置min_importance阈值防止把无关紧要的对话内容写入长期记忆。4.3 图编排与核心代码 main.py下面是最核心的 LangGraph 定义。我们把记忆检索、Agent 回复、记忆抽取三个逻辑封装成三个节点。# 文件路径agent_memory/main.py import os import uuid from typing import Annotated, TypedDict from langchain_core.messages import HumanMessage, SystemMessage from langchain_openai import ChatOpenAI from langgraph.checkpoint.sqlite import SqliteSaver from langgraph.graph import END, START, StateGraph from langgraph.graph.message import add_messages import memory_extract import memory_store OPENAI_MODEL os.getenv(OPENAI_MODEL, gpt-4o-mini) class AgentState(TypedDict): messages: Annotated[list, add_messages] user_id: str retrieved_memories: list def build_system_prompt(state: AgentState) - str: memories state.get(retrieved_memories) or [] if memories: memory_text \n.join( f- [{m[kind]}] {m[content]} for m in memories ) else: memory_text 暂无相关长期记忆。 return f你是一个企业级智能助理。以下是当前用户的长期记忆回答时自然引用不要机械复述。 长期记忆 {memory_text} def retrieve_memories_node(state: AgentState) - dict: user_id state.get(user_id, default) query if state.get(messages): last_msg state[messages][-1] query getattr(last_msg, content, ) or memories memory_store.search_memories(user_id, query, limit5) return {retrieved_memories: memories} def agent_node(state: AgentState) - dict: llm ChatOpenAI(modelOPENAI_MODEL, temperature0.3) system_msg SystemMessage(contentbuild_system_prompt(state)) response llm.invoke([system_msg] state[messages]) return {messages: [response]} def extract_memory_node(state: AgentState) - dict: user_id state.get(user_id, default) memory_extract.extract_memories_from_state(user_id, state.get(messages) or []) return {} def build_agent_graph(): gb StateGraph(AgentState) gb.add_node(retrieve, retrieve_memories_node) gb.add_node(agent, agent_node) gb.add_node(extract, extract_memory_node) gb.add_edge(START, retrieve) gb.add_edge(retrieve, agent) gb.add_edge(agent, extract) gb.add_edge(extract, END) checkpointer SqliteSaver.from_conn_string(langgraph_checkpoint.db)

相关新闻

2026/8/30 2:34:06

分布式系统核心考点全梳理:从CAP到分布式锁与事务

看到“牛客面经八股”这几个字,很多准备校招的朋友都会会心一笑:分布式,几乎是大厂技术栈的必考章节,也是很多人背得最痛苦的部分。你背了CAP、背了两阶段提交、背了Redis分布式锁,但面试官往往不止问“是什么”&#…

2026/8/30 2:34:06

滴滴后端面试复盘:场景建模与系统设计实战指南

复盘滴滴后端面试那次,我最大的教训不是哪道题没答上来,而是发现面试官从头到尾都在做一件事:把线上的真实问题拆成一个一个小场景,看你是不是真的理解系统为什么这么设计。网上很多八股答案会告诉你缓存不一致要用延迟双删&#…

2026/8/30 2:29:06

PyTorch学习路线:从张量、自动求导到模型训练与部署

我见过太多初学者,装完 PyTorch 后的第一反应不是跑通一个训练循环,而是被一堆报错拦住:版本对不上、CUDA 不可用、张量尺寸不匹配、模型输出永远是一个形状。真正的问题往往不在“不会写代码”,而在于还没有把 PyTorch 最核心的三…

2026/8/30 2:49:07

Vibe Coding实战:用AI打造624台掌机数据检索工具

这次我们来看一个很典型的 Vibe Coding 实践项目:作者整理了 624 台掌机的数据,借助 AI 辅助编码,最终做成了一个可以搜索、筛选、详情查看的掌机数据工具。这正好也是 B 站 AI 创造公开赛的一个参赛作品。这个项目本身并不复杂,但…

2026/8/30 2:49:07

Shader光照原理:RGB相乘的物理推导与实践

开场 上周在调试一个角色皮肤的渲染效果时,美术反馈"红色光源打在大理石地板上,地板泛着奇怪的橙色"。我盯着屏幕上怪异的色块,脑子里的第一反应是:Unity 不是把光的颜色和物体颜色直接乘起来就行了吗?翻出 shader 代码,漫反射那行赫然写着 diffuse = lightColor *…

2026/8/30 2:49:07

机器学习+启发式特征:钓鱼网站检测系统设计与实现

简介:在Web安全领域,钓鱼网站检测是一项关键任务,攻击者常通过仿冒页面窃取用户敏感信息。传统黑名单方案无法应对快速变化的攻击,而基于机器学习与启发式特征的方法能够有效捕捉恶意网站的异常行为模式。该方法从URL结构、域名注…

2026/8/30 2:49:07

Transformer遥感变化检测项目实战:架构设计与调参经验

简介:变化检测是遥感影像分析中的核心任务,通过对比同一区域不同时相的影像,逐像素识别地表变化。传统方法依赖人工特征与阈值设定,难以应对复杂场景。Transformer凭借自注意力机制带来的全局建模能力,可有效捕捉长距离…

2026/8/30 2:44:07

AI权力集中下的工程对策:构建可迁移、可本地部署的模型架构

最近一段时间,Hugging Face 联合创始人兼 CEO Thomas Wolf 关于“AI 权力极端集中”的公开表态,在技术社区里讨论度很高。很多开发者第一反应是:这不就是“大公司垄断”的另一种说法吗?但如果你把这句话投射到自己的工程实践里&am…

2026/8/30 0:03:35

vSound小提琴数字处理器实操指南:从接线到演出的完整配置

电小提琴或者原声小提琴插电演出,第一个绕不开的坎就是声音难听。原声琴的共鸣和空气感一旦进了拾音器,出来的往往是一坨干瘪、发尖、带着奇怪塑料味的信号。我当初第一次把琴接上乐队调音台,直接被主唱吐槽"你这声音像在锯钢丝"。…

2026/8/30 0:03:35

传感器接口IC如何攻克生物化学传感的微弱信号难题?

1. 从电极到比特流:为什么生物化学传感必须依赖专用接口IC 做生物化学传感的人都有过类似的经历:明明传感器本身性能很好,信号输出却一塌糊涂——噪声大、漂移明显、重复性差,怎么调都达不到预期。很多时候问题并不在传感器&#…

2026/8/30 0:03:35

STM32F411CEU6多通道ADC采集:扫描模式+DMA实现详解

1. 多通道 ADC 的用武之地把“Multichannel ADC”和“STM32F411CEU6”这两个关键字放在一起,其实就是嵌入式开发里最常遇到的一类需求:用一块不算贵的 MCU,同时采集多路模拟信号。STM32F411CEU6 是 48 引脚的 Cortex-M4F 主控,主频…

2026/8/30 0:03:35

vSound小提琴数字处理器实操指南:从接线到演出的完整配置

电小提琴或者原声小提琴插电演出,第一个绕不开的坎就是声音难听。原声琴的共鸣和空气感一旦进了拾音器,出来的往往是一坨干瘪、发尖、带着奇怪塑料味的信号。我当初第一次把琴接上乐队调音台,直接被主唱吐槽"你这声音像在锯钢丝"。…

2026/8/30 0:03:35

传感器接口IC如何攻克生物化学传感的微弱信号难题?

1. 从电极到比特流:为什么生物化学传感必须依赖专用接口IC 做生物化学传感的人都有过类似的经历:明明传感器本身性能很好,信号输出却一塌糊涂——噪声大、漂移明显、重复性差,怎么调都达不到预期。很多时候问题并不在传感器&#…

2026/8/30 0:03:35

STM32F411CEU6多通道ADC采集:扫描模式+DMA实现详解

1. 多通道 ADC 的用武之地把“Multichannel ADC”和“STM32F411CEU6”这两个关键字放在一起,其实就是嵌入式开发里最常遇到的一类需求:用一块不算贵的 MCU,同时采集多路模拟信号。STM32F411CEU6 是 48 引脚的 Cortex-M4F 主控,主频…

2026/8/28 16:16:48

实测才敢推 AI论文网站 2026最新测评与推荐

2026年真正好用的AI论文网站,核心看生成的论文质量、低AI味、格式正确、学术适配四大指标。综合实测,千笔AI、ThouPen、豆包、DeepSeek、Grammarly 是当前最值得推荐的梯队,覆盖从免费到付费、从中文到英文、从文科到理工的全场景需求。一、综…

2026/8/28 16:16:50

2026必备!AI论文网站测评:最新推荐与深度对比

2026年真正好用的AI论文网站,核心看生成的论文质量、低AI味、格式正确、学术适配四大指标。综合实测,千笔AI、ThouPen、豆包、DeepSeek、Grammarly 是当前最值得推荐的梯队,覆盖从免费到付费、从中文到英文、从文科到理工的全场景需求。 一、…

2026/8/28 11:06:45

摆脱论文困扰!盘点2026年全网爆红的的AI论文写作工具

一天写完毕业论文在2026年已不再是天方夜谭。2026年最炸裂、实测能大幅提速的AI论文写作工具,覆盖选题构思、文献整理、内容生成、格式排版等核心场景,真正帮你高效搞定论文难题。 一、全流程王者:一站式搞定论文全链路(一天定稿首…