OpenClaw 里 TAVILY_API_KEY 明明写在 ~/.bashrc,为什么还是失效?一次完整排查与修复
这次踩了一个很典型、也很容易误判的坑:
明明 ~/.bashrc 里已经配置了 TAVILY_API_KEY,但在 OpenClaw 里使用 Tavily skill 时,依然报 Missing TAVILY_API_KEY 。与此同时,内置 web_search 还因为 Brave Search API 没配 key 直接报错。
看起来像是"配置丢了",但真正的问题并不在 ~/.bashrc 本身,而在 Gateway 进程的启动方式。
这篇文章把完整的排查链路、根因分析和修复步骤整理出来,给遇到类似问题的同学一个可复用的参考。
问题现象
最开始暴露出来的是两个现象:
1. 内置 web search 报 Brave API key 缺失
调用内置搜索时,直接拿到类似下面的错误:
text
missing_brave_api_key
这说明当前 OpenClaw 的内置 web_search 走的是 Brave Search,而不是 Tavily。
2. Tavily skill 明明装了,但实际不可用
Tavily skill 的 SKILL.md 里已经写得很清楚:
markdown
Needs TAVILY_API_KEY from https://tavily.com
我进一步检查运行环境,结果是:
text
TAVILY_API_KEY_SET=no
这就奇怪了:终端里明明能看到 ~/.bashrc 中存在 export TAVILY_API_KEY=...,为什么 OpenClaw 运行时却拿不到?
第一层判断:不是 Tavily 没装,而是运行环境没拿到 key
先看 Tavily skill 本身。
它的搜索脚本逻辑非常直接:
javascript
const apiKey = (process.env.TAVILY_API_KEY ?? '').trim();
if (!apiKey) {
console.error('Missing TAVILY_API_KEY');
process.exit(1);
}
这意味着只要当前进程环境里没有 TAVILY_API_KEY,它就一定失败。
所以问题就从"有没有写配置"转变成了:
到底是谁在启动 OpenClaw Gateway,它启动时有没有继承 shell 环境变量?
第二层判断:Gateway 不是从当前 shell 启动的
继续检查 OpenClaw Gateway 状态:
bash
bash -i -lc 'openclaw gateway status'
输出里有一个关键点:
text
Service: systemd (enabled)
Service file: ~/.config/systemd/user/openclaw-gateway.service
这一下就基本破案了。
OpenClaw Gateway 不是我当前 terminal session 里手工启动的长期进程,而是 systemd user service 托管的服务。
这意味着:
- 你在当前 shell 里
source ~/.bashrc - 你在 terminal 里
echo $TAVILY_API_KEY能看到值 - 并不等于 systemd 管理的 Gateway 进程也能看到这个值
因为它们根本不是同一个环境来源。
根因:~/.bashrc 给了 interactive shell,但没给 systemd user service
这是这次问题的核心。
~/.bashrc 什么时候会生效?
通常是:
- 交互式 shell
- 手动打开的 terminal session
- 某些明确 source 它的 bash 进程
但 systemd user service 启动的进程,并不会自动读取你的 ~/.bashrc。
所以会出现一种非常迷惑的状态:
你看到的环境
bash
echo $TAVILY_API_KEY
# 有值
Gateway 真实拿到的环境
text
TAVILY_API_KEY = 空
这也是为什么很多人会说:
"我明明已经 export 了,为什么程序还说没有?"
因为 你 export 给的是当前 shell,不是 systemd service。
修复前顺手做的一个动作:关掉 Brave 内置 web search
既然目前主要想用的是 Tavily 和 LangSearch,而 Brave Search API 不是免费方案,那一个实际的处理方式就是:
先把内置 web_search 关掉 ,避免以后继续因为 BRAVE_API_KEY 报错。
配置修正后,搜索路径就会更清晰:
- LangSearch:查技术文档、代码、资料
- Tavily:做通用网页搜索
- web_fetch:已知 URL 直接抓页面
这个动作不是必须,但在多搜索源共存时很有价值:
先减少噪音,再修主问题。
正确修法:把环境变量导入 systemd user manager
既然 Gateway 是由 systemd user service 启动,那么最短修法就是:
- 在当前 shell 中确认变量存在
- 导入到 systemd user manager
- 重启 Gateway
- 验证新进程已经继承到变量
第一步:确认当前 shell 有值
bash
bash -i -lc 'echo $TAVILY_API_KEY'
如果这里为空,说明你的 ~/.bashrc 本身就没配对,或者没被当前 shell 加载。
第二步:导入 systemd user 环境
bash
systemctl --user import-environment TAVILY_API_KEY FIRECRAWL_API_KEY
这一步非常关键。它会把当前 shell 中的环境变量同步给 systemd user manager。
第三步:重启 OpenClaw Gateway
bash
systemctl --user restart openclaw-gateway.service
这样新的 Gateway 进程就有机会拿到刚刚导入的变量。
第四步:检查 systemd 环境是否已经存在
bash
systemctl --user show-environment | grep -E '^(TAVILY_API_KEY|FIRECRAWL_API_KEY)='
如果能看到输出,说明 systemd user manager 已经持有这些变量。
第五步:验证 Gateway 进程本身是否真的拿到了
可以直接检查进程环境,或者更简单,直接实测 Tavily:
bash
bash -i -lc 'node skills/tavily-search/scripts/search.mjs "OpenClaw latest release" -n 3'
如果能正常返回答案和来源,说明修复已经生效。
实际验证结果
修复完成后,验证结果如下:
shell 环境
text
SHELL_TAVILY=yes
SHELL_FIRECRAWL=yes
systemd user manager 环境
text
TAVILY_API_KEY=<redacted>
FIRECRAWL_API_KEY=<redacted>
Gateway 进程环境
text
PROC_TAVILY=yes
PROC_FIRECRAWL=yes
Tavily 实测
已经成功返回 OpenClaw 最新 release 的答案和来源。
这说明修复不是"看起来像好了",而是 从 shell → systemd → Gateway → skill 调用链路全部打通了。
还有一个容易被忽略的问题:~/.bashrc 里重复定义了两次 TAVILY_API_KEY
排查过程中还发现一个隐患:
~/.bashrc 里曾经同时存在两个 export TAVILY_API_KEY=...。
这类问题的风险不在于 bash 不能运行,而在于:
- 你自己会误以为某个 key 在生效
- 实际上后面的定义会覆盖前面的定义
- 一旦前后 key 不同,排查时会非常混乱
因此后面又做了一步清理:
只保留一个
TAVILY_API_KEY,删掉旧的/重复的定义。
这一步不直接决定功能是否可用,但会显著降低后续维护成本。
为什么这个问题在 AI Agent / 自动化环境里特别常见?
因为这类系统经常同时存在多种"环境来源":
- 当前终端 shell
- systemd service
- cron
- Docker / container runtime
- IDE 集成终端
- 浏览器自动化子进程
如果你只在某一个地方 export KEY=...,很容易出现"这个地方能用,另一个地方不能用"的现象。
对 AI Agent 场景来说,这类问题尤其常见,因为工具调用往往发生在:
- 后台守护进程
- 独立 worker
- system service
- 子进程链路里
所以经验上更稳妥的原则是:
不要假设
~/.bashrc= 全局真相。要搞清楚:到底是谁在启动你的服务。
一份可复用的最短修复步骤
如果你也遇到类似问题,可以直接按下面这份清单来:
bash
# 1) 确认当前 interactive shell 里有变量
bash -i -lc 'echo $TAVILY_API_KEY'
# 2) 导入到 systemd user manager
systemctl --user import-environment TAVILY_API_KEY FIRECRAWL_API_KEY
# 3) 重启 Gateway
systemctl --user restart openclaw-gateway.service
# 4) 检查 systemd 环境
systemctl --user show-environment | grep -E '^(TAVILY_API_KEY|FIRECRAWL_API_KEY)='
# 5) 检查 Gateway 状态
bash -i -lc 'openclaw gateway status'
# 6) 实测 Tavily
bash -i -lc 'node skills/tavily-search/scripts/search.mjs "OpenClaw latest release" -n 3'
如果第 6 步成功返回结果,基本就说明整条链路已经修好了。
最后的经验总结
这次问题最值得记录的,不是某一条命令,而是排查思路:
- 先看报错发生在哪一层:Brave 还是 Tavily
- 再看 skill 的真正依赖是什么:环境变量还是配置文件
- 再确认服务是谁启动的:interactive shell 还是 systemd
- 最后验证真实运行进程是否继承到变量
很多"明明写了环境变量却不生效"的问题,本质上都不是 key 配错,而是:
你把变量写进了 A 环境,但程序跑在 B 环境。
一旦把这层想清楚,定位和修复就会快很多。
如果你也在折腾 OpenClaw、Tavily、LangSearch 或其他 AI Agent 工具链,希望这篇记录能帮你少踩一个坑。