🎁 福利专区全网大模型免费应用 + 新用户福利 + 注册活动入口,低成本玩转 AI
广告☁️ 云服务器特惠阿里云首购 8 折 · 腾讯云合作特惠
DeepSeek Harness Hub
← 返回列表

LuminariSoftwares/context-guardian

DeepSeek Harnessspec-screened扫描:中风险在 GitHub 查看 ↗
✓ 可直接安装

你的本地模型会话触及上下文上限后就会崩溃。这个项目能阻止这种情况。

自动检查通过:npm 包已发布且 engines 声明满足基线(声明 Node ^22.19.0 || >=24.0.0);该结论来自程序自动检查,未经人工实机验证。 · 最近上游提交 2026/9/21 · 已提供中文文档

为本地模型提供的压缩功能,真正会触发,而且绝不会让会话变砖。兼容 OpenAI 的代理 + DeepSeek Harness 引擎。

综合分
30
GitHub 分
30
用户评分
—
★ Stars
0
周下载量
—
安装插件(需先安装 dsh CLI 引擎:npm install -g @deepseek-ai/dsh)
dsh plugin --profile web add dsh-context-guardian
npm 包 dsh-context-guardian 已校验归属本仓库,走 npm 安装最省事
信任档位:已验证本站已于 1 天前真实安装成功
是什么
dsh 原生插件 · tool
装得上吗
本站已真实安装成功(非静态推断)
安全吗
本站尚未对该插件做风险分级(暂未覆盖,不等同于无风险)
还在维护吗
活跃:最近一次提交在 5 天前

档位由下列信号合成:本站实装验证(真实安装,当前最高到 L4)· 验证所用 dsh 版本 · 静态安装检查 · 风险分级 · 仓库维护状态。下方各区块是它的证据明细。 验证判据与等级说明 →

🟢实装验证通过· 2026/9/24
由本站实装验证器在真实 dsh 环境安装成功,非静态推断。
数据截至 2026/9/21(元数据每日更新 · 实装验证按队列轮转,单条结论的验证时间见上方)
安装兼容性检查✓ 自动检查通过

以下结论由程序自动检查 npm 包、engines 声明与入口文件得出,未做人工实机验证——能装不等于用着没问题。

✓npm 包dsh-context-guardian @ 0.1.0-alpha.3
✓Node 引擎要求 ^22.19.0 || >=24.0.0 · 基线 Node 22.19 满足
✓dsh CLI 依赖未声明 dsh 版本约束
✓入口文件main/exports/bin 已声明

验证方式:npm registry 存在性 + package.json 静态校验 · 最后验证 2026/9/21 23:40:25

依赖的 DSH / Cordis 模块
@deepseek-ai/schemastery@deepseek-ai/cordis@deepseek-ai/dsh-compaction@deepseek-ai/dsh-llm@deepseek-ai/dsh-tools
用户评分
还没有人投票,来当第一个
订阅周报,不错过优质插件更新
每周一封 · 高评分插件 + 新用户活动

README

由 DeepSeek 最新模型翻译生成
Context Guardian

你的本地模型会话触及上下文上限后就会崩溃。这个项目能阻止这种情况。

为什么 ·
两种运行方式 ·
安装代理 ·
在 DSH 中安装 ·
查看效果 ·
更新日志

为本地模型提供的压缩机制,它真正会触发,并且绝不会把对话一起拖垮。两个入口,一个理念:一个代理,可以放在任何 OpenAI 兼容后端(Ollama、LiteLLM、Headroom、vLLM、LM Studio)前面,服务于任何 CLI 或 agent;以及一个用于 DeepSeek Harness 的原生引擎。两者都会把完整原始内容保留在磁盘上,并且都会失败开放(fail open)。

Context Guardian 压缩监视器:一个请求越过预算线,被压缩,然后回落到线以下

