① provider 配置(可直接照抄)
文件 .zcode\v2\provider_config.json。值是当前生效版,演进过程见 ②③。
// provider 主体
{
"providerId": "88ff30fa-af55-4443-a1ff-ba8a7ff681c6",
"providerName": "Local Ollama",
"config": {
"group": "standard-personal",
"access": { "type": "api-key", "apiKey": "ollama-local-no-key" },
"api": { "type": "openai-chat-completions",
"baseUrl": "http://127.0.0.1:11435/v1" },
"personalModelIds": ["qwen3.8:27b-offload"],
"modelOrder": ["qwen3.8:27b-offload"]
}
}
// 模型规则(能力声明必须与模型真实能力一致)
{
"modelId": "qwen3.8:27b-offload",
"config": { "properties": {
"contextWindow": 190000,
"requiresMfjsToolSchema": false,
"supportsToolCall": true,
"supportsJsonSchemaOutput": false,
"supportsMidConversationSystem": false,
"inputFormat": { "supportsText": true, "supportsImage": true },
"outputFormat": { "supportsText": true }
}}
}
能力声明字段改错会直接制造故障:2026-09-20 曾把 supportsImage 声明为 true 而模型没有视觉投影器 → 带图请求一律 500 → "重新连接中 N/10"重试风暴。启用 mmproj(9/29)后才是真正的 true。改 provider 配置必须重启 ZCode——它只在启动时读一次。
② 两个数字必须成对维护
服务端 -c 与客户端 contextWindow——只调一边必然复发故障。
| 服务端 -c | contextWindow | 实占(UE 同开) | 判断 |
|---|---|---|---|
| 65536 | 49152 | ~18,900 MB | 保守,但 ZCode 容易冲过去 |
| 81920 | 65536 | ~19,200 MB | 实测被冲过去过(82,324 > 81,920) |
| 114688 | 81920 | ~20,608 MB | 稳定运行过 |
| 262144 | 190000 | ~20.5 GiB | ✅ 当前(Bonsai 2 + KV4) |
1.26 这个系数怎么来的:同一套环境下三次实测,ZCode 的 token 估算低估 5.5% → 15% → 26%(偏差不稳定)。压缩请求还要在历史之上加 ~2,563 token 指令。所以校验式必须按最坏观测值再留一截——不要按"刚好够"来配。反例:98,304 × 1.26 + 2,563 ≈ 126,426 > 114,688,所以旧时代触发点不能提到 9.8 万。
③ 为什么压缩线是 65%,不是 85%
ZCode 的自动压缩线不是"窗口的百分比",而是"窗口先固定扣掉 34,000 token"。
| contextWindow | 实际触发线 | 触发百分比 |
|---|---|---|
| 49,152 | 15,152 | 30.8% |
| 65,536 | 32,536 | 48.1% |
| 98,304 → 190,000 沿用同一公式 | 64,304(98,304 时) | 65.4% |
| 1,000,000(云端) | 966,000 | 96.6% |
两个预留是写死的常数——185 次压缩事件、跨 6 个窗口档、含云端 1M 模型,数值从未变过。所以"85% 才压缩"的直觉只在大窗口成立。两条实用结论:
- 要更多可用空间,唯一有效手段是把窗口开大:81,920 → 98,304 使触发线 47,920 → 64,304,可用 token +34%;
- 面板显示的"已用 X/上限(P%)"分母是窗口不是触发线——看到 70% 才压缩,说明实际 token 已越过那条线。
复现命令:python D:\_Qwen3.8-27b\_zcode_setup\_compact_probe.py(解析 ZCode 的 jsonl 日志)。
④ 修改清单(新建 / 改动 / 备份)
接入时新建与改动的文件全景——排障时先想清楚"这个功能在哪个文件里"。
新建的文件(核心项):
| 文件 | 作用 |
|---|---|
start_local_llm.bat | 唯一的启动入口:先杀残留并确认端口真的空了再启动;等健康;打印显存 |
stop_local_llm.bat | 立刻释放显存。只杀 llama-server,不乱杀 python.exe |
status_local_llm.bat | 一键体检(进程/监听/健康/显存/共享内存/日志/请求记录) |
autostart_local_llm.bat + .vbs | 开机幂等启动器 + 隐藏窗口包装 |
_zcode_setup\qwen35_chat_template.jinja | 打补丁的 chat template(修两个 500 根因) |
_zcode_setup\is_ready.ps1 / wait_ready.ps1 | 静默健康探测 / 等待加载完成(替代批处理里不可靠的引号转义) |
_zcode_setup\last_usage.py | 读 ZCode 的 sqlite,打印最近请求的 in/out/ttft——"ZCode 到底发了什么"最快取证 |
_zcode_setup\session_sizes.py | 列出各会话真实最大提示词,判断能不能跑本地模型 |
_zcode_setup\api_test.py / zcode_sim.py | 6 项 API 自检 / 模拟 ZCode 请求形状(96 工具 + 18K 提示词) |
改动的文件(每处都对应一个真因):
| 文件 | 改动 | 原因 |
|---|---|---|
| provider_config.json | baseUrl 11436 → 11435/v1;contextWindow 1000000 → 真实值(现 190000);能力声明补齐 | 直连;假 ctx 永不压缩;声明错=500 风暴 |
| openai_proxy.py | 删 max_tokens 注入 / 删 HARD_MSG_CAP 二次裁剪 / 修 _trim_messages 全删光 / 加锁+冷却 | 256 夹子;整条丢消息;空对话;并发活锁 |
| 启动文件夹 .lnk | 改指向 wscript 跑 .vbs | 开机隐藏窗口 + 幂等启动 |
| ZCode config.json | 关 cloudbase-skills 插件、摘除 chrome-devtools / rider MCP | 工具 schema 是窗口杀手(38K → 4.6 万底噪) |
所有改动都有时间戳备份(*.bak_日期_时间),还原即拷贝覆盖。
⑤ 开机链路(两条,互相独立)
设计目标:开机 20 秒模型自动加载;每条路径幂等(先探 /health),同时触发也不打断正在加载的模型。
主路径(启动文件夹):
NVFP4_llama-server.lnk
→ wscript.exe autostart_local_llm.vbs (完全隐藏窗口)
→ autostart_local_llm.bat (等 20 秒给 GPU 驱动)
→ is_ready.ps1 探 /health
├─ 已经 200 → 写一行日志,什么都不动(幂等)
└─ 没在服务 → start_local_llm.bat 启动
→ 顺带拉起 CherryStudio 的 proxy(若 11436 空闲)
→ 拉起 watchdog(60 秒一轮,发现服务没了就重启)
冗余路径(注册表 Run 键 LocalLLM_ensure):
powershell.exe -WindowStyle Hidden -File ensure_model.ps1
→ 先自愈:把 .bat/.cmd/.vbs/.ps1 的 LF 行尾就地修成 CRLF
→ 再调用同一条 autostart_local_llm.bat
为什么要有冗余路径:主路径整条链曾经哑掉两天、不留任何痕迹(LF 行尾事故)。冗余路径用 PowerShell 写(不受该陷阱影响)且每次开机先自愈行尾。计划任务版本更强但被否决——非提权环境 Register-ScheduledTask 报 0x80070005 拒绝访问。
"开机后不能用"排查顺序:status_local_llm.bat → 按 [1] Processes(0 = 模型没了)→ [9] Watchdog(在跑就等 1 分钟自动拉起;NOT running 就手动 cscript //nologo //B watchdog.vbs)→ [8] Logon autostart(开机到底执没执行)→ [5] 日志收尾(应有 listening on)。
⑥ 6 个 UE 子智能体
动机是省 token:全套工具 schema 吃 ~46K,而每个子智能体只带 6 个基础工具(Read/Write/Edit/Glob/Grep/Bash),schema 降到 ~7K,省出 39K 给任务本身。
| # | 文件 | 定位 | 循环上限 |
|---|---|---|---|
| 1 | ue-local-runner.md | 主要执行器:给本地模型跑 UE 任务 | 2 次 |
| 2 | ue-anim-debugger.md | 动画溯源:查"为什么播了 X 动画"的证据链 | 3 次 |
| 3 | ue-pcg-builder.md | PCG 场景生成:节点链 + 空生成排查 | 4 次 |
| 4 | ue-asset-explorer.md | 只读调查员:查蓝图变量/材质参数/CDO | 无(只读) |
| 5 | ue-build-runner.md | 编译 + 验证:Live Coding / UBT 全量 | 无(固定流程) |
| 6 | project-rule-guard.md | 合规审查:读规则文件验证改动 | 无 |
循环设计哲学(二次迭代的结论):UE 资产的真实状态只有运行时读 CDO 才知道,探索式循环必须保留(每步 Bash 后回读验证);砍掉的是循环里的无效开销——Monolith 统一走 Python client(不走 MCP schema,那会吃 46K)、default_timeout=120(编辑器忙时 15 秒会假失败)、每步 2-4 次硬上限防兜圈子、输出 ≤ 200 行。三种策略对比:无上限循环 71 分钟(25% 在兜圈子)、单次脚本假快、二次迭代 10-15 分钟且保自适应。
UE 内存 CDO 铁律(踩 AM_CL_Attack_01 污染坑后沉淀):会改资产的 run_python 事前先备份 .uasset;load_asset() 返回的就是内存 CDO,改前必须 clone;reimport / refresh 都不覆盖已加载的脏 CDO;全失败 → 报告"需要重启编辑器"并停任务,把 bak 路径写进回复。
⑦ 日常使用四条纪律
平时
什么都不用做
开机 20 秒自动加载;3 分钟不用自动还显存给 UE;再用 7 秒唤醒。
用的时候
开新会话,一上来就选本地模型
绝不把老云端会话切过来——几十万 token 的历史必然压缩死锁。不确定就跑 session_sizes.py。
边界
啃大网页 / 大文档别用本地
一次抓整页 HTML 就吃一两万 token。改代码、看文件、跑工具才是主场。
信号
看到"已自动压缩"就准备新开会话
压缩摘要永久累积,唯一清法是新开会话把结论贴进去。
常用命令:
D:\_Qwen3.8-27b\start_local_llm.bat REM 手动启动 D:\_Qwen3.8-27b\stop_local_llm.bat REM 立刻释放显存 D:\_Qwen3.8-27b\status_local_llm.bat REM 一键体检(出问题先跑这个)