目录

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

你的 Agent 给你乱装工具了吗

起因:我只是想看看装了啥

有一天我打开终端,随口问了一句:

帮我看一下 Homebrew 安装了啥,列一下都是干啥的。

然后我看到了一个让我愣住的列表:175 个 formula、4 个 GUI 应用

问题不在于数量多。问题是,里面绝大多数我根本不认识,更不可能是我主动安装的。

真正引起警惕的是这句话:

其余都是啥的依赖?太多了我看着。

当用户开始对一台新电脑产生“垃圾场”的感觉时,就该认真查一次了。

问题一:agent 为什么会乱装工具?

现在电脑里不止 Codex,还有 Claude Code、Gemini、OpenCode、WorkBuddy、QoderWork、Trae、Cursor、QClaw 等一堆 agent。

它们有一个共同特点:工具缺失时,第一反应不是“问用户”,而是“自己装一个”。

背后的原因并不难理解:

  1. 技能文档里写着 brew install popplerbrew install tesseract,agent 照做。
  2. agent 把“任务完成”看得比“环境干净”重要。
  3. agent 没有“这是我的电脑”的主人翁意识。
  4. 用户没有在规则里告诉它:安装前要问、用完要删。

尤其危险的是这类组合:

  • 一次性的 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 autoremove

Homebrew 会自动清掉那些“只被已删除包需要”的依赖。

不过这里有一个坑:依赖环会让自动清理失效

我这次遇到一组:

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-skillbrew install tesseract
  • QoderWork 的 docx skill:brew install pandocbrew install popplerbrew install --cask libreoffice
  • CodeBuddy 市场 skills:大量 ffmpegpopplertesseractghostscriptlibreofficewebpnode@20python@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。

这套规则解决三个真实痛点:

  1. 不拦着完成任务,只拦着污染环境。
  2. 给出替代方案,否则 agent 还是会选择它最熟悉的方式。
  3. 把“装完怎么收尾”也写进去

给不同 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.md

QClaw 则可以直接修改已有规则:

~/.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/binnode_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