> For the complete documentation index, see [llms.txt](https://docs.convai.com/api-docs/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.convai.com/api-docs/zh/cha-jian-yu-ji-cheng/unity-plugin-beta-overview/features/long-term-memory/troubleshooting-and-diagnostics.md).

# 故障排查与诊断

## 诊断并解决长期记忆问题

大多数长期记忆问题都属于以下三类之一：记忆未在会话之间保留、错误的用户接收到了记忆，或者 API 调用失败。本页提供了一个结构化检查清单、针对最常见失败路径的决策树，以及每个已知问题的参考表。

## 首要排查

在深入查看具体症状之前，请先按此检查清单逐项排查。大多数问题会在第 1 步或第 2 步得到解决。

{% stepper %}
{% step %}
**确认角色已启用记忆**

打开 [Convai 控制台](https://convai.com)，选择角色，然后导航到 **记忆 → 记忆设置**。验证 **长期记忆** 开关已开启。

记忆是 **默认关闭**。除非您明确启用，否则不会存储或检索任何内容。这是 LTM 看起来不起作用的最常见原因。
{% endstep %}

{% step %}
**验证 end\_user\_id 在会话之间是否保持稳定**

添加一个临时的 `Debug.Log` 以确认相同的 `end_user_id` 在每个会话中都会发送：

```csharp
using Convai.Runtime.Identity;
using UnityEngine;

public class IdentityDebugger : MonoBehaviour
{
    private void Awake()
    {
        string id = new DeviceEndUserIdProvider().GetEndUserId();
        Debug.Log($"[LTM] end_user_id for this session: {id}");
    }
}
```

运行 Play Mode 两次并比较日志中的 ID。如果 ID 在会话之间发生变化，记忆将不会保留——请参阅 End-User Identity 以了解原因及修复方法。
{% endstep %}

{% step %}
**检查会话是否成功连接**

长期记忆需要一个处于活动状态的 Convai 会话。如果 `ConvaiManager` 连接失败——API 密钥错误、没有互联网连接、服务器不可达——则无论后端存储了什么，角色都无法接收记忆上下文。

打开 Unity Console，查找来自 `ConvaiManager`的连接错误。在排查记忆问题之前先解决这些错误。
{% endstep %}
{% endstepper %}

## 记忆未持久保存——决策树

```mermaid
flowchart TD
    A[记忆未持久保存] --> B{角色上已启用\n记忆吗？}
    B -- 否 --> C[在控制台中启用：\n记忆 → 记忆设置]
    B -- 是 --> D{两个会话中的\nend_user_id 相同吗？}
    D -- 否 --> E[会话之间的身份已更改。\n请参阅 End-User Identity 页面]
    D -- 是 --> F{会话是否\n成功连接？}
    F -- 否 --> G[先修复连接错误。\n检查 Console 中的错误]
    F -- 是 --> J{对话是否\n包含可记忆的事实？}
    J -- 否 --> K[清晰说出：姓名、角色、\n偏好、目标——AI 可以提取的事实]
    J -- 是 --> L[检查 end_user_id 是否与\nMemoryService 使用的值一致。\n使用 ListAsync 列出记忆]
```

## 常见问题

| 症状                             | 可能原因                            | 修复                                                                                            |
| ------------------------------ | ------------------------------- | --------------------------------------------------------------------------------------------- |
| 角色从不回忆任何内容                     | 角色上未启用记忆                        | 在 Convai 控制台中启用： **记忆 → 记忆设置 → 长期记忆**                                                         |
| 记忆在编辑器中可用，但在玩家构建中不可用           | 玩家构建中的设备标识符不同                   | 这是预期行为——玩家构建使用 `SystemInfo.deviceUniqueIdentifier`。请在同一设备上测试。                                 |
| 所有设备共享同一角色记忆                   | 相同的 `end_user_id` 对所有用户都相同      | 每个用户都需要一个唯一标识符。实现一个自定义 `IEndUserIdentityProvider`。请参阅 End-User Identity。                      |
| 重新安装后，玩家没有记忆                   | `PlayerPrefs` 重新安装时 GUID 被清除    | 这是 GUID 回退的预期行为。若要实现跨安装的持久记忆，请使用由服务器支持的身份（账户 ID）。                                             |
| 来自 Play Mode 的记忆出现在生产构建中       | 编辑器和生产环境使用相同的角色 ID              | 为开发/测试使用单独的角色 ID，这样编辑器测试数据就不会污染生产记忆。                                                          |
| 角色回忆起本应已删除的旧记忆                 | `DeleteAllAsync` 在重新启用之前未被调用    | 调用 `MemoryService.DeleteAllAsync(characterId, endUserId)` 以清除该分区。                             |
| `end_user_id` 在日志中为 null       | 身份提供器返回空字符串                     | `DeviceEndUserIdProvider` 会回退为 GUID——它永远不会返回 null。如果您使用的是自定义提供器，请确保 `GetEndUserId()` 返回非空字符串。 |
| API 调用抛出 401 Unauthorized      | API 密钥无效或缺失                     | 请验证 **工具 → Convai → 配置**。确保 `ConvaiSettings.Instance.ApiKey` 在运行时不为空。                         |
| API 调用抛出 404 Not Found         | 角色 ID 或 end\_user\_id 错误        | 确认来自 `ConvaiCharacter` Inspector。确认 `end_user_id` 来自一个 `Debug.Log` 在调用 API 之前。                |
| `AddAsync` 返回 `Event = "NONE"` | 事实是现有记忆的重复项                     | 服务器会去重。该事实已存储——无需操作。                                                                          |
| `ListAsync` 返回空列表              | 尚未存储任何记忆，或者使用了不同的 end\_user\_id | 请验证 `end_user_id` 与会话发送的值一致。记忆只有在至少进行过一次对话会话后才会创建。                                            |
| 编辑器工具中的最终用户列表为空                | 尚未有用户连接，或者 API 密钥无效             | 先在 Play Mode 中与一个已启用记忆的角色对话以创建用户记录，然后点击 Refresh。                                              |
| 禁用记忆后，下一个会话仍返回旧记忆              | 禁用后记忆仍然保留                       | 禁用记忆会停止新的累积，但不会删除现有记录。调用 `DeleteAllAsync` 如果需要从头开始，请在禁用前调用。                                   |

## 运行时诊断

### 验证角色已知内容

列出用户-角色对的所有记忆记录，以确认已存储的内容：

```csharp
using System;
using System.Threading;
using Convai.RestAPI;
using Convai.RestAPI.Internal;
using UnityEngine;

public class MemoryDiagnostics : MonoBehaviour
{
    [SerializeField] private string _characterId;

    private ConvaiRestClient _client;

    private void Awake()
    {
        _client = new ConvaiRestClient(ConvaiSettings.Instance.ApiKey);
    }

    private void OnDestroy()
    {
        _client?.Dispose();
    }

    [ContextMenu("转储所有记忆")]
    public async void DumpAllMemories()
    {
        string endUserId = new Convai.Runtime.Identity.DeviceEndUserIdProvider().GetEndUserId();
        Debug.Log($"[LTM Diagnostics] end_user_id: {endUserId}");

        try
        {
            int page = 1;
            int total = 0;

            do
            {
                MemoryListResponse response = await _client.Memory.ListAsync(
                    _characterId, endUserId, page, pageSize: 50);

                foreach (MemoryRecord record in response.Memories)
                {
                    Debug.Log($"  [{record.Id[..8]}...] {record.Memory}");
                    total++;
                }

                if (!response.HasMore) break;
                page++;

            } while (true);

            Debug.Log($"[LTM Diagnostics] Total memories: {total}");
        }
        catch (Exception e)
        {
            Debug.LogError($"[LTM Diagnostics] {e.Message}");
        }
    }
}
```

将此组件添加到场景中的任意 GameObject 上。在 Inspector 中右键单击该组件标题并选择 **转储所有记忆** 以在不进入 Play Mode 的情况下将每个已存储的事实记录到 Console。

### 以编程方式检查记忆设置

```csharp
[ContextMenu("检查记忆是否启用")]
public async void CheckMemoryEnabled()
{
    try
    {
        bool enabled = await _client.Characters.GetMemoryEnabledAsync(_characterId);
        Debug.Log($"[LTM Diagnostics] Memory enabled for {_characterId}: {enabled}");
    }
    catch (Exception e)
    {
        Debug.LogError($"[LTM Diagnostics] {e.Message}");
    }
}
```

## API 错误参考

| HTTP 状态    | 可能原因                           | 修复                           |
| ---------- | ------------------------------ | ---------------------------- |
| `401 未经授权` | API 密钥缺失、已过期或不正确               | 在 **工具 → Convai → 配置**       |
| `403 禁止访问` | API 密钥没有权限访问该角色                | 确保该角色与 API 密钥属于同一个 Convai 账户 |
| `404 未找到`  | `characterId` 或 `memoryId` 不存在 | 在调用 API 之前记录并验证这些 ID         |
| `429 请求过多` | 超出速率限制                         | 退避后重试；避免在紧密循环中调用记忆 API       |
| 网络异常       | 没有互联网连接，或 Convai 后端不可达         | 检查连接性；在生产环境中实现带指数退避的重试逻辑     |

## 结论

从首要检查清单开始——角色已启用记忆并且稳定的 `end_user_id` 即可解决绝大多数问题。使用 `DumpAllMemories` 诊断功能来确认服务器实际存储了什么，并对照常见问题表排查任何特定症状。如果在完成本指南后问题仍然存在，API 错误参考提供了从 HTTP 状态码到可操作修复方法的映射。


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.convai.com/api-docs/zh/cha-jian-yu-ji-cheng/unity-plugin-beta-overview/features/long-term-memory/troubleshooting-and-diagnostics.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
