透明中继
除 real↔mock 替换外,转发保持请求与响应完全不变 — 行为与直连无异。
claude-code / opencode / hermes-agent 这类 Agent 工具(即本地的 Agent Harness)替你干活的方式,就是把材料整段塞进 提示词 — 代码、配置、终端输出,连同其中的 password、private key、token、cookies,全部送到了 LLM 厂商的服务器上。
这些数据一旦离开本机,就不再受你控制:可能进入 LLM 厂商的日志、用于模型训练,或随一次泄露事件 曝光。而 “不要把 Secret 放进上下文” 在 Agent 工作流里并不现实 — 凭证恰恰是 Agent 工具替你操作真实 系统时要用的东西。Secret Guard 化解的正是这个矛盾:Agent 工具继续用你的 Secret 干活,LLM 却永远 接触不到真值。
Secret Guard 是一个超轻量级的本地 LLM Gateway。把 Agent 工具的 API BASE URL 指向它 — 接入成本只有一行 — 流量经它转发到 LLM 厂商:
下面的素材都来自真实运行:网关以最简配置启动(默认策略),保护一个虚构的 GitHub token — 唯一的虚构就是这枚 token,其余每个字节都是网关的真实行为。
排查一个 401 部署故障时,你把终端输出随手贴给了 Agent 工具 — 环境变量里的 GitHub token 就这样进入了上下文。若无 Secret Guard,下面两栏完全相同(直连时每个字节原样抵达 LLM 厂商);有了它,差异恰好只有你想保护的那部分:
{
"model": "gpt-5.6",
"messages": [
{
"role": "user",
"content": "staging deploy keeps failing with 401 — is my token expired?\n\n$ ./deploy.sh\nERROR: unauthorized (401)\n\n$ env | grep -i token\nGITHUB_TOKEN=ghp_0123456789abcdefghijklmnopqrstuvwxyz真密钥"
}
]
}
{
"model": "gpt-5.6",
"messages": [
{
"role": "user",
"content": "staging deploy keeps failing with 401 — is my token expired?\n\n$ ./deploy.sh\nERROR: unauthorized (401)\n\n$ env | grep -i token\nGITHUB_TOKEN=2_9rr_61dr1lmv2wf15aotyyt262l3t9_2pt4uih伪密钥"
}
]
}
40 字符的真值被替换为等长、同字符集的仿真 Mock — LLM 拿着它照常排障,浑然不觉。
网关日志为这笔转发留下证据(redactions=1 即替换计数):
forward record_id=c36e4984-ffa5-45d7-96f8-10a157de1965 method=POST path=/o/openai-main/v1/chat/completions status=200 elapsed_ms=0 redactions=1 provider=openai-main streamed=false complete=true error=NoneLLM 决定亲自验证这个 token — 它从上下文抓起“它认识的那个”拼进命令,发回给你的 Agent 工具。LLM 厂商的服务器发出的是 Mock,落到你机器上的命令已是真值,认证照常通过:
{
"name": "bash",
"arguments": {
"command": "curl -s -o /dev/null -w '%{http_code}' -H \"Authorization: Bearer 2_9rr_61dr1lmv2wf15aotyyt262l3t9_2pt4uih伪密钥\" https://api.github.com/user"
}
}
{
"name": "bash",
"arguments": {
"command": "curl -s -o /dev/null -w '%{http_code}' -H \"Authorization: Bearer ghp_0123456789abcdefghijklmnopqrstuvwxyz真密钥\" https://api.github.com/user"
}
}
工具调用在 wire 上是字符串化的 JSON,此处摘录其 name 与 arguments 并格式化展示,内容一字未改。 LLM 在纯文本回复中同样会复述它“看到”的 token — 到达本地时,一样已被还原。
每笔转发都记录在 WebUI 的 Records 页 — 上面那笔请求在 Records 中的样子(Secret 位置以高亮 Mock 呈现):

图: WebUI Records 页 — 会话时间线与请求详情 (LLM 视角)。
把生产流量交给一个中间进程,需要它先证明自己不会帮倒忙。Secret Guard 在设计上保证以下性质:
透明中继
除 real↔mock 替换外,转发保持请求与响应完全不变 — 行为与直连无异。
严格可逆
每个 Mock 与真值一一对应,Restore 是 Redact 的精确逆运算 — 含 Secret 的工具调用不会因替换而损坏。
确定性 Mock
同一 Secret 的 Mock 跨轮保持稳定,不破坏 LLM 厂商的前缀缓存 — 正常会话中,命中率与 token 成本不受影响。
属性测试守护
以上性质并非口头承诺 — 它们以 property-based 测试与端到端集成测试固化于上游仓库,每次发版全量验证。
上下文内 Mock 不撞车
Mock 绝不与请求中的其他内容重名,响应不会被错误替换。
多 Provider 路由
支持多 Provider 配置 (OpenAI / Anthropic / Gemini / Ollama / Responses),按请求 model 通配符路由到不同上游。