dsh-ocr1-memory 测试报告
August 30, 2026 · View on GitHub
[简体中文] | English
dsh-ocr1-memory 测试报告
目标:在隔离临时环境中持续测试与修复,直到插件稳定实现 DeepSeek-OCR1(Contexts Optical Compression)的记忆系统效果。 本文档持续更新,所有测试均使用隔离临时目录,不污染
~/.dsh/ocr1-memory。
测试环境
| 项目 | 值 |
|---|---|
| 插件目录 | <Agent_Extensions>\dsh-plugins\dsh-ocr1-memory |
| 真实 OCR 后端 | http://127.0.0.1:18080/v1(llama-server + DeepSeek-OCR Q4_K_M + mmproj q8_0) |
| 真实 Embedding 后端 | 与 OCR 共用 http://127.0.0.1:18080/v1(combined --embeddings --pooling mean) |
| 采样参数 | temperature=0、repeat_penalty=1.2、no_repeat_ngram_size=30 |
| 渲染 | Python + Pillow + CJK 字体(微软雅黑/黑体) |
| 隔离方式 | 每个测试 mkdtemp 独立目录,测试结束自动删除 |
当前通过状态(2026-08-30)
| 套件 | 结果 |
|---|---|
npm test(健康真实后端在线) | 88/88 通过,0 fail,0 skip |
| 核心 store 测试 | 12/12 通过 |
| context 测试 | 7/7 通过 |
| 复杂隔离测试(T1–T24) | 24/24 通过 |
| OCR HTTP | 2/2 通过 |
| OCR server 生命周期 | 4/4 通过 |
| Embedding 测试(E1–E5) | 5/5 通过 |
| 定位器测试(L1–L8) | 8/8 通过 |
| 治理层与取消信号测试 | 13/13 通过 |
| 集成接线与自动治理测试 | 2/2 通过 |
| 渲染几何测试(RG1–RG2) | 2/2 通过 |
| Robustness 测试(M1–M9) | 9/9 通过 |
| 真实 OCR / Embedding 用例 | PASS(T6/T15/T16/T21/T23/T24/E4;无后端时共 8 个 live-backend 用例跳过) |
当前 Web 运行验证
- profile 使用
ocrBaseUrl=http://127.0.0.1:18080/v1、requireOcr=true、autoStartOcrServer=true;OCR 与 embedding 共用 CPU-onlyllama-server。 ocr1_mem_status、ocr1_mem_calibrate和真实图像 embedding 均成功;校准基线为prompt_tokens=5,独立 embedding probe 为 1280 维、prompt_tokens=785、直接视觉 token=784。- 连续
memory_maintain每批最多刷新 8 条并返回remaining/complete;重复 namespace 维护不会并发执行,取消和卸载会等待已拥有的任务。 - 上述是本机运行证据;更换模型、量化、后端或服务参数时应重新验收。
单元测试覆盖
splitSegments:空行分段、连续 id、超长段落切分scoreSegment:命中、未命中、空文本tierIndexFor:vivid/normal/fuzzy 年龄边界- 动态衰减:默认关闭、近期频率、平滑过期、倍率上限和注入时钟
- context 快照:热度排序、字符上限、空/损坏 manifest 容错
- store + retrieve:verbatim 返回、OCR 文本写入
- active recall:fuzzy → vivid
- OCR 驱动召回:原始文本未命中但 OCR 命中时仍召回
- OCR HTTP 客户端:OpenAI 兼容
/v1/chat/completions集成 - 渲染缓存:相同分段集合 + 分辨率复用图像
复杂隔离测试覆盖
| ID | 场景 | 结果 |
|---|---|---|
| T1 | 时间旅行:fuzzy → 命中 → vivid | PASS |
| T2 | 30 条模糊记忆中只升级命中的 1 条 | PASS |
| T3 | 多主题记忆检索互不串扰 | PASS |
| T4 | 50 段大文本中准确命中目标段 | PASS(修复后) |
| T5 | 中文/英文/日文/Emoji/特殊符号 | PASS |
| T6 | 真实 DeepSeek-OCR 连续 3 次读图稳定 | PASS |
| T7 | OCR 后端不可用:严格模式报错/宽松模式降级 | PASS |
| T8 | 20 个并发 store 后 JSON 完整 | PASS |
已发现并修复的问题
1. 检索打分污染(T4 暴露)
现象:查询 unique-key-37 时,所有包含 unique/key 的无关片段被整条记忆的聚合分抬到 topK,目标段 37 被挤出。
原因:retrieveSegments 给每个字面命中片段使用了 Math.max(segScore, est.score * 0.5),其中 est.score 是整条记忆的聚合分,导致泛化词片段集体虚高。
修复:
- 字面命中片段直接使用片段级得分
segScore; - OCR 聚合分只用于“原始文本无命中时的 OCR 兜底召回”,不再污染普通片段得分。
回归:T4 通过;当前 core/context 单元测试共 19/19 通过。
2. 分辨率层级未对齐 OCR1 官方模式
修改:DEFAULT_TIERS 从 1024/768/512 调整为:
vivid 1280 → 400 tokens(对应 OCR1 Large)
normal 1024 → 256 tokens(对应 OCR1 Base)
fuzzy 640 → 100 tokens(对应 OCR1 Small)
原因:更贴近 DeepSeek-OCR 论文中的原生分辨率模式。
Embedding 测试覆盖
| ID | 场景 | 结果 |
|---|---|---|
| E1 | measureImageEmbedding 通过 media marker 请求,返回 embedding / 直接视觉 token 数 | PASS |
| E2 | 记忆 store 存储真实 multimodal embedding 与 visualTokensDirect | PASS |
| E3 | embedding 后端失败时降级为像素 embedding 并记录 embeddingError | PASS |
| E4 | 真实 DeepSeek-OCR embeddings 后端生成 1280 维视觉 embedding | PASS |
| E5 | 启用 embedding 检索时:向量更近的记忆排在前面 | PASS |
真实 E4 在当前健康 CPU-only llama-server 上通过;当前 ocr1_mem_embed_test 记录 prompt_tokens=785、空文本基线 prompt_tokens=1、直接视觉 token=784、embedding 维度=1280。该数值随图像、prompt 和服务配置变化,不能当作论文内部 token 数。
真实 OCR 隔离测试记录
ISOLATED_REAL_TEST_PASS
storeDir=临时目录(已删除)
输入文本:
Orbit API 需要登录并携带 token。
OCR 回读(节选):
"### 题目内容
**Orbit API 需要登录并携带 token。**
..."
检索结果:
[entryId=..., segmentId=1, score=1.00, tier=vivid]
content: "Orbit API 需要登录并携带 token。"
第二轮复杂隔离测试
| ID | 场景 | 结果 |
|---|---|---|
| T9 | 路径穿越安全:source 注入 ../、绝对路径 | PASS |
| T10 | memories.json 损坏后安全重建为空库 | PASS |
| T11 | 500 轮 store/retrieve/forget 长稳 | PASS |
| T12 | 10 路并发 active recall 命中同一目标 | PASS(修复后) |
| T13 | 分辨率模式对齐 OCR1:1280/1024/640 | PASS |
| T14 | 压缩比指标:textTokens / visualTokens | PASS |
| T15 | 真实 OCR 记录 usage.prompt_tokens | PASS |
| T16 | 真实 OCR 近似视觉 token 数 / 近似压缩比 | PASS |
| T17 | update 冲突消解:旧值被新值覆盖 | PASS |
| T18 | 选择性遗忘:删除后检索不到 | PASS |
| T19 | 跨会话持久化:重建 store 后仍可检索 | PASS |
| T20 | 实测视觉 token 使用文本-only baseline 校准 | PASS |
| T21 | 文本-only prompt_tokens 校准请求 | PASS |
| T22 | 相同 source 的 store 自动更新为最新值 | PASS |
| T23 | optical memory 存储 visual token 元数据 | PASS |
| T24 | 渲染图像生成并存储视觉 embedding(无 embeddings 后端时为 64 维像素 embedding) | PASS |
Robustness 测试覆盖(M1–M9)
| ID | 场景 | 结果 |
|---|---|---|
| M1 | 多 Agent 共享 store:两个 store 实例通过 reload 互相看到新增记忆 | PASS |
| M2 | 原子保存:多次写入后无 .tmp 残留 | PASS |
| M3 | 图像文件丢失后自动重新渲染恢复 | PASS |
| M4 | 渲染缓存损坏(缓存路径被替换为目录)时回退到全新渲染 | PASS |
| M5 | 超长多段落输入(>200KB)分段存储并检索命中目标 | PASS |
| M6 | 超长单段落(约 250KB)切分后无数据丢失 | PASS |
| M7 | list 为纯查询,不隐式修复或重渲染 | PASS |
| M8 | tier refresh 受 maintenanceBatchSize 限制并报告剩余工作 | PASS |
| M9 | tier refresh 在 renderer 内观察取消信号 | PASS |
已发现并修复的问题(第二轮)
并发 active recall 渲染竞争(T12 暴露)
现象:多个并发 retrieve 同时命中同一条 fuzzy 记忆时,渲染缓存写入报 EBUSY: resource busy or locked。
原因:同一输出路径被多个异步渲染同时写入/复制。
修复:
- 在
createMemoryStore内增加renderLocks,同一outputPath的并发渲染只执行一次; - 缓存写入改为 best-effort,失败不阻断主流程。
回归:T12 通过;相关核心/context 回归以及并发锁测试均通过。
已发现并修复的问题(第三轮:DSH 级 R5/R6 验证)
DSH 工具输出 schema 严格性(R5 暴露)
现象:headless Agent 调用 ocr1_mem_store / ocr1_mem_list 时提示 "invalid output",因为返回对象包含 schema 未声明字段(updated / ocrText / visualMemory)。
修复:
ocr1_mem_store输出 schema 增加updated: boolean;ocr1_mem_list在 execute 中只返回 schema 声明字段;ocr1_mem_metrics去掉 null 可选字段,避免严格 schema 拒绝。
回归:DSH 级 R5 再次执行无 invalid output,结果 PASS。
OCR 服务生命周期验证
验证结果:
ocr-server.test.mjs覆盖健康检查、URL 显式端口、同 endpoint 并发启动去重;4/4 通过;autoStartOcrServer直接 detached spawnllama-server,不会通过 PowerShell wrapper 管理子进程;- 启动取消或健康检查超时会回收本次 spawn 的进程;插件 dispose 会取消 pending startup、等待 startup task,并停止记录过的自启动 PID;
- 已运行的外部服务只返回
already-up,不会被插件卸载。
端到端本机配置使用 http://127.0.0.1:18080/v1,OCR 与 embedding 可共用一个 CPU-only 服务。
对比基准:dsh-ocr1-memory vs dsh-memory
- 设计文档:
BENCHMARK.md - 执行脚本:
scripts/compare-memory.mjs - 隔离环境:两个临时 store +
--patch互斥禁用插件 - 结果:已用修正后的
scripts/compare-memory.mjs完整重跑 R1–R6;dsh-ocr1-memory 全部 PASS,dsh-memory 本次也全部 PASS(R5 此前手动验证曾 FAIL,行为不稳定)。dsh-ocr1-memory 未出现落后于 dsh-memory 的情况。
后续计划
- 固化复杂测试脚本为
test/complex.test.mjs并纳入npm test - 自动拉起 OCR 服务(
lib/ocr-server.js+autoStartOcrServer) - 对比基准脚本
scripts/compare-memory.mjs - 多 Agent 共享 store(
sharedStore+ reload + 原子保存) - 图像缺失/缓存损坏恢复测试
- 超长输入边界测试(>200KB 多段落 + 超长单段落)
-
list纯查询、bounded tier refresh 与 renderer 取消传播(M7–M9) - namespace single-flight 维护与 disposer drain
- 超长输入(10MB)与内存压力
- LoRA 定位器训练/评估脚本与合并部署链:详见
docs/DEPLOYMENT.md - 直接视觉 token 数:通过 embeddings 端点 marker-only 请求测量(
visualMemory.visualTokensDirect) - 命中频率动态衰减(默认关闭,保留旧库行为)
- 可选
systemPrompt.context()记忆摘要注入(L1/光学元数据默认开启;snapshot正文快照需显式开启) - 论文规模训练与完整主表评测
- DeepEncoder 内部逐层 token/embedding 导出
测试结论与适用范围
1. 结论
在本机当前运行条件下,记忆系统的核心闭环可以正常工作:
store → SoM 图像与原文持久化 → tier 刷新 → 检索 → segment Fetch → verbatim 返回
证据范围如下:
| 能力 | 结论 | 证据 |
|---|---|---|
| 文本存储、分段、持久化、更新、遗忘 | 已确认 | 核心测试、T8/T10/T17–T19/T22、M1–M2 |
| SoM 渲染、分辨率 tier、老化和 active recall | 已确认 | T1/T2/T13/T14、RG1–RG2、M3–M4 |
| 真实 OCR 读图 | 当前配置已确认 | T6/T15/T16/T21;严格模式覆盖 T7 |
| 视觉 embedding | 当前配置已确认 | E1–E5,E4 使用真实后端返回 1280 维向量 |
| 光学定位协议与 verbatim Fetch | 已确认 | L1–L8;此前 DSH 隔离闭环 R1–R6 通过 |
| 动态衰减与 context 快照 | 已确认 | 核心/context 测试;动态衰减默认关闭,index context 默认开启 |
| 维护 batch、single-flight 与取消 | 已确认 | 治理取消测试、M7–M9、自动治理 disposer 测试 |
| DSH 插件加载 | 已确认 | host 注入通过,运行时状态返回 OK |
npm test 当前为 88/88 通过(健康真实后端在线);无后端时 80 项通过、8 项 live-backend 用例跳过。另有 npm run build、npm run test:smoke 和 Markdown 链接检查通过。测试使用隔离临时 store,不代表任意模型、量化格式、后端或生产数据都无需额外验收。
2. 无独立显卡运行结论
记忆系统本身不要求本机独显:
- DSH 插件的 Node.js 逻辑、JSON 持久化、tier 管理、context 快照和 Python/Pillow 渲染都可由 CPU 完成;
- OCR、Locate 和视觉 embedding 是外部服务,当前已验证的运行方案是 Windows CPU-only llama.cpp,OCR 与 embedding 共用一个 CPU 服务,不依赖 RX 7800 XT 独显;
- 如果不配置 OCR 后端且
requireOcr=false,文本记忆路径仍可工作;需要 OCR、Locate 或视觉 embedding 时才需要对应服务; - LoRA 训练是独立的开发流程,本机训练时使用过独显,但普通运行不需要重新训练,因此不构成运行时依赖。
核显不是必需条件。若采用带 Vulkan 后端的 llama.cpp,可以把核显作为可选加速设备,但本报告的真实运行证据是 CPU-only 路径,尚未把当前插件的全部 OCR/embedding/定位链在核显上单独验收。要保证不使用独显,应将 OCR_SERVER_PATH/ocrServerPath 指向 CPU-only 的 llama-server;通用 PATH 解析本身不会替你选择 GPU 或核显。
这只说明 OCR1 记忆服务 不依赖独显;DSH 使用的其他主模型是否占用独显,是另一条与本插件无关的链路。