为什么你的 AI 代理需要一个 Shell(以及如何安全地为它们提供)
I’m happy to translate the article for you, but I need the actual text of the article in order to do so. Could you please paste the content you’d like translated (excluding the source link you’ve already provided)? Once I have the text, I’ll translate it into Simplified Chinese while preserving the formatting, markdown, and any code blocks or URLs.
Claude Code — 对代理架构的新视角
Claude Code 改变了我对代理架构的看法。它的表现超越了那些装载了 50 个不同 MCP 服务器和自定义集成的代理,并且其内部实现异常简洁:
- 没有工具蔓延。
- 没有占用大量上下文的庞大模式定义。
- 只有文件系统和 Bash。
AI 社区正开始拼凑出 它为何如此有效 的原因,许多人也在重新审视我们在自己的代理上堆砌的复杂性。
两种“默认”方法
当构建需要处理数据的代理时,我们大多数人会默认使用以下三种模式之一:
- Prompt stuffing – 将所有内容塞入上下文窗口并寄望于最佳结果。
- Tool libraries – 连接 MCP 服务器,定义自定义工具,为代理提供获取所需信息的方式。
- Vector search – 对数据进行嵌入,运行语义相似度检索,祈祷检索结果相关。
这些方法可行,但各有权衡:
| Approach | Pros | Cons |
|---|---|---|
| Prompt stuffing | 简单,无需额外基础设施 | 很快触及 token 限制 |
| Vector search | 在语义相似性方面表现出色 | 在处理结构化数据的精确值时表现不佳 |
| Tool libraries | 解决能力问题 | 每新增一个工具都需要添加模式定义,增加模型需要推理的选项,并扩大故障的潜在范围 |
第三选项 – 文件系统 + Bash
为什么它有意义
- 训练数据 – 大型语言模型在数十亿行代码上进行训练,其中包括无数开发者浏览目录、grep 文件以及在复杂代码库中管理状态的示例。
- 原生原语 – 像
grep、cat、find和awk这样的命令是模型的“原生语言”,不需要额外教它们。
Vercel 团队在重建内部代理时发现了这一点。通过用 仅两样东西——文件系统工具和 Bash 工具——替换大多数自定义工具,他们:
- 将他们的销售通话摘要代理的成本从 ≈ 每通话 $1.00 降至 ≈ Claude Opus 上的 $0.25。
- 提升了输出质量。
Bash 启用的代理可以做什么
- 连接任何东西 –
curlAPI、数据库的 CLI 工具、云服务、Kubernetes 等。 - 存储并检索自身上下文 – 将发现写入文件,暂停,稍后再回来;文件系统成为工作记忆。
- 精确检索 –
grep -r "pricing objection" transcripts/返回精确匹配,而不是相似度分数。 - 自然的数据层次结构 – 客户记录、工单历史、CRM 导出可以干净地映射到目录。
- 完整的可调试性 – 你可以看到每个被读取的文件、执行的命令以及写入的输出。
直觉: 如果一个代理能够在代码库中导航以查找错误,它同样可以以相同方式在你的业务数据中导航。如果它能够运行 shell 命令,它就能与几乎所有你已经在使用的系统交互。
Source: …
安全 – 对 Bash 访问进行沙箱化
让 AI 代理拥有无限制的 Bash 访问是令人恐惧的。一次幻觉式的 rm -rf 就可能导致灾难。解决方案是沙箱化:
- 在一个隔离的环境中运行代理的命令,防止其触及生产系统。
- 将代理能够思考的内容(挂载的目录)与它实际能够执行的操作(沙箱执行器)分离。
架构概览
Agent receives task
↓
Explores filesystem (ls, find)
↓
Searches for relevant content (grep, cat)
↓
Sends context + request to LLM
↓
Returns structured output
Bash 执行在隔离的沙箱中进行,让你在没有风险的前提下拥有本地文件系统操作的能力。
沙箱需求
| 需求 | 描述 |
|---|---|
| 进程隔离 | 命令在受限环境中运行,无法突破到宿主机。WebAssembly 运行时是理想选择,因为它们天生提供内存安全的执行。 |
| 目录挂载 | 只暴露代理需要的目录(例如,将 /project 挂载为 /workspace)。其他所有内容在代理视角下根本不存在。 |
| 会话持久化 | 对于多步骤工作流,保持配置和状态跨命令持续,而不会泄漏到其他会话。 |
| 可见执行路径 | 捕获 stdout、stderr 以及完整的命令历史,以便你能够审计到底发生了什么。 |
安全模型是深度防御:即使代理生成了意外的命令,沙箱也会限制实际能发生的事情。
关于 MCP(模型上下文协议)的简要说明
如果你一直在关注 AI 工具领域,可能已经听说过 MCP。Anthropic 于 2024 年底发布了它,并迅速成为将代理(agent)连接到外部工具和数据的事实标准。
- MCP 之前:每一对配对(例如,GitHub ↔ agent、Slack ↔ agent、数据库 ↔ agent)都需要定制集成。
- MCP 之后:你只需为每个工具构建 一个 MCP 服务器,为每个代理构建 一个 MCP 客户端——把 N × M 的集成问题转化为 N + M 的问题。
TL;DR
- 将 filesystem + Bash 作为面向代理的通用本地工具集。
- 对 Bash 执行进行 Sandbox,以确保生产环境安全。
- 利用 MCP 处理所有剩余的外部工具连接需求。
这种方法可以消除工具杂乱,降低成本,并为您提供透明、易于调试且强大的代理架构。
为什么选择 CLI 工具而非 MCP?
当 MCP 的使用规模扩大时,会出现一个严重问题:工具定义会占用 LLM 的上下文窗口。每个工具都带有描述、参数和返回模式。连接数十个 MCP 服务器、上百个工具,你会在代理甚至开始工作之前就耗尽 token。
Unix 哲学的优势
- 小巧、模块化、可组合 – CLI 工具接受文本输入,输出文本,并且可以串联使用。
- 经受考验 –
git、grep、curl、jq已经在生产环境中运行了数十年。 - 稳定且文档完善 – 它们的接口很少改变。
LLM 在训练期间已经见过这些工具数十亿次。它们已经掌握了语法、标志、常见模式和错误信息。这不是“上下文学习”;而是深层、内化的知识。
MCP 与 CLI 的对比
| 方面 | MCP | CLI |
|---|---|---|
| 学习曲线 | 代理必须从提供的模式(插件式能力)中学习每个工具。 | 代理已经了解该工具(原生理解)。 |
| 可组合性 | 并非真正可管道化;将输出链入输入相当笨拙。 | 简单的管道:grep "error" logs.txt | wc -l – 模型知道如何构造它们。 |
| Token 效率 | 高 – 每个工具定义都会增加 token。 | 低 – 只需要命令文本。 |
| 安全性 | 需要为每个服务器定制沙箱。 | 需要对任意 Shell 访问进行沙箱(真正的挑战)。 |
MCP 在分发和可发现性方面表现出色,尤其适用于非技术用户或高度领域特定的工作流。但就原始能力而言——让代理真正能够执行任务——CLI 工具更胜一筹:它们更省 token、可组合性更强,并且与模型已经擅长的操作相契合。
核心问题:安全的 CLI 访问
允许代理执行任意 shell 命令是极其危险的。我们需要一个沙箱,它能够:
- 在 macOS、Linux 和 Windows 上 可移植。
- 提供 强隔离(WASM 或微型 VM)。
- 易于在命令行使用。
介绍 Bashlet
Bashlet 是一个开源工具,为 AI 代理提供沙箱化的 Bash 访问。
它根据平台和安全需求,支持多种隔离后端。
| 后端 | 特性 |
|---|---|
| Wasmer (WASM) | 跨平台、轻量级沙箱。可在 macOS、Linux、Windows 上运行。启动约 50 ms。 |
| Firecracker (microVM) | 完整的 Linux VM 隔离,提供硬件级安全。仅限 Linux,需 KVM。启动约 125 ms。 |
默认情况下,Bashlet 会自动选择最佳可用后端。
- Linux + KVM → 使用 Firecracker VM。
- 其他所有平台 → 使用 Wasmer WASM 沙箱。
基本工作流
# 1️⃣ Create a session with a mounted directory
bashlet create --name demo --mount ./src:/workspace
# 2️⃣ Run commands in isolation
bashlet run demo "ls /workspace"
bashlet run demo "grep -r 'TODO' /workspace"
# 3️⃣ Terminate when done
bashlet terminate demo
一次性命令(无会话管理)
bashlet exec --mount ./src:/workspace "ls /workspace"
预设:停止重复设置
许多工作流需要相同的挂载、环境变量和设置命令。只需在 ~/.config/bashlet/config.toml 中定义一次:
[presets.kubectl]
mounts = [
["/usr/local/bin/kubectl", "/usr/local/bin/kubectl", true],
["~/.kube", "/home/.kube", true]
]
env_vars = [["KUBECONFIG", "/home/.kube/config"]]
setup_commands = ["kubectl version --client"]
[presets.nodejs]
mounts = [["~/.npm", "/home/.npm", false]]
env_vars = [["NODE_ENV", "development"]]
workdir = "/app"
使用预设
# Create a session with a preset
bashlet create --name k8s-env --preset kubectl
# One‑shot command with a preset
bashlet exec --preset kubectl "kubectl get pods"
# Auto‑create session if missing, apply preset, then run
bashlet run dev -C --preset nodejs "npm install"
后端特定预设
想让工作负载始终在 Firecracker 中运行吗?在预设中添加 backend(以及可选的自定义 rootfs_image):
[presets.dev-vm]
backend = "firecracker"
rootfs_image = "~/.bashlet/images/dev.ext4"
env_vars = [["EDITOR", "vim"]]
对 rootfs 的更改会在会话之间持久保留——只需安装一次软件包,即可永久复用。
安装
Bashlet 可在 GitHub 上获取。只需运行一个脚本(包括 Wasmer 和 Linux 上的 Firecracker),约 30 秒即可完成安装:
curl -fsSL https://bashlet.dev/install.sh | sh
更大的图景
随着大型语言模型在编码方面的提升,基于 filesystem primitives 构建的代理也会自动变得更好。通过利用模型训练时使用的工具——而不是与需要持续维护的自定义工具作斗争——我们可以保持代理架构 simple, fast, and secure。
Give your agents the tools they were trained on.