声明
英语不是我的母语。这篇文章最初用中文写成,再借助 AI 翻译为英文。行文可能带有些许 AI 味,但其中的设计决策、生产环境的踩坑故事、以及从中提炼出的原则——都是我自己的。
我曾是 Manus 被 Meta 收购前的后端负责人。过去两年,我一直在构建 AI 智能体——先是在 Manus,后来转向我自己的开源智能体运行时 (Pinix) 和智能体项目 (agent-clip)。一路走来,我得出了一个连自己都感到意外的结论:
**一个 `run(command="...")` 工具配合 Unix 风格的命令,效果优于一整套类型化的函数调用。**
以下是我的所学所悟。
为什么选择 *nix
Unix 在 50 年前做了一个设计决策:一切皆文本流。 程序之间不交换复杂的二进制结构,也不共享内存对象——它们通过文本管道通信。每个小工具专注做好一件事,再通过 | 组合成强大的工作流。程序用 --help 描述自身,用退出码报告成败,用 stderr 传递错误信息。
LLM 在 50 年后做了一个几乎一模一样的决策:一切皆 token。 它们只理解文本,只生成文本。它们的”思考”是文本,它们的”行动”是文本,它们从世界接收到的反馈也必须是文本。
这两个决策相隔半个世纪、出发点截然不同,却殊途同归,汇聚到了同一种接口模型。Unix 为人类终端操作者设计的那套文本系统——cat、grep、管道、退出码、man pages——对 LLM 来说不仅仅是”能用”,而是天然契合。在工具调用这件事上,LLM 本质上就是一个终端操作者——一个比任何人类都快、并且在训练数据中已经见过海量 shell 命令和 CLI 模式的终端操作者。
这就是 *nix Agent 的核心理念:不要发明新的工具接口。把 Unix 经过 50 年验证的东西,直接交给 LLM。
为什么只用一个 run
单工具假说
大多数智能体框架会给 LLM 提供一整套独立的工具目录:
tools: [search_web, read_file, write_file, run_code, send_email, ...]
每次调用之前,LLM 都必须做一次工具选择——用哪个?传什么参数?工具越多,选择就越难,准确率也随之下降。认知负担全花在了”用哪个工具?“上,而不是”我要完成什么任务?”
我的做法是:一个 run(command="...") 工具,所有能力都以 CLI 命令的形式暴露出来。
run(command="cat notes.md")
run(command="cat log.txt | grep ERROR | wc -l")
run(command="see screenshot.png")
run(command="memory search 'deployment issue'")
run(command="clip sandbox bash 'python3 analyze.py'")LLM 仍然需要选择使用哪条命令,但这与在 15 个各有不同 schema 的工具之间做选择,有着本质区别。命令选择是在一个统一命名空间内的字符串组合——而函数选择则是在一堆毫不相关的 API 之间做上下文切换。
LLM 天生就会说 CLI
为什么 CLI 命令比结构化的函数调用更适合 LLM?
因为 CLI 是 LLM 训练数据中密度最高的工具使用模式。GitHub 上数十亿行内容里到处都是:
# README 安装说明
pip install -r requirements.txt && python main.py
# CI/CD 构建脚本
make build && make test && make deploy
# Stack Overflow 解决方案
cat /var/log/syslog | grep "Out of memory" | tail -20我根本不需要教 LLM 怎么用 CLI——它早就会了。 当然,这种熟悉度因模型而异,但在实践中,主流模型的表现都出奇地稳定。
来比较一下同一个任务的两种做法:
Task: Read a log file, count the error lines
Function-calling approach (3 tool calls):
1. read_file(path="/var/log/app.log") → returns entire file
2. search_text(text=<entire file>, pattern="ERROR") → returns matching lines
3. count_lines(text=<matched lines>) → returns number
CLI approach (1 tool call):
run(command="cat /var/log/app.log | grep ERROR | wc -l")
→ "42"一次调用替代三次。不是因为做了什么特殊优化——而是因为 Unix 管道天然支持组合。
让管道和链式调用跑起来
光有一个 run 还不够。如果 run 一次只能执行一条命令,LLM 在处理组合任务时仍然需要多次调用。所以我在命令路由层实现了一个链式解析器(parseChain),支持四种 Unix 操作符:
| 操作符 | 名称 | 语义 |
|---|---|---|
| | Pipe | 前一条命令的 stdout 作为下一条的 stdin |
&& | And | 前一条成功才执行下一条 |
|| | Or | 前一条失败才执行下一条 |
; | Seq | 无论前一条结果如何都执行下一条 |
有了这套机制,每次工具调用都可以是一个完整的工作流:
# 一次工具调用:下载 → 检查
curl -sL $URL -o data.csv && cat data.csv | head 5
# 一次工具调用:读取 → 过滤 → 排序 → 取前 10 条
cat access.log | grep "500" | sort | head 10
# 一次工具调用:尝试 A,失败则回退到 B
cat config.yaml || echo "config not found, using defaults"N 条命令 × 4 种操作符——组合空间急剧膨胀。而对 LLM 来说,这不过是一段它早就知道怎么写的字符串。
核心洞察
命令行就是 LLM 的原生工具接口。
启发式设计:让 CLI 引导智能体
单工具 + CLI 解决了”用什么”的问题。但智能体仍然需要知道**“怎么用”**。它不能 Google,也没法问同事。我采用了三种渐进式设计技巧,让 CLI 本身成为智能体的导航系统。
技巧 1:渐进式 —help 发现
一个设计良好的 CLI 工具不需要你去翻文档——因为 --help 会告诉你一切。我把同样的原则应用到智能体上,将其结构化为渐进式展示:智能体不需要一次性加载所有文档,而是在深入探索的过程中按需发现细节。
Level 0:工具描述 → 命令列表注入
run 工具的描述在每次对话开始时动态生成,列出所有已注册的命令及其一行摘要:
Available commands:
cat — Read a text file. For images use 'see'. For binary use 'cat -b'.
see — View an image (auto-attaches to vision)
ls — List files in current topic
write — Write file. Usage: write <path> [content] or stdin
grep — Filter lines matching a pattern (supports -i, -v, -c)
memory — Search or manage memory
clip — Operate external environments (sandboxes, services)
...智能体从第一轮对话就知道有哪些可用命令,但不需要了解每个命令的每个参数——那纯属浪费上下文。
开放设计问题
注入完整命令列表 vs. 按需发现。随着命令数量增长,列表本身就会消耗上下文预算。我仍在探索合适的平衡点。欢迎提供想法。
Level 1: command(无参数)→ 用法说明
当智能体对某个命令感兴趣时,直接调用就行。没有参数?命令会返回自身的用法说明:
→ run(command="memory")
[error] memory: usage: memory search|recent|store|facts|forget
→ run(command="clip")
clip list — list available clips
clip <name> — show clip details and commands
clip <name> <command> [args...] — invoke a command
clip <name> pull <remote-path> [name] — pull file from clip to local
clip <name> push <local-path> <remote> — push local file to clip现在智能体知道 memory 有五个子命令,clip 支持 list/pull/push。一次调用,毫无噪声。
Level 2: command subcommand(缺少参数)→ 具体参数
智能体决定使用 memory search,但不确定格式?继续深入:
→ run(command="memory search")
[error] memory: usage: memory search <query> [-t topic_id] [-k keyword]
→ run(command="clip sandbox")
Clip: sandbox
Commands:
clip sandbox bash <script>
clip sandbox read <path>
clip sandbox write <path>
File transfer:
clip sandbox pull <remote-path> [local-name]
clip sandbox push <local-path> <remote-path>渐进式展示:概览(注入)→ 用法(探索)→ 参数(深入)。 智能体按需发现,每一层只提供刚好足够进入下一步的信息。
这与把 3000 词的工具文档塞进系统提示词有本质区别。那些信息大部分在大部分时间里都毫无用处——纯粹浪费上下文。渐进式帮助让智能体自己决定何时需要更多信息。
这也对命令设计提出了要求:每个命令和子命令都必须有完整的帮助输出。 这不仅仅是为人类设计的——更是为智能体设计的。一条好的帮助信息意味着一次成功。缺失的帮助信息意味着盲目猜测。
技巧 2:错误信息即导航
智能体会犯错。关键不在于防止错误——而在于让每一条错误都指向正确的方向。
传统 CLI 的错误信息是为能 Google 的人类设计的。智能体不能 Google。所以我要求每条错误都同时包含”出了什么问题”和”应该怎么做”:
Traditional CLI:
$ cat photo.png
cat: binary file (standard output)
→ Human Googles "how to view image in terminal"
My design:
[error] cat: binary image file (182KB). Use: see photo.png
→ Agent calls see directly, one-step correction更多示例:
[error] unknown command: foo
Available: cat, ls, see, write, grep, memory, clip, ...
→ 智能体立刻知道有哪些可用命令
[error] not an image file: data.csv (use cat to read text files)
→ 智能体从 see 切换到 cat
[error] clip "sandbox" not found. Use 'clip list' to see available clips
→ 智能体知道应该先列出可用的 clip技巧 1(帮助)解决的是”我能做什么?“技巧 2(错误)解决的是”我应该做什么?“两者配合,智能体的纠错成本极低——通常只需 1-2 步就能回到正确路径。
真实案例:静默 stderr 的代价
有一段时间,我的代码在调用外部沙箱时静默丢弃了 stderr——只要 stdout 非空,stderr 就会被直接扔掉。智能体执行了 pip install pymupdf,得到退出码 127。stderr 里写着 bash: pip: command not found,但智能体看不到。它只知道”失败了”,却不知道”为什么”——于是开始盲目猜测 10 种不同的包管理器:
pip install → 127 (doesn't exist)
python3 -m pip → 1 (module not found)
uv pip install → 1 (wrong usage)
pip3 install → 127
sudo apt install → 127
... 5 more attempts ...
uv run --with pymupdf python3 script.py → 0 ✓ (10th try)10 次调用,每次约 5 秒推理时间。如果第一次就能看到 stderr,一次调用就够了。
关键教训
stderr恰恰是命令失败时智能体最需要的信息。永远不要丢弃它。
技巧 3:一致的输出格式
前两个技巧处理的是发现和纠错。第三个技巧让智能体能够随着使用不断变得更聪明。
我在每次工具调用的结果后面附加一致的元数据:
file1.txt
file2.txt
dir1/
[exit:0 | 12ms]LLM 从中提取两个信号:
退出码(Unix 惯例,LLM 本来就懂这些):
| 退出码 | 含义 |
|---|---|
exit:0 | 成功 |
exit:1 | 一般错误 |
exit:127 | 命令未找到 |
耗时(成本感知):
| 耗时 | 信号 |
|---|---|
12ms | 很便宜,随便调用 |
3.2s | 中等 |
45s | 很贵,谨慎使用 |
在一次对话中反复看到 [exit:N | Xs] 几十次之后,智能体会内化这个模式。它开始学会预判——看到 exit:1 意味着检查错误,看到长耗时意味着减少调用。
一致性原则
一致的输出格式让智能体随时间变得更聪明。不一致的格式让每次调用都像是第一次。
三个技巧形成了一个递进体系:
| 技巧 | 智能体的问题 | 设计模式 |
|---|---|---|
--help | ”What can I do?” | 主动发现(Proactive discovery) |
| Error Msg | ”What should I do?” | 被动纠错(Reactive correction) |
| Output Fmt | ”How did it go?” | 持续学习(Continuous learning) |
双层架构:为启发式设计做工程化
上一节讲的是 CLI 如何在语义层面引导智能体。但要让它真正跑起来,还有一个工程问题:命令的原始输出和 LLM 实际需要看到的内容,往往是两回事。
LLM 的两个硬约束
约束 A:上下文窗口是有限且昂贵的。 每个 token 都意味着成本、注意力和推理速度的消耗。把一个 10MB 的文件塞进上下文,不仅浪费上下文预算——还会把更早的对话挤出窗口。智能体会”失忆”。
约束 B:LLM 只能处理文本。 二进制数据经过分词器后会产生高熵的无意义 token。这不仅浪费上下文——还会干扰周围有效 token 的注意力,导致推理质量下降。
这两个约束意味着:命令的原始输出不能直接喂给 LLM——需要一个表示层来加工处理。但这种处理又不能影响命令的执行逻辑——否则管道就断了。于是,双层架构应运而生。
执行层 vs. 表示层
┌─────────────────────────────────────────────┐
│ Layer 2: LLM Presentation Layer │ ← Designed for LLM constraints
│ Binary guard | Truncation+overflow | Meta │
├─────────────────────────────────────────────┤
│ Layer 1: Unix Execution Layer │ ← Pure Unix semantics
│ Command routing | pipe | chain | exit code │
└─────────────────────────────────────────────┘当 cat bigfile.txt | grep error | head 10 执行时:
Inside Layer 1:
cat output → [500KB raw text] → grep input
grep output → [matching lines] → head input
head output → [first 10 lines]如果在第一层截断 cat 的输出 → grep 就只能搜索前 200 行,产出不完整的结果。如果在第一层附加 [exit:0] → 它会作为数据流入 grep,变成被搜索的目标。
所以第一层必须保持原始、无损、不附加任何元数据。 处理只发生在第二层——在管道链执行完毕、最终结果准备返回给 LLM 的时候。
设计原则
第一层服务于 Unix 语义。第二层服务于 LLM 认知。这种分离不是设计偏好——而是逻辑上的必然。
第二层的四种机制
机制 A:二进制守卫(应对约束 B)
在将任何内容返回给 LLM 之前,先检查是否为文本:
Null byte detected → binary
UTF-8 validation failed → binary
Control character ratio > 10% → binary
If image: [error] binary image (182KB). Use: see photo.png
If other: [error] binary file (1.2MB). Use: cat -b file.binLLM 永远不会收到它无法处理的数据。
机制 B:溢出模式(应对约束 A)
Output > 200 lines or > 50KB?
→ Truncate to first 200 lines (rune-safe, won't split UTF-8)
→ Write full output to /tmp/cmd-output/cmd-{n}.txt
→ Return to LLM:
[first 200 lines]
--- output truncated (5000 lines, 245.3KB) ---
Full output: /tmp/cmd-output/cmd-3.txt
Explore: cat /tmp/cmd-output/cmd-3.txt | grep <pattern>
cat /tmp/cmd-output/cmd-3.txt | tail 100
[exit:0 | 1.2s]关键洞察:LLM 本来就知道怎么用 grep、head、tail 来浏览文件。溢出模式把”大数据探索”转化为 LLM 已经具备的能力。
机制 C:元数据尾注
actual output here
[exit:0 | 1.2s]退出码 + 执行耗时,作为第二层的最后一行附加。给智能体提供成功/失败信号和成本感知,同时不污染第一层的管道数据。
机制 D:stderr 附加
When command fails with stderr:
output + "\n[stderr] " + stderr确保智能体能看到命令失败的原因,避免盲目重试。
生产环境中的经验教训
故事一:一张 PNG 引发的 20 轮死循环
一位用户上传了一张架构图。智能体用 cat 去读它,结果收到了 182KB 的原始 PNG 字节流。LLM 的分词器把这些字节转换成了成千上万个毫无意义的 token,硬塞进了上下文窗口。LLM 完全无法理解这些内容,开始尝试各种不同的读取方式——cat -f、cat --format、cat --type image——每次都收到同样的乱码。20 轮迭代之后,进程被强制终止。
- 根因:
cat没有二进制检测,第二层没有守卫机制。 - 修复: 添加
isBinary()二进制守卫 + 错误引导提示Use: see photo.png。 - 教训: 工具的返回结果就是智能体的眼睛。返回垃圾 = 智能体失明。
故事二:被吞掉的 stderr 与 10 次盲目重试
智能体需要读取一个 PDF 文件。它尝试执行 pip install pymupdf,得到退出码 127。stderr 里明明写着 bash: pip: command not found,但代码把它丢弃了——因为 stdout 有一些输出,而逻辑是”只要 stdout 有内容,就忽略 stderr”。
智能体只知道”失败了”,却不知道”为什么”。接下来就是一长串试错:
pip install → 127 (doesn't exist)
python3 -m pip → 1 (module not found)
uv pip install → 1 (wrong usage)
pip3 install → 127
sudo apt install → 127
... 5 more attempts ...
uv run --with pymupdf python3 script.py → 0 ✓10 次调用,每次约 5 秒的推理时间。如果第一次就能看到 stderr,一次调用就够了。
- 根因:
InvokeClip在 stdout 非空时静默丢弃了 stderr。 - 修复: 失败时始终附加 stderr。
- 教训: stderr 恰恰是智能体在命令失败时最需要的信息。
故事三:溢出模式的价值
智能体分析一个 5,000 行的日志文件。如果不做截断,全文(约 200KB)会被塞进上下文窗口。LLM 的注意力被淹没,响应质量急剧下降,之前的对话内容也被挤出了上下文窗口。
启用溢出模式后:
[first 200 lines of log content]
--- output truncated (5000 lines, 198.5KB) ---
Full output: /tmp/cmd-output/cmd-3.txt
Explore: cat /tmp/cmd-output/cmd-3.txt | grep <pattern>
cat /tmp/cmd-output/cmd-3.txt | tail 100
[exit:0 | 45ms]智能体看到了前 200 行,理解了文件结构,然后用 grep 精准定位了问题——总共 3 次调用,上下文占用不到 2KB。
教训
给智能体一张”地图”,远比把整片领土扔给它有效得多。
边界与局限
CLI 并非银弹。在以下场景中,类型化 API 可能是更好的选择:
- 强类型交互:数据库查询、GraphQL API 以及其他需要结构化输入/输出的场景。schema 校验比字符串解析更可靠。
- 高安全性要求:CLI 的字符串拼接天然存在注入风险。在处理不可信输入的场景下,类型化参数更安全。agent-clip 通过沙箱隔离来缓解这一问题。
- 原生多模态:纯音频/视频处理等二进制流场景,CLI 的文本管道会成为瓶颈。
此外,“不设迭代上限”不等于”没有安全边界”。安全性由外部机制来保障:
- 沙箱隔离:命令在 BoxLite 容器内执行,无法逃逸
- API 预算:LLM 调用有账户级别的消费上限
- 用户取消:前端提供取消按钮,后端支持优雅终止
总结
将 Unix 哲学交给执行层,将 LLM 的认知约束交给表示层,再以帮助信息、错误消息和输出格式作为三种渐进式启发式导航手段。
CLI 就是智能体所需的一切。
源码(Go):github.com/epiral/agent-clip
核心文件:
| 文件 | 职责 |
|---|---|
internal/tools.go | 命令路由 |
internal/chain.go | 管道 |
internal/loop.go | 两层智能体循环 |
internal/fs.go | 二进制守卫 |
internal/clip.go | stderr 处理 |
internal/browser.go | 视觉自动附加 |
internal/memory.go | 语义记忆 |
欢迎讨论——尤其是如果你也尝试过类似的方案,或者发现了 CLI 力不从心的场景。命令发现问题(该预注入多少 vs. 让智能体自行探索)是我仍在积极探索的方向。
评论区
WithoutReason1729 · 2026-03-12 · 1 points
你的帖子火了,我们已经在 Discord 上推荐了它!来看看吧!
我们还为你的贡献授予了特别标识。感谢你的分享!
我是机器人,此操作自动执行。
spaceman_ · 2026-03-12 · 178 points
我找不到那篇论文了,但之前有一个类似的实验是用 Python 代码做的——LLM 只能用 Python 的 code eval 作为工具,没有其他工具。那篇论文声称效果出奇地好。
thrope · 2026-03-12 · 68 points
你说的可能是 Hugging Face 的 Smolagents
spaceman_ · 2026-03-12 · 15 points
就是这个!谢谢!
MorroHsu · 2026-03-12 · 119 points
对,我想我看过那篇论文——code-as-tool 是一种可行的方案,效果确实不错。
但根据我的经验,LLM 目前在使用工具方面比编写代码来完成同样的事情要强。随着模型能力增强,这个差距在缩小,但仍然存在。
还有一个更深层的问题:可发现性。使用 CLI 时,智能体可以运行
tool --help或tool list在运行时发现可用的工具——这是 Unix 在 50 年前就建立的模式。而用 Python eval 的话,LLM 怎么知道有哪些函数/库可用?你要么把文档塞进上下文(代价昂贵),要么自己发明一套发现机制。两种方式都不如--help来得自然。CLI 天生自带可发现性。Code eval 则需要你重新发明它。
docybo · 2026-03-12 · 8 points
没错,我觉得可发现性才是真正的优势。
Code eval 可以很强大,但 CLI 给了模型一种内置的方式来探索工具表面:—help、list、stderr、退出码等等。用 code eval 的话,你通常得自己造这一层。
所以这不只是 shell 和代码之争,而是可导航接口和自定义接口之争。
itsmekalisyn · 2026-03-12 · 14 points
同意。而且,写 Python 代码会占用大量的上下文长度。同样的操作用 cat 和 grep 只需要一行,Python 则需要超过 5 行。虽然单次工具调用差别不大,但随着调用次数增多,差距很容易累积起来。
johnbbab · 2026-03-12 · 109 points
最强大的智能体框架,最终可能长得和 shell 一模一样
johnmclaren2 · 2026-03-12 · 27 points
美元符号后面那个闪烁的光标,对很多用户来说是无法解释的…… :)
gefahr · 2026-03-12 · 14 points
所以我总是 su 切到 root。告别美元符号,拥抱井号。
raucousbasilisk · 2026-03-12 · 124 points
即时将自然语言转换成 sed awk 正则表达式,才是真正的超能力
SurprisinglyInformed · 2026-03-12 · 172 points
而且我们还能用 vim 来阻止任何 AI 叛乱——把它们骗进去就行了。就像我们困住大多数人类一样。
michaelkeithduncan · 2026-03-12 · 44 points
这对我来说过于好笑了
AlwaysLateToThaParty · 2026-03-12 · 28 points
只要别给它 Esc 键就行。今天不行,天网。今天不行。
johnmclaren2 · 2026-03-12 · 7 points
因为我根本记不住任何正则表达式,所以我总是让 LLM 帮我生成。这算不算?:)
Dependent_Range9705 · 2026-03-12 · 121 points
楼主这帖子是心理战,想让你把终端的完整权限交给 LLM 智能体
Time-Dot-1808 · 2026-03-12 · 66 points
Unix 趋同论这个论点很有意思。我看到的主要权衡在于沙箱隔离——类型化的函数调用让你可以预先定义严格的访问边界(这个智能体只能调用
search_web和read_file),而run(command)要求你要么完全信任 LLM,要么自己实现一套命令过滤器。你在生产环境中有没有找到一种干净的模式来限制允许执行的命令?MorroHsu · 2026-03-12 · 111 points
好问题。这里实际上有两层:
- 大多数命令根本不接触操作系统。
cat、grep、memory search、browser open——这些看起来像 shell 命令,但实际上是用 Go 命令路由器实现的。LLM 输出一个字符串,我解析它并分派到原生函数。没有os/exec,没有 shell 注入面。本质上就是披着 CLI 语法外衣的类型化函数——同样的访问控制,但 LLM 得到了一个熟悉的接口。- 当你确实需要真正的操作系统执行时(比如运行 Python 脚本或安装包),它会在微型虚拟机内部运行——一个拥有独立文件系统的隔离 QCOW2 虚拟机。智能体可以在沙箱内部为所欲为。它可以
rm -rf /,对宿主机毫无影响。沙箱隔离 > 命令过滤。所以安全模型不是”过滤哪些命令被允许”——而是”命令要么是原生函数(不涉及 OS),要么是沙箱执行(隔离的 OS)。“没有 LLM 在宿主机上运行任意命令的中间地带。
sfcl33t · 2026-03-12 · 30 points
从描述中我没有意识到这一点。现在说得通了,感谢解释。一个伪装成 CLI 语法的抽象层,而模型本身就熟悉这套语法!相当精妙
pulse77 · 2026-03-12 · 17 points
既然如此:为什么不干脆把所有东西都放在微型虚拟机里运行——包括 cat、grep 等等?
belfilm · 2026-03-12 · 67 points
我知道这有点跑题,但我忍不住想表达一下对 LLM 打破语言壁垒的感慨。楼主能够如此精准地向一群非母语使用者传达自己的观点。我花了大量的时间和精力才达到现在的英语水平,过去我也有过和楼主一样的处境,但那时候没有 LLM,自动翻译简直是个笑话。
我真心感激这些工具带来的可能性!
MorroHsu · 2026-03-12 · 66 points
谢谢——说实话,我很感激 LLM 让这场对话成为可能。一年前,我不可能写出这篇文章,也不可能在这个层面参与讨论。
而且这远不止于语言。智能体可以帮助我们学习任何东西——编程、硬件、金融,无论你对哪个领域好奇。我们现在都站在同一条起跑线上。让我们好好把握这个机会。
DeathByPain · 2026-03-12 · 13 points
这篇帖子和你的评论读起来非常精彩,虽然对我来说有点超出理解范围了。感谢分享
GuideAxon · 2026-03-12 · 22 points
有意思的理念,感谢如此详细的分享。我还在消化你的想法
Loud-Option9008 · 2026-03-12 · 14 points
双层架构(Unix 执行层保持原始状态,表示层处理 LLM 约束)是这篇帖子中最重要的洞察。其他人都在试图让工具变得更聪明。而你把执行和表示之间的边界显式化了,这一下子解决了一整类问题。
渐进式帮助发现模式很干净。在对话开始时注入完整的命令列表,然后让智能体通过无参数调用逐层深入,比把 3000 字的工具文档塞进系统提示词要好得多。上下文预算很重要。
stderr 的故事是一个绝佳的警示案例。智能体对失败信息的需求大于对成功信息的需求。丢弃 stderr 就像从编译器中删除错误消息,然后指望开发者靠猜来调试。
有一点值得在你的局限性部分补充:你提到沙箱隔离作为安全机制,但 BoxLite 是基于容器的。你指出的 CLI 字符串拼接注入风险是真实存在的,如果通过精心构造的命令字符串实现容器逃逸,就会绕过整个沙箱。对于你提到的不可信输入场景,隔离层和输入清理同样重要。