Solon AI 开发学习11 - chat - 工具调用与定制(Tool Call)

Tool call(或 Function call)能够让大语言模型在生成时,"按需"调用外部的工具,进而连接外部的数据和系统。通过定义一组函数作为模型可访问的工具(也叫函数工具),并根据对话历史在适当的时候使用它们。然后在应用端执行这些函数,并将结果反馈给模型。

可以实现最新的数据状态(比如,联网查询时实天气)或者指令交互(比如,做运维操作)。是 AI 交互系统的基础技术。

相关接口:

接口或类 描述 备注
FunctionTool 函数工具接口 为 ChatModel 提供工具
ToolProvider 工具提供者接口 为 ChatModel 提供批量工具
FunctionToolDesc 函数工具描述类
@ToolMapping 工具映射注解
MethodFunctionTool 方法工具
MethodToolProvider 方法工具提供者 分析出对象中的 @ToolMapping 函数,并构建出方法工具集合
@Param 参数映射注解

1、FunctionTool (函数工具声明)接口与注解

工具,目前主要是指函数工具 FunctionTool(未来可能有不同类型的工具)。接口需要声明工具的类型和名字,描述,输入架构(由输入参数的名字、描述、类型,组合构成),及以处理方法。

java 复制代码
//工具接口
public interface ChatTool {
    //工具类型
    String type();
}

//函数工具接口
public interface FunctionTool extends ChatTool {
    //工具类型
    default String type() { return "function"; }

    //名字
    String name();

    //描述
    String description();
    
    //是否直接返回给调用者(v3.2.1 后支持)
    boolean returnDirect();

    //输入架构
    ONode inputSchema();
    
    //输出架构
    default String outputSchema() { return null;  }

    //处理
    String handle(Map<String, Object> args) throws Throwable;
}

开发时,也可以使用注解简化工具声明(不需要 Bean 容器驱动):

java 复制代码
@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface ToolMapping {
    //名字
    String name() default "";

    //描述
    String description();

    //是否直接返回给调用者
    boolean returnDirect() default false;

    //结果转换器
    Class<? extends ToolCallResultConverter> resultConverter() default ToolCallResultConverter.class;
}

2、支持的参数类型

原则上,支持任意参数类型(jsonSchema 能描述的类型)。尽量,使用基础类型和数据实体类型;像 Socket、Session 这类的不适合。

3、关于 returnDirect (直接返回)的作用

默认状态时,Tool 处理的结果是交给大模型,大模型加工后再返回。通过 returnDirect 可以跳过大模型直接返回。

  • returnDirect=false(默认)

    user -> llm -> tool -> llm -> user

  • returnDirect=true

    user -> llm -> tool -> user

MCP 协议目前不支持这个特性透传。但当 server 和 client 都是 solon-ai-mcp 时,可支持此特性透传。

4、三种函数工具的定制方式

  • (1) 注解声明的定制(比较简洁,一个类里可有多个函数工具)。示例:

我们定义个工具类,并设定一个 "天气查询" 函数和 "联网搜索" 的函数

java 复制代码
import org.noear.solon.ai.annotation.ToolMapping;
import org.noear.solon.annotation.Param;

//可以加组件注解(支持注入和拦截)
public class Tools {
    //天气查询
    @ToolMapping(description = "获取指定城市的天气情况")
    public String get_weather(@Param(name = "location", description = "根据用户提到的地点推测城市") String location) {
        return "晴,24度"; //可使用 "数据库" 或 "网络" 接口根据 location 查询合适数据;
    }

    //...//可以加其它注解函数
}

应用示例(提醒:如果一次请求,若多个函数有交差描述,自动识别可能会混乱):

