> 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/convai-unity-sdk/features/long-term-memory/troubleshooting-and-diagnostics.md).

# 排查长期记忆问题

大多数 LTM 问题可归为三类：记忆在会话之间没有持久化、错误的用户收到了记忆，以及 API 调用因 HTTP 错误而失败。请先按照下面的诊断流程排查，再查看参考表。

***

### 第一线排查

在检查其他任何内容之前，请按顺序完成以下三个步骤：

**1. 确认角色已启用记忆**

在以下位置登录 [convai.com](https://convai.com)，打开角色，并验证 **Memory** 选项卡显示 **长期记忆：开启**。记忆默认是禁用的——这是 LTM 看起来不起作用的最常见原因。

**2. 验证终端用户 ID 在各会话之间保持稳定**

将下面的诊断脚本添加到你的场景中。运行 Play Mode，停止，然后再次运行。两次记录的 ID 必须完全相同。

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

public class EndUserIdDebug : MonoBehaviour
{
    private void Start()
    {
        var provider = new DeviceEndUserIdProvider();
        string id = provider.GetEndUserId();
        Debug.Log($"[LTM] 本次会话的 end_user_id: {id}");
    }
}
```

如果两次会话之间 ID 发生变化，记忆就无法累积——服务器会把每个新 ID 当作新用户。

**3. 确认会话已成功连接**

检查 Console 中的 Convai 启动消息。连接失败（无效 API 密钥、网络错误）会阻止所有 LTM 操作，无论已存储的数据如何。

***

### 决策流程

当记忆没有持久化时，请使用此流程：

```mermaid
graph TD
    A[角色仪表板上已启用 LTM？] -->|否| B[在 convai.com 启用并重试]
    A -->|是| C[跨会话记录到的是同一个 end_user_id？]
    C -->|否| D[身份来源正在变化——请参阅常见问题]
    C -->|是| E[会话已成功连接？]
    E -->|否| F[先修复连接问题——API 密钥或网络]
    E -->|是| G[对话中包含值得记住的事实？]
    G -->|否| H[进行更有实质性的对话后重试]
    G -->|是| I[向 Convai 支持提供角色 ID 和会话时间戳]
```

***

### 常见问题

| 症状                      | 可能原因                                     | 修复                                                                                                         |
| ----------------------- | ---------------------------------------- | ---------------------------------------------------------------------------------------------------------- |
| 角色从不引用之前的会话             | 角色未启用 LTM                                | 在角色的 Memory 选项卡中启用它，位于 [convai.com](https://convai.com)                                                    |
| 在编辑器中有效，但在构建中无效         | `DeviceEndUserIdProvider` 在编辑器和构建中返回不同的值 | 预期行为——编辑器使用 `PlayerPrefs` GUID；构建使用设备 ID。确保构建中的设备 ID 稳定。要实现跨上下文一致性，请实现自定义 `IEndUserIdentityProvider`.      |
| 重装后记忆丢失                 | `PlayerPrefs` 在重新安装时被清除                  | 请通过自定义提供程序使用服务器分配的账户 ID。基于设备和基于 GUID 的 ID 不会在重新安装后保留。                                                      |
| 同一设备上的不同用户共享记忆          | 多个用户共用一台设备                               | 每个用户都必须获得唯一的 `end_user_id`。如果 `DeviceEndUserIdProvider` 正在使用时，设备范围的 GUID 会被共享。请实现一个自定义提供程序，返回每个用户的账户 ID。   |
| 自定义提供程序未生效              | 提供程序在之后注册 `ConnectAsync`                 | 请在 `Awake()`中注册，早于 `ConvaiRoomManager.Start()` 完成。如果 `ConvaiCharacter` 具有 **自动连接** 已启用， `Start()` 可能已经太晚了。 |
| 记忆事实看起来不正确或已过时          | 测试记录残留                                   | 使用 `client.Memory.DeleteAllAsync` 在开始新的评估之前清除测试数据。                                                         |
| `GetEndUserId()` 返回空字符串 | 自定义提供程序返回 null 或空白                       | SDK 在发送前会将 null/空白规范化为 `null` ，从而导致匿名会话。请确保你的提供程序始终返回非空值。                                                  |

***

### 运行时诊断

#### 列出某用户的所有记忆

使用此脚本确认服务器已存储的内容。通过在 Inspector 中右键 → **列出记忆**.

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

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

    [ContextMenu("列出记忆")]
    private async void ListMemories()
    {
        var provider = new DeviceEndUserIdProvider();
        string endUserId = provider.GetEndUserId();

        Debug.Log($"[LTM] 正在查询 end_user_id 的记忆：{endUserId}");

        using var client = new ConvaiRestClient(ConvaiSettings.Instance.ApiKey);

        int page = 1;
        bool hasMore = true;

        while (hasMore)
        {
            var response = await client.Memory.ListAsync(_characterId, endUserId, page);

            Debug.Log($"[LTM] 第 {page} 页 — {response.Memories.Count} 条记录（总计：{response.TotalCount}）");

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

            hasMore = response.HasMore;
            page++;
        }

        if (page == 1)
            Debug.Log("[LTM] 未找到此用户-角色组合的记忆记录。");
    }
}
```

#### 检查记忆启用状态

以编程方式确认角色当前是否已启用 LTM。

```csharp
[ContextMenu("检查记忆是否启用")]
private async void CheckMemoryEnabled()
{
    using var client = new ConvaiRestClient(ConvaiSettings.Instance.ApiKey);

    bool isEnabled = await client.Characters.GetMemoryEnabledAsync(_characterId);
    Debug.Log($"[LTM] 角色 '{_characterId}' 已启用记忆：{isEnabled}");
}
```

***

### API 错误代码

所有 Memory Management API 错误都会抛出 `ConvaiRestException`。该 `StatusCode` 属性对应下面的原因。

| HTTP 状态码      | 原因                                                 | 修复                                                                                                                      |
| ------------- | -------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------- |
| `400 错误请求`    | 缺少必需参数（`character_id`, `end_user_id`，或 `memories`) | 在调用之前，请确认所有必需参数都非空且非空字符串                                                                                                |
| `401 未授权`     | API 密钥无效或缺失                                        | 重新配置你的 API 密钥——请参阅 [配置 API 密钥](/api-docs/zh/cha-jian-yu-ji-cheng/convai-unity-sdk/getting-started/configure-api-key.md) |
| `403 禁止访问`    | 该角色不属于拥有该 API 密钥的账户                                | 验证角色 ID 是否属于与你的 API 密钥关联的账户                                                                                             |
| `404 未找到`     | 无效的角色 ID、终端用户 ID 或记忆 ID                            | 请对照 Convai 仪表板仔细核对这些 ID。如果按 `memoryId`查询，请从之前的 `ListAsync` 调用。                                                          |
| `429 请求过多`    | 超过速率限制                                             | 请实现指数退避。例如：在 `2^attempt` 秒后重试，配合 `CancellationToken` 在达到最大重试次数后中止。                                                      |
| `500 内部服务器错误` | 瞬时服务器错误                                            | 请在短暂延迟后重试请求。如果错误持续存在，请查看 Convai 状态页面，并携带你的角色 ID 和时间戳联系支持。                                                               |

