更新时间:2026-07-01。依据是当前机器上
~/.comate/extensions/baidu.baidu-cc-2.1.158-rc.0/的实地探查(duccshell、claude-go二进制 strings、resources/settings.json、~/.baidu-cc/user.json)。版本升级后细节可能变,但分层思想不会。
Ducc 是什么,不是什么?
Ducc(baidu-cc)不是 Claude Code 的分叉,也不是自己实现的 agent runtime,而是官方 Claude Code CLI 的二次分发容器。它把官方 claude.exe 完整打包进扩展目录,运行时不 patch 一行 CLI 代码,只做三件事:合成配置、注入签名、拉起官方 CLI。
它要解决的核心问题很清楚:让 Claude Code 在不知道自己被代理的前提下,把请求发到百度内部 oneapi 网关,并携带足够信息让网关完成鉴权、模型路由和审计。
一次 ducc 启动的四层调用链
先看整条链路的形状,后面再逐层拆开:
每一层的职责边界都很薄,这也是它能在 Claude Code 版本频繁更新时保持稳定的关键。
第一层:ducc 只是个 shell 包装
入口脚本 ~/.comate/baidu-cc/bin/ducc 是软链,指向扩展 resources 里的同名 shell(native-binary/bin/ducc)。整个脚本只做三件事:
- 清
http_proxy/https_proxy等代理变量,避免走本机全局代理导致签名请求被拦。 - 导出
DISABLE_BAIDU_CLAUDE_UPDATE=1和BAIDU_CC_PLATFORM=AIIDE-terminal,前者关掉官方 auto-update,后者让上游区分调用平台。 sed就地把resources/settings.json和no-baidu-settings.json里的占位符~/.baidu-cc/baidu-cc替换成 resources 的真实绝对路径,然后 exec 同目录的claude-go。
⚠️ 这里的
sed -i ''会改扩展目录里的 settings.json 本身,所以扩展升级后占位符会被重置为下一次启动时再替换,这个副作用是有意为之,不是 bug。
第二层:claude-go 才是 Ducc 主体
claude-go 是一个 6.3 MB 的 Go 编译产物,负责真正的桥接工作。从二进制 strings 能确认它至少做四件事。
合并两份配置
Ducc 有两份配置文件,分工非常清晰:
| 文件 | 角色 | 谁在维护 |
|---|---|---|
resources/settings.json | 扩展默认模板(含 ANTHROPIC_BASE_URL、hooks、permissions、statusLine) | 扩展安装/升级时写入 |
~/.baidu-cc/user.json | 用户覆盖层(含 ANTHROPIC_AUTH_TOKEN、模型别名、登录态) | Ducc 登录流程写入 |
claude-go 启动时读 user.json 的 env 段,merge 进 settings.json 的 env 段,日志里能看到 Synced N env configs from user.json to <settings.json>。这套分层的好处是:扩展升级会覆盖模板,但 token 存在用户目录不会丢。
⚠️ 这不是内存 merge,是持久化写入。
claude-go会把 user.json 的 env 项真的写回扩展目录的resources/settings.json里。这带来一个反直觉后果:你在 user.json 里加过的任何 env 项(比如ANTHROPIC_BASE_URL),即使之后从 user.json 里删掉,settings.json 里的那条不会被自动清除。想彻底回滚,必须两份文件都还原(详见文末回滚清单)。
如果 settings.json 损坏,claude-go会从https://oneapi-comate.baidu-int.com或http://baidu-cc-client.bj.bcebos.com远端拉一份回来(Restored settings.json from remote download),这是 Ducc 自愈能力。
计算 ANTHROPIC_CUSTOM_HEADERS
这是整个桥接机制里最关键的一步。claude-go 会拼一段 JSON 塞进 ANTHROPIC_CUSTOM_HEADERS,格式大致是:
comate_custom_header:{
"agentId": "ducc:user:<username>",
"username": "...",
"repo": "...",
"source": "ducc",
"os": "darwin",
"x-source-auth-version": "v1",
"x-source-auth-timestamp": "2026-07-01T12:50Z",
"x-source-auth-signature": "<HMAC/RSA 签名>"
}x-source-auth-signature 是拿本地密钥对 timestamp 做的签名,让 oneapi 网关能验证请求确实来自合法 Ducc 客户端,而不是有人抓到 token 后自己伪造。
⚠️ 签名字段每次启动重算,光有
ANTHROPIC_AUTH_TOKEN也无法绕过网关鉴权,这是 token 泄露的兜底防线。
有两种场景会跳过这段头:命令行显式加 --disable-model-proxy,或者使用组织级模型(日志:Using org model - skipping ANTHROPIC_CUSTOM_HEADERS)。
拉起官方 claude.exe
最后 claude-go exec resources/claude-code/bin/claude.exe(215 MB,官方 Claude Code CLI 的独立打包版本),并通过 --settings <path> 把合并好的 settings.json 传进去。所有 env 变量随子进程继承。
第三层:官方 Claude Code 完全无感
对官方 CLI 而言,这就是一次「读到了几个 env 变量」的普通启动:
| 环境变量 | 作用 |
|---|---|
ANTHROPIC_BASE_URL | 请求发到 https://oneapi-comate.baidu-int.com 而不是 Anthropic 官方 |
ANTHROPIC_AUTH_TOKEN | 当作 API key 放进 Authorization 头 |
ANTHROPIC_CUSTOM_HEADERS | 每次 HTTP 请求都带上百度自定义头(含签名) |
ANTHROPIC_MODEL / ANTHROPIC_DEFAULT_OPUS_MODEL 等 | 请求 body 里的 model id,如 Claude Opus 4.7[1m] |
--settings <path> | 复用同一份 settings.json 里的 hooks / permissions / statusLine |
所以官方 CLI 什么都不用改,oneapi-comate 网关承担了「校验签名 → 换算模型 id → 转发到真正上游」的工作。这也是 Ducc 敢宣传「兼容 Claude Code 全部开放能力」的根本前提——它压根没碰这些能力的实现。
为什么这套设计能稳?
Ducc 的精妙之处在于每一层只做自己的事:
duccshell 只做环境清洗和路径修复,改也是改配置模板不是改代码。claude-go只做配置合成和签名注入,不实现任何 agent 逻辑。- 官方
claude.exe只做 Claude Code 的本职工作。 - oneapi-comate 网关只做鉴权和路由,模型上游可以随时换。
这带来两个直接后果:Claude Code 版本更新时 Ducc 只需要换 claude.exe 包,不用改任何桥接逻辑;上游模型切换时(比如某天换成百度自研)只需要改网关端映射,客户端零感知。
这套「不改内核,只改入口 + 配置 + 网关」的思路和 Codex 低侵入扩展架构思想 里提炼的「统一入口 + 生命周期事件 + 外挂控制面」是同一套心智模型的两个变种。
想动 baseUrl / authKey 的时候看这里
三份文件的实际分工
虽然只有两份配置文件,但因为 sync 机制的存在,实操时要同时想着三个位置:
| 位置 | 作用 | 手改风险 |
|---|---|---|
~/.baidu-cc/user.json 的 env | 用户覆盖层,改这里最安全 | 扩展升级不会丢;claude-go 会 sync 到 settings.json |
resources/settings.json 的 env | 模板+运行态混合,同时被扩展升级和 sync 覆盖 | 直接改会被下次 sync 覆盖;扩展升级也会重置 |
| Ducc 进程环境变量 | 上述两份合并后的最终生效值 | 只读,看 env | grep ANTHROPIC_ 就知道实际读到什么 |
正确改法
想持久生效、不被扩展升级冲掉:只改 user.json 的 env 段,让 claude-go 每次启动帮你 sync 到 settings.json。
⚠️ 但要注意:换掉
ANTHROPIC_BASE_URL后,ANTHROPIC_CUSTOM_HEADERS里的x-source-auth-signature依然会被注入。如果目标网关不校验百度签名(比如原生 Anthropic API 或自建代理),多带这段头一般无害;如果目标网关严格校验且签名对不上,反而会失败。想彻底关掉签名注入,加--disable-model-proxy启动。
彻底回滚清单(踩过的坑)
只从 user.json 里删掉一条 env 项不够,因为它已经被 sync 到 settings.json 落盘了。必须两份都还原:
# 1. 还原 user.json
cp ~/.baidu-cc/backups/user.json.bak-XXXX ~/.baidu-cc/user.json
# 2. 还原扩展 settings.json(关键,最容易漏)
cp ~/.baidu-cc/backups/settings.json.bak-XXXX \
~/.comate/extensions/baidu.baidu-cc-*/resources/settings.json
# 3. 新开 ducc 窗口验证
env | grep -E "ANTHROPIC_BASE_URL|ANTHROPIC_AUTH_TOKEN"所以改之前一定先备份两份文件:
TS=$(date +%Y%m%d-%H%M%S)
mkdir -p ~/.baidu-cc/backups
cp ~/.baidu-cc/user.json ~/.baidu-cc/backups/user.json.bak-$TS
cp ~/.comate/extensions/baidu.baidu-cc-*/resources/settings.json \
~/.baidu-cc/backups/settings.json.bak-$TS一次真实的踩坑复盘
clawguard-llm.baidu-int.com 这类 UUAP/零信任网关不能直接当 Anthropic API 用。表现是根路径 302 跳 uuap.baidu.com/login,/v1/messages 无论带不带 token 都是 403(对比 oneapi 无 token 是 401,差别就能看出鉴权方式不同)。这类值往往属于其它协议(OpenAI 兼容 / 内部 SDK 专用),换域名前先用 curl 探测协议和鉴权方式:
# 401 = Anthropic 协议、只是缺 token(可以试)
# 403 + Location 到 uuap = 走 SSO cookie,CLI 场景不能用
# 302 到 login = 同上
curl -sSI -m 8 -X POST https://<target>/v1/messages