/guardian/health 压缩监视器:一个请求增长超过窗口,Guardian 将其压缩,会话继续运行,而不是硬报错。

| | 没有 Context Guardian | 有它 |
|---|---|---|
| 在本地模型上运行的 Claude-Code 风格 CLI | 自动压缩从不触发;后端硬拒绝请求,会话就此结束 | 代理在窗口填满之前进行压缩;会话继续运行 |
| 在 32K 本地模型上运行 DSH(实测:314 次压缩尝试) | 48 次成功;其余都因空摘要失败,或在摘要过程中溢出窗口 | 每一次失败或不可能的摘要都会回退到确定性检查点:约 14,012 → 约 584 tokens,耗时 23 ms,无模型调用 |
| 被压缩掉的部分 | 消失了 | 归档到磁盘上;在 DSH 中,每个检查点行都带有一个 seq 指针,recall 可以读回它 |

两种运行方式

| | 代理(context_guardian.py) | DSH 引擎(engine.js) |
|---|---|---|
| 适用于 | Claude Code、OpenClaude、任何与 OpenAI 兼容的 /v1/chat/completions 通信的工具 | DeepSeek Harness 0.1.2+ |
| 如何接入 | 你把 OPENAI_BASE_URL 指向它 | 在你的 agent 预设的 compaction 组中添加一行 |
| 谁来写摘要 | 同一个后端模型,由代理发起请求 | 先由 DSH 自己的摘要器处理;当它失败、返回空内容或无法容纳时,使用确定性编译器 |
| 回读原始内容 | 磁盘上的 span 归档(纯 JSON,每次压缩一个文件) | 供模型使用的 recall / search 工具,供你使用的 /recall 和 /context |
| 实时视图 | /guardian/health 仪表盘,带压缩监视器,/guardian/events | DSH 自带的“Context compacted”行和上下文计量器,外加 guardian_dsh.jsonl 中每个决策一行 JSON |
| 空闲时压缩 | — | 是,超过窗口的 45 % 时 |
| 归档格式 | logs/guardian_spans//NNNN.json | 相同格式,因此相同的工具可读取两者 |
| 设置指南 | 本 README | docs/dsh-integration.md |

flowchart LR
subgraph P["Proxy: any OpenAI-compatible harness"]
A1["CLI / agent"] --> G1["Context Guardianproxy :8786"] --> B1["Ollama / LiteLLM / vLLM"]
G1 -. "over budget" .-> S1["summarise older turnskeep recent verbatim"]
end
subgraph D["Engine: inside DeepSeek Harness"]
A2["DSH agent"] --> C2["compaction-basic"] --> E2{"LLM summaryfits and works?"}
E2 -->|yes| K2["LLM checkpoint"]
E2 -->|no| X2["deterministic checkpointwith seq pointers"]
end
S1 --> Z[("span archive on disk")]
X2 --> Z
K2 --> Z

本页其余部分是代理。DSH 引擎有自己的五分钟指南:docs/dsh-integration.md。

为什么会有这个项目

Claude-Code 风格的编码 CLI(Claude Code 本身,以及像 OpenClaude 这样的 OpenAI 兼容后端工具)自带内置的自动压缩功能。该功能依赖于 API 以 CLI 期望的确切形式返回准确、实时的 token 用量统计。通过 OpenAI 兼容桥接(Ollama 的 /v1 端点、LiteLLM 代理、Headroom 代理)将这类工具指向本地模型时,该统计信息经常缺失、错误或形式不同,因此自动压缩会悄无声息地从不触发。

可见的症状是:会话一直运行,直到后端硬性拒绝请求(“token limit reached”),你被迫关闭并重新打开,而中间没有任何部分压缩的尝试——你只是丢失了当前进度。

