引言
在构建 AI 应用时,我们常常听到LLM API、Function Calling、Tools、Skills等概念。它们之间到底是什么关系?底层逻辑又是如何运作的?本文将从第一性原理出发,结合Spring AI的技术实践,带你彻底理清这些概念的本质区别与联系。
一、底层认知:一切始于无状态的 HTTP API
首先必须明确一个核心事实:对接大模型,底层永远是通过 HTTP API 接口进行无状态访问。
每一次请求都是独立的,大模型本身不记忆任何上下文。我们常说的“对话记忆”、“多轮交互”,本质上都是在客户端(如 Java 服务)侧维护状态,通过将历史消息和工具结果重新塞入下一次请求来模拟“有状态”的行为。
这个认知是理解所有上层概念的基石。
二、Function Calling:让模型“伸出援手”
Function Calling 的出现,打破了纯文本交互的局限。
本质:大模型不再仅仅返回纯文本,而是可以返回结构化的 JSON 指令(包含函数名和参数)。客户端解析这个 JSON,本地调用对应方法,然后将执行结果再次发送给大模型,最终生成自然语言回复。
关键流程:
- 开发者将**工具定义(名称、描述、参数 Schema)**合并到请求中发给大模型。
- 大模型判断是否需要调用工具,如需调用,则返回
tool_calls的 ID 和参数。 - 客户端执行本地方法,将结果回传给大模型。
- 大模型根据结果生成最终回答。
核心价值:大模型通过Function Calling获得了“伸出援手”的能力,可以操作外部世界。
三、Tools:Function Calling 的泛化与资源抽象
Tools 是 Function Calling 的泛化和扩展。
如果说 Function Calling 强调“函数调用”,那么 Tools 则更强调**“外部能力接入”**。它不仅仅局限于本地函数,还可以是:
- 外部 API(如查询天气、发送邮件)
- 数据库操作(如 SQL 查询)
- 脚本执行(如 Python 脚本)
- 文件系统操作
在 Spring AI 中,@Tool注解和ToolCallback接口提供了统一的工具注册与调用机制。Tools 本质仍是函数调用,但抽象层次更高,它代表了一个可被模型调用的能力单元。
四、Skills:多工具编排与智能体行为封装
Skills(技能)是站在 Tools 之上的高层封装。它不是单个工具,而是多个工具的编排 + 推理步骤(Chain of Thought)的组合。
4.1 Skill 的底层逻辑(核心)
我在实践中理解的 Skill 底层逻辑是这样的:
Skill 类似于一个大号的 Tool 说明。一方面,它描述了 Skill 适用的场景;另一方面,它将场景、思考过程、执行脚本等信息发送给大模型,同样是通过Function Calling机制实现的。
但与普通 Tool 不同的是,Skill 内部包含了完整的推理和执行计划。
4.2 为什么需要分级处理?
一个重要原因是:适应大模型一次处理 message 的信息量有限的问题。
为了解决上下文窗口的限制,Skill 通常将信息分为目录(摘要)和详细内容进行分级多次调用:
- 目录(摘要):即 Skill 的场景描述。第一次全部发给大模型,用于匹配。
- 详细内容:包括思考过程(推理链)和执行脚本(参数定义)。只有在匹配成功后,才会在后续轮次中动态拼装发送。
4.3 Skill 的典型执行流程(三轮交互)
以我拆解的实现为例,Skill 的执行通常分为三轮:
| 轮次 | 阶段 | 发送内容 | 模型输出 | 客户端动作 |
|---|---|---|---|---|
| 第一轮 | 匹配阶段 | 所有 Skill 的名称、简短描述(场景) | 决定“哪个 Skill 可能有用” | 选中目标 Skill |
| 第二轮 | 规划阶段 | 选中 Skill 的详细指令(Prompt Template)+思考示例(Few-shot) | 生成结构化的执行参数(JSON) | 解析参数,准备本地执行 |
| 第三轮 | 执行阶段 | 本地执行脚本(@Tool方法) | (等待结果回传) | 将执行结果再次发回大模型,生成最终自然语言回复 |
注意:这不是“一次性发给大模型”,而是多轮、动态拼装的过程,目的正是为了应对上下文窗口有限的问题。
五、一图看懂:五者的本质区别与联系
5.1 演进关系
访问 LLM API(基础) ↓ (增加结构化工具体系) ↓ Function Calling(原子能力) ↓ (扩展为资源抽象层) ↓ Tools(工具泛化) ↓ (引入规划与编排) ↓ Skills(智能体行为封装)5.2 对比表格
| 维度 | 访问 LLM API | Function Calling | Tools | Skills |
|---|---|---|---|---|
| 输入输出 | 纯文本 ↔ 纯文本 | 文本 ↔结构化 JSON 指令 | 文本 ↔结构化指令 + 外部资源 | 文本 ↔文本 + 多个外部动作 + 最终回答 |
| 模型职责 | 仅生成文本 | 生成函数名 + 参数 | 同 Function Calling,但强调资源定位 | 生成执行计划,并分步决策 |
| 客户端职责 | 仅展示文本 | 解析 JSON → 调用本地方法 → 结果回传 | 同左,但支持多资源类型 | 状态管理 + 多轮循环 + 上下文拼接 |
| 是否改变模型状态 | 否(无状态) | 否(无状态,但附加了工具定义) | 否(无状态) | 否(无状态,但通过多轮请求模拟有状态) |
| 复杂度 | 低 | 中 | 中 | 高 |
| 典型场景 | 知识问答、翻译 | 查天气、发邮件 | 查询数据库、调用第三方 API | 自动订机票酒店、智能客服全流程 |
六、Spring AI 中的实现映射
在Spring AI框架中,这些概念的具体对应关系如下:
| 概念 | Spring AI 实现 |
|---|---|
| 访问 LLM API | ChatClient或ChatModel.call(prompt) |
| Function Calling | @Tool注解 +FunctionCallback注册 |
| Tools | ToolCallback接口 +ToolExecutionChain(可批量注册) |
| Skills | 非内置,需自行用ChatClient+PromptTemplate+ 状态机实现 |
⚠️特别注意:Spring AI官方未直接提供 Skill 抽象,它只提供了 Tools 层。如果你看到“Skill”这个概念,通常是在社区扩展或自定义 Service 层实现的。
因此,在 Spring AI 中实现 Skill,本质上就是用 Java 写一个状态机或循环控制器,把多个 Tools 的调用串起来,并在每次调用前后动态修改 Prompt —— 这正体现了我前面提到的“分级多次调用”的精髓。
七、一句话总结
LLM API是“嘴巴”,Function Calling是“手”,Tools是“工具箱”,Skills是“大脑指挥手用工具箱完成复杂任务”的整套流程。
它们共享无状态的 HTTP 通道,但复杂度依次递增,上层向下层请求原子能力,下层向上层提供执行基础。理解这套演进逻辑,是设计和实现高效 AI Agent 的关键。
如果你正在 Spring AI 中构建 Skill 能力,希望这篇文章能帮你少走弯路。欢迎在评论区交流你的实现思路!