尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

用 1Password 管理 OpenClaw 的 DeepSeek API 密钥:Docker Compose 报错排查与 config.toml 配置骨架

用 1Password 管理 OpenClaw 的 DeepSeek API 密钥:Docker Compose 报错排查与 config.toml 配置骨架 1. 为什么 Docker Compose 部署 OpenClaw 时密钥总是注入失败如果你正在用 Docker Compose 跑 OpenClaw并且打算用 1Password 来托管 DeepSeek API 密钥那你大概率会遇到下面这几类报错容器启动几秒就退出、日志里写着apiKey is empty、Model is not allowed或者配置向导把 DeepSeek Chat 错误地挂到了 Anthropic 提供方下面。这些问题的根源往往不在 OpenClaw 本身而在于密钥从 1Password 到容器环境变量这条链路上某一环断了。OpenClaw 是一个可以本地部署、通过网关暴露能力的智能体框架它支持 OpenAI 兼容协议所以接 DeepSeek API 是可行的。DeepSeek 提供deepseek-chat和deepseek-reasoner两个主力模型走的是 OpenAI 兼容的/v1接口。问题在于很多人把密钥直接写进docker-compose.yml或者.env既不安全又容易在 Compose 变量替换时踩坑。1Password 的 CLI 工具op可以在启动容器前把密钥注入环境变量做到密钥不落盘但前提是注入命令、Compose 变量引用、容器内读取这三步必须对齐。这篇内容面向的是已经会用 Docker Compose、但对 1Password 注入流程不熟、或者注入后仍然报错的开发者。我会给出可复制的docker-compose.yml和config.toml骨架然后逐条验证先确认 1Password CLI 注入结果再确认容器内环境变量最后复现并定位报错日志。整套流程我自己在本地和一台测试机上跑过踩过的坑会直接标出来。2. TaoToken 前置先把 DeepSeek 密钥和接入信息准备好在讲 1Password 注入之前得先有一个可用的 DeepSeek API 密钥以及一个稳定的接入地址。如果你还没有密钥或者想用统一的网关来管理多个模型的调用可以先去 TaoToken 的控制台创建一个 API Key。TaoToken 的 API 地址是https://taotoken.net/api它兼容 OpenAI 协议所以 OpenClaw 里配置openai-completions协议时可以直接指向它。具体操作上你可以打开 TaoToken 控制台 生成一个 Key然后在 API Keys 页面 管理你的密钥。如果你只是想先验证模型能不能通可以用 模型对话 页面直接发一条消息测试。对于长期跑编码任务或者 Agent 的场景Coding Plan 会更合适因为它的额度策略偏向持续调用。拿到 Key 之后先别急着写进 Compose。你要做的是把这个 Key 存进 1Password 的一个条目里比如命名为OpenClaw DeepSeek字段名用credential或者自定义的api_key。后面op命令会通过op://引用格式来读取它。这一步的意义在于密钥只存在于 1Password 的加密库里Compose 文件和.env里都不出现明文。注意不要把密钥直接写进docker-compose.yml的environment字段也不要用echo打印出来。一旦写进文件Git 提交或者镜像层里就可能残留。3. 可复制配置docker-compose.yml 与 config.toml 骨架下面这份docker-compose.yml的核心思路是用op run包裹docker compose命令让 1Password CLI 在启动前把op://引用解析成真实环境变量再传给容器。这样容器内拿到的就是已经注入好的值。services: openclaw: image: openclaw/openclaw:latest container_name: openclaw restart: unless-stopped ports: - 18789:18789 environment: - DEEPSEEK_API_KEY${DEEPSEEK_API_KEY} - OPENCLAW_CONFIG_DIR/home/node/.openclaw volumes: - ./data:/home/node/.openclaw - ./data/conf:/home/node/.openclaw/conf command: [node, dist/index.js, gateway, --config, /home/node/.openclaw/conf/config.toml]这里的关键是DEEPSEEK_API_KEY${DEEPSEEK_API_KEY}。这个变量不会从.env文件读而是由op run在运行时注入。你启动容器的命令应该是op run --env-file./op.env -- docker compose up -d其中op.env文件内容长这样DEEPSEEK_API_KEYop://Private/OpenClaw DeepSeek/credentialop://后面的路径对应你在 1Password 里的条目和字段。op run会解析这个引用把真实密钥作为环境变量传给后面的docker compose进程Compose 再把它传给容器。整个过程密钥不会出现在 shell 历史里也不会写进磁盘。接下来是config.toml骨架。OpenClaw 的配置格式在不同版本间有差异有的版本用 JSON有的用 TOML。这里给一份 TOML 版本重点是把baseUrl写成带/v1的完整路径并且apiKey用环境变量占位符。[models] mode merge [models.providers.deepseek] baseUrl https://api.deepseek.com/v1 apiKey ${DEEPSEEK_API_KEY} api openai-completions [[models.providers.deepseek.models]] id deepseek-chat name DeepSeek Chat reasoning false input [text] contextWindow 128000 maxTokens 8192 [[models.providers.deepseek.models]] id deepseek-reasoner name DeepSeek Reasoner reasoning true input [text] contextWindow 128000 maxTokens 8192 [agents.defaults.model] primary deepseek/deepseek-chat fallbacks [] [agents.defaults] workspace /home/node/.openclaw/workspace [gateway] port 18789 mode local bind lan [gateway.auth] mode token token ${OPENCLAW_GATEWAY_TOKEN}注意baseUrl这里写的是https://api.deepseek.com/v1而不是https://api.deepseek.com。少了/v1会导致端点探测失败日志里会出现 404 或者unsupported protocol。另外apiKey用${DEEPSEEK_API_KEY}占位OpenClaw 启动时会从环境变量里读。如果你用的是 TaoToken 的网关把baseUrl换成https://taotoken.net/api/v1即可协议仍然是openai-completions。4. 逐条验证从 1Password 注入到容器内环境变量配置写完之后不要直接docker compose up按下面四步逐条验证能省掉大量排查时间。第一步验证 1Password CLI 能不能读到密钥。执行op read op://Private/OpenClaw DeepSeek/credential如果返回一串sk-开头的字符串说明 1Password 条目和字段路径没问题。如果报item not found检查条目名称和字段名是否和op.env里写的一致。注意字段名是区分大小写的。第二步验证op run注入结果。执行op run --env-file./op.env -- env | grep DEEPSEEK_API_KEY你应该看到DEEPSEEK_API_KEYsk-...。如果这里输出为空说明op.env的格式有问题或者op run没有正确解析。常见错误是op.env里写了引号比如DEEPSEEK_API_KEYop://...引号会让op把它当成普通字符串而不是引用。第三步启动容器后确认容器内环境变量。执行docker compose exec openclaw env | grep DEEPSEEK_API_KEY如果容器已经退出用docker compose run --rm openclaw env | grep DEEPSEEK_API_KEY来检查。这一步能确认变量是否真的传进了容器。如果宿主机有、容器里没有检查docker-compose.yml的environment字段有没有写对变量名。第四步复现并定位报错日志。执行docker compose logs --tail100 openclaw重点看有没有apiKey is empty、Model is not allowed、ECONNREFUSED这几类关键词。apiKey is empty说明环境变量没读到Model is not allowed说明agents.defaults.models白名单里没有把deepseek/deepseek-chat加进去ECONNREFUSED通常是baseUrl写错或者网络不通。5. 本篇常见错排查五类高频报错与对应修法5.1 容器启动即退出日志显示 apiKey is empty这是最常见的一类。原因通常是op run没有包裹docker compose命令或者op.env文件路径不对。检查你启动容器的命令是不是op run --env-file./op.env -- docker compose up -d。如果你用的是docker compose up -d直接启动那${DEEPSEEK_API_KEY}会从 shell 环境或者.env文件读而这两处都没有值容器自然拿不到密钥。另一个可能是config.toml里apiKey写成了${DEEPSEEK_API_KEY}但 OpenClaw 的版本不支持这种占位符语法。这种情况下改成从环境变量读取的写法或者确认你的 OpenClaw 版本是否支持${}插值。如果不支持可以在docker-compose.yml里直接把DEEPSEEK_API_KEY传给容器然后config.toml里留空让 OpenClaw 自动从环境变量读。5.2 配置向导把 DeepSeek Chat 关联到 Anthropic 提供方这个报错在通过docker compose run --rm openclaw-cli configure跑配置向导时特别容易出现。原因是向导在探测模型兼容性时可能因为baseUrl缺少/v1或者协议字段没写对误判了提供方类型。修法很简单不要依赖向导自动写入直接编辑data/conf/openclaw.json或者config.toml手动把deepseek提供方的api字段设为openai-completionsbaseUrl设为https://api.deepseek.com/v1。如果你用的是 JSON 配置结构大概是{ models: { mode: merge, providers: { deepseek: { baseUrl: https://api.deepseek.com/v1, apiKey: ${DEEPSEEK_API_KEY}, api: openai-completions, models: [ { id: deepseek-chat, name: DeepSeek Chat, reasoning: false, input: [text], contextWindow: 128000, maxTokens: 8192 } ] } } } }改完之后重启容器docker restart openclaw。注意容器名要换成你自己的比如1Panel-openclaw-uTlW这种。5.3 Model is not allowed 报错这个报错和密钥无关是agents.defaults.models白名单的问题。如果你在配置里定义了agents.defaults.models对象那么智能体只能使用这个列表里列出的模型。如果列表里只有openrouter/deepseek/deepseek-chat而你的primary写的是deepseek/deepseek-chat切换模型时就会报Model is not allowed。修法有两种要么把deepseek/deepseek-chat加进白名单要么直接删掉agents.defaults.models这个对象禁用白名单限制。推荐后者简单直接。5.4 1Password CLI 报 permission denied 或 not signed inop命令需要你先登录并授权。如果你在 CI 或者无头环境里跑需要用OP_SERVICE_ACCOUNT_TOKEN来做服务账号认证。本地开发的话先执行op signin完成登录。如果报permission denied检查 1Password 条目所在的保险库是否对当前账号可见。5.5 容器内能读到密钥但请求仍然 401如果env | grep DEEPSEEK_API_KEY有值但请求 DeepSeek API 返回 401先检查密钥本身是否有效。可以用 curl 直接测curl https://api.deepseek.com/v1/chat/completions \ -H Authorization: Bearer $DEEPSEEK_API_KEY \ -H Content-Type: application/json \ -d {model:deepseek-chat,messages:[{role:user,content:hi}]}如果 curl 也返回 401说明密钥过期或者被撤销去控制台重新生成一个。如果 curl 正常但 OpenClaw 报 401检查config.toml里apiKey的占位符有没有被正确替换有时候 TOML 解析器会把${DEEPSEEK_API_KEY}当成字面量而不是变量。6. 接入验证与后续操作入口配置改完、容器重启之后验证是否真的通了。最直接的方式是看日志里有没有成功的模型调用记录或者用 OpenClaw 的网关接口发一条测试消息。如果你只是想快速确认模型能不能响应可以用 模型对话 页面发一条消息对比返回结果和 OpenClaw 日志里的请求记录。如果你在排障过程中需要重新生成密钥或者检查额度去 API Keys 页面 操作。接入文档在 doc 里里面有不同协议的 baseUrl 写法和参数说明。对于长期跑编码任务或者 Agent 的场景Coding Plan 的额度策略更适合持续调用不用频繁换 Key。最后提醒一句每次改完config.toml或者docker-compose.yml都要重新走一遍op run启动流程不要直接docker restart因为restart不会重新注入环境变量。正确的重启方式是先docker compose down再op run --env-file./op.env -- docker compose up -d。这样能保证密钥始终从 1Password 读取而不是残留在旧容器的环境里。
返回列表