> ## Documentation Index
> Fetch the complete documentation index at: https://docs.veadk.xyz/llms.txt
> Use this file to discover all available pages before exploring further.

# 长期记忆

长期记忆跨会话、跨时间保存重要信息，包括用户偏好、任务历史、知识要点或长期状态。短期记忆按会话恢复历史，长期记忆按查询召回相关内容，而长期记忆让智能体在**不同会话**之间也能记住事实。

为什么需要它：

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

## 统一入口：`LongTermMemory`

无论使用哪种后端，均通过统一的 `veadk.memory.long_term_memory.LongTermMemory` 接入。它可直接作为智能体的记忆服务，并根据 `backend` 选择存储后端。

```python lines theme={null}
from veadk.memory.long_term_memory import LongTermMemory

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

### 参数

| 参数 | 类型 | 默认值 | 说明 |
| :- | :- | :- | :- |
| `backend` | `"local" \| "opensearch" \| "redis" \| "viking" \| "mem0" \| "openviking" \| "tos_context"` | `"opensearch"` | 选择后端。`viking_mem` 已废弃，自动转为 `viking` |
| `backend_config` | `dict` | `{}` | 后端专用配置；若不含 `index`，会用 `index` 或 `app_name` 补齐 |
| `top_k` | `int` | `5` | 检索时返回最相似的片段数量 |
| `index` | `str` | `""` | 存储记忆所用的索引/集合名。不提供 backend\_config 时回退到 `app_name`，再为空则用 `default_app`；提供配置字典时应设置非空 index |
| `app_name` | `str` | `""` | 拥有该记忆的应用名，常用作数据隔离与 `index` 的回退值 |
| `user_id` | `str` | `""` | **已废弃**，仅为向后兼容保留 |

<Note>
  向量类后端（`local`、`opensearch`、`redis`）会对记忆做向量化，需要安装扩展依赖并配置 embedding 模型。`viking`、`mem0`、`openviking` 与 `tos_context` 使用外部服务，无需本地 embedding。
</Note>

## 选择后端

调试可以用 `local`；生产环境可根据已有云服务和数据管理要求选择 `viking`、`mem0` 或 `tos_context`

| 后端 | 存储 | 依赖 | 适用场景 | 文档 |
| :- | :- | :- | :- | :- |
| `local` | 内存向量索引 | `extensions` + embedding | 本地调试 | [本地内存](/productions/veadk/preview/zh/components/memory/local) |
| `viking` | VikingDB 记忆库（托管） | 火山引擎账号 | 托管记忆 | [VikingDB](/productions/veadk/preview/zh/components/memory/vikingdb) |
| `mem0` | Mem0 记忆库（托管） | Mem0 API Key | 托管记忆 | [Mem0](/productions/veadk/preview/zh/components/memory/mem0) |
| `opensearch` | OpenSearch 向量库 | OpenSearch + embedding | 自建向量检索 | [OpenSearch](/productions/veadk/preview/zh/components/memory/opensearch) |
| `redis` | Redis 向量库 | Redis(RediSearch) + embedding | 自建向量检索 | [Redis](/productions/veadk/preview/zh/components/memory/redis) |
| `openviking` | OpenViking 用户记忆 | OpenViking 服务 | 实体、事件与偏好记忆 | [OpenViking](/productions/veadk/preview/zh/components/memory/openviking) |
| `tos_context` | TOS ContextBucket（托管） | 火山引擎账号与 TOS SDK `>=2.9.4b1` | 托管记忆推理与按用户隔离 | [TOS ContextBucket](/productions/veadk/preview/zh/components/memory/tos-context) |

## 绑定到智能体

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

```python lines theme={null}
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` 会根据自动保存策略过滤事件，默认只保留用户文本事件以提升检索质量；你也可以通过 `auto_save_memory_policy` 参数自定义过滤规则，再交给后端写入。

```python lines theme={null}
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)
```

`add_session_to_memory` 接受可选的 `auto_save_memory_policy` 关键字参数，用于覆盖默认过滤策略：

```python lines theme={null}
from veadk.memory import MemoryAutoSavePolicy

await ltm.add_session_to_memory(
    completed_session,
    auto_save_memory_policy=MemoryAutoSavePolicy(preset="all"),
)
```

### 检索：`search_memory`

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

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

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

## 自动保存会话

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

```python lines theme={null}
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 会自动把上一个会话写入长期记忆。

自动保存采用增量写入：每次触发保存时只持久化自上次保存以来新增的事件，而非整个会话。如果两次保存之间没有新事件，则跳过写入。

### 控制保存内容：`auto_save_memory_policy`

`Agent` 接受 `auto_save_memory_policy` 参数，用于控制自动保存时哪些事件会被写入长期记忆。该参数同样作为 `auto_save_memory_policy` 关键字参数传递给 `add_session_to_memory`。

参数类型为 `MemoryAutoSavePolicyInput`，接受以下形式之一：