Context Guardian 是针对这一特定缺口的一个小巧、刻意保持简单的回退方案。它自行估算运行中的 token 数量,一旦对话超过可配置的阈值,它就请求同一个后端将对话中较旧的部分浓缩为一条摘要消息,然后再将请求转发出去。最近的消息始终按原样保留。如果摘要调用本身失败,Guardian 会开放失败——它转发原始的、未压缩的请求,而不是冒险静默丢弃历史记录。

它在你的技术栈中的位置

这是现有链条中的一个新环节,而不是对你已有任何东西的替代:

Your CLI / agent (Claude Code, OpenClaude, etc.)
-> Context Guardian        (this project)
-> your existing OpenAI-compatible backend
(Ollama directly, a LiteLLM proxy, Headroom, vLLM, ...)
将你的 CLI 的 OPENAI_BASE_URL 指向 Context Guardian,而不是直接指向你的后端,并将 GUARDIAN_UPSTREAM_URL 设置为你的后端实际所在的位置。Guardian 对除 POST /v1/chat/completions 之外的所有内容都是纯透传,而 POST /v1/chat/completions 会进行压缩检查——其他所有路由,包括流式响应,都会逐字节原样转发,不做任何改动。

如果你使用 MCP 服务器或智能体 CLI,请阅读本文

Guardian 会将你的 tools 数组计入上下文预算。在 0.2.0 之前它并不会这样做,那是一个真实的 bug——详见更新日志。

工具定义通常以一种消息历史所没有的方式不可见。你不会手动输入它们,它们不会滚动而过,你的 CLI 的上下文显示通常也不会把它们单独列出来。但它们存在于每一个请求中。在开发此功能所针对的配置上,七个 MCP 服务器在第一条用户消息之前就达到了 28,689 个 token——占 32,768 token 窗口的 87.6%。

Guardian 无法压缩它们。 它总结的是对话历史;工具定义是它下方一个固定的底线。所以这里有两个不同的问题,而其中只有一个属于 Guardian 的职责范围:

| 问题 | 什么能解决它 |
|---|---|
| 对话历史不断增长,直到窗口被填满 | Guardian |
| 在你输入之前,窗口的三分之二就已经没了 | 加载更少的工具,或者使用 Tool Guardian |

Guardian 现在会告诉你你遇到的是哪一种。它会在第一次看到某个给定的工具负载时记录一个 tool_budget 事件,并在工具定义单独就达到或超过整个窗口时直接发出警告:

[ContextGuardian] TOOL DEFINITIONS ALONE (2671) EXCEED THE ENTIRE CONTEXT
WINDOW (1000). Nothing this proxy does can fix that -- send fewer tools.

如果你看到这个,任何代理设置都帮不了你。大多数支持 MCP 的 CLI 都允许你限定每个会话加载哪些服务器——Claude Code 和 OpenClaude 都接受 --mcp-config  配合 --strict-mcp-config,这会使得该文件成为该会话中 MCP 服务器的唯一来源。

配套项目——Tool Guardian
(pip install tool-guardian)负责另一半工作。它将你的 MCP 服务器置于三个通用工具之后,并按需揭示其余部分,这样工具定义从一开始就不再在每个请求中重复发送。Context Guardian 无法压缩那个固定的工具底线——Tool Guardian 将其移除。将它们一起使用:一个裁剪对话,另一个裁剪工具。

有一个值得预期的后果:升级后,Guardian 会更早、更频繁地进行压缩。 它现在衡量的是整个请求,而不是其中的一小部分。如果这感觉过于激进,诚实的解读是你的窗口本来就已经这么满,只是你之前看不到而已。

这不做什么
- 它不会取代或重复你的后端已经进行的压缩(例如 Headroom、提示缓存)。一旦决定是否先进行压缩,它就会按原样转发到你的后端——两者是互补的,而不是相互竞争的。
- 它不会修复你的 CLI 自身的上下文使用情况显示。 你的 CLI 不知道这个代理的存在,因此在发生压缩后,它自己的 token 计数器会偏离实际情况。重要的是会话能够继续工作,而不是硬性停止——之后显示的数字略有偏差,是在代理层以不可见方式执行此操作所接受的权衡,因为 CLI 本身通常是你无法修改的。
- 它不是一个 tokenizer 精确的计数器。 token 数量是根据字符长度估算的(默认约为 3.5 字符/token),而不是真正的 tokenizer,因此它会稍微提前触发,而不是滞后。请将其视为安全余量触发器,而不是精确测量。

