Agent 怎么查数据库、调 API?Function Calling 与工具封装
Agent 的 Action 必须依赖外部工具——查数据库、调 API、发邮件。怎么让 LLM 稳定输出工具调用?怎么安全地授权?
Function Calling 让 LLM 输出结构化调用指令,Executor 负责执行。工具封装涉及 Schema 设计、权限治理、幂等性。本篇解析 Function Calling 机制与工具标准化设计,让 Agent 安全连接外部世界。
Function Calling = LLM 输出结构化 JSON(调哪个工具、传什么参数),Executor 解析后调用真实函数。Tool Schema 是”说明书”,告诉 LLM 有哪些工具、怎么用。LLM 只能”说”不能”做”——查库、调 API 都要靠工具;结构化输出比自由文本易解析,也更安全。
一、Function Calling 的机制本质
Function Calling 是 LLM 提供的一种高级能力,将自由文本输出转化为 结构化函数调用对象,使 LLM 能够安全、可控地调用外部工具。
1.1 核心流程:Schema → JSON → 执行
Tool Schema 注入(定义)
开发者将可用工具规范描述注入 LLM(通常为 JSON Schema)
包含工具名、功能描述、参数及类型
LLM 推理(决策)
LLM 接收到用户指令和工具 Schema
在 ReAct 循环中判断是否调用工具
生成符合 Schema 的 Action Call JSON 对象
Executor 执行(行动)
解析 JSON,调用真实函数
执行结果返回给 LLM 作为 Observation
1.2 Function Calling 的优势
高稳定性: 模型底层优化输出 JSON,解析成功率高
减少歧义: LLM 仅可选择预定义工具,参数明确
安全性: LLM 输出的是 JSON,而非直接代码,确保执行环境受控
💡 名词卡片
- Tool Schema: 使用 JSON Schema 定义的工具蓝图
- Function Calling: 结构化 JSON 输出,指示函数调用
- Executor: 解析 JSON 并实际执行工具的模块
🛠️ 二、工具封装与规范化设计
优质工具遵循 原子性(一工具一事)和 可理解性(描述清晰,让 LLM 知道何时用)。就像设计 RESTful API。
2.1 工具封装核心原则
1. 原子性(Atomicity)
一工具一事,别把多功能塞进一个工具。例子:
- ❌ 错误:一个工具既能”处理数据”又能”发送邮件”
- ✅ 正确:
AnalyzeData()和SendEmail()分开
代码示例:
# ❌ 错误:违反原子性原则 |
为什么需要原子性?
- 可复用性:工具可以独立使用
- 可组合性:多个工具可以组合完成复杂任务
- 可测试性:每个工具可以独立测试
- 可理解性:LLM 更容易理解每个工具的用途
2. 描述性(Descriptiveness)
描述要清晰,让 LLM 知道何时用。例子:
- ❌ 错误:
tool_1: Search DB(太简单,不知道什么时候用)- ✅ 正确:
tool_1: 专业数据库查询工具,用于检索公司最新销售数据,参数必须包含时间范围和产品名称(清晰明确)
代码示例:
# ❌ 错误:描述不够清晰 |
描述性检查清单:
- ✅ 工具做什么?(功能)
- ✅ 什么时候用?(使用场景)
- ✅ 需要什么参数?(参数说明)
- ✅ 返回什么?(返回格式)
3. 明确的输入/输出
输入输出要明确,尽量结构化(如 JSON)。示例:
# ❌ 错误:输出不明确 |
输出格式建议:
- ✅ JSON 格式:结构化,易于解析
- ✅ 简洁文本:如果必须返回文本,要简洁明了
- ❌ 冗长日志:避免返回调试日志
- ❌ 非结构化:避免返回难以解析的数据
2.2 工具设计最佳实践
设计检查清单:
| 原则 | 检查项 | 示例 |
|---|---|---|
| 原子性 | 一个工具只做一件事 | ✅ query_database() 只查询数据库❌ process_and_send() 既处理又发送 |
| 描述性 | 描述清晰、详细 | ✅ “专业数据库查询工具,用于…” ❌ “Search DB” |
| 输入/输出 | 输入明确,输出结构化 | ✅ JSON 格式返回 ❌ 返回冗长日志 |
| 错误处理 | 有明确的错误处理 | ✅ 返回 {"success": False, "error": "..."}❌ 抛出异常但不处理 |
| 可测试性 | 工具可以独立测试 | ✅ 有单元测试 ❌ 依赖外部状态 |
2.3 工具与 RAG 的集成
RAG 可作为工具 RetrieveKnowledge(query),Agent 需要事实时调用。机制:
- RAG 作为工具:
RetrieveKnowledge(query)- 功能:调用向量数据库,返回最相关的 Top K 记忆片段
- Agent 使用场景:当 LLM 缺乏事实信息时执行 Action,补充 Context
代码示例:
# RAG 作为工具(伪代码) |
使用场景:
- Agent 需要事实信息时,调用
retrieve_knowledge()检索知识- 检索到的知识作为 Context 注入到 LLM Prompt 中
- Agent 基于检索到的知识进行推理和决策
🔒 三、工具系统的安全与权限治理
Agent 可以执行数据库写入、文件操作等实际行为,安全治理是落地生产的最高优先级。
简单理解:
就像给员工分配权限:
- 最小权限原则:只给必要的权限
- 权限隔离:不同员工有不同的权限
- 高风险操作审批:重要操作需要审批
3.1 权限分级与最小权限原则
简单理解:
最小权限原则:Agent 只拥有完成任务所需的最小权限,不要给太多权限。
生活例子:
- ❌ 错误:给所有 Agent 所有权限(包括删除数据库)
- ✅ 正确:查询 Agent 只能查询,不能删除;管理 Agent 才能删除
权限分级示例:
# 权限分级(伪代码) |
最小权限原则:
- Agent 仅拥有完成任务所需权限
- 不要给不必要的权限
- 定期审查权限,及时回收不需要的权限
权限隔离:
- 不同 Agent 实例使用不同 API Key
- 工具集互相隔离
- 避免权限泄露
3.2 沙箱机制与风险隔离
简单理解:
沙箱:就像”隔离房间”,在隔离环境中运行代码,即使出错也不会影响主系统。
生活例子:
- 就像在实验室做实验,即使爆炸也不会影响外面
沙箱机制:
# 沙箱机制(伪代码) |
高风险操作审批:
关键操作如数据库写入需 Human-in-the-Loop 审批
代码示例:
# 高风险操作审批(伪代码) |
3.3 完整的安全校验流程
代码示例:
# 完整的安全校验(伪代码) |
3.4 安全最佳实践
安全检查清单:
| 安全措施 | 说明 | 简单理解 |
|---|---|---|
| 权限分级 | 不同 Agent 有不同的权限 | 只给必要的权限 |
| 权限隔离 | 不同 Agent 使用不同的 API Key | 避免权限泄露 |
| 参数清理 | 清理用户输入,防止注入攻击 | 过滤危险字符 |
| 沙箱机制 | 在隔离环境中执行代码 | 即使出错也不影响主系统 |
| 高风险审批 | 重要操作需要人工审批 | 防止误操作 |
| 日志记录 | 记录所有操作日志 | 便于审计和追踪 |
💡 关键理解:
- 最小权限原则:只给必要的权限
- 权限隔离:不同 Agent 有不同的权限
- 沙箱机制:在隔离环境中执行代码
- 高风险审批:重要操作需要人工审批
🔍 总结:工具决定 Agent 的能力边界
💡 快速回顾:你学到了什么?
- Function Calling 机制:LLM 如何调用外部工具(Schema → JSON → 执行)
- 工具封装设计:原子性、描述性、明确的输入/输出
- 工具系统安全:权限分级、沙箱机制、高风险审批
- 工程实践:如何实现完整的工具系统
工具系统的核心作用
| 组件 | 作用 | 简单理解 |
|---|---|---|
| Planner(大脑) | 决定智能上限 | Agent 的思考能力 |
| 工具集(手脚) | 决定能力边界与实用价值 | Agent 的执行能力 |
关键理解:
- Planner(大脑) 决定智能上限
- 工具集(手脚) 决定能力边界与实用价值
高效、安全的 Agent 系统依赖于 Function Calling 机制 + 原子化工具 + 权限治理,是 Agent 从”思考”到”改变世界”的关键一步。
设计原则总结
| 原则 | 说明 | 示例 |
|---|---|---|
| 原子性 | 一个工具只做一件事 | ✅ query_database()❌ process_and_send() |
| 描述性 | 描述清晰、详细 | ✅ “专业数据库查询工具,用于…” ❌ “Search DB” |
| 安全性 | 权限控制、沙箱隔离 | ✅ 最小权限原则 ❌ 给所有权限 |
| 可测试性 | 工具可以独立测试 | ✅ 有单元测试 ❌ 依赖外部状态 |
实战建议
- 从简单开始:先实现基本的 Function Calling,再逐步优化
- 遵循原子性:一个工具只做一件事,不要把所有功能都塞到一个工具里
- 重视安全性:权限控制、参数清理、沙箱隔离,一个都不能少
- 完善文档:工具的描述要清晰详细,让 LLM 知道什么时候用它
💡 核心理解:
工具系统是 Agent 连接外部世界的桥梁,设计好的工具系统能让 Agent 更强大、更安全、更可靠。
📚 延伸阅读(含可直接访问链接)
以下资源按主题分类,每个资源都附有简要说明,帮助你选择合适的学习材料。
🔧 Function Calling
OpenAI Function Calling 文档(OpenAI 函数调用官方文档):OpenAI Function Calling 的官方文档,包含详细的 API 说明和示例。必读,适合使用 OpenAI API 的开发者。
Anthropic Tool Use(Claude 工具使用):Anthropic 的工具使用文档。适合使用 Claude 的开发者。
LangChain Tools(LangChain 工具):LangChain 的工具实现,包含丰富的工具示例。强烈推荐,适合使用 LangChain 的开发者。
🛠️ 工具设计原则
Agent Tool Design Principles(Agent 工具设计原则):LangChain 的工具设计原则和最佳实践。适合想设计好工具的开发者。
Tool Calling Best Practices(工具调用最佳实践):工具调用的最佳实践指南。适合想优化工具调用的开发者。
🔒 Agent 安全
LLM Agent Security & Sandboxing(LLM Agent 安全与沙箱):LLM Agent 安全性的研究论文。适合想了解 Agent 安全性的读者。
Agent Security Best Practices(Agent 安全最佳实践):LangChain 的安全最佳实践。适合想确保 Agent 安全的开发者。
🔨 Executor 实现
LangChain Executor 源码分析(LangChain 执行器源码):LangChain Executor 的源码实现。适合想深入了解 Executor 实现的开发者。
LlamaIndex Agent Executor(LlamaIndex Agent 执行器):LlamaIndex 的 Agent Executor 实现。适合使用 LlamaIndex 的开发者。
🔔 系列说明
本文是《🧠 LLM/Agent 从入门到精通:告别浅尝辄止》系列第 12 篇。上一篇:Agent 输出飘忽不定?用 Schema 锁死格式。下一篇:Agent 失控了怎么办?日志、审计与可观测性。













