fix: stabilize background operations and large embedding results
This commit is contained in:
@@ -0,0 +1,156 @@
|
||||
# Agent 与任务压测报告
|
||||
|
||||
> 日期:2026-09-06。范围:当前第二阶段 Agent Runtime、任务 API、任务列表及 Trace 组件。测试在 Windows 11、Python 3.12.6、独立无头 Chrome 下执行,前端为 Vite 开发模式,纸间时光版本 1.8.1。
|
||||
|
||||
## 1. 结论
|
||||
|
||||
功能正确性检查通过:Agent 工具调用、事件序号与回放、终态持久化恢复、容量拒绝、取消、权限等待、故障隔离,以及任务增删改查和分页均得到预期结果。性能仍有三项明确问题:
|
||||
|
||||
| 优先级 | 问题 | 本轮证据 | 建议方向 |
|
||||
| --- | --- | --- | --- |
|
||||
| P1 | 任务列表未加载后续页;Agent 历史列表也没有后续分页入口 | 100、1000 条任务的实际页面均只请求 `/api/tasks` 并显示 50 条;Agent store 同样仅调用默认分页一次,接口默认 50 | 增加服务端筛选与分页/加载更多,显示总量,防止统计仅基于已加载项 |
|
||||
| P1 | 高并发 Agent 阻塞事件循环 | 200 并发的完成延迟 P95 约 10.55 秒;进程内心跳最大延迟约 3.56 秒 | 分析同步持久化,设计有界执行调度及顺序写入,保留事件落盘、终态与回放一致性 |
|
||||
| P1 | 大 Trace 的树形筛选长时间阻塞 | 2000 事件树形搜索约 483–617 ms;10000 事件约 25.91 秒 | 为匹配的 sequence/tool/model ID 建 Set,避免逐节点重复遍历事件;再评估分段显示及增量更新 |
|
||||
|
||||
本次新增的是可复现压测与报告,没有把上述生产问题标记为已修复。页面滚动与树形搜索是不同瓶颈:10000 事件的滚动 P95 约 40 ms,并不能说明搜索交互也流畅。
|
||||
|
||||
## 2. 隔离与方法
|
||||
|
||||
- 后端脚本在导入任何 app 模块前,将 `APP_DATA_DIR`、`APP_DB_PATH`、`APP_VAULT_PATH` 指向临时目录,结束后清理;不读写用户 Vault、现有任务及 Provider 凭据。
|
||||
- Agent 使用内置 Mock Provider,每轮模型调用注入 50 ms 异步等待,正常样本包含一次 `system.echo` 工具调用和两轮模型调用;不调用真实厂商,也不衡量回答质量或真实模型吞吐。
|
||||
- 进程内运行直接调用真实 Runtime、SQLite 和任务 ASGI 路由。任务 HTTP 复核另起独立 Uvicorn 进程,用真实回环连接执行,避免将 ASGI 驱动的连续无让出执行误解为网络服务延迟。
|
||||
- 前端挂载真实 TasksView、TraceTimeline 和 Pinia store。压测页拦截全部 fetch,不向真实后端发出请求。任务接口夹具保留默认 50 条分页,先测实际加载条数,再注入完整列表测试渲染上限,两者分开记录。
|
||||
- Trace 由确定性模型开始/完成、工具调用/结果事件组成,带调用与父节点 ID;测量首次渲染、时间线过滤、树形切换、匹配全部节点的树形搜索。
|
||||
- 滚动用 CDP 派发 120 次滚轮事件,记录真实滚动容器及 `maxScrollTop`,防止对未滚动页面统计帧间隔。Trace 测试容器显式解除应用根节点的裁剪,由独立滚动区承担真实 Agent 页滚动容器的职责。
|
||||
|
||||
本轮每个前端配置测一次;开发编译、后台负载、缓存和浏览器调度都会影响结果,数据用于发现瓶颈,不作为生产环境 SLA。首次渲染计时不包含模块下载,包含 Vue 更新及两个 animation frame。
|
||||
|
||||
## 3. Agent 后端
|
||||
|
||||
### 3.1 正常工具调用与回放
|
||||
|
||||
| 并发数 | 运行数 | 完成延迟中位数(ms) | 完成延迟 P95(ms) | 场景心跳最大延迟(ms) |
|
||||
| ---: | ---: | ---: | ---: | ---: |
|
||||
| 1 | 20 | 146.20 | 170.13 | 26.84 |
|
||||
| 10 | 20 | 405.75 | 505.74 | 136.71 |
|
||||
| 50 | 50 | 2234.45 | 2304.42 | 798.84 |
|
||||
| 200 | 200 | 10262.47 | 10554.52 | 3559.97 |
|
||||
|
||||
290 个正常运行全部完成,工具返回内容逐项一致;实时订阅事件序号连续,`after_sequence=2` 回放与原事件后缀一致。新的 Runtime 实例可以从 SQLite 恢复这些终态运行。订阅者集合最终清空,进程内保留记录不超过 200。
|
||||
|
||||
“并发”是同时提交的协程数,不代表独立 CPU 工作线程。当前 queued 是启动前状态,Runtime 并没有把超额活跃运行无限排入执行队列。场景心跳还包含提交、持久化回放与恢复校验,不能将其全部归为模型执行耗时;50、200 并发场景的心跳采样数仅 8 个,表中因此列最大值而非宣称稳定分位数。
|
||||
|
||||
代码定位:`AgentRuntime._publish()` 同步调用 `AgentTraceRepository.append_event()`,后者逐事件连接 SQLite 并提交事务;`connect()` 还加载扩展和检查迁移。这是需要进一步拆分测量的阻塞路径,本轮未完成各子步骤 CPU/磁盘成本归因。
|
||||
|
||||
### 3.2 容量、取消与故障注入
|
||||
|
||||
- 保持 200 个模型调用活跃,第 201 次创建得到 `AgentCapacityError`;随后取消全部 200 个运行,全部进入 cancelled,后台任务均结束。
|
||||
- 20 个运行等待权限:10 个允许后完成,10 个等待中取消,订阅者均释放。
|
||||
- 20 个混合运行:5 个正常完成、5 个 Provider 异常、5 个模型超时、5 个工具超时,均获得预期状态或错误码;工具执行器剩余数量为 0。
|
||||
- 正常回放和故障场景合计创建 530 个运行,临时数据库最终约 2.95 MB。工具超时被记录为 ToolResult 错误,后续 Mock 模型仍可能完成运行,不将它误算为整个 Run 必然失败。
|
||||
|
||||
这里的“恢复”是新 Runtime 读取终态持久化数据,未模拟 OS 强杀时的写入中断。SSE 通过 Runtime 的事件生成器验证序号及断点回放,没有进行真实网络慢读者/断网压力测试。
|
||||
|
||||
## 4. 任务 API
|
||||
|
||||
进程内分别对 100、1000 条任务执行创建、逐页读取、更新为 done、删除,所有 ID 完整,最终总量为 0。默认接口每页 50 条,显式每页 100 条遍历可以取回全部数据。
|
||||
|
||||
ASGITransport 的 1000 条突发操作中,心跳出现约 14 秒延迟:测试客户端与同步路由处于同一事件循环,连续就绪协程缺少网络等待,不能将其视作真实 HTTP 健康检查延迟。因此增加独立 Uvicorn + 回环 HTTP 复核:
|
||||
|
||||
| 操作 | 数量 | P95(ms) | 最大值(ms) |
|
||||
| --- | ---: | ---: | ---: |
|
||||
| 创建 | 1000 | 116.45 | 134.91 |
|
||||
| 更新 | 1000 | 159.29 | 193.37 |
|
||||
| 删除 | 1000 | 156.43 | 190.10 |
|
||||
| 分页/收尾查询 | 11 | 20.96 | 20.96 |
|
||||
| 并行健康检查 | 117 | 157.00 | 195.07 |
|
||||
|
||||
HTTP 客户端并发 20,总耗时约 18.31 秒;健康检查零失败,分页无重复/遗漏,最终任务数为 0。此处是本机单次结果,未覆盖跨网络、长期持久负载或多进程同时写同一数据库。
|
||||
|
||||
## 5. 前端
|
||||
|
||||
### 5.1 任务列表
|
||||
|
||||
100、1000 条数据的实际加载阶段都只有一次 `/api/tasks` 请求,store 中均为 50 条。以下是额外注入完整 1000 条数据后的结果,不是生产页面当前可以加载 1000 条的证明。
|
||||
|
||||
| 主题 | 完整列表渲染(ms) | 完成状态筛选(ms) |
|
||||
| --- | ---: | ---: |
|
||||
| 默认浅色 | 117.4 | 44.1 |
|
||||
| 默认深色 | 137.8 | 47.8 |
|
||||
| 纸间时光 1.8.1 | 150.0 | 59.5 |
|
||||
|
||||
1000 条列表约 11007 个 DOM 节点,实际滚动最远达到 81000 px;筛选 done 得到 334 条,与夹具期望一致。100 条样本筛选得到 34 条,也一致。默认浅色的 1000 条滚动 P95 约 30.2 ms,纸间时光约 50.1 ms;样本数少,暂不据此认定新的单一 CSS 根因。
|
||||
|
||||
### 5.2 Agent Trace
|
||||
|
||||
| 事件数/主题 | 首次渲染(ms) | 时间线搜索(ms) | 树形切换(ms) | 树形全匹配搜索(ms) |
|
||||
| --- | ---: | ---: | ---: | ---: |
|
||||
| 2000 / 默认浅色 | 283.8 | 97.4 | 64.0 | 617.2 |
|
||||
| 2000 / 默认深色 | 289.0 | 74.5 | 62.9 | 483.0 |
|
||||
| 2000 / 纸间时光 | 337.3 | 86.3 | 62.1 | 540.1 |
|
||||
| 10000 / 纸间时光 | 1803.9 | 582.8 | 317.5 | 25914.8 |
|
||||
|
||||
200 事件的树形搜索约 20–29 ms。2000 事件时间线约 20542 个 DOM 节点,10000 事件约 102542 个。查询“压力测试 1”分别命中 444、4444 条事件,与直接检查输入数据的结果一致;树形搜索“压力测试”匹配所有事件,会自动展开匹配子树。
|
||||
|
||||
代码定位:`TraceTimeline.filteredTree` 为每个节点调用 `filteredEvents.some(...)`。节点数和匹配事件数一起增加时,会产生近似二次增长的匹配工作,随后还需构造并渲染展开子树。建议先用匹配 ID 集合消除嵌套扫描,再测 DOM 更新成本;不要仅用防抖隐藏单次 25 秒阻塞。
|
||||
|
||||
10000 是扩大数据规模的诊断测试,高于 Runtime 默认内存事件保留量 2000;它直接向组件传入事件,不代表当前单次 API 页或实时 store 默认会收到这一数量。也未覆盖逐事件 SSE 增量刷新的端到端成本。
|
||||
|
||||
## 6. 复现与原始数据
|
||||
|
||||
```powershell
|
||||
# 后端:独立临时数据,离线 Mock
|
||||
backend/.venv/Scripts/python.exe backend/scripts/agent-task-stress.py --output .local-plans/agent-task-backend.json
|
||||
# 真实 HTTP:独立 Uvicorn、随机回环端口
|
||||
backend/.venv/Scripts/python.exe backend/scripts/task-http-stress.py --count 1000 --concurrency 20 --output .local-plans/task-http.json
|
||||
# 前端:先启动独立 Vite,另一个终端执行后续命令
|
||||
npm --prefix frontend run dev -- --port 5175 --strictPort
|
||||
backend/.venv/Scripts/python.exe frontend/tests/performance/run-stress.py --url 'http://127.0.0.1:5175/tests/performance/agent-task.html?kind=tasks&theme=paper-moments' --scroll --sizes 100 1000 --runs 1 --output .local-plans/task-ui.json
|
||||
backend/.venv/Scripts/python.exe frontend/tests/performance/run-stress.py --url 'http://127.0.0.1:5175/tests/performance/agent-task.html?kind=trace&theme=paper-moments' --scroll --sizes 200 2000 10000 --runs 1 --output .local-plans/trace-ui.json
|
||||
```
|
||||
|
||||
URL 的 theme 可换为 light、dark。测试应串行运行,避免不同负载相互争用;10k Trace 树形筛选可能长时间占用测试浏览器。浏览器使用临时用户目录,不接管用户当前浏览器。
|
||||
|
||||
- [Agent 与进程内任务 API 数据](performance/2026-09-06-agent-task-backend.json)
|
||||
- [真实 HTTP 任务数据](performance/2026-09-06-task-http.json)
|
||||
- [前端 13 组样本数据](performance/2026-09-06-agent-task-ui.json)
|
||||
- [前端压测工具](../../frontend/tests/performance/README.md)
|
||||
|
||||
附加回归:`test_agent_core.py`、`test_api.py` 共 26 项通过。脚本中的状态、序号、输出、分页与筛选断言均通过。未提交或推送本次材料。
|
||||
|
||||
## 7. 修复后复测(2026-09-06)
|
||||
|
||||
以上保留首次压测基线。本节对应后台 Trace 批量写入、任务后台写入、完整列表加载、Trace 集合匹配/分页和统一日志接入后的实现。样本开启新操作日志,仍只调用隔离 Mock。
|
||||
|
||||
| 项目 | 修复前 | 修复后 |
|
||||
| --- | ---: | ---: |
|
||||
| 200 并发 Agent 完成 P95 | 10,554.52 ms | 1,233.12 ms |
|
||||
| 200 并发测量区间事件循环最大延迟 | 3,559.97 ms | 509.00 ms |
|
||||
| 纸间时光 10k Trace 首次渲染 | 1,803.9 ms | 94.4 ms |
|
||||
| 纸间时光 10k Trace 树形全匹配筛选 | 25,914.8 ms | 189.2 ms |
|
||||
| 纸间时光 10k Trace 首屏 DOM 节点 | 约 102,542 | 1,852 |
|
||||
| 1,000 条任务首次实际加载 | 50 条 | 1,000 条(10 次 API 请求) |
|
||||
|
||||
Agent 测量区间还包含同步读回、校验和重启恢复,最大心跳延迟不是纯执行阶段指标。290 次普通运行、200 个容量/取消场景、20 个权限场景、20 个失败/超时场景全部通过,订阅者和工具执行器释放。不能声称消除了所有主线程工作。
|
||||
|
||||
Trace 搜索检查完整数据,只有渲染分页。10k 样本滚动 frame gap P95 为 10.1 ms,无 longtask;时间线筛选 284.9 ms,树形切换 100.9 ms。这是单次本机样本,不代表所有硬件与实时 SSE 输入。
|
||||
|
||||
1,000 条任务界面每页 100 条;筛选后数据总数 334,当前页 100。筛选 18.7 ms,滚动 frame gap P95 为 30 ms,无 longtask。断言同时检查完整数据量和分页渲染数量。
|
||||
|
||||
真实 HTTP 测试 1,000 条任务、20 并发,CRUD 全部成功,分页完整,最终任务数 0:
|
||||
|
||||
| 指标 | 修复前 | 修复后 |
|
||||
| --- | ---: | ---: |
|
||||
| health P95 | 157.00 ms | 38.64 ms |
|
||||
| 创建 P95 | 116.45 ms | 157.68 ms |
|
||||
| 更新 P95 | 159.29 ms | 208.68 ms |
|
||||
| 删除 P95 | 156.43 ms | 205.45 ms |
|
||||
| 总耗时 | 18.31 s | 24.51 s |
|
||||
|
||||
后台排队和操作记录改善了无关请求的响应,但这组样本写入吞吐下降,不能描述为 CRUD 全面提速。后续可以评估任务事务批量化与连接初始化开销;本次没有降低 SQLite 持久化级别。
|
||||
|
||||
- [Agent / 进程内任务复测](performance/2026-09-06-agent-task-backend-fixed.json)
|
||||
- [真实 HTTP 任务复测](performance/2026-09-06-task-http-fixed.json)
|
||||
- [Trace 浏览器复测](performance/2026-09-06-agent-trace-ui-fixed.json)
|
||||
- [任务浏览器复测](performance/2026-09-06-task-ui-fixed.json)
|
||||
- [日志架构与验收说明](后台运行日志与压力问题修复.md)
|
||||
Reference in New Issue
Block a user