你的 AI 助手,正在悄悄污染你的电脑环境

你的 Agent 给你乱装工具了吗
起因:我只是想看看装了啥
有一天我打开终端,随口问了一句:
帮我看一下 Homebrew 安装了啥,列一下都是干啥的。
然后我看到了一个让我愣住的列表:175 个 formula、4 个 GUI 应用。
问题不在于数量多。问题是,里面绝大多数我根本不认识,更不可能是我主动安装的。
真正引起警惕的是这句话:
其余都是啥的依赖?太多了我看着。
当用户开始对一台新电脑产生“垃圾场”的感觉时,就该认真查一次了。
问题一:agent 为什么会乱装工具?
现在电脑里不止 Codex,还有 Claude Code、Gemini、OpenCode、WorkBuddy、QoderWork、Trae、Cursor、QClaw 等一堆 agent。
它们有一个共同特点:工具缺失时,第一反应不是“问用户”,而是“自己装一个”。
背后的原因并不难理解:
- 技能文档里写着
brew install poppler、brew install tesseract,agent 照做。 - agent 把“任务完成”看得比“环境干净”重要。
- agent 没有“这是我的电脑”的主人翁意识。
- 用户没有在规则里告诉它:安装前要问、用完要删。
尤其危险的是这类组合:
- 一次性的 PDF 转换,结果装了
poppler全家桶。 - 一次性的视频处理,结果装了
ffmpeg-full加 99 个依赖。 - 一次性的 OCR,结果装了
tesseract和语言包。 - agent 明明看到你在用
nvm,还是执行了brew install node。
于是系统环境越来越乱,但没有任何一个 agent 觉得自己做错了。
问题二:乱装之后会留下什么?
以一个典型的“媒体处理”安装为例:
ffmpeg-full → 拉入约 99 个依赖
imagemagick-full → 拉入约 59 个依赖
poppler → 拉入约 45 个依赖
tesseract-lang → 拉入约 37 个依赖
cfr-decompiler → 拉入约 26 个依赖这些数字是已安装的传递依赖数量,不是“安装文件数”。
而且它们之间高度重叠:
- 一堆 X11 图形库
- 一堆图片编解码库
- 一堆字体库
- 一堆压缩库
- 一堆加密库
你可能只是想把 PDF 转成文字,但系统却多出了几十个以后永远不会主动用到的 C 库。
更麻烦的是重复安装:
nvm 已经装好了 node@22
agent 又执行:brew install node结果就是:
- 两套 Node
- 两套 PATH
- 全局包装到了错误的位置
- 你删掉一个,另一个 agent 又装回来
排查思路:先分清楚“我装的”和“依赖”
真正有用的第一刀,不是 brew list,而是这条命令:
brew list --formula --installed-on-request它列出的是你明确要求安装的 formula,而不是被其他包拖进来的依赖。
完整排查链路如下:
# 1. 全量安装清单
brew list --formula
brew list --cask
# 2. 哪些是你主动装的
brew list --formula --installed-on-request
# 3. 哪些是顶层包(没有被其他已安装包依赖)
brew leaves
# 4. 版本
brew list --versions
# 5. 某个包拉入了哪些依赖
brew deps --installed <包名>
# 6. 反向查:某个依赖被谁使用
brew uses --installed <依赖名>
# 7. 可自动清理的孤儿
brew autoremove --dry-run
# 8. 是否有依赖缺失
brew missing实战中我发现的最有价值的组合是:
for p in $(brew list --formula --installed-on-request); do
echo "$p: $(brew deps --installed "$p" | wc -w) deps"
done | sort -t: -k2 -nr它直接告诉我:谁才是“依赖大户”。
结果非常清晰:
ffmpeg-full 99 deps
imagemagick-full 59 deps
poppler 45 deps
tesseract-lang 37 deps
cfr-decompiler 26 deps清除方法:删根包,不要手动删依赖
最常见的错误是:看到一堆依赖,一个个 brew uninstall。
正确做法是:
# 删掉主动安装的大包
brew uninstall ffmpeg-full imagemagick-full poppler tesseract-lang
# 让 Homebrew 自己判断还有哪些依赖没人用
brew autoremoveHomebrew 会自动清掉那些“只被已删除包需要”的依赖。
不过这里有一个坑:依赖环会让自动清理失效。
我这次遇到一组:
libtiff <-> webp两者互相依赖,形成一个环,于是 brew autoremove 认为它们都不是孤儿:
giflib
jpeg-turbo
libpng
libtiff
lz4
webp
xz
zstd这 8 个包已经没有任何“主动安装”的包在使用了,但自动清理扫不出来。
解决办法是手动拆环:
brew uninstall libtiff webp
brew autoremove拆掉环之后,剩下的 6 个依赖也被自动清掉了。
清理后,整机从 175 个 formula 降到 24 个,并且:
brew autoremove --dry-run # 无输出
brew missing # 无输出问题三:skill 才是真正的“安装入口”
清完 Homebrew 后,我又做了一次更深的排查:
这些包是不是某个 agent skill 要求安装的?
于是我把所有 agent 的配置目录都翻了一遍:
| Agent | 主要配置目录 |
|---|---|
| Codex | ~/.codex/、~/.agents/skills/ |
| Claude Code | ~/.claude/ |
| Gemini | ~/.gemini/ |
| OpenCode | ~/.config/opencode/ |
| WorkBuddy | ~/.workbuddy/ |
| QoderWork | ~/.qoderwork/、~/.qoderworkcn/ |
| Trae | ~/.trae/、~/.trae-cn/ |
| CodeBuddy CN | ~/.codebuddy/ |
| QClaw | ~/.qclaw/ |
每个目录里再搜 skills 和 MCP:
find ~/.workbuddy ~/.qoderwork ~/.qclaw ~/.trae ~/.codebuddy \
-iname 'SKILL.md' -o -iname '*mcp*.json' 2>/dev/null然后在所有 skill 里搜 Homebrew 安装指令:
rg -n -i 'brew install|homebrew' \
~/.workbuddy/skills \
~/.qoderwork/skills \
~/.qclaw/skills \
~/.trae/builtin \
~/.codebuddy/skills-marketplace \
~/.claude/plugins 2>/dev/null搜索结果比我预想的更密集:
- WorkBuddy 的
markitdown-skill:brew install tesseract - QoderWork 的
docxskill:brew install pandoc、brew install poppler、brew install --cask libreoffice - CodeBuddy 市场 skills:大量
ffmpeg、poppler、tesseract、ghostscript、libreoffice、webp、node@20、python@3.11 - QClaw 的
qclaw-env:直接是一个“环境安装器 skill”,覆盖 node、python、go、uv、gh、jq、ripgrep、ffmpeg 等 - Claude 官方插件市场:LSP 插件、code-review、plugin-dev 等都写了 brew 安装命令
结论很明确:agent 不是随机乱装的,它是照着 skill 文档装的。
所以要管住 agent,就要管住它的规则文件。
制定约束:一套可以给所有 agent 用的安装守则
我最终沉淀了一套规则,核心如下:
环境安装守则:
1. 禁止直接执行 brew install / npm install -g / pip install --global / go install,
除非用户明确同意。
2. 安装前必须检查现有环境:
- command -v <工具>
- nvm ls(Node)
- pyenv versions(Python)
- sdk list java / sdk current(Java、Maven)
3. Node 只能用 nvm;Python 只能用 pyenv;Java/Maven 只能用 SDKMAN。
4. 一次性工具优先使用 npx、pipx、uvx、docker run --rm,用完即弃。
5. 必须 brew install 时,先确认,用后立即 uninstall + autoremove。
6. 安装前说明:装什么、装到哪里、是否写 PATH、是否自动清理。
7. 优先复用项目环境:.venv/bin、node_modules/.bin、$(go env GOPATH)/bin。这套规则解决三个真实痛点:
- 不拦着完成任务,只拦着污染环境。
- 给出替代方案,否则 agent 还是会选择它最熟悉的方式。
- 把“装完怎么收尾”也写进去。
给不同 agent 加约束
不同 agent 的规则读取位置不一样,我按实际目录整理了一份:
| Agent | 放哪里 |
|---|---|
| Codex | 工作区 AGENTS.md |
| Claude Code | ~/.claude/CLAUDE.md |
| Gemini | 工作区 AGENTS.md 或会话开头 |
| OpenCode | 工作区 AGENTS.md |
| WorkBuddy | ~/.workbuddy/skills/install-policy/SKILL.md |
| QoderWork | ~/.qoderwork/skills/install-policy/SKILL.md |
| QClaw | ~/.qclaw/skills/qclaw-rules/ |
| Trae / Trae CN | 自定义 skill 或规则设置 |
| CodeBuddy CN | App 设置或自定义 skill |
| Cursor | .cursor/rules/*.mdc |
以 Claude Code 为例,直接把规则追加到:
echo '# 环境安装守则
- 禁止直接执行 brew install / npm install -g。
- 安装前先检查 nvm、pyenv、sdkman。
- 一次性工具优先 npx、pipx、uvx、docker run --rm。
- 必须 brew 时先询问,用后 uninstall + autoremove。' >> ~/.claude/CLAUDE.md以 QoderWork 为例,可以新建一个自定义 skill:
---
name: install-policy
description: 环境安装守则。任何安装类任务必须先读取本 skill。
---
1. 禁止 brew install node、python、openjdk。
2. 优先 nvm、pyenv、SDKMAN 已有版本。
3. 一次性工具用 npx、pipx、uvx、docker run --rm。
4. 必须 brew install 时先询问用户,用后立即清理。放到:
~/.qoderwork/skills/install-policy/SKILL.mdQClaw 则可以直接修改已有规则:
~/.qclaw/skills/qclaw-rules/一次性工具的“用完即弃”方案
如果以后真的需要临时工具,建议按这个表选:
| 场景 | 方式 |
|---|---|
| npm 工具 | npx 包名 |
| Python 工具 | pipx run 包名 或 uvx 包名 |
| Go 工具 | go run,不写 GOPATH |
| 音视频处理 | docker run --rm -v $PWD:/work -w /work <镜像> |
| PDF 处理 | 带 poppler 的 docker 镜像 |
| 临时二进制 | 下载到 /tmp,用完删除 |
| 项目内工具 | .venv/bin、node_modules/.bin |
原则只有一个:让它活不过这次任务。
定期体检命令
给 agent 定好规矩之后,也不能完全不管。建议每隔一段时间跑一遍:
# 我主动装了什么
brew leaves
brew list --formula --installed-on-request
# 有没有孤儿
brew autoremove --dry-run
# 有没有坏依赖
brew missing
# 谁是大户
for p in $(brew list --formula --installed-on-request); do
echo "$p: $(brew deps --installed "$p" | wc -w) deps"
done | sort -t: -k2 -nr | head -20
# 哪些 skill 想装东西
rg -n -i 'brew install' ~/.claude ~/.gemini ~/.workbuddy ~/.qoderwork \
~/.qclaw ~/.trae ~/.codebuddy 2>/dev/null | head -50结尾
Agent 会越来越主动,这是趋势。
但“主动”不等于“自作主张”。工具安装应该是环境治理中最需要权限控制的一类操作,因为它不可见、累积快、清理成本高。
给每个 agent 加一条规则,比事后清理一百次都有效:
先看有没有,再问要不要,用完必须走。
干净的系统不是靠一次清理,而是靠一套约束。
附录:本次使用的主要排查命令
brew list --formula
brew list --cask
brew list --versions
brew list --formula --installed-on-request
brew leaves
brew deps --installed <包名>
brew uses --installed <依赖名>
brew autoremove --dry-run
brew autoremove
brew missing