#### 指数退避模式

```csharp
using System;
using System.Threading;
using System.Threading.Tasks;
using Convai.RestAPI;

public static class MemoryRetryHelper
{
    public static async Task<T> WithRetry<T>(
        Func<Task<T>> operation,
        int maxAttempts = 3,
        CancellationToken cancellationToken = default)
    {
        for (int attempt = 0; attempt < maxAttempts; attempt++)
        {
            try
            {
                return await operation();
            }
            catch (ConvaiRestException ex) when (ex.StatusCode == 429 || ex.StatusCode == 500)
            {
                if (attempt == maxAttempts - 1) throw;

                int delayMs = (int)Math.Pow(2, attempt) * 1000;
                await Task.Delay(delayMs, cancellationToken);
            }
        }

        throw new InvalidOperationException("无法到达。");
    }
}
```

***

### 下一步

{% content-ref url="/pages/9c55a31cd790424665e521972bff5affc2dbe7f9" %}
[长期记忆脚本参考](/api-docs/zh/cha-jian-yu-ji-cheng/convai-unity-sdk/features/long-term-memory/long-term-memory-scripting-reference.md)
{% endcontent-ref %}

{% content-ref url="/pages/b54beab8714c42a31356b3abe240c02692f3d79b" %}
[为角色配置记忆](/api-docs/zh/cha-jian-yu-ji-cheng/convai-unity-sdk/features/long-term-memory/configure-memory-for-a-character.md)
{% endcontent-ref %}


---

# 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/convai-unity-sdk/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.
