六、工具调用

Tool calling

AI大模型借助工具来完成自己本身不能完成的一些事情。

AI 工具调用

1、web搜索,天气API

2、数据库数据获取

3、PDF生成、文件生成

4、API访问

大模型工具调用流程图:

注意:工具的调用一定是程序中自己去调用的,而非直接给大模型去调用,LLM本身具备不稳定性,在这种意料之外的情况发生时,可能造成你的数据被异常删改等情况。

这里很关键的一点是安全性,AI模型永远无法直接接触你的API或者系统资源,所有操作都必须通过你的程序来执行,这样你可以完全控制AI能做什么,不能做什么。

举例,你有一个爆破工具,用户给AI提需求拆房子,AI表示我要用爆破工具,但是需要经过你的同意才能执行爆破。

建议使用已有的成熟框架来进行工具的开发调用,因为LLM调用的成功率会高,效果会好一些。

工具调用成功率:本应去调用工具的一个问题,一些LLM判断问题不需要工具,则其回答很可能是有偏差或错误的。

推荐使用SpringAI langChain等框架,经过专业测试的,成功率会高,效果会好。

工具上下文:

作用:

1、安全性,一些用户登录信息保存在系统的上下文中,而不传给AI。

2、避免给AI传递一些多余的信息。

SpringAI提供了两种控制工具调用的方式:

  • SpringAI框架来调用
  • 自己手动来调用

ToolCoolingManager: 管理工具调用的整个生命周期。

和LLM沟通对话,并且将对话内容保存, 以此来提供给大模型和SpringAI框架交互的上下文信息。以便LLM语义理解,给出一个恰当合适的答案。

java 复制代码
public ToolExecutionResult executeToolCalls(Prompt prompt, ChatResponse chatResponse) {
        Assert.notNull(prompt, "prompt cannot be null");
        Assert.notNull(chatResponse, "chatResponse cannot be null");
        Optional<Generation> toolCallGeneration = chatResponse.getResults().stream().filter((g) -> !CollectionUtils.isEmpty(g.getOutput().getToolCalls())).findFirst();
        if (toolCallGeneration.isEmpty()) {
            throw new IllegalStateException("No tool call requested by the chat model");
        } else {
            AssistantMessage assistantMessage = ((Generation)toolCallGeneration.get()).getOutput();
            ToolContext toolContext = buildToolContext(prompt, assistantMessage);
            InternalToolExecutionResult internalToolExecutionResult = this.executeToolCall(prompt, assistantMessage, toolContext);
            List<Message> conversationHistory = this.buildConversationHistoryAfterToolExecution(prompt.getInstructions(), assistantMessage, internalToolExecutionResult.toolResponseMessage());
            return ToolExecutionResult.builder().conversationHistory(conversationHistory).returnDirect(internalToolExecutionResult.returnDirect()).build();
        }
    }

Spring AI和LLM的交互:

根据LLM的响应结果,来判断是否需要工具调用。需要调用时则LLM以固定格式来返回工具名,参数,SpringAI拿到工具名和参数之后去执行工具调用。工具执行结果再添加到对话上下文中,再继续请求AI,结合工具执行结果来回到用户问题。或者直接返回工具执行结果returnDirectly。

鱼皮提供的用户自定义的手动工具执行的示例:

java 复制代码
// 配置不自动执行工具
ChatOptions chatOptions = ToolCallingChatOptions.builder()
    .toolCallbacks(ToolCallbacks.from(new WeatherTools()))
    .internalToolExecutionEnabled(false)  // 禁用内部工具执行
    .build();

// 创建工具调用管理器
ToolCallingManager toolCallingManager = DefaultToolCallingManager.builder().build();

// 创建初始提示
Prompt prompt = new Prompt("获取编程导航的热门项目教程", chatOptions);
// 发送请求给模型
ChatResponse chatResponse = chatModel.call(prompt);
// 手动处理工具调用循环
while (chatResponse.hasToolCalls()) {
    // 执行工具调用
    ToolExecutionResult toolExecutionResult = toolCallingManager.executeToolCalls(prompt, chatResponse);
    // 创建包含工具结果的新提示
    prompt = new Prompt(toolExecutionResult.conversationHistory(), chatOptions);
    // 再次发送请求给模型
    chatResponse = chatModel.call(prompt);
}

// 获取最终回答
System.out.println(chatResponse.getResult().getOutput().getText());

异常处理

当工具调用出现异常,这是很常见的情况,例如,AI识别参数有误,构造的参数格式不正确,选择错了工具等等。在工具执行过程中都会出现异常。当工具调用时异常,默认是不中断不抛出,打日志,让LLM继续执行。也可以手动将alwaysThrow改为true,则出现异常时直接中断。

实现工具执行异常处理器的接口,直接返回默认异常处理器,设置alwaysThrow为true,则每次都抛出异常。

java 复制代码
@Bean
ToolExecutionExceptionProcessor toolExecutionExceptionProcessor() {
    // true 表示总是抛出异常,false 表示返回错误消息给模型
    return new DefaultToolExecutionExceptionProcessor(true);
}

自定义异常的处理

java 复制代码
@Bean
ToolExecutionExceptionProcessor customExceptionProcessor() {
    return exception -> {
        if (exception.getCause() instanceof IOException) {
            // 网络错误返回友好消息给模型
            return "Unable to access external resource. Please try a different approach.";
        } else if (exception.getCause() instanceof SecurityException) {
            // 安全异常直接抛出
            throw exception;
        }
        // 其他异常返回详细信息
        return "Error executing tool: " + exception.getMessage();
    };
}
相关推荐
markinmarkin1 小时前
Spring 中有哪些方式可以把Bean 注入到IOC 容器?
java·spring
带刺的坐椅2 小时前
Hot-Plug 实战:运行期管理 Solon 插件
java·solon·插件·热插拔
大黄说说2 小时前
SQL Server 执行计划怎么看?快速定位 SQL 慢的根源
java·linux·数据库
雪之下雪乃的代码日记2 小时前
Python快速入门(Java开发者版)
java·开发语言·笔记·python
敲个大西瓜3 小时前
Springboot核心面试题
java·spring boot·后端
器灵科技3 小时前
Seedance2.5 VS MiniMax H3 同日上线:AI短剧创作者该怎么选?
java·人工智能·阿里云·prompt·aigc
xbgRS3 小时前
Mybatis源码-核心流程及核心类
java·mybatis
zzh___zzh3 小时前
Java Stream API 常用方法笔记
java·笔记
爱吃土豆的马铃薯ㅤㅤㅤㅤㅤㅤㅤㅤㅤ3 小时前
Spring‑AI Document 对象 JSON 字段详解
人工智能·spring·json
萌动的小火苗3 小时前
1、python基础面试题
java·开发语言·python