🎯 OpenCode插件系列:
类型: OpenCode Plugin — DCP 上下文限制同步器
1. 这是什么插件?
opencode-dcp-dynamic-limits 是一个专门为 DCP (@tarquinen/opencode-dcp) 服务的 OpenCode 插件。核心概念:
- DCP(Dynamic Context Pruning)是个独立的上下文裁剪插件
- DCP 不知道你当前用的模型上下文窗口有多大
- 当你切换模型时,DCP 经常被留下陈旧的限制 —— 该剪的时候不剪,不该剪的时候乱剪,更糟的是把
dcp-system-reminder持续塞进聊天里 - 这个插件在真实的 chat 请求上钩入 OpenCode,识别当前模型并即时更新 DCP 配置
写这个插件的人是个本地 GGUF 玩家(用 llm-server + ik_llama.cpp / llama.cpp),经常在云端模型和本地 GGUF 之间来回切,所以吃了这个亏。
与"自动配置 DCP"的区别:
| 方面 | 静态 DCP 配置 | dcp-dynamic-limits |
|---|---|---|
| 上下文窗口 | 写死在 `dcp.jsonc` | 跟随当前模型动态计算 |
| 切换模型 | 需手动改配置 | 自动同步 |
| 检测来源 | 无 | 进程参数 → `/slots` → `/v1/models` → manifest 逐级回退 |
| 限制区间 | 单一值 | 60%(min)/ 85%(max)随上下文缩放 |
| 安静模式 | 无 | min=max,跳过软警告区 |
2. 用来做什么?
使用它来:
- ✅ 本地 ↔ 云端模型 切换时自动同步上下文窗口
- ✅ 修复 DCP 在错误时机裁剪 的问题
- ✅ 消除
dcp-system-reminder在聊天里持续刷屏 - ✅ 支持
llm-server/ik_llama.cpp/llama.cpp/ Ollama / LM Studio / Jan / text-generation-webui - ✅ 同时支持 OpenCode model manifest 里的云端模型
- ✅ 写一个进程参数 →
/slots→/v1/models的多层回退检测 - ✅ 5 秒节流,不打扰正常 chat 流程
典型场景:
你:把模型从云端 Claude 切到本地 ik_llama 的 Qwen2.5-1M.gguf
[dynamic-limits]
- chat.params 钩子触发
- 读 ps ax → 找到 ik_llama 进程的 --ctx-size 262144
- 计算 dcpMin=157286, dcpMax=222822
- 写入 ~/.config/opencode/dcp.jsonc
- 把 pruneNotificationType 改成 toast,nudgeForce 改成 soft
DCP 重新加载,立即知道自己的限制 = 222822
后续对话不再误剪,不再乱塞 reminder
3. 如何使用?
安装
需要先装 DCP(本插件是 DCP 的"修正"层):
npm install -g @tarquinen/opencode-dcp
npm install -g opencode-dcp-dynamic-limits
在 ~/.config/opencode/opencode.json 中:
{
"$schema": "https://opencode.ai/config.json",
"plugin": [
"@tarquinen/opencode-dcp@latest",
"opencode-dcp-dynamic-limits"
]
}
DCP 必须先加载。本插件只在 DCP 已存在的基础上调整它的配置。
检测逻辑
对于本地 llama.cpp 风格的服务:
- 优先读运行时
-ctx-size(通过ps ax) - 回退到
/slots的n_ctx - 再回退到
/v1/models的max_model_len/n_ctx_train - 最后用 model manifest 的 context
-parallel的 slot 大小只作为诊断信息,不会被当作完整上下文窗口。
对于云端模型:
-
直接用 OpenCode model manifest 里的
limit.context具体来说,OpenCode 在 chat.params 钩子里会传入 input.model 对象,其中:
-
model.limit.context — OpenCode 内置的该模型上下文窗口
-
model.limit.output — OpenCode 内置的该模型最大输出 token 对 Anthropic / OpenAI / Google 等 OpenCode 内置 provider,这些字段是 OpenCode 自己知道并自动填的。calculateOnlineLimits 直接读它们: const contextLimit = model.limit?.context ?? 128000 const outputLimit = model.limit?.output ?? 8192 如果某个云端模型 OpenCode 不认识(limit 字段缺失),就会落到硬编码的默认值 128000 / 8192 —— 这是个已知盲点,但常见云端模型都被 OpenCode 内置覆盖了。
一个边界情况需要你注意 如果你配的是自定义 cloud provider(比如自己 proxy 转发的非标准 OpenAI 兼容端),isLocalModel(index.ts:24)会通过 provider.source === “custom” 误判为本地,走 llama.cpp 检测路径,那八成会失败。 解决方法:要么把 endpoint 指向 localhost(被 url.startsWith("http://localhost") 兜底
安静模式
默认开启安静模式(避免软警告区反复触发):
{
"pruneNotificationType": "toast",
"compress": {
"nudgeForce": "soft",
"nudgeFrequency": 50,
"iterationNudgeThreshold": 50
}
}
安静模式下 minContextLimit = maxContextLimit,DCP 只在硬上限处裁剪,跳过中间的软警告刷屏。
4. 何时使用?
在以下情况使用:
- ✅ 你的 OpenCode 在多个模型间切换(尤其本地 ↔ 云端)
- ✅ 用 llm-server /
ik_llama.cpp/llama.cpp/ Ollama 之类的本地后端 - ✅ DCP 在错误时机裁剪 —— 上下文远没满就开始剪
- ✅ 看到
dcp-system-reminder持续出现在聊天 里 - ✅ 不同模型的上下文窗口差异很大(例如 32K vs 262K)
- ✅ 想要零配置切换 —— 不用每次手动改
dcp.jsonc
不要在以下情况使用:
- ❌ 不使用 DCP —— 没装 DCP 这个插件就是空转
- ❌ 只用单一模型且上下文窗口稳定 —— 写死配置就够
- ❌ 本地后端不是 llama.cpp / Ollama 风格 API —— 检测可能失败
- ❌ 不希望 DCP 配置被自动改写 —— 这个插件会直接写
dcp.jsonc
⚠️ 重要注意事项
插件加载顺序:
{
"plugin": [
"@tarquinen/opencode-dcp@latest",
"opencode-dcp-dynamic-limits"
]
}
DCP 不存在时这个插件不会报错,但也没意义。
限制值固定为 60% / 85%:
dcpMin= 上下文 × 0.6dcpMax= 上下文 × 0.85- 安静模式下
dcpMin被强制等于dcpMax
这两个百分比不在配置里暴露,需要不同比例得改源码。
输出 token 估算(仅本地):
- 估算为
perSlotCtx / 4 - 限制在
[8192, 16384]区间 - 这个值不会写进 DCP 配置,只用于日志
节流:
5 秒内不会重复同步。但模型 ID 变化或计算结果变化会强制同步。
跳过的 agent:
title agent 触发的 chat 请求不会触发同步 —— 否则每次生成标题都会把 DCP 限制改一遍。
配置文件位置:
插件会写两个常见位置:
~/.config/opencode/dcp.jsonc
~/.opencode/dcp.jsonc
与 oh-my-opencode 等无关:
这个插件是纯配置同步层,不引入任何 agent / 工具 / 通知。和 opencode-background-agents 这类异步委派插件完全正交。
🔗 有用链接
- 仓库: https://github.com/raketenkater/opencode-dcp-dynamic-limits
- 依赖 DCP: https://github.com/tarquinen/opencode-dcp
- 配套后端 llm-server: https://github.com/raketenkater/llm-server
- OpenCode 文档: https://opencode.ai/docs