* 字符串预设值：`"default"`、`"all"` 或 `"custom"`；
* `MemoryAutoSavePolicy` 实例；
* 与 `MemoryAutoSavePolicy` 字段同构的 `dict`；
* `None`（等效于 `"default"`）

| 预设 | 保存内容 |
| :- | :- |
| `"default"` | 仅保存用户角色的文本事件（默认值）。`openviking` 后端因自身限制会同时包含助手角色 |
| `"all"` | 保存所有角色、所有事件类型的全部内容，包括思考内容和空文本 |
| `"custom"` | 以默认策略对象为起点，角色与事件类型不限制，但默认仍排除思考和空文本；显式字段可覆盖这些行为 |

使用预设字符串：

```python lines theme={null}
from veadk import Agent
from veadk.memory.long_term_memory import LongTermMemory

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

使用 `MemoryAutoSavePolicy` 实例进行精细控制：

```python lines theme={null}
from veadk import Agent
from veadk.memory import MemoryAutoSavePolicy
from veadk.memory.long_term_memory import LongTermMemory

agent = Agent(
    name="ltm_agent",
    auto_save_session=True,
    auto_save_memory_policy=MemoryAutoSavePolicy(
        preset="custom",
        include_roles=["user", "assistant"],
        include_event_types=["text", "function_call", "function_response"],
        include_thought=False,
    ),
    long_term_memory=LongTermMemory(backend="viking", app_name="ltm_demo"),
)
```

`MemoryAutoSavePolicy` 的完整字段：

| 字段 | 类型 | 默认值 | 说明 |
| :- | :- | :- | :- |
| `preset` | `"default" \| "all" \| "custom"` | `"default"` | 选择基础预设，未显式覆盖的字段沿用预设值 |
| `include_roles` | `list["user" \| "assistant" \| "system"] \| None` | 取决于预设 | 仅保存这些角色的事件。设为 `None` 表示不按角色过滤 |
| `exclude_roles` | `list["user" \| "assistant" \| "system"]` | `[]` | 排除这些角色的事件 |
| `include_authors` | `list[str] \| None` | 取决于预设 | 仅保存这些作者（`author`）的事件。设为 `None` 表示不按作者过滤 |
| `exclude_authors` | `list[str]` | `[]` | 排除这些作者的事件 |
| `include_event_types` | `list[MemoryEventType] \| None` | 取决于预设 | 仅保存这些事件类型。设为 `None` 表示不按事件类型过滤 |
| `exclude_event_types` | `list[MemoryEventType]` | `[]` | 排除这些事件类型 |
| `text_only` | `bool` | 取决于预设 | 为 `True` 且未显式指定 `include_event_types` 时，仅保留文本和思考类内容 |
| `include_thought` | `bool` | 取决于预设 | 是否保存思考（thought）内容 |
| `include_empty_text` | `bool` | 取决于预设 | 是否保存没有实际内容的空文本事件 |

`MemoryEventType` 包含以下事件类型：`text`、`thought`、`function_call`、`function_response`、`tool_call`、`tool_response`、`media`、`executable_code`、`code_execution_result`、`transcription`、`error`。

<Note>
  预设字符串提供快捷配置。传入 `MemoryAutoSavePolicy` 实例或 `dict` 时，以 `preset` 指定的基础预设为起点，仅显式设置的字段会覆盖预设值，其余字段保持预设的默认行为。
</Note>

## 跨会话示例

先完成[模型配置](/productions/veadk/preview/zh/components/agent/model)和[本地记忆 embedding 配置](/productions/veadk/preview/zh/components/memory/local)，再运行端到端流程：会话 #1 告诉智能体一个事实并自动归档，然后在**全新的**会话 #2 提问，智能体通过检索长期记忆（而非上下文窗口）回忆起该事实。这里用 `local` 后端，需要 `pip install "veadk-python[extensions]"`。

```python lines theme={null}
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 留下的偏好，给出连贯、个性化的回答，如推荐一道无花生的素食菜品。

## 隔离和保存边界

长期记忆不等于永久保存：`local` 只在当前实例内存中保留数据，而且不按用户过滤检索。Mem0 不把 index 当作服务端隔离标识；OpenViking 需要明确 owner/context 和 peer 映射。应按后端说明确定应用与用户隔离，不能仅凭 LongTermMemory 构造参数推断

自动保存的时间阈值不是后台定时任务，进程退出前也不保证触发最后一次保存；对必须保留的信息应主动调用保存并检索验证。`search_memory()` 返回空列表时也可能发生了后端错误。手动重复保存完整会话可能重复写入，自动保存的增量行为不适用于任意重复手动调用

上文记忆管理代码为同一异步流程中的片段：先为 APP\_NAME、USER\_ID、SESSION\_ID 赋值并确认查询得到非空 Session，再调用保存；完整入口见跨会话示例。启用 all 策略会将思考、工具输入输出和媒体信息发送到存储服务，执行前确认这些内容适合保留
