使用 Embabel Agentic AI 框架实现 LLM 工具调用推理
[LOADING...]
1. 概述
工具调用推理通过捕捉 LLM 工具选择背后的理由,而非仅仅记录模型调用了哪个工具,从而提升 AI Agent 的可观测性。
深入了解 Agent 的工具选择决策有助于开发者调试 Agent 工作流、验证决策质量,并发现改进提示词或工具设计的机会。随着 Agent 自主性增强并与更多工具交互,这种透明度变得越来越重要。
在本教程中,我们将了解如何使用 Embabel Agentic AI 框架在 Java 应用中实现这一级别的可观测性。
2. 使用 Spring AI 进行工具调用推理
在深入探讨如何使用 Embabel 之前,我们先看看 Spring AI Tool Argument Augmenter 是如何解决这个问题的。
Tool Argument Augmenter 会动态地使用额外的推理字段(如 innerThought 或 confidence)来增强工具模式。 其结果是提升了 Agent 行为的可观测性,同时无需更改现有工具的实现。
在 Spring AI 中,工具通过定义 JSON Schema 来指定预期的参数。LLM 评估这些模式并决定调用哪个工具以及传递哪些参数。Spring AI 的增强层利用这一机制,通过向模式的属性中添加模型可见的额外属性来实现增强(即模式增强)。
一个关键的实现特性是:在工具调用时应用的真实工具定义保持不变。 增强层会拦截工具调用的负载,提取推理字段,将其移除,然后仅使用预期的参数调用实际工具。工具本身对增强过程毫不知情。
用户通过一个单独的 DTO(包含 innerThought 和 confidence 属性)获取工具调用推理的详细信息。
2.1. Spring AI 解决方案设计分析
该设计在多个方面表现出色。
首先,它提供了结构化且机器可读的可观测性。由于推理字段是模式的一部分,它们更容易被评估、存储或输入到分析管道中。
其次,它保持了高度的非侵入性。现有工具(包括 MCP 工具 和本地的 @Tool 方法)无需修改即可继续工作。
第三,该解决方案利用了现有的 LLM 能力,而不是发明专有的推理 API。任何支持结构化工具调用的模型原则上都可以支持这种方法。
然而,该设计也引入了权衡;一个关键的局限性是暴露的模式不再是实际的契约。 LLM 所见的模式包含基础工具实际从不接受的字段。从架构上看,这意味着增强后的工具模式与运行时工具方法契约并非同一回事。
该方法通过以下方式增加了额外的复杂性:
- 增强型 DTO
- 模式合并
- 增强字段提取
- 工具包装基础设施
这既增加了概念负担,也增加了与 Spring AI 内部 JSON Schema 工具模型的耦合。
3. 使用系统提示词进行工具调用推理
一个更简单的替代方案是通过提示词定义标准化的系统级协议。当调用工具时,提示词应要求 LLM:
- 简要解释为什么需要该工具
- 说明预期获取什么信息
- 提供一个置信度级别
这将推理捕获从模式级契约转移到提示词级协议——从结构性强制转变为语义性指导。在实践中,模式增强强制要求一个硬性契约(“字段必须存在”),而提示词则建立一个软性约定(“按此方式行为”)。
两种方法都依赖于模型生成的解释,因此在内容和措辞上具有相同的可变性。实际区别在于输出结构:模式增强强制要求显式字段的存在,使解释更容易捕获和解析,而基于提示词的方法则将其保留在半结构化格式中。
基于提示词方法的主要优势是可移植性。 模式增强依赖于框架特定的机制(例如工具模式生成、回调提供者、参数拦截),而系统提示词仅依赖于一种通用能力:向模型发送指令。这使得它可以跨其他 Agent 框架移植,例如 Spring AI、LangChain4j、Semantic Kernel、OpenAI、Anthropic 和 Google DeepMind。
与 Spring AI 增强方法相比,基于提示词的解决方案避免了合成模式、增强 DTO、模式转换和自定义工具包装基础设施,从而保持了更简单的实现。
两种方法没有绝对的优劣——它们体现了不同的工程权衡。在实践中,混合模型通常效果最佳:使用提示词级协议进行通用指导,并在需要更强保证时选择性应用模式级增强。## 4. 使用 Embabel 进行工具调用推理
Embabel 是一个由 Spring 框架创始人 Rod Johnson 创立的 Agentic AI 框架。关于 Embabel 的介绍信息,请参考 Baeldung 的文章《使用 Embabel Agent 框架》。你可以在此处找到官方文档,或在 Medium 上获取更多资源。
4.1. Embabel 模式快速介绍
Embabel 是一个用于在 JVM 上开发 Agentic AI 应用程序的综合性框架。其关键特性之一是在所有模式中采用具有结构化输出的流畅 API——这是 JVM 上 Agentic AI 领域的一个重要特性:
- 基础模式(无“思考”或流式输出)
- 思考模式(详情见下文)
- 流式模式
我们将探讨“思考”模式,该模式是工具调用推理解决方案的基础。
4.2. Embabel Agentic AI 依赖
首先,定义测试所需的主要 Embabel 依赖项:
embabel-agent-starter-openai 依赖提供使用 Embabel 配合 OpenAI 模型所需的核心类。
我们还引入了 embabel-agent-test-internal,以便在 @SpringBootTest 中使用 AgentTestApplication 测试支持类。
4.3. 思考模式流畅 API 概念
接下来引入 Embabel “思考”模式流畅 API 的关键概念:
Ai是 LLM 连接的网关;我们可以在配置文件中定义默认的AiLLM,或显式提供。ThinkingResponse是一个包装对象,包含对底层业务对象ParkingRecommendation的引用,以及包含 LLM 推理内容的所谓ThinkingBlock。withToolObject()是对ParkingTooling工具对象的引用(详情见后文)。withToolInspectors()指可选的回调函数,有助于额外的日志记录、指标收集等。CallbackTracker收集统计数据(LLM 调用次数、工具调用次数、已调用工具列表),而ToolLoopLoggingInspector记录 LLM 和工具调用的详细信息(例如:ToolLoopLoggingInspector -- afterLlmCall: iteration=1, toolCalls=2, contentLength=1063, usage=prompt=834, completion=260)。withToolLoopTransformers()演示了通过ToolLoopTransformer进行用户控制的对话历史管理。在本例中,转换器配置了两条系统消息,并始终将它们置于 LLM 调用前的对话历史顶部。thinking()表示流畅 API 的子类型为“思考模式”,并输出ThinkingResponse,该响应包装了由 API 的createObject()方法构建的业务对象。- 最后,
prompt变量包含我们的用户消息。
思考模式还包括其他一些 API,其中非常有用的是 createObjectIfPossible()。如果 LLM 无法创建对象,ThinkingResponse 仍会包含其背后的推理信息。
4.4. 用例
我们的用例是一个受时间和成本限制的最优停车方案查找器。我们将使用三个工具:
- 免费街边停车定位器
- 计时停车定位器
- 车库预约
最终的思考块将解释基于通过探查多个工具收集的信息而给出的推荐理由。
我们将提示分为两部分:一个通用的、与领域无关的系统消息(可用于多种业务场景),以及一个特定领域的用户消息。
先定义系统消息:
再定义用户消息:
接下来将提供可用工具。
4.5. 工具定义
定义工具对象:
此处,LlmTool 是 Embabel 的工具注解,包含工具描述。 Embabel 允许我们通过实现 Embabel 的 Tool 接口,或使用带注解的 Java 方法来向 LLM 暴露工具。此处我们采用后一种方法。
4.6. 测试结果讨论
我们的测试类 ToolCallReasoningIntegrationTest 调用 LLM(LLM 再调用工具并总结工具选择推荐),并使用自定义日志函数记录结果。
我们有一个 reportToolCallPattern() 方法,该方法以 CallbackTracker 为参数,记录工具模式和统计信息:
此外,我们的 reportThinkingBlocks() 方法从结果中提取 ParkingRecommendation 对象和 ThinkingBlock 项,格式化并记录它们。
下面查看 reportThinkingBlocks() 产生的日志:
Embabel 返回了一个类型为 ParkingRecommendation 的结构化对象,包含所有预期字段,包括 summary。
每个 ThinkingBlock 包含工具选择的解释;tagType 指定 LLM 推理格式——本例中为 XML TAG(也可能是 PREFIX 或无标签),tagValue=tool_use_reasoning 和 tagValue=final_decision_reasoning,这些是我们系统提示中定义的动态用户自定义 XML 标签。请注意,每个工具调用对应两个 ThinkingBlock。
最后,输出了包含推荐的 ThinkingBlock,并按预期替换了占位符 confidence。
使用占位符可以进一步自动化处理工具选择推理。方法 extractAttributes()(请参考文章关联的代码)扫描 ThinkingBlock 中的 [key=value] 格式属性,并将其作为键值对映射返回。例如,它将文本 [confidence=0.9] 转换为条目 "confidence" -> 0.9。
因此,Embabel 的思考模式输出是半结构化的。
5. 结论
在本文中,我们看到了 Embabel 如何通过其“思考”API 提供工具选择推理的解决方案。
虽然 Spring AI 提供了开箱即用的工具选择推理支持,但该解决方案存在明显的权衡。使用 Embabel 的替代解决方案非常简单,与 Spring AI 不同,它不需要隐藏的模式操作或引入自定义 DTO,完全基于现有的 Embabel 基础 API 构建。
使用 Embabel,还可以通过 LLM 工具循环回调实现另一种解决方案,但这超出了本文的范围。
文章代码可在 GitHub 上获取。
作者感谢 Rod Johnson 和 Ajen Poutsma 的审阅和建议。
文章《LLM Tool Call Reasoning Using Embabel Agentic AI Framework》首发于 Baeldung。