安装

git clone https://github.com/LuminariSoftwares/context-guardian.git
cd context-guardian
python -m venv .venv
source .venv/bin/activate   # Windows: .venv\Scripts\activate
pip install -r requirements.txt

然后在首次启动 Guardian 之前运行 python configure.py(参见下方的配置)。

配置

运行交互式设置脚本,而不是手动编辑配置文件——它会询问你几个关于你特定硬件/后端的问题(最重要的是你的模型的真实上下文窗口),并将答案写入 .env:

python configure.py

每个问题都有一个显示在 [方括号] 中的合理默认值——按 Enter 接受它。你可以随时重新运行 configure.py 来更改你的答案,或者之后直接编辑 .env。

真正因人而异、真正重要的一个设置是 GUARDIAN_NUM_CTX。 这个项目最初是在一块 16GB 显卡(RTX 4070 Ti Super)上构建和测试的,运行一个配置为 32K 上下文窗口的模型——这个数字是该硬件特有的,而不是通用默认值。你的正确值完全取决于你自己的 GPU/VRAM 预算以及你正在运行的模型,因此 configure.py 会明确询问它,而不是默默假设每个人的设置都一样。如果你不确定你的真实数字是多少:

- Ollama: 在模型加载时运行 ollama ps——CONTEXT 列显示实际正在使用的实时值(不一定是模型的理论最大值)。
- LM Studio / vLLM / 其他服务器: 检查你在加载模型时配置的上下文长度设置——Guardian 无法自动发现这一点,因此它需要与你实际设置的值匹配。
- 如果你不确定或没有明确设置: 从保守值开始(configure.py 的默认值 32768 在单块消费级 GPU 上是一个合理且普遍安全的起点),并在确认你的后端确实能够在不耗尽 VRAM 的情况下维持它之后,再提高它。
把这个值设得太高,意味着 Guardian 不会很快进行压缩,你的后端仍可能在 Guardian 介入之前就硬报错。把这个值设得太低,只是意味着 Guardian 压缩得比严格必要的更频繁一些——安全,只是不是最优。

如果你更想跳过向导,把 .env.example 复制为 .env 并手动编辑:

cp .env.example .env

