0 结论摘要
更新 Trilium 长笔记失败,【与上下文长度无关】✓(两侧夹逼证明 ✓)
· 与 provider 窗口无关 ✓(实测可收 1,000,031 tokens)
· 与输出上限无关 ✓(max_tokens 有效区间 [1, 393216])
· 与 Hermes 限长代码无关 ✓(arg_coercion / tool_search_validation 内无任何限长逻辑)
· 与 Trilium MCP 无关 ✓(服务端无长度参数)
⇒ 唯一失败路径 = bridge(tool_call)✗;直连工具 3.2k 字节稳过 ✓
⇒ 失败形态:参数 JSON【按比例丢尾 ~1/5】✗(断点/载荷 = 74% / 81% / 84% / 73%)
1 静态链路(四处约束,全部实测)
① provider(opencode-go / deepseek-v4.1-flash,base https://opencode.ai/zen/go/v1)
· /models 不声明 context ✗
· 请求硬要求 x-opencode-session 头 ✗ 否则 400 MissingSessionID
· 输出上限 = [1, 393216] ✓(服务端报错原文)
· 输入窗口逐级实测:400,031 ✓ → 450,031 ✓ → 600,031 ✓ → 800,031 ✓ → 1,000,031 ✓ 全部接受
⇒ 真实窗口 ≥ 1M ✓(略超 1M 也收)
· 上游真身:x-opencode-upstream-model-id = deepseek-ai/DeepSeek-V4.1-Flash
· 需带 x-opencode-endpoint-id = luminal-dsv4.1flash(套餐路由)
② Hermes 元数据
· 声明 deepseek-v4.1-flash = 1,000,000 ✓ ⇒ 与实测相符(它没猜错)
· 探不到时回落 DEFAULT_FALLBACK_CONTEXT = 256,000(CONTEXT_PROBE_TIERS[0])本机未触发
· 元数据表里【没有】Qwen3.5-27B ✗(只有 Qwen/Qwen3.5-397B-A17B、35B-A3B = 131072)
③ 压缩设置(三版演化)
· v1 原值:min(0.47×1M, 440000) = 440,000;proactive_prune 48000;target_ratio 0.2
· v2 建议:min(0.5×1M, 260000) = 260,000;auxiliary.compression 改为跟随主模型
· v3 当前:纯比例 min(0.4×1M) = 400,000(不设 threshold_tokens ⇒ 随窗口弹性);
target_ratio 0.1;max_attempts 10;threshold 0.8 仅兜底
· 阻塞事件:compression_locks 残留 1 行(18:56 取 / 19:05 到期)⇒ 堵住压缩 ✗
⇒ 19:08 压缩跑成(calls 10→11,in 880,774)⇒ 现 0 行 ✓
· 源码语义:model_thresholds 的值是【比例 float】✗(agent_init.py:1600 float(v);
context_compressor.py:2066 resolve_model_threshold(dict[str,float]))⇒ 写 400000 ⇒ 永不触发 ✗
④ session 实际
· UI 显示 ~444.7k / 1M = ~44%(安全区)
· messages:active=0 共 11,576 行;active=1 共 389 行 / 430,781 字符(中文≈1 token/字)
· 用量:主对话 788 次 in 9.48M(均值 ~12k/次)out 1.29M;compression 11 次 in 880,774 out 154,634
2 动态链路(失败现场实际数据)
失败断点序列:char 829 / 1155 / 1304 / 1544 / 1914 / 2243 / 3016 / 2373 ✗
⇒ 断点/载荷比例 = 74% / 81% / 84% / 73% / 78% ⇒ 【按比例丢尾】✗ 不是固定上限
⇒ 同一内容连试 4 次均失败(非随机)
成功对照:1.7k 字符写入成功(blobId t1EpeVRXElJz6PFkqyMV)
2.4k 纯 ASCII 经 tool_call ⇒ 外层 JSON 解析通过(仅报缺 name)
探针(write_file 路径,全部通过):ASCII 2643 字节;引号密集 1952 字节;中文密集 2016 字节
DB 对照:直连 terminal 调用 1,767 / 1,886 / 2,073 / 2,123 / 3,245 字节
⇒ 外层合法、内层 arguments 合法、尾部完整无缺 ⇒ 直连工具稳过 3.2k
失败不落库:bridge 校验未过 ⇒ 未执行 ⇒ messages 表无该记录(无法从 DB 复原现场)
校验报错出处:tools/tool_search_validation.py:160(只 json.loads,无 limit 常量)
日志原文:gateway-stdio.log「model_tools: coerce_tool_args: failed to parse string as JSON
for expected type list」+「Expecting ',' delimiter: line 1 column N (char N-1)」
3 已排除的假设(逐条)
✗ 上下文不够 / 窗口不足(445k 时断;压缩跑成后仍断 949;窗口实测 ≥1M)
✗ session 长度(445k 与 12k 两态同样断)
✗ provider 输出被截(上限 393216,与 1.5k 内容无关)
✗ Hermes 限长代码(无 limit 常量)
✗ Trilium MCP(服务端无长度参数)
✗ 长度 / 字节 / CJK / 引号(三探针 + 2.4k ASCII 全过)
✗ 「≤1.7k 稳过」的旧说法(后续 1.5k 也断,已推翻)
✗ 「12k tokens」的旧估算(数行数 + 3.2 字符/token 都错;中文≈1 字/token)
✗ model_thresholds 可写绝对值(float(v) ⇒ 必须比例)
✗ 「换新会话最稳」这类绕过式结论(不成立,也不接受 —— 应修根因)
4 当前假设与定案手段
假设(未定案):流式 delta 的切点落在转义序列内部(反斜杠与其后字符之间)
⇒ 拼接后 \" 被劈开 ⇒ 字符串提前结束 ⇒ 报 Expecting ',' delimiter ⇒ 位置随内容浮动
定案手段(一步):python.logging.level: debug ⇒ 重启 ⇒ 复现一次
⇒ 日志会印出【拼接后的原始 arguments 字符串】
⇒ 若断点恰在反斜杠与引号之间 ⇒ 结案
⇒ 该段日志即「动态链路现场实际数据」的最终形态
5 附:压缩参数语义(源码依据)
model_thresholds = {str(k): float(v)}(agent_init.py:1600)⇒ 值是【比例】✗ 非 token 数
resolve_model_threshold(model, dict[str,float], default, provider)(context_compressor.py:2066)
threshold_tokens = 绝对上限(与比例取 min;不设 ⇒ 纯比例 ⇒ 随窗口弹性)
target_ratio = 压后目标占比;proactive_prune_tokens = 越线后先瘦身量
protect_last_n / protect_first_n / min_tail_user_messages = 压后地板(决定压不小)
tail_mode / idle_compact_after_seconds = 形态与时机(间接)
max_attempts = 摘要调用重试次数(摘要模型吃不下大输入 ⇒ 连败则会话卡死)
auxiliary.compression = {provider: main, model: ''} ⇒ 跟随会话当前模型
(官方约定原文:'auto' + '' = main agent's model)
6 附录:本笔记早前版本的原文(保留)
【结论(实测定案)】用 bridge 工具(tool_call)写大块 HTML 会失败,真因不是长度、
不是 Hermes 字数限制、不是 provider 上限,而是内容里的裸双引号在嵌套 JSON 里没被正确转义。
【判据链】① 纯 ASCII 2643 字节 经 write_file ⇒ 通过
② 引号密集 1952 字节 经 write_file ⇒ 通过
③ 中文密集 2016 字节 经 write_file ⇒ 通过
④ 纯 ASCII 约 2.4k 经 tool_call ⇒ JSON 解析通过(报错变成缺 name)
⑤ 含裸双引号的 HTML 经 tool_call ⇒ 失败,位置随内容变(829/1155/1569)
【修法】走 bridge 写 HTML 时属性用单引号或不用属性;或把双引号写成实体。
【注】上表③④后来被进一步实验推翻:中文探针走的是 write_file 路径(非 bridge),
2.4k ASCII 只是侥幸通过;真正规律是【bridge 按比例丢尾】,见本页第 0–4 节。
【配置层面保留】model.reasoning_effort: none(省思考 token);model.max_tokens: 131072
(provider 上限 393216 的 1/3,留输入余量)