AI 编程中如何设计工具调用?

AI 编程中如何设计工具调用?文件读取、命令执行、测试运行分别怎么封装?
这道题考的是 Agent Harness 的设计理念,本质上是在问:怎么给大模型装上一个能操作外部世界的"操作系统"。核心就三个字——封装层。
一、Agent Harness 是什么?
Harness 是包裹在大模型外面的完整软件架构。你可以理解成:模型只负责思考,Harness 负责执行。
打个比方:模型像是餐厅里的大脑,它知道菜怎么做,但它不会自己跑去厨房炒菜。Harness 就是那个服务员,把大脑的意图翻译成具体操作。
从架构角度看,Harness 重新发明了冯·诺依曼架构:
- 上下文管理 = 内存
- 持久化存储 = 硬盘
- 工具调用 = I/O
这就是为什么 AI 编程不是简单调用 API,而是一套完整的系统设计。
二、工具调用的本质链路
模型输出的是 Function Call——一个结构化的 JSON,包含了意图和参数。注意,模型只是"说"要干什么,实际执行由 Harness 负责。
完整链路分六步:
- 意图识别 → 模型决定要做什么
- 工具选择 → 从工具库里挑哪个工具
- 参数生成 → 构造调用参数
- 代码执行 → Harness 执行具体操作
- 安全防护 → 权限检查、参数校验
- 结果返回 → 把执行结果塞回上下文
就像你跟服务员说"我要宫保鸡丁",后厨负责做菜,服务员负责传话和上菜。模型不会自己跑去执行 shell 命令。
三、文件读取怎么封装?
文件读取有两个核心原则:权限分级 和 按需加载。
权限分级
不同操作风险不同,所以要分级处理:
- 低权限(读取、搜索)→ 直接执行,不用确认
- 中权限(创建、修改)→ 需要用户确认
- 高权限(删除、shell)→ 必须显式授权
按需加载
一个关键研究叫"位置效应":信息放在上下文中间时,模型性能下降 30%。所以不要把整个文件夹塞给模型,只加载当前步骤需要的部分。
工具不是越多越好。暴露最小工具集往往效果最佳——让模型每次只看到它现在需要的工具。
四、命令执行怎么封装?
命令执行必须进沙箱,这是安全底线。
核心策略就三条:
1. 沙箱隔离
所有代码执行限制在隔离环境中,危险操作(比如 rm -rf /)不能真的跑出去搞破坏。
2. 参数校验
执行前必须校验参数。比如一个读取文件的工具,你要检查路径是不是真的存在、是不是在允许范围内。
3. 结构化输出
不要让工具返回一堆自由文本等着模型去解析。返回 结构化 JSON,Harness 解析起来毫不费力。
简单说:给 AI 编程环境加一道"安全门禁",危险操作必须过闸机。
五、测试运行怎么封装?
测试不是跑一下就完了,而是嵌入验证循环。
三种反馈机制
| 机制 | 适用场景 |
|---|---|
| 基于规则 | 语法错误、类型错误这类明确的问题 |
| 视觉反馈 | UI 界面有没有渲染出来 |
| LLM 评估 | 逻辑错误、语义问题 |
自愈机制
Harness 捕获错误后,把错误信息返回给模型,让模型自己修复,然后再次验证。这就是"自愈"——代码装上自动体检系统,发现问题自己修。
流程就是:测试执行 → 结果捕获 → 错误分析 → 模型自愈 → 再次验证,循环迭代直到通过。
六、不同 SDK 的设计哲学
主流框架有三种思路:
| 框架 | 设计理念 |
|---|---|
| Claude Code | "笨循环"——智慧全在模型,Harness 极简 |
| OpenAI Agents SDK | 代码优先,把编程能力做到极致 |
| LangGraph | 显式状态机建模,流程可控 |
这里有个趋势:模型越来越强,Harness 应该越来越笨。Claude Code 的"笨循环"反而是最好的证明——不需要复杂的编排,模型自己能搞定。
工具设计也一样:暴露当前步骤所需的最小工具集往往效果最佳。
面试怎么答
基础版:
工具调用的本质是 Function Call,模型只输出意图和参数,实际执行由 Harness 负责。文件读取采用权限分级策略——读直接执行、写需确认、危险操作强制授权;同时按需加载避免上下文污染。命令执行必须沙箱隔离,执行前校验参数和权限,结果用结构化 JSON 返回。测试运行嵌入验证循环,通过规则/视觉/LLM 三种反馈机制发现问题,Harness 把错误返回给模型实现自愈。
加分版:
加一个"位置效应"——关键信息在上下文中间时性能下降 30%,这说明按需加载的必要性。然后点一下核心洞察:Harness 本质是重新发明的冯·诺依曼架构,模型越强它应该越简单,不要过度设计。
一句话总结
工具调用的核心是 Harness 作为模型与外部世界的桥梁,通过权限分级、沙箱隔离、验证循环实现安全可控的文件读取、命令执行和测试运行。
