---
title: "长期记忆"
---

长期记忆（Long-term Memory）跨会话、跨时间保存重要信息——用户偏好、任务历史、知识要点或长期状态。[短期记忆](/cn/docs/framework/memory/short-term)只在单次会话内有效，而长期记忆让智能体在**不同会话**之间也能记住事实。

为什么需要它：

- 支持跨会话的连续对话体验；
- 让智能体在多次交互中保留学习成果和用户特定信息；
- 减少重复询问，提升满意度与效率；
- 支撑长期策略优化，如个性化推荐或任务追踪。

## 统一入口：`LongTermMemory`

无论用哪种后端，你都只与 `veadk.memory.long_term_memory.LongTermMemory` 打交道。它实现了 Google ADK 的 `BaseMemoryService`，因此可直接作为智能体的记忆服务；同时根据 `backend` 选择并初始化底层实现。

```python
from veadk.memory.long_term_memory import LongTermMemory

ltm = LongTermMemory(backend="viking", app_name="ltm_demo")
```

### 参数

| 参数 | 类型 | 默认值 | 说明 |
| :--- | :--- | :--- | :--- |
| `backend` | `"local" \| "opensearch" \| "redis" \| "viking" \| "mem0"` 或后端实例 | `"opensearch"` | 选择后端实现，也可直接传入一个 `BaseLongTermMemoryBackend` 实例。`viking_mem` 已废弃，自动转为 `viking`。 |
| `backend_config` | `dict` | `{}` | 传给后端构造函数的配置；若不含 `index`，会用 `index` 或 `app_name` 补齐。 |
| `top_k` | `int` | `5` | 检索时返回最相似的片段数量。 |
| `index` | `str` | `""` | 存储记忆所用的索引/集合名。为空时回退到 `app_name`，再为空则用 `default_app`。 |
| `app_name` | `str` | `""` | 拥有该记忆的应用名，常用作数据隔离与 `index` 的回退值。 |
| `user_id` | `str` | `""` | **已废弃**，仅为向后兼容保留。 |

<Callout type="info">
向量类后端（`local`、`opensearch`、`redis`）会对记忆做向量化（embedding），需要安装扩展依赖：`pip install "veadk-python[extensions]"`，并配置 embedding 模型（环境变量前缀 `MODEL_EMBEDDING_`，缺省时复用 `MODEL_AGENT_API_KEY`）。`viking` 与 `mem0` 是托管服务，无需本地 embedding。
</Callout>

## 后端契约：`BaseLongTermMemoryBackend`

所有后端都继承自 `BaseLongTermMemoryBackend`，需实现三个方法：

```python
class BaseLongTermMemoryBackend(ABC, BaseModel):
    index: str

    @abstractmethod
    def precheck_index_naming(self): ...
    """校验 index 命名是否合法。"""

    @abstractmethod
    def save_memory(self, user_id: str, event_strings: list[str], **kwargs) -> bool: ...
    """把记忆写入后端。"""

    @abstractmethod
    def search_memory(self, user_id: str, query: str, top_k: int, **kwargs) -> list[str]: ...
    """从后端按语义检索记忆。"""
```

`LongTermMemory` 负责把会话事件过滤、序列化后交给后端的 `save_memory`，并把 `search_memory` 的结果包装为 ADK 的 `MemoryEntry`。因此**上层使用方式与后端无关**，区别仅在存储介质与检索实现。要自定义后端，继承该基类实现这三个方法，并把实例直接传给 `LongTermMemory(backend=<实例>)`。

## 选择后端

调试可以用 `local`，生产更建议使用 `viking` 或 `mem0`。

| 后端 | 存储 | 依赖 | 适用场景 | 文档 |
| :--- | :--- | :--- | :--- | :--- |
| `local` | 内存向量索引 | `extensions` + embedding | 本地调试 | [本地内存](/cn/docs/framework/memory/long-term/local) |
| `viking` | VikingDB 记忆库（托管） | 火山引擎账号 | 生产推荐 | [VikingDB](/cn/docs/framework/memory/long-term/vikingdb) |
| `mem0` | Mem0 记忆库（托管） | Mem0 API Key | 生产推荐 | [Mem0](/cn/docs/framework/memory/long-term/mem0) |
| `opensearch` | OpenSearch 向量库 | OpenSearch + embedding | 自建向量检索 | [OpenSearch](/cn/docs/framework/memory/long-term/opensearch) |
| `redis` | Redis 向量库 | Redis(RediSearch) + embedding | 自建向量检索 | [Redis](/cn/docs/framework/memory/long-term/redis) |