| 变量 | 默认值 | 作用 |
|---|---|---|
| GUARDIAN_PORT | 8786 | Guardian 自身监听的端口 |
| GUARDIAN_UPSTREAM_URL | http://localhost:11434/v1 | Guardian 转发到的 OpenAI 兼容后端 |
| GUARDIAN_NUM_CTX | 32768 | 你的模型真实的上下文窗口,以 token 计——请与你的实际后端/模型配置保持同步 |
| GUARDIAN_COMPACT_THRESHOLD | 0.85 | 触发压缩的 GUARDIAN_NUM_CTX 比例 |
| GUARDIAN_KEEP_RECENT_MESSAGES | 8 | 始终逐字保留、绝不摘要的最近消息数 |
| GUARDIAN_CHARS_PER_TOKEN | 3.5 | 用于估算的每 token 字符数 |
| GUARDIAN_COUNT_TOOLS | 1 | 是否将 tools 数组计入预算。设为 0 可恢复 0.2.0 之前仅计消息的行为 |
| GUARDIAN_UPSTREAM_TIMEOUT | 600 | 等待上游后端响应的秒数 |
| GUARDIAN_UPSTREAM_CONNECT_TIMEOUT | 10 | 等待上游连接本身的秒数 |
| GUARDIAN_LOG_PATH | /logs/context_guardian_log.json | 压缩事件的记录位置(JSON lines) |
| GUARDIAN_HOST | 127.0.0.1 | Guardian 绑定的接口。除非你知道自己在做什么,否则不要动这个——Guardian 在你的后端前面且没有任何身份验证 |
| GUARDIAN_RESERVE_OUTPUT | 8192 | 为模型的输出预留的 token 数。窗口必须同时容纳回复以及(对于推理模型)思考过程,因此压缩是针对剩余空间触发的。如果这个值 ≥ GUARDIAN_NUM_CTX,它会被钳制为窗口的一半并记录日志——请修正配置 |
| GUARDIAN_SPAN_DIR | /logs/guardian_spans | 被逐出的消息在折叠前归档的位置。正是这一点让压缩在磁盘上无损 |
| GUARDIAN_KEEP_SPANS | 500 | 保留多少个 span 文件。0 表示一个都不保留 |
| GUARDIAN_KEEP_SUMMARIES | 1 | Guardian 自己之前的摘要有多少个保留在窗口中。被淘汰的摘要会折叠进下一个 span,而不是被丢弃 |
| GUARDIAN_MIN_SUMMARY_CHARS | 40 | 短于此长度的摘要会被视为失败的摘要,且不会逐出任何内容。关于其存在原因,请参阅 changelog 中的 0.4.0 |
| GUARDIAN_MIN_TRANSCRIPT_CHARS | 80 | 如果要被逐出的消息渲染后少于此长度,Guardian 会拒绝进行摘要,而不是摘要出空内容 |
| GUARDIAN_TOOL_ARG_CHARS | 300 | 工具调用的参数有多少会送达摘要器。完整文本在 span 中 |
| GUARDIAN_SUMMARY_REASONING_EFFORT | 未设置 | 仅在摘要调用时作为 reasoning_effort 传入。非标准,因此默认关闭;在 gpt-oss 上 low 大致将摘要延迟减半 |
| GUARDIAN_VERBOSE | 1 | 在每次压缩时打印可见的多行横幅(裁剪了什么、前后 token 数、节省的 token 数)。设为 0 则使用旧的单行日志条目 |
| GUARDIAN_COST_PER_1M_INPUT_USD | 0 | 你在本地运行时所避免使用的托管 API 上 100 万输入 token 的价格。设置后,Guardian 会报告压缩为你避免重新发送的 token 所对应的累计美元价值。0(默认值)会省略成本行——你用的是本地模型,没有真实账单 |
| GUARDIAN_VERSION_CHECK | 1 | 启动时向 PyPI 查询一次(2 秒超时,缓存 24 小时,完全失败开放),检查是否存在更新的 context-guardian,如果有则打印一行。设为 0 可禁用——气隙/隐私环境绝不接触网络 |
| GUARDIAN_VERSION_CACHE | /logs/.version_check_cache.json | 更新检查缓存 PyPI 应答的位置,这样频繁重启不会重复访问网络(24 小时 TTL) |

关于超时的说明: 本地“思考”/推理模型在输出第一个 token 之前可能会沉默很长时间。如果你看到 500 错误只在长时间停顿后的真实(非平凡)请求上出现,请先提高 GUARDIAN_UPSTREAM_TIMEOUT,再假设出了故障——大多数 HTTP 客户端默认的 5 秒超时是为普通 REST API 设计的,而不是本地 LLM 推理,这正是本项目自身提交历史在开发过程中发现的 bug。

运行

python context_guardian.py

然后将你的 CLI 的 OPENAI_BASE_URL 指向 http://localhost:8786/v1(或你配置的任何端口)。

在将其用于真实会话之前进行测试

