背景
AI Agent 和普通大模型聊天最大的区别,是它不只会生成文本,还能调用工具完成任务。
普通聊天更像是:
用户提问 -> 模型回答Agent 更像是:
用户提出目标 -> 模型判断下一步 -> 调用工具 -> 读取结果 -> 再判断下一步 -> 最终回答所以 Agent 的核心不是“模型更聪明”,而是让模型进入一个可以观察、行动、反馈的循环。
Agent Loop
一个最基础的 Agent Loop 可以理解成四步:
- 接收用户目标
- 模型决定下一步动作
- 如果需要工具,就执行工具
- 把工具结果放回上下文,让模型继续判断
简单写成伪代码:
while task_not_done: action = model(messages, tools)
if action.type == "final": return action.content
if action.type == "tool_call": result = run_tool(action.name, action.arguments) messages.append(result)这就是很多 Agent 系统最底层的结构。复杂系统会在上面继续加计划、记忆、权限、任务队列、子 Agent,但基础循环大体都是这个思路。
工具是什么
工具本质上就是提前暴露给模型的一组函数。
比如:
{ "name": "read_file", "description": "读取指定路径的文件内容", "parameters": { "path": { "type": "string", "description": "文件路径" } }}模型看到这个描述后,并不是直接执行代码,而是生成一个结构化调用请求:
{ "name": "read_file", "arguments": { "path": "README.md" }}真正执行工具的是 Agent 运行时,不是模型本身。
这一点很重要:模型负责“决定要调用什么”,系统负责“判断能不能调用、怎么调用、调用后怎么处理结果”。
工具描述很重要
工具描述写得不好,模型就容易乱用工具。
比如一个搜索工具,如果只写:
search: 搜索内容模型并不知道它搜索哪里、什么时候该用、返回什么。
更好的描述应该包含:
- 工具用途
- 参数含义
- 适合什么时候使用
- 不适合什么时候使用
- 返回结果格式
比如:
search_notes: 根据关键词搜索用户本地笔记。适合在用户询问自己记录过的内容时使用。不适合搜索互联网信息。返回匹配笔记标题和摘要。工具越多,描述越要清楚。否则 Agent 会把工具当成万能入口,导致调用链变乱。
参数生成
工具调用的一个常见问题是:模型生成的参数不一定可靠。
比如工具要求:
{ "user_id": "number", "limit": "number"}模型可能生成:
{ "user_id": "abc", "limit": "很多"}所以工具执行前要做参数校验。
模型生成参数 -> schema 校验 -> 权限判断 -> 执行工具不要相信模型生成的参数一定正确。它只是根据上下文猜了一个结构,运行时必须验证。
工具结果回传
工具执行完以后,结果不能只给用户看,还要放回模型上下文里。
比如工具返回:
{ "success": true, "content": "找到 3 条相关笔记", "data": [ { "title": "Flutter 本地存储", "summary": "记录了 shared_preferences 和 Drift 的区别" } ]}模型拿到结果后,才能继续组织最终回答。
如果工具失败,也要把失败原因明确返回:
{ "success": false, "error": "文件不存在"}不要只返回“失败了”,否则模型无法判断下一步该重试、换参数,还是直接告诉用户。
权限边界
Agent 能调用工具以后,权限边界就很重要。
可以把工具分成几类:
| 类型 | 例子 | 风险 |
|---|---|---|
| 只读工具 | 搜索、读取文件、查询状态 | 较低 |
| 写入工具 | 创建文件、修改数据库 | 中等 |
| 外部动作 | 发邮件、下单、支付、发布内容 | 高 |
| 系统操作 | 执行命令、删除文件、修改配置 | 高 |
高风险工具不能让模型直接执行。比较稳的做法是:
- 工具执行前做权限判断
- 高风险动作要求用户确认
- 记录完整调用日志
- 限制工具可访问的目录、账号和数据范围
Agent 的能力越强,越需要边界。否则它不是自动化助手,而是不受控的自动执行器。
可观测性
Agent 出问题时,经常不是最终回答能看出来的,而是中间某一步工具调用错了。
所以日志至少要记录:
- 模型选择了哪个工具
- 生成了什么参数
- 参数校验是否通过
- 工具执行结果是什么
- 失败原因是什么
- 最终回答是否使用了工具结果
调试 Agent 时,最好能看到完整轨迹:
user: 帮我总结昨天的笔记tool_call: search_notes({"date":"yesterday"})tool_result: 找到 5 条笔记assistant: 总结内容...没有轨迹,就只能猜模型为什么这么回答。
小结
AI Agent 的工具调用机制可以简单理解成:
模型决定调用 -> 系统校验参数 -> 运行时执行工具 -> 结果回到上下文 -> 模型继续推理这里面真正关键的不是“调用函数”本身,而是:
- 工具描述是否清楚
- 参数是否可靠
- 权限边界是否明确
- 工具结果是否能继续被模型使用
- 中间过程是否可追踪
把这些基础做好,Agent 才会从一个会聊天的模型,变成一个能稳定执行任务的系统。