收敛稳定性风险

This commit is contained in:
2026-05-31 16:27:49 +08:00
parent 49fd9b3130
commit 4388a168f1
31 changed files with 1445 additions and 384 deletions
+7 -6
View File
@@ -488,8 +488,9 @@ AI 回复完成 → idle
配置文件损坏时,不要直接覆盖,先备份为:
```text
app_config.broken.json
ai_config.broken.json
app_config.broken.yyyyMMdd-HHmmss.json
ai_config.broken.yyyyMMdd-HHmmss.json
conversation_history.broken.yyyyMMdd-HHmmss.json
```
然后再生成默认配置。
@@ -1682,8 +1683,8 @@ MIT License 开源
当前仍需补齐:
```text
1. 设置页内 AI 连通性测试
2. 对话历史内存上限和可选持久化
3. 角色包导入和角色切换
4. 发布前素材授权确认与打包验证
1. 角色包导入和角色切换
2. 对话历史导出、搜索或更完整管理界面
3. 发布前素材授权确认与打包验证
4. 长期性能压测记录
```
+33 -16
View File
@@ -120,9 +120,10 @@ error 20 帧
```text
1. character.json 中 base.width/base.height 当前为 512x512
2. 当前实现会预加载当前角色包的全部状态帧,后续需要观察内存和低配设备表现
2. 当前实现已接入状态级懒加载:enableLazyLoad=true 时先保存帧路径,状态首次播放时再加载对应帧
3. 如果项目公开发布或推送远程仓库,需要确认 shiroko 素材版权和再分发权限
4. 版权不明确前,不应把它作为正式开源发布素材承诺
5. 当前已接入主线程分批预热和状态级 LRU 卸载,并避免低缓存上限下的重复预热/卸载循环;尚未做后台线程预热、单帧级缓存和长期压测记录
```
---
@@ -285,7 +286,7 @@ error 20 帧
1. AnimationClip
2. FrameAnimator
3. 使用 QTimer 按 idle fps 播放帧
4. 启动时加载 idle 帧到内存
4. 启动后播放 idle 时加载 idle 帧到内存
5. loop=true 时循环播放
6. 仍然只播放 idle 状态
```
@@ -371,7 +372,7 @@ error 20 帧
5. 保存窗口位置、置顶状态、缩放、性能模式
6. Logger
7. 基础日志轮转
8. 配置损坏时备份为 .broken.json
8. app config、AI config 和 conversation history 损坏时备份为带时间戳的 .broken 文件
```
暂不做:
@@ -470,7 +471,7 @@ error 20 帧
4. Model 为空时有提示
5. 错误 API Key 不崩溃
6. 错误 URL 或超时不崩溃
7. 日志不输出完整 API Key
7. 日志不输出完整 API Key、Authorization Header、完整消息正文和完整错误响应正文
8. 对话历史不会无限增长
```
@@ -496,6 +497,16 @@ error 20 帧
7. 整理发布包
```
发布包排除:
```text
tools/
docs/
reports/
build/
.git/
```
暂不做:
```text
@@ -550,7 +561,9 @@ error 20 帧
7. 阶段 5 稳定性与性能检查:
已做过一轮人工稳定性观察,包括静置、idle 动画、托盘隐藏/显示、重复状态切换和资源损坏兜底
当前尚未形成自动化性能测试或长期压测记录
已新增开发用性能采样脚本 tools/perf_sample.ps1
已新增稳定性检查记录模板 docs/performance_stability_check.md
当前尚未形成长期压测记录
8. 阶段 6 AI 接入:
已新增 LLMProvider / OpenAICompatibleProvider / GoogleGeminiProvider / ConversationManager
@@ -558,25 +571,30 @@ error 20 帧
已支持 Google Gemini generateContent / streamGenerateContent、x-goog-api-key、contents 多轮上下文和 systemInstruction
已支持 SSE 流式输出,气泡中流式显示,历史面板只记录最终对话
已限制同一时间只允许一个 AI 请求
已避免在日志中输出完整 API Key 和完整消息正文
已避免在日志中输出完整 API Key、Authorization Header、完整消息正文和完整错误响应正文
9. 阶段 7 UI 基础优化:
已新增 ChatBubble、ChatInputDialog、ChatHistoryPanel、SettingsDialog
已支持右键聊天、显示对话、取消 AI 请求、清空对话、设置
已删除临时 AI 测试入口和气泡测试入口
已将 AI 连通性测试迁移到设置页
已支持 OpenAI / Google / DeepSeek / Custom 配置分 Provider 保存
已移除废弃 Provider 配置入口,并在读取旧配置时清理废弃 Provider 配置
已支持应用设置页:缩放、性能模式、隐藏暂停、懒加载
将 AppConfig 的 scale / performanceMode / pauseWhenHidden / enableLazyLoad 接入运行时
已支持内存历史上限和可选本地历史保存
支持应用设置页:缩放、性能模式、隐藏暂停、懒加载、动画预热、动画缓存上限、隐藏时释放动画缓存
已将 AppConfig 的 scale / performanceMode / pauseWhenHidden / enableLazyLoad / enableAnimationPrewarm / animationCacheLimitMb / unloadAnimationsWhenHidden 接入运行时
懒加载当前为状态级首次播放加载,并已接入主线程分批预热和状态级 LRU 卸载;单轮预热不会反复重新加载刚被 LRU 卸载的状态
Windows 下 API Key 使用 DPAPI 加密保存,非 Windows 需用户确认后才允许明文保存
运行时资源优先读取可执行文件同级 resources/,找不到时回退到源码目录 resources/
```
当前实现与计划仍存在差异:
```text
1. SettingsDialog 仍是最小设置界面,尚未包含完整角色切换流程和更完整的分区布局
2. ConversationManager 请求上下文会截取最近 12 条历史,但内存中的 m_history 尚未做最大长度裁剪
3. README 和开发文档已开始同步当前进度,但仍需随功能继续维护
2. 对话历史已有内存上限和可选本地保存,但尚未提供导出、搜索或完整管理界面
3. 状态级懒加载尚未包含后台线程预热、单帧级缓存和长期压测记录
4. README 和开发文档已开始同步当前进度,但仍需随功能继续维护
```
---
@@ -596,9 +614,7 @@ error 20 帧
- 等待阶段拖动松开应回到 think
- 收到首段回复后应进入 talk
- 长文本流式输出期间应持续 talk
3. 给 ConversationManager 增加内存历史上限,避免长期对话无限增长
4. 把 AI 测试能力迁移到后续设置页,不再放在角色右键菜单
5. 用户手测应用设置:
3. 用户手测应用设置:
- 缩放比例
- 标准 / 低功耗性能模式
- 隐藏到托盘时暂停动画
@@ -611,7 +627,8 @@ error 20 帧
1. 完善设置界面:
- AI 配置和测试
- 角色包导入和角色切换
2. 补一轮可重复的稳定性与性能测试记录
2. 使用 tools/perf_sample.ps1 补一轮可重复的稳定性与性能测试记录
3. 使用 tools/perf_sample.ps1 验证状态级 LRU 卸载、主线程分批预热和动画缓存上限策略
```
---
@@ -622,6 +639,6 @@ error 20 帧
```text
1. shiroko 素材是否允许作为正式开源发布素材继续保留在仓库中
2. 设置页下一步先做 AI 测试入口,还是先做角色包配置
3. 是否需要把对话历史持久化保存,还是第一版只保留内存会话
2. 设置页下一步先完善角色包配置,还是先补发布打包配置
3. 对话历史后续是否需要导出、搜索或按角色/Provider 分组管理
```
+107
View File
@@ -0,0 +1,107 @@
# 性能与稳定性检查记录
本文档用于记录可重复的阶段性性能与稳定性检查。采样脚本和本记录只面向开发与回归测试,不进入普通用户发布包。
## 测试环境
| 项目 | 内容 |
| --- | --- |
| 测试日期 | TODO |
| Git commit | TODO |
| 构建类型 | TODO: Debug / Release |
| 操作系统 | TODO |
| CPU | TODO |
| 内存 | TODO |
| 显示器 / DPI | TODO |
| Qt 版本 | TODO |
| 角色包 | `resources/characters/shiroko` |
| AppConfig 关键项 | scale=TODO, performanceMode=TODO, pauseWhenHidden=TODO, enableLazyLoad=TODO, enableAnimationPrewarm=TODO, animationCacheLimitMb=TODO, unloadAnimationsWhenHidden=TODO |
## 采样脚本
默认采样当前 `QtDesktopPet` 进程 5 分钟,每 5 秒一条:
```powershell
powershell -NoProfile -ExecutionPolicy Bypass -File tools/perf_sample.ps1
```
指定 PID 采样:
```powershell
powershell -NoProfile -ExecutionPolicy Bypass -File tools/perf_sample.ps1 -Pid 12345 -DurationSeconds 600
```
输出目录默认是:
```text
reports/perf/
```
`reports/perf/` 已加入 `.gitignore`。需要沉淀结论时,只把摘要写入本文档,不提交原始采样 CSV。
## 检查项
| 场景 | 步骤 | 采样命令 | 预期结果 | 实际结果 | 结论 | 备注 |
| --- | --- | --- | --- | --- | --- | --- |
| 启动后静置 | 启动程序后不操作 5 分钟 | `tools/perf_sample.ps1` 默认参数 | CPU 保持低占用,内存无持续上涨 | TODO | TODO | TODO |
| idle 连续播放 | 保持桌宠可见并播放 idle 10 分钟 | `tools/perf_sample.ps1 -DurationSeconds 600` | 动画持续播放,内存曲线稳定 | TODO | TODO | TODO |
| 隐藏到托盘 | 可见采样 3 分钟,隐藏后再采样 3 分钟 | 两次采样分别记录 | 隐藏后 CPU 下降或保持低占用 | TODO | TODO | TODO |
| 重复显示 / 隐藏 | 连续显示/隐藏 10 次 | `tools/perf_sample.ps1 -DurationSeconds 300` | 无崩溃,句柄数和内存无异常增长 | TODO | TODO | TODO |
| 重复切换状态 | 通过右键状态测试切换 `idle/think/talk/error/drag` | `tools/perf_sample.ps1 -DurationSeconds 300` | 首次切换状态允许加载资源,缓存达到上限后按 LRU 卸载非保护状态 | TODO | TODO | 结合日志确认加载/卸载记录 |
| 动画预热与卸载 | 默认配置启动后静置,随后隐藏到托盘再显示 | `tools/perf_sample.ps1 -DurationSeconds 600` | 日志出现有限次分批预热;隐藏后非保护动画缓存释放;显示后不会反复预热刚被卸载的状态 | TODO | TODO | 不应影响当前播放状态恢复 |
| 缩放 / 置顶切换 | 设置页切换缩放,右键切换置顶 | `tools/perf_sample.ps1 -DurationSeconds 300` | 窗口尺寸和状态稳定,无崩溃 | TODO | TODO | TODO |
| AI 对话 | 连续发送 20 轮短消息 | `tools/perf_sample.ps1 -DurationSeconds 900` | 请求期间 UI 不阻塞,内存不持续上涨;日志不包含完整消息正文、API Key 或完整错误响应正文 | TODO | TODO | 使用错误 Key/Base URL 时检查脱敏摘要 |
| 配置损坏兜底 | 备份后分别破坏 app 配置、AI 配置或本地聊天记录再启动 | 启动后采样 3 分钟 | 程序恢复默认配置或忽略损坏历史,并生成带时间戳的 broken 备份,不覆盖旧备份 | TODO | TODO | 使用备份副本测试 |
| 角色包损坏兜底 | 使用临时复制的损坏角色包测试 | 启动后采样 3 分钟 | 程序不崩溃,回退 preview 或默认显示 | TODO | TODO | 不直接破坏仓库内默认角色包 |
## 懒加载现状
当前实现是状态级懒加载、主线程分批预热和 LRU 卸载:
```text
1. enableLazyLoad=true 时,构建 AnimationClip 只保存帧路径
2. 某个状态首次播放时调用 ensureLoaded() 加载该状态帧
3. enableAnimationPrewarm=true 时,启动后在主线程按批次预热常用状态
4. 已加载状态按状态级 LRU 策略管理,超过 animationCacheLimitMb 时卸载非保护状态
5. 单轮预热记录会避免反复重新加载刚被 LRU 卸载的状态
6. unloadAnimationsWhenHidden=true 时,隐藏到托盘会释放非保护动画缓存
7. enableLazyLoad=false 时,仍保持启动阶段加载全部状态帧的兼容行为
```
尚未实现:
```text
1. 后台线程预热
2. 单帧级缓存
3. 自动化长期压测记录
```
## 发布包说明
普通用户发布包不包含:
```text
tools/
docs/
reports/
build/
.git/
```
普通用户发布包应包含运行必需内容:
```text
QtDesktopPet.exe
Qt 运行时依赖
resources/characters/
resources/icons/
LICENSE
README.md
```
运行时资源查找顺序:
```text
1. QtDesktopPet.exe 同级 resources/
2. 开发源码目录 resources/
```