利用 Spring AI 实现可解释的 AI 智能体:捕获 LLM 工具调用推理过程
1. 概述
当我们构建具备工具调用(Tool-calling)能力的 AI 智能体时,通常能看到大模型(LLM)选择了哪个工具,却无法得知它为何做出该决定。这种洞察力的缺失增加了调试难度,降低了可观测性,并限制了用户对 AI 驱动系统的信任。对于生产级的智能体而言,理解模型的推理过程是必不可少的。可解释 AI 智能体通过在工具选择期间捕获 LLM 的额外上下文来解决这一问题。
在本文中,我们将通过一个实际示例来了解“工具参数增强器”(Tool Argument Augmenter)。我们将探讨如何在工具调用期间捕获 LLM 的推理过程,以及如何在 Spring AI 应用程序中使用这些数据。
2. 工具调用的难题
当模型仅凭训练数据无法可靠回答问题时,我们会使用工具调用。例如,当 LLM 需要实时数据(如当前价格或用户特定信息)、需要访问外部系统(如数据库或内部服务),或者必须触发操作(如创建记录或发送通知)时,我们都会用到它。
在 Spring AI 中,模型通过工具调用将工作委托给应用程序代码,而 LLM 则专注于理解用户请求并生成最终响应。假设我们的应用程序提供了两个工具:
通过 @Tool 注解,我们将方法标记为可供 LLM 调用的工具。当我们向应用程序询问“患者状态是否稳定?”时,幕后流程如下:
- Spring AI 将两个工具的定义(包括输入模式)发送给 LLM。
- LLM 分析请求并评估可用工具。
- LLM 决定调用 retrievePatientHealthStatus。
- LLM 返回一个包含所需参数的工具调用请求。
- 工具管理器调度并执行选定的工具。
- 工具将结果返回给 LLM,LLM 随后生成最终响应。
从应用程序的角度来看,我们只能看到工具被调用了。问题在于,我们无法看到该选择背后的推理过程。这种推理缺失限制了可观测性,并使调试变得困难。 我们可以确认调用了哪个工具,但无法解释 LLM 为何选择它。Spring AI 的“工具参数增强器”正是为了解决这一局限而设计的。
3. 工具参数增强器
工具参数增强器在标准工具调用之上添加了一层可解释性。我们可以动态地使用额外参数来扩展工具的 JSON Schema。 这些参数捕获了应用程序所需的元数据,例如推理过程、见解或置信度。工具本身保持不变,且无需感知这种增强。通过 @ToolParam,我们可以描述各个方法参数,以便模型理解必须提供哪些输入:
启用工具参数增强器后,工具调用流程变为:
- 我们询问“患者状态是否稳定?”。
- Spring AI 将 retrievePatientHealthStatus() 和 retrievePatientHealthStatusChangeDate() 的工具定义发送给“工具调用顾问”(Tool Call Advisor)。
- 工具参数增强器拦截这两个工具定义。
- 增强器使用 innerThought 参数扩展每个工具的 JSON Schema。
- Spring AI 将增强后的工具架构发送给 LLM。
- LLM 决定调用 retrievePatientHealthStatus(),并返回一个包含原始参数以及增强参数 innerThought 的工具调用请求,解释了选择该工具的原因。
- 增强器提取 innerThought 并将其转发给消费者,用于日志记录、内存存储或分析。
- Spring AI 仅使用预期的参数调用 retrievePatientHealthStatus()。
- LLM 使用工具结果生成最终响应。
这种方法捕获了 LLM 选择特定工具的原因。 我们可以记录推理过程、将其存储为长期记忆,或将其用于调试和分析。同时,我们保持了工具的简洁性和可重用性,在不更改现有工具契约的情况下,增强了智能体行为的可解释性和可信度。
4. 患者健康状况检查器示例
让我们实现一个简单的“患者健康状况检查器”应用程序。我们将提供几个工具来获取不同类型的患者健康状况信息,然后让用户询问有关不同患者的问题,LLM 将决定调用哪个工具来提供所需信息。
4.1. 依赖项
首先添加 spring-ai-starter-model-openai 依赖:
该依赖项已包含底层的 Spring AI 类,并提供了我们在此应用程序中使用的 OpenAI 模型集成。
4.2. 工具规范
创建一个 PatientHealthInformationTools 类。该类将公开 AI 智能体可以调用的工具方法,以检索患者健康信息。它充当 LLM 与我们内部健康数据源之间的桥梁:
4.3. 智能体推理 DTO
现在引入 AgentThinking DTO。我们使用此对象来捕获模型在工具选择过程中的推理。它有助于使工具调用的决策过程更加透明且易于分析:
4.4. PatientHealthStatusService
创建 PatientHealthStatusService。该服务协调 LLM 调用并集成我们的增强工具逻辑:
我们创建了一个附带工具的 AugmentedToolCallbackProvider 实例,注入了 AgentThinking DTO,并添加了日志逻辑以打印每次调用的推理详情。
4.5. 测试服务
最后,测试 PatientHealthStatusService 以验证工具选择是否正确,以及推理元数据是否被正确捕获:
日志输出示例:
5. 工具调用链示例
有时我们需要调用一系列工具。例如,根据患者姓名获取健康状况。我们添加一个新工具:
当 LLM 无法直接获取状态时,它会先调用 retrievePatientId 获取 ID,再调用 retrievePatientHealthStatus 获取状态。日志将完整记录这一推理链,帮助我们优化提示词并避免不必要的调用。
6. 结论
在本文中,我们探讨了如何使用“工具参数增强器”使 AI 集成具备可解释性。我们在不修改工具实现的情况下,捕获了模型在工具选择期间的推理过程。
通过这种方法,我们提高了 LLM 工具调用决策的可观测性,并为提示词优化收集了宝贵的反馈。此外,我们还可以利用推理数据进行审计、监控或分析,从而优化智能体随时间的表现。代码示例可在 GitHub 上获取。