## 绑定到 Agent

把 `long_term_memory` 传给 `Agent` 后，智能体会**自动获得 `load_memory` 工具**，可在运行时检索过往会话。

```python
from veadk import Agent, Runner
from veadk.memory.long_term_memory import LongTermMemory

APP_NAME = "ltm_demo"
ltm = LongTermMemory(backend="viking", app_name=APP_NAME)

root_agent = Agent(
    name="ltm_agent",
    instruction="回答用户问题。如果答案可能在过往对话里，使用 `load_memory` 工具检索。",
    long_term_memory=ltm,
)
runner = Runner(agent=root_agent, app_name=APP_NAME)
```

## 记忆管理

### 写入：`add_session_to_memory`

会话结束或达到某个节点时，调用异步方法 `add_session_to_memory` 把会话持久化。`LongTermMemory` 会先过滤事件（只保留用户文本事件以提升检索质量），再交给后端写入。

```python
completed_session = await runner.session_service.get_session(
    app_name=APP_NAME, user_id=USER_ID, session_id=SESSION_ID
)
await ltm.add_session_to_memory(completed_session)
```

### 检索：`search_memory`

除了智能体运行时通过 `load_memory` 自动检索，你也可以直接调用异步方法 `search_memory` 做语义搜索，用于调试或自定义 RAG：

```python
response = await ltm.search_memory(
    app_name=APP_NAME,
    user_id=USER_ID,
    query="favorite project",
)
print(response.memories)
```

<Callout type="info">
`get_user_profile(user_id)` 仅 `viking` 后端支持，用于获取用户画像；其他后端会返回空字符串。
</Callout>

## 自动保存会话

在初始化 `Agent` 时开启 `auto_save_session=True` 并配置好长期记忆，VeADK 会自动把会话写入长期记忆，无需手动调用 `add_session_to_memory`。

```python
from veadk import Agent
from veadk.memory.long_term_memory import LongTermMemory

agent = Agent(
    name="ltm_agent",
    auto_save_session=True,
    long_term_memory=LongTermMemory(backend="viking", app_name="ltm_demo"),
)
```

为避免索引被频繁初始化，VeADK 提供 `MIN_MESSAGES_THRESHOLD` 与 `MIN_TIME_THRESHOLD` 两个环境变量自定义保存周期：默认在累计 10 条 event 或间隔 60 秒时触发保存；此外，当切换 `session_id` 并发起新问答时，VeADK 会自动把上一个会话写入长期记忆。

## 跨会话示例

下面是端到端流程：会话 #1 告诉智能体一个事实并自动归档，然后在**全新的**会话 #2 提问——智能体通过检索长期记忆（而非上下文窗口）回忆起该事实。这里用 `local` 后端，需要 `pip install "veadk-python[extensions]"`。

```python
import asyncio

from veadk import Agent, Runner
from veadk.memory.long_term_memory import LongTermMemory

APP_NAME = "ltm_demo"
USER_ID = "user-42"


def build_runner() -> Runner:
    ltm = LongTermMemory(backend="local", app_name=APP_NAME)
    agent = Agent(
        name="ltm_agent",
        instruction=(
            "你是个人助理。当用户问起之前告诉过你的事情时，"
            "使用 `load_memory` 工具去回忆。"
        ),
        long_term_memory=ltm,
        auto_save_session=True,
    )
    return Runner(agent=agent, app_name=APP_NAME, user_id=USER_ID)


async def main() -> None:
    runner = build_runner()

    print(
        "Session 1 ->",
        await runner.run(
            messages="记一下：我对花生过敏，而且我是素食者。",
            session_id="session-1",
        ),
    )

    print(
        "Session 2 ->",
        await runner.run(
            messages="帮我推荐一道适合我的菜，要考虑我的饮食限制。",
            session_id="session-2",
        ),
    )


if __name__ == "__main__":
    asyncio.run(main())
```

智能体能在会话 #2 中识别同一用户在会话 #1 留下的偏好，给出连贯、个性化的回答（如推荐一道无花生的素食菜品）。