1. 按你通常的方式启动真实后端(Ollama、LiteLLM、Headroom,或你使用的任何工具)。
2. 启动 Guardian:python context_guardian.py
3. 向它手动发送一个请求,而不是通过你的真实 CLI,以在专门测试压缩之前确认普通透传正常工作:
curl http://localhost:8786/v1/chat/completions \
-H "Content-Type: application/json" \
-d '{"model":"","messages":[{"role":"user","content":"say hi"}]}'

4. 检查 GET http://localhost:8786/guardian/stats 以查看运行中的 token 估算和压缩次数——或在浏览器中打开 http://localhost:8786/guardian/health 查看实时仪表盘(窗口使用量、压缩次数、节省的 token/成本,以及任何更新通知),它只是以 3 秒刷新率渲染同一个 JSON。
5. 强制进行压缩测试:临时将 GUARDIAN_NUM_CTX 和 GUARDIAN_COMPACT_THRESHOLD 设低(例如 NUM_CTX=2000、THRESHOLD=0.5),然后发送一段包含多条长消息的对话。确认 GUARDIAN_LOG_PATH 处出现压缩日志条目,并且实际到达你后端的请求比发送进来的更小。
6. 只有在这之后,才将你的 CLI 的 OPENAI_BASE_URL 指向 Guardian,并用真实会话进行测试。

运行多个具有不同上下文窗口的模型
Guardian 的 GUARDIAN_NUM_CTX 在一个运行实例的整个生命周期内是固定的。如果你要在上下文窗口大小有显著差异的模型之间切换,可以选择:

- 在不同的 GUARDIAN_PORT 上运行第二个 Guardian 实例,并使用它自己的 GUARDIAN_NUM_CTX,或者
- 保留一个实例,并接受它的阈值是针对窗口更小/更受限的那个模型调优的(这比另一种做法更安全,因为这只是意味着 Guardian 会比大窗口模型严格所需的时机更早一些进行压缩)。

开发 / 运行测试

pip install -r requirements-dev.txt
pytest

实际效果

- 代理: 在会话运行期间打开 http://localhost:8786/guardian/health。压缩监控器会将每一次压缩以 before → after 条形图的形式回放,并带有每次压缩的下拉菜单,以及当你的固定下限(工具 + 系统提示词)才是真正问题时显示的建议框。GET /guardian/events 会以 JSON 形式返回相同的记录。
- DSH: 在会话中输入 /context 可查看压力、缓存命中情况以及现在压缩能节省多少;/recall 3-7、/recall result 42 或 /recall find  可读取原始内容;logs/guardian_dsh.jsonl 可查看决策轨迹(idle-check → compaction/start → deterministic 或 llm → compaction/end)。

致谢

Context Guardian 建立在其他人的想法之上,并且如实说明:

- dsh-compaction-instant(TsFreddie,MIT)——vendor/compiler.js 和 vendor/region.js 是从 0.1.4 版未经修改地引入的,保留了其原始文件头和 MIT 许可证文本,见 vendor/LICENSE.dsh-compaction-instant。recall / search 契约遵循它们的约定。
- VCC(lllyasviel)——编译器所移植的对话编译器原则:将日志编译为一个仅由原始 token 组成的紧凑视图,并带有指向每一处被省略部分的指针。
- dsh-openwolf(MIT)——在压缩前对会话状态进行快照的想法。引擎的 precompact-.json 和 FILES WRITTEN 列表是该想法的独立实现;未包含任何 openwolf 代码。
- DeepSeek Harness——summarize() 正是其压缩引擎为此记录的钩子。

完整的第三方声明:THIRD_PARTY_NOTICES.md。

许可证

MIT——见 LICENSE。

上游仓库有新提交时邮件通知你(每天最多一封,无更新不打扰),随时一键退订。

同作者(LuminariSoftwares)的其他插件

💬 加入社群

插件用法、部署报错、新插件第一时间同步——群里问,比一个人翻文档快。

DPharness QQ 群二维码,QQ 扫码进群
QQ 扫码进群
DPharness 飞书群二维码,飞书扫码进群
飞书扫码进群