java 复制代码
public void case3() throws IOException {
    ChatResponse resp = chatModel
            .prompt("今天杭州的天气情况?")
            .options(o -> o.toolsAdd(new MethodToolProvider(new Tools()))   //会自动匹配天气函数
                           .toolsAdd(new MethodToolProvider(new Tools2()))   //可以添加多套工具
            .call();
}
  • (2) 构建声明方式(比较简洁)。示例:
java 复制代码
FunctionToolDesc weatherTool = new FunctionToolDesc("get_weather")
                .description("获取指定城市的天气情况")
                .stringParamAdd("location", "根据用户提到的地点推测城市")
                .doHandle(map -> {
                    return "24度";
                });

应用示例:

java 复制代码
public void case3() throws IOException {
    ChatResponse resp = chatModel
            .prompt("今天杭州的天气情况?")
            .options(o -> o.toolsAdd(weatherTool))  //会自动匹配天气函数
            .call();
}
  • (3) 接口实现的定制方式(比较原始)。示例:
java 复制代码
//可以加组件注解(支持注入和拦截)
public class WeatherTool implements FunctionTool {
    private List<ParamDesc> params = new ArrayList<>();
    public WeatherTool() {
        //友好的描述,有助于大模型推测参数值
        params.add(new ParamDesc("location", String.class, true, "根据用户提到的地点推测城市"));
    }

    @Override
    public String name() {
        return "get_weather";
    }

    @Override
    public String description() {
        //友好的描述,有助于大模型组织回复消息
        return "获取指定城市的天气情况";
    }
    
    @Override
    public boolean returnDirect() {
        return false;
    }

    @Override
    public ONode inputSchema() {
        return ToolSchemaUtil.buildToolParametersNode(params, new ONode());
    }

    @Override
    public String handle(Map<String, Object> args) {
        String location = (String) args.get("location");

        if(location == null) {
            //大模型有可能会识别失败
            throw new IllegalStateException("arguments location is null (Assistant recognition failure)");
        }

        return "24度";// 可使用 "数据库" 或 "网络" 接口根据 location 查询合适数据;
    }
}

应用示例:

java 复制代码
public void case3() throws IOException {
    ChatResponse resp = chatModel
            .prompt("今天杭州的天气情况?")
            .options(o -> o.toolsAdd(new WeatherTool()))  //会自动匹配天气函数
            .call();
}

5、工具的添加和作用域

  • 默认工具(是即每次请求时都会附加)。可在语言模型构建时添加。
java 复制代码
public void case3() throws IOException {
    ChatModel.of("http://127.0.0.1:11434/api/chat")
                .provider("ollama")
                .model("llama3.2")
                .defaultToolsAdd(new WeatherTool()) //添加默认工具(即所有请求可用)
                .defaultToolsAdd(new WeatherTool2()) //可以添加多套工具(只是示例下)
                .build();
                
                
    ChatResponse resp = chatModel
            .prompt("今天杭州的天气情况?")
            .call();

    //打印消息
    log.info("{}", resp.getMessage());
}
  • 请求工具(当次请求时附加)。和全局工具相比,只是作用域不同。
java 复制代码
public void case3() throws IOException {
    ChatModel.of("http://127.0.0.1:11434/api/chat")
                .provider("ollama")
                .model("llama3.2")
                .build();
                
                
    ChatResponse resp = chatModel
            .prompt("今天杭州的天气情况?")
            .options(o -> o.toolsAdd(new WeatherTool())) //添加请求函数
            .call();

    //打印消息
    log.info("{}", resp.getMessage());
}
相关推荐
casterQ22 分钟前
4. Agent Quality ——【Google 5-Day AI Agents】
人工智能·llm·agent·langgraph·adk
HuggingFace26 分钟前
用开源模型强化你的 OCR 工作流
人工智能
子綦27 分钟前
Andrej Karpathy 推荐的 AI 读书法:我是如何结合“沉浸式翻译”啃动英文顶会论文的?(附 Prompt 模板)
人工智能·经验分享·prompt·学习方法
陈天伟教授28 分钟前
机器学习策略(1)四大学派
人工智能·机器学习
AA陈超29 分钟前
Lyra学习6:GameFeatureAction_AddComponents分析
c++·笔记·学习·ue5
极客BIM工作室30 分钟前
AI论文整理:TOKENCOMPOSE: Text-to-Image Diffusion with Token-level Supervision
人工智能
Elastic 中国社区官方博客32 分钟前
Elasticsearch:在隔离环境中安装 ELSER 模型
大数据·数据库·人工智能·elasticsearch·搜索引擎·ai·全文检索
跨境卫士—小依39 分钟前
深耕 Ozon:俄罗斯电商精准盈利的核心玩法
大数据·人工智能·矩阵·跨境电商·亚马逊·防关联
love530love43 分钟前
【ComfyUI/SD环境管理指南(二)】:如何避免插件安装导致的环境崩溃与“外科手术式”修复
人工智能·windows·python·stable diffusion·github·aigc·comfyui