AI Agent(学习五-长期记忆(向量库 + FAISS))

上一篇加了Memory,但是由于是短期记忆,所以有很多限制,从这篇开始,我们学习长期记忆,长期记忆(向量库 + FAISS) 是 Agent 从「聊天玩具」➡「可成长系统」的分水岭

一、概念

长期记忆:把“重要信息”存成向量,需要时再自动找回来

比如:

你:我叫wp

(5天后)

你:我叫什么

Agent: 你好,wp

二、整体架构

用户输入
   ↓
短期 Memory(对话上下文)
   ↓
向量检索(FAISS,找相关历史)
   ↓
拼 Prompt
   ↓
LLM 决策 / Tool / 回复

三、安装依赖

pip install faiss-cpu langchain-community sentence-transformers
  • faiss-cpu:本地向量库
  • sentence-transformers:免费嵌入模型(不用 OpenAI)

四、长期记忆模块

将上一篇短期Memory的代码复制过来,创建一个新的文件main4.py,然后在上面进行修改

1、初始化向量库(程序启动一次)

from langchain_community.embeddings import HuggingFaceEmbeddings
from langchain_community.vectorstores import FAISS
# ===== 长期记忆(向量库) =====
embedding_model = HuggingFaceEmbeddings(
    model_name="sentence-transformers/all-MiniLM-L6-v2"
)
vector_store = FAISS.from_texts(
    texts=["系统初始化占位文本"],
    embedding=embedding_model
)

这个逻辑的作用是:

用一个“文本 → 向量”的模型,创建一个“可以用语义搜索文本的长期记忆库(FAISS)”。

  • 选择一个 免费的语义向量模型
  • 把一句话变成一串数字(向量)

比如:

"我叫wp" -> [0.12,-0.33,0.88,..]

第二句:

vector_store = FAISS.from_texts(
    texts=["系统初始化占位文本"],
    embedding=embedding_model
)

注意:我开始写的是:texts=[],建立一个空的向量库,但是报错了,后面加了一个初始化占位文本

这句作用:

  • 用FAISS创建一个向量数据库
  • 每条文本会:
    • 先用 embedding_model 变成向量
    • 再存进 FAISS 里

整体架构:

文本
 ↓
Embedding 模型(理解语义)
 ↓
向量
 ↓
FAISS(存 + 查相似内容)

2、写入长期记忆

规则:不是所有的话都存,只存:事实性/用户信息

def save_long_term_memory(text: str):
    vector_store.add_texts([text])

这个就是存储内容:

save_long_term_memory("用户叫wp")
save_long_term_memory("用户在北京从事 Java 后端开发")

3、检索长期记忆

这个就是给Agent用的

def search_long_term_memory(query: str, k: int = 3) -> str:
    docs = vector_store.similarity_search(query, k=k)
    if not docs:
        return ""
    result = "以下是你过往的重要信息:\n"
    for doc in docs:
        result += f"- {doc.page_content}\n"
    return result

这段逻辑它会把当前用户输入转成向量,在 FAISS 向量库中检索语义最相近的历史事实,
再作为上下文的一部分注入到 Prompt 中,辅助大模型理解用户意图。

4、把长期记忆接入 Agent(核心)

修改原有的agent_run

def agent_run(user_input: str) -> str:
    #取短期记忆(最近对话)
    short_memory = render_memory()
    #查长期记忆(历史事实)
    long_memory = search_long_term_memory(user_input)
		#构造 Prompt(关键设计)
    prompt = (
        long_memory
        + short_memory
        + ROUTER_PROMPT
        + "用户输入:\n"
        + user_input
    )
		#模型做「是否用 Tool」的决策-这是Agent和普通Chat的本质区别
    decision_msg = llm.invoke(prompt)
    decision_text = decision_msg.content.strip()
		#JSON 解析失败 → 降级兜底
    try:
        decision = json.loads(decision_text)
    except json.JSONDecodeError:
        #立刻退化成普通聊天
        reply_msg = llm.invoke(long_memory + short_memory + user_input)
        reply = reply_msg.content

        add_to_memory("用户", user_input)
        add_to_memory("Agent", reply)
        return reply
		#解析 Tool 决策
    tool_name = decision.get("tool")
    tool_input = decision.get("input", "")
		#执行 Tool(程序做事)
    if tool_name in TOOLS:
        result = TOOLS[tool_name](tool_input)
        #更新短期记忆(无论哪种路径)
        add_to_memory("用户", user_input)
        add_to_memory("Agent", result)
        return result
		#普通对话路径(不用 Tool)
    reply = tool_input

    # ⭐ 判断是否值得写入长期记忆(简单规则)
    if "我叫" in user_input or "我是" in user_input:
        save_long_term_memory(user_input)

    add_to_memory("用户", user_input)
    add_to_memory("Agent", reply)
    return reply

这个逻辑:把短期记忆、长期记忆和当前用户输入组合成 Prompt,让模型决定是否调用工具,并在每一步维护记忆。

顺序(你是谁、你记得什么、你能用什么、现在要干嘛):

  1. 长期记忆(背景事实)
  2. 短期记忆(对话上下文)
  3. 路由规则(工具选择约束)
  4. 当前输入(最新意图)

这段代码架构:

            用户输入
                ↓
    ┌────────────────────┐
    │   长期记忆(FAISS) │
    └────────────────────┘
                ↓
    ┌────────────────────┐
    │   短期记忆(上下文)│
    └────────────────────┘
                ↓
    ┌────────────────────┐
    │  LLM 决策(Router) │
    └────────────────────┘
        ↓           ↓
     Tool 执行    直接回答
        ↓           ↓
        └──── 更新 Memory ────┘

五、运行与测试

运行:

python main4.py

测试

你:我叫wp
Agent: 你好,wp
你:你好啊
Agent: 你也好,wp
你:我的名字是啥来着
Agent: 你叫wp
你:我在北京从事JAVA后端开发
Agent: 很好,wp,你在北京从事JAVA端开发,很不错的职业选择。

不是关键词匹配,而是向量语义

Logo

Agent 垂直技术社区,欢迎活跃、内容共建。

更多推荐