给大模型做记忆,听起来不像是个“硬核模型”项目,但在 Agent、私有化部署和 To B 落地的语境里,这几乎是必须跨过去的一道坎。郝建业团队半年内完成三轮融资,给这个方向又添了一把火。资本关注的是“记忆”能不能成为大模型的基础设施,而技术人更关心的是另一件事:记忆到底怎么存、怎么取、怎么和大模型接口接起来,以及我自己的服务器上能不能跑一套。
这篇文章不做资本复盘,先讲清楚大模型记忆的技术本质:它分几类、开源实现有哪些、本地部署怎么搭、Agent 怎么通过 API 读写记忆、批量任务怎么做,以及最容易踩哪些坑。如果你正在做大模型应用开发、Agent 工作流,或者准备给私有大模型加长期记忆,这篇可以直接当参考。
先说结论:大模型本身是无状态的,记忆能力必须靠外部系统补。主流的做法是“大模型 + 向量数据库 + 记忆管理模块”,再往上就是带记忆的 Agent 框架。下面从规格开始拆。
1. 大模型记忆核心能力速览
| 能力项 | 说明 |
|---|---|
| 解决的核心问题 | 让大模型跨会话、跨任务记住用户偏好、历史操作、业务规则和项目上下文 |
| 技术本质 | 外部记忆系统 + 检索增强 + 上下文管理,不修改模型权重 |
| 主要实现方式 | 上下文窗口拼接、向量数据库、知识图谱、LangChain Memory、LangGraph Checkpoint |
| 大模型选型 | 本地可用 Ollama、vLLM 部署开源模型;商业场景可接云端大模型 API |
| 硬件门槛 | 取决于模型参数量;仅跑 Embedding 和向量检索时 CPU 也可承担 |
| 显存占用 | 需按实际模型和推理参数测试,无固定值 |
| 支持批量任务 | 支持,文本切块、向量化入库、记忆压缩都可批量处理 |
| 是否提供 API | 各框架通常提供 Python API;自建服务可用 REST API 封装 |
| 适合场景 | Agent 长期任务、私有大模型知识问答、用户画像记忆、自动化工作流 |
| 版权与隐私边界 | 记忆内容涉及用户数据时必须脱敏、授权并控制访问范围 |
从规格上看,这个方向不挑显卡,也不依赖某个特定大模型。你完全可以用一个小的开源模型做推理,再配一个向量库负责记忆存取,整体门槛比微调低得多。这也解释了为什么资本市场会看好“给大模型做记忆”:它不是重资源游戏,而是一个能快速落地的工程层机会。
2. 为什么大模型需要记忆:从无状态到有状态
大模型默认是无状态的。你发一句“帮我写一份周报”,它返回结果,然后对话结束。下一次你再发起请求时,它不会记得你上周做了什么,不会记得你偏好的语气,也不会记得你之前已经在对话里确认过的项目信息。对普通聊天场景,这个问题可以靠“多轮对话上下文拼接”解决,因为模型输入里会把最近几轮对话一起塞进去。但真到了 Agent、企业知识库、自动化流程里,这种“临时上下文”远远不够。
典型的问题有三个。
第一,会话一断,上下文全丢。浏览器刷新、任务超时、服务重启,之前聊的所有内容都消失了。用户必须重新描述一遍背景,Agent 也必须重新初始化状态。
第二,长任务做不下去。一个 Agent 要执行“调研市场 -> 写方案 -> 做 PPT -> 给用户过目 -> 按反馈修改”这种多步骤任务,中间任何一次模型调用的上下文都是有限的。模型记不住前面调研的结论,后面写方案就是瞎写。
第三,用户级记忆缺失。同一个用户今天问“我要预算偏保守的方案”,明天再问“做一版激进点的”,如果系统不记得用户偏好,每次都要用户重新交代。这在 To B 场景里非常影响体验。
所以“给大模型做记忆”的本质,是把模型从无状态的函数变成有状态的服务。实现思路不是去改模型参数,而是在模型外面加一层记忆管理层:写入、存储、检索、更新、过期,然后在你调用模型接口之前,把相关的历史记忆取出来拼进上下文里。这个思路和 RAG 很像,但比单一 RAG 更全面——RAG 偏向“知识检索”,记忆系统还要处理“用户偏好”“任务进度”“多轮状态”这些动态信息。
3. 大模型记忆的分类:短期、长期、工作记忆
在具体落地之前,先把记忆分类理清楚。不同种类的记忆,存储方式和读取时机完全不同。
| 记忆类型 | 典型内容 | 存储方式 | 读取时机 |
|---|---|---|---|
| 短期记忆 | 当前会话的对话历史、临时状态 | 模型上下文窗口、内存变量 | 每次请求全部携带或滑动窗口截取 |
| 长期记忆 | 用户偏好、历史行为、业务配置 | 向量数据库、关系数据库、键值存储 | 根据当前输入检索出最相关的部分 |
| 工作记忆 | Agent 当前任务执行进度、中间结果 | 状态存储、任务队列、文件 | 任务流每个步骤开始时恢复 |
| 语义记忆 | 知识库、文档、规则、术语表 | 向量数据库、图数据库 | 用户提问时检索增强 |
| 情景记忆 | 用户与系统之前的交互记录 | 事件日志、时序数据库 | 按时间或场景回放 |
工程上最常见的组合是:短期记忆靠上下文窗口,长期记忆靠向量检索,工作记忆靠状态机或 Checkpoint。
这里要特别提醒一句:不要把长期记忆做成“把全部历史都塞给大模型”。上下文窗口再大也有上限,而且塞得越多,模型注意力越分散,响应越慢,成本越高。长期记忆的正确做法是“按需检索”——根据当前问题,从记忆库里取最相关的一小段,而不是把整库倒进提示词。
4. 主流开源记忆框架速览
目前给大模型加记忆的开源方案不少,下面几个是社区里讨论最多、与“大模型记忆”热搜词直接相关的方向。
4.1 LangChain Memory 模块
LangChain 是接触最多的 Agent 开发框架,它把记忆抽象成几个常用类:ConversationBufferMemory 保存所有对话记录;ConversationSummaryMemory 用模型历史对话生成摘要并保存;ConversationBufferWindowMemory 只保留最近 N 轮;VectorStoreRetrieverMemory 把历史对话向量化后存储,检索时取相关片段。对于快速做 Demo,LangChain Memory 是最省事的。
from langchain.memory import ConversationBufferWindowMemory from langchain.chains import ConversationChain from langchain_ollama import ChatOllama memory = ConversationBufferWindowMemory(k=5, return_messages=True) llm = ChatOllama(model="qwen2.5:7b") conversation = ConversationChain(llm=llm, memory=memory) print(conversation.run("我叫小王,负责服务器运维。")) print(conversation.run("你还记得我是谁吗?"))上面是一个最简示例,实际项目中 memory 的存储方式可以替换成 Redis、数据库或向量库。需要注意的是,LangChain 不同版本的 API 有差异,使用时以项目文档为准。它适合单机快速验证,但生产环境的长期记忆还是建议用下面的 LangGraph 做持久化。
4.2 LangGraph Checkpoint 持久化记忆
LangGraph 更贴合“有状态 Agent”这个需求。它把 Agent 执行过程建模成一张图,图中每个节点的状态变化可以被 Checkpoint 记录到 SQLite、Postgres 或 Redis 里。任务中断后,可以从最近的 Checkpoint 恢复,属于典型的工作记忆实现。和 LangChain Memory 相比,LangGraph 更强调跨任务的状态恢复,适合多步骤、可中断的复杂 Agent。
from langgraph.graph import StateGraph from langgraph.checkpoint.sqlite import SqliteSaver # 使用 SqliteSaver 做 Checkpoint 持久化 with SqliteSaver.from_conn_string("checkpoints.db") as saver: graph = StateGraph(SomeStateSchema) # 添加节点和边 app = graph.compile(checkpointer=saver) # 每次执行时传入 thread_id 作为会话标识 config = {"configurable": {"thread_id": "task-001"}} result = app.invoke(initial_state, config=config)这个方案解决了“任务执行到一半服务重启”的问题。需要注意的是,Checkpoint 保存的往往是原始对话状态和数据,如果涉及敏感业务数据,落库前先做脱敏。
4.3 向量数据库 + RAG 长期记忆
长期记忆的底层存储,现在的主流是向量数据库。常见选择包括 Chroma、FAISS、Milvus、Qdrant、pgvector。流程是:用 Embedding 模型把文本转成向量,存入向量库;查询时把用户输入也转成向量,做相似度检索,把 TopK 结果拼进提示词。
from langchain_ollama import OllamaEmbeddings from langchain_community.vectorstores import Chroma from langchain.text_splitter import RecursiveCharacterTextSplitter from langchain.docstore.document import Document # 初始化 Embedding 模型 embeddings = OllamaEmbeddings(model="nomic-embed-text") # 构造一个记忆文档 doc = Document( page_content="用户小王偏好预算保守的运维方案,常用语言是中文,关注费用和稳定性。", metadata={"user_id": "xiaowang"} ) # 切分并入库 splitter = RecursiveCharacterTextSplitter(chunk_size=500, chunk_overlap=50) docs = splitter.split_documents([doc]) vectorstore = Chroma.from_documents(docs, embeddings, persist_directory="./memory_db") # 检索 results = vectorstore.similarity_search("小王选择方案时最看重什么?", k=3) print(results)这套组合的优势是:模型可以随时换,记忆库独立存在;用户历史数据积累后不需要重新训练模型;批量导入历史知识只需要跑一次离线 Embedding。缺点是向量检索的质量取决于 Embedding 模型和切块策略,不是“丢进去就能用”。
5. 本地部署大模型并添加记忆:环境准备
无论用哪个框架,本地部署大模型 + 记忆系统都遵循同一套流程:启动推理模型、启动 Embedding 模型、选择存储介质、配置记忆读写逻辑。以下给出通用步骤,具体版本和路径按实际项目调整。
先看环境清单:
| 检查项 | 说明 |
|---|---|
| 操作系统 | Linux 服务器或 Windows/WSL 均可;推荐 Linux |
| GPU | 有 NVIDIA 显卡最好,没有也可用 CPU 跑小模型 |
| 内存 | 8GB 起步,跑 7B 模型建议 16GB 以上 |
| 磁盘 | 模型文件 5GB 到 20GB 不等,另留存储空间 |
| Python | 3.9 到 3.11 均可 |
| 模型运行器 | Ollama 或 vLLM |
| 向量库 | Chroma、FAISS、Milvus 等 |
| 端口规划 | Ollama 默认 11434,自建服务预留独立端口 |
如果只做记忆功能验证,不需要一开始就上大显存显卡。Embedding 模型非常轻量,CPU 跑完全没问题;推理模型可以先用 1.5B 或 3B 的小模型验证流程,通了以后再换大模型。
6. 安装部署与启动方式
6.1 快速启动 Ollama 模型服务
Ollama 是目前本地部署大模型最方便的工具之一,支持一键下载模型并暴露 API。以 Linux/macOS 为例:
# 安装 Ollama curl -fsSL https://ollama.com/install.sh | sh # 拉取推理模型 ollama pull qwen2.5:7b # 拉取 Embedding 模型 ollama pull nomic-embed-text # 启动服务(默认端口 11434) ollama serve启动后可以测试接口是否正常:
curl http://127.0.0.1:11434/api/generate -d '{ "model": "qwen2.5:7b", "prompt": "你好,用一句话介绍你自己" }'注意:如果 Ollama 已经在后台运行,ollama serve会提示端口被占用,直接访问 11434 即可。模型文件默认存储在~/.ollama/models下,磁盘空间不足时可以设置OLLAMA_MODELS环境变量改路径。
6.2 在 Windows 上部署
Windows 推荐使用 Ollama 官方安装包,安装后直接执行:
ollama pull qwen2.5:7b ollama pull nomic-embed-text ollama serve然后打开浏览器访问 http://127.0.0.1:11434 确认服务状态。如果你用的是老显卡,建议先确认驱动是否支持 CUDA;如果不支持,就选 CPU 推理的小模型。
6.3 vLLM 高并发部署
如果需要更高并发或批量推理,可以用 vLLM。它是专门为高吞吐推理设计的框架,适合把大模型部署成 API 服务:
# 安装 vLLM(Linux + CUDA 环境) pip install vllm # 启动 OpenAI 兼容 API 服务 python -m vllm.entrypoints.openai.api_server \ --model Qwen/Qwen2.5-7B-Instruct \ --host 127.0.0.1 \ --port 8000启动后,客户端可以用 OpenAI SDK 风格调用。vLLM 的显存占用和模型量化精度有关系,首次启动会做 warmup,实际显存以任务管理器或nvidia-smi观察为准。
6.4 自建记忆服务
推理模型启动后,还需要一个“记忆服务”来统一管理写入和检索。最简单的做法是写一个 Python FastAPI 服务,内部依赖向量库和 Embedding 模型。
from fastapi import FastAPI from pydantic import BaseModel from langchain_ollama import OllamaEmbeddings from langchain_community.vectorstores import Chroma app = FastAPI() embeddings = OllamaEmbeddings(model="nomic-embed-text") vectorstore = Chroma( persist_directory="./memory_db", embedding_function=embeddings ) class MemoryItem(BaseModel): user_id: str content: str class QueryRequest(BaseModel): user_id: str query: str top_k: int = 5 @app.post("/memory/write") def write_memory(item: MemoryItem): vectorstore.add_texts( texts=[item.content], metadatas=[{"user_id": item.user_id}] ) return {"status": "ok"} @app.post("/memory/query") def query_memory(req: QueryRequest): docs = vectorstore.similarity_search(req.query, k=req.top_k) results = [ {"content": d.page_content, "metadata": d.metadata} for d in docs ] return {"results": results}启动这个服务后,大模型应用就可以通过 HTTP 接口写入用户记忆和读取相关记忆了。生产环境建议用 Milvus 或 Qdrant 替代本地 Chroma,并加上用户权限过滤。
7. 给大模型应用接入记忆:功能测试与效果验证
框架搭好之后,下面做一套简单的功能测试,验证记忆是否真的生效。测试目标不是看模型多聪明,而是确认“写入的记忆能查到,查到的内容能进入提示词”。
7.1 记忆写入测试
先写入一条明确的用户偏好:
curl -X POST http://127.0.0.1:8000/memory/write \ -H "Content-Type: application/json" \ -d '{ "user_id": "xiaowang", "content": "小王是运维负责人,喜欢预算保守的解决方案,关注系统稳定性。" }'预期返回{"status": "ok"}。如果失败,检查记忆服务是否启动、向量库目录是否可写、Embedding 模型是否可用。
7.2 记忆检索测试
再查询这条记忆:
curl -X POST http://127.0.0.1:8000/memory/query \ -H "Content-Type: application/json" \ -d '{ "user_id": "xiaowang", "query": "小王选方案时在意什么?", "top_k": 3 }'预期结果里应该包含“预算保守”“稳定性”这些关键词。如果没有检索到,先看提问表述和原文差异是否过大,再调整切块大小和 TopK 参数。
7.3 带记忆的大模型问答测试
检索到记忆后,把它拼进提示词再让大模型回答:
curl http://127.0.0.1:11434/api/generate -d '{ "model": "qwen2.5:7b", "prompt": "根据以下记忆信息回答问题。\n记忆信息:小王是运维负责人,喜欢预算保守的解决方案,关注系统稳定性。\n问题:请为他推荐一个监控方案。", "stream": false }'判断成功的标准:回答里出现了“稳定性”“成本控制”等与记忆匹配的内容。如果模型完全没用到记忆,说明提示词拼接逻辑需要调整,或者检索到的记忆片段和问题不相关。
7.4 批量记忆导入测试
长期记忆不可能一条条手写,通常要批量导入历史对话、业务文档或用户标签。推荐流程是:文本切块 -> 批量 Embedding -> 批量入库 -> 人工抽检检索效果。
import requests docs = [ "用户A偏好使用 Grafana 展示监控数据。", "用户A的告警阈值是 CPU 使用率超过 80% 时通知。", "用户A所在的团队有 5 名运维工程师。", ] for doc in docs: resp = requests.post( "http://127.0.0.1:8000/memory/write", json={"user_id": "user_a", "content": doc}, timeout=30, ) print(resp.status_code, resp.json())批量导入的重点不是“全量入库”,而是导入后的检索准确率。建议每导入一批,就抽几条和业务相关的 query 测试检索结果,必要时调整切块策略或重选 Embedding 模型。
8. 接口 API 与批量任务设计
如果要把记忆能力集成到现有系统里,不能只停留在 Python 函数调用层面。推荐把记忆服务封装成独立 API,方便不同业务模块调用。
| 接口 | 方法 | 用途 |
|---|---|---|
| /memory/write | POST | 写入一条用户记忆或文档记忆 |
| /memory/query | POST | 查询与输入最相关的记忆 |
| /memory/delete | POST | 删除指定用户或指定内容的记忆 |
| /memory/clear | POST | 清空一个用户的所有记忆 |
| /memory/batch_import | POST | 批量导入历史对话或文档 |
| /memory/stats | GET | 查看当前记忆库规模、向量数量 |
批量任务设计上,要注意三个点。第一,批量导入建议异步执行,用任务队列接住,避免一次性阻塞 API。第二,每条记忆都加user_id、timestamp、source等元数据,方便后续做权限控制和过期清理。第三,记忆库要有幂等机制,同一批数据重复导入时不能产生大量重复向量,否则检索结果会被重复片段污染。
下面是一个异步批量导入的简单示意:
from fastapi import BackgroundTasks def do_batch_import(items): for item in items: vectorstore.add_texts( texts=[item["content"]], metadatas=[{"user_id": item["user_id"], "source": "import"}] ) @app.post("/memory/batch_import") async def batch_import(payload: dict, background: BackgroundTasks): items = payload["items"] background.add_task(do_batch_import, items) return {"status": "accepted", "count": len(items)}这个接口适合处理“历史聊天记录一次性导入”“知识库全量重建”等场景。需要注意的是,异步任务要搭配日志和重试机制,不然大量导入时中途挂了很难排查。
9. 资源占用与性能观察
“给大模型做记忆”并不等于只跑一个大模型。实际系统里有推理模型、Embedding 模型、向量库、记忆服务四部分,资源占用要分开看。
- 推理模型:占大头。7B 模型在 GPU 上通常需要 6GB 左右显存,在 CPU 上则取决于内存和量化等级。显存不足时可以换量化版本,或改用 1.5B 小模型。
- Embedding 模型:非常轻量。比如 nomic-embed-text 这类模型,CPU 也能跑,批量向量化时主要吃内存。
- 向量库:Chroma 本地模式占用很小;Milvus、Qdrant 这类独立服务要单独计算内存和磁盘。
- 记忆服务:FastAPI 这类轻量服务占用很小,主要瓶颈在向量检索并发。
观察资源占用的方法:
- GPU 显存:
nvidia-smi -l 2,每隔两秒刷新一次。 - CPU 和内存:
top或htop。 - 向量库磁盘:
du -sh ./memory_db。 - 接口耗时:在记忆服务里给每个查询加计时日志。
如果发现检索速度慢,优先查这几个方向:索引类型是否选对、向量维度是否过大、单次查询返回的 TopK 是否过高、向量库有没有分区。检索慢和大模型推理慢是两回事,先定位瓶颈再调优。
降低显存占用的通用手段包括:模型量化(GGUF/Q4)、使用更小模型、减小上下文长度、关闭非必要工具进程、给 embedding 和推理模型分机部署。具体数值必须以本机实际测试为准,不建议照搬网上的“某某卡占用几 G”的结论。
10. 常见问题与排查方法
| 问题现象 | 可能原因 | 排查方式 | 解决方案 |
|---|---|---|---|
| 模型下载慢或失败 | 网络不稳定、磁盘空间不足 | 检查磁盘剩余空间和网络 | 换镜像源,或用离线文件导入模型 |
| Ollama 端口无法访问 | 服务未启动或端口被占用 | curl 127.0.0.1:11434,lsof -i | 重启服务,或修改OLLAMA_HOST |
| 显存不足导致生成失败 | 模型过大或并发太高 | nvidia-smi查看显存 | 换量化模型,降低并发,减小上下文 |
| 记忆写入成功但检索不到 | 文本切块不合理,或 Embedding 效果差 | 直接打印检索结果,检查关键词 | 调整切块大小,换 Embedding 模型 |
| 检索到的记忆和问题无关 | 向量相似度区分度不够 | 检查 TopK 和阈值 | 加相关性阈值,或给记忆加标签过滤 |
| 批量导入重复数据 | 没有幂等机制 | 查看入库记录 | 按source + content hash去重 |
| 接口调用报 502 或超时 | 服务崩溃或负载过高 | 查看日志、检查并发 | 加负载控制,任务改异步 |
| Agent 任务中断后状态丢失 | 没有做 Checkpoint | 查看是否有持久化状态存储 | 使用 LangGraph Checkpoint 或自建任务状态表 |
排查思路只有一条:先确认服务是否活,再确认数据是否在,最后确认检索链路是否通。不要一上来就怀疑模型能力,大多数记忆失效问题出在存储和拼接阶段。
11. 最佳实践与使用建议
给大模型做记忆,工程上建议遵守下面几条。
第一,记忆和业务数据分离。不要把用户的所有原始聊天记录都塞进记忆库,更不要把密码、密钥、身份证号等敏感信息写入长期记忆。记忆库里只保留“对后续任务有用的摘要化信息”。
第二,权限控制必须前置。不同用户的数据要隔离,查询时带上user_id过滤条件。如果自建服务面向内部使用,至少限制访问 IP 和端口;如果部署在公网,必须加认证。
第三,先小参数测试,再上全量。第一次跑通记忆链路时,用最小模型、最小数据量、单用户测试。链路没有问题后再扩展模型规模和用户量。
第四,保留一个最小可运行配置。把启动 Ollama、启动记忆服务、安装依赖的命令和版本记录成文档。环境坏了可以快速恢复,不用重新踩坑。
第五,定期清理过期记忆。长期记忆不是只增不减。用户偏好会变,业务规则会更新,旧记忆如果不清理,不仅占存储,还可能干扰检索结果。建议给记忆加时间戳,按业务需要做过期策略。
第六,涉及人脸、声音、用户行为、版权内容时,必须确认授权和合规边界。这是底线问题,不是技术问题。大模型记忆系统里如果存了用户的历史对话和偏好,需要履行告知义务并允许用户删除。
12. 总结与下一步
郝建业团队半年内完成三轮融资,说明“给大模型做记忆”已经从一个技术概念变成了被资本认可的基础设施方向。对于技术人来说,这个方向最大的价值在于:它不需要你去训练模型,只需要在模型外面搭一层记忆管理层,就能让大模型在真实业务里“记住”该记住的东西。
这篇文章给出的路线是:用 Ollama 或 vLLM 部署推理模型,用 Embedding + 向量库做长期记忆存储,再用 FastAPI 封装成记忆服务,通过 HTTP 接口接入大模型应用或 Agent 工作流。整套方案可以本地部署,支持批量导入,也支持按用户隔离。
下一步你可以先做三件事:第一,用一个小模型跑通“写入记忆 -> 检索记忆 -> 拼接提示词”的最小闭环;第二,导入你自己的历史对话或文档,抽几条真实问题测试检索准确率;第三,把记忆服务封装成 API,接到你现有的 Agent 或聊天机器人里,观察是否解决了“换会话就失忆”的问题。
最容易踩的坑有两个:一是把长期记忆理解成“所有历史都塞进上下文”,导致成本和效果双双恶化;二是只做存储不做检索质量验证,结果记忆库建好了,真正查询时却拿不到有用信息。先把这两点做好,大模型记忆就算真正落地了。