mirror of
https://gitcode.com/JianFeeeee/HomeAgent.git
synced 2026-11-01 14:57:38 +00:00
问题(WSL2 真机诊断报告问题 2):单条工具结果 36783 token,直接冲破
整个对话预算 → overflow 判「单条超限,裁剪救不了」→ 整轮终止。
模型看到的只是"对话没反应"。日志:max_ctx=32768 target=26214
fixed=498 mem=8572 ctx=17144,而单条 36783 是它的 2.1 倍。
此前两条路都不通,本提交走第三条:
· **截断**(方案 A):模型拿到残缺信息且**不知道**被截过,会基于残缺
数据下结论 —— 与本仓反复吃亏的「静默降级」同族。
· **只统计不裁剪**(方案 B,toolresult_budget.go):设计上正确(不欺骗
模型),但停在「报告」一步 —— oversizeTools 计数**没有任何消费者**
(OversizeToolReports/OversizeToolNames 全仓零调用者),所以那条超大
结果照样整条进上下文、照样撞窗口。
本提交把方案 B 缺的那一半补上:
结果超限(沿用 toolresult_budget.go 的 ContextTokens/8 阈值)
→ 正文完整写入 <context.json 同级>/toolresults/<evt_id>/tool_N.txt
→ 上下文里换成「预览 + event_id 句柄 + 总字节/行数 + 读法」
→ 模型调 toolresult_read(event_id, offset, limit) 取任意区间(≤64KB/次)
→ 事件离开 L1 时全文目录一并删除
设计要点:
· **存活期跟随事件,不引入 TTL**。与 Blocks 同一套处置(见 mediaref.go
「块存储在事件自身,不维护引用账本」)。刻意不做独立过期/清理定时器
——那会让"一件事记两处",两处一旦不一致就出现"事件还在但全文没了"。
· **正文不内联进 context.json**:它每 5s 全量重写,内联几 MB 正文会让
每次 flush 都写几 MB。
· **磁盘 IO 放 context.go**(记忆面持久化,架构守卫允许的唯一落点),
toolresult_store.go 只留纯逻辑 —— 满足 TestKernelHasNoMediaFileReading。
· **toolresult_read 按需暴露**:只在真有落盘结果时注册 schema
(本仓已有"175 个工具占满上下文"的教训)。
· 落盘失败**保持原内容**:宁可撞窗口也不让模型什么都看不到。
判据(toolresult_store_test.go,7 条,3 条经变异验证):
· TestOffloadReplacesFullTextWithPreview —— 上下文拿预览非全文,且三要素
齐全(说明是预览/给句柄/给读法)。变异:返回全文 ⇒ 红。
· TestReadBackReassemblesByteIdentical —— 分段拼回**逐字节相同**,含中文
多字节字符。这是"信息不丢"的唯一硬证据。变异:少读 1 字节 ⇒ 红。
· TestAppendClaimsPendingToolResults —— 事件进 L1 必须认领落盘记录,
否则重启后句柄全失效。变异:不认领 ⇒ 红。
· TestReadAfterPurgeIsExplicit —— 淘汰后明确告知,不静默返回空串。
· TestPersistedToEventDirNotInline / TestReadWithBadHandleIsActionable /
TestSmallResultNotOffloaded