LangChain4j 工具调用
LangChain4j 工具调用——让 AI 从”聊天”到”行动”
一、什么是工具调用?
1.1 从”聊天”到”行动”的进化
传统的 AI 对话是这样的:
- 用户问:”今天北京天气怎么样?”
- AI 答:”很抱歉,我无法获取实时天气信息。”
为什么?因为大模型本身只是一个”知识库”,他的训练数据是有截止时间的,它不知道此时此刻的温度。
工具调用(Function Calling / Tool Calling)解决了这个问题:当 AI 遇到自己不会的问题时,它会在响应中表达”我想调用某个工具”的意图,而不是直接输出文字。
开发者拿到这个意图后,执行真正的工具(查天气、发邮件、算数学),再把结果返回给 AI,AI 基于结果生成最终回答。
.2 工作原理:一次完整的工具调用流程
用户:”今天北京天气怎么样?”
↓
【第1轮请求】UserMessage + 工具定义(getWeather)
↓
【第1轮响应】AI说:我要调用 getWeather(“北京”)
↓
【开发者执行】调用第三方天气平台获取北京天气
↓
【第2轮请求】UserMessage + AiMessage(工具请求) + ToolExecutionResultMessage(结果)
↓
【第2轮响应】AI说:”北京天气是 25摄氏度,晴朗”
整个过程完全自动,开发者只需要:
- 用
@Tool注解定义工具方法 - 在创建 AI Service 时注册这些工具
1.3 两个抽象级别
LangChain4j 提供了两个层次的工具 API:
| 级别 | API | 适用场景 |
|---|---|---|
| 低级别 | ChatLanguageModel + ToolSpecification |
需要完全控制请求/响应流程 |
| 高级别(推荐) | AiServices + @Tool 注解 |
日常开发,自动处理工具执行和结果回传 |
二、核心概念:@Tool 注解详解
2.1 最简示例
java
1 |
|
然后把工具注册到 AI Service:
1 |
|
2.2 @Tool 注解参数
根据官方文档,@Tool 注解提供以下配置项:
| 参数 | 说明 | 默认值 |
|---|---|---|
value / description |
工具描述,AI 根据这个判断何时调用 | 空字符串 |
name |
工具名称,不提供则使用方法名 | 方法名 |
returnBehavior |
返回值处理方式, TO_LLM: 将自己的工具给的结果再请求LLM,LLM会再对结果“润色”, IMMEDIATE: 直接返回结果,不再二次请求 LLM | TO_LLM |
searchBehavior |
工具是否可被搜索 | SEARCHABLE |
searchBehavior是 LangChain4j 中@Tool注解的一个属性,用于控制工具在工具搜索策略 (ToolSearchStrategy) 下的可见性和发现方式。它是一个枚举类型,包含两个值:
枚举值 说明 适用场景 SEARCHABLE(默认值) 工具不会在对话开始时就直接暴露给LLM,而是需要在需要时通过“工具搜索”的过程被LLM发现后才会变得可见。 当你的AI服务中配置了大量工具时,为避免占用LLM的上下文窗口(Token),让LLM按需动态发现相关工具,节省资源。 ALWAYS_VISIBLE工具始终对LLM可见,无论是否配置了工具搜索策略。 对于核心、高频使用的工具(如获取用户信息的 getUserProfile),确保LLM总能直接调用,无需额外搜索步骤。
核心概念解析:为什么需要
searchBehavior?要理解
searchBehavior的作用,需要先了解ToolSearchStrategy(工具搜索策略)。
- 默认行为:如果不配置任何
ToolSearchStrategy,AI服务会将所有通过.tools()注册的工具一次性全部发送给LLM。当工具数量很少时,这没有问题。- 问题与优化:但如果你有几十个甚至上百个工具,每次都把所有工具的元数据(名称、描述、参数结构)发给LLM,会消耗大量Token,降低响应速度,甚至可能让LLM在众多工具中“挑花眼”,影响决策准确性。
ToolSearchStrategy的价值:它允许你配置一种策略,让LLM先通过一两个“搜索工具”来按需查找真正相关的工具,然后再进行调用。这大大提高了效率。实践对比
假设你为AI助手配置了20个工具,其中包括“搜索订单”和“查询天气”,并启用了
ToolSearchStrategy。
- 如果
searchBehavior = SEARCHABLE(默认):
- 初始对话:LLM只知道“工具搜索”这一两个特殊工具,不知道具体的20个工具。
- 用户问:“帮我查一下最近的订单。”
- LLM 行动:LLM会调用“工具搜索”工具,并提供“查询订单”作为关键词。
- 框架行动:
ToolSearchStrategy的执行器会从20个可搜索工具中找到“搜索订单”这个工具。- 后续调用:找到后,这个“搜索订单”工具才会被加载到上下文中,LLM接着用它完成最终查询。
- 如果
searchBehavior = ALWAYS_VISIBLE:
- 无论是否配置了
ToolSearchStrategy,“查询天气”这个工具在对话一开始就会和“工具搜索”工具一起暴露给LLM。- 用户问任何问题,LLM都能直接看到并尝试调用它。
2.3 参数定义:@P 注解
为了帮助 AI 正确填充参数,应该为每个参数提供描述:
1 | public class WeatherService { |
参数必需性:默认所有参数都是必需的。可以通过 @P(required = false) 标记可选参数
2.4 多个工具
1 | package com.example.assistant.service; |
配置工具:
可以把多个工具写到一个类里,如上述代码所示:
1 |
也可以将工具分别写到多个类里:
1 |
四、高级特性
4.1 并行工具调用
某些模型(如 OpenAI)支持一次响应中调用多个工具。LangChain4j 默认串行执行工具,但可以开启并发:
1 | SmartAssistant assistant = AiServices.builder(SmartAssistant.class) |
4.2 工具搜索策略(减少 Token 消耗)
当工具有很多时(比如 50+),每次都把所有工具定义发给 AI 会消耗大量 Token。LangChain4j 支持工具搜索策略:
java
1 | // 使用 @Tool(searchBehavior = SearchBehavior.SEARCHABLE) 标记 |
4.3 工具执行前后通知
1 | SmartAssistant assistant = AiServices.builder(SmartAssistant.class) |
4.4 MCP 集成:接入海量现成工具
MCP(Model Context Protocol) 是 Anthropic 推出的开放协议,允许 AI 应用通过标准化接口调用外部工具服务器。
1 | // 1. 创建 MCP 客户端连接工具服务器 |
通过 MCP,你可以接入 GitHub、Slack、数据库等官方和社区提供的工具服务器,无需自己实现。
五、最佳实践与注意事项
5.1 工具描述要清晰
AI 靠提示词描述判断何时调用工具,描述越清晰,调用越准确:
1 | // 不好 |
5.2 参数命名用英文
AI 训练数据中英文字段名更常见,中文参数名可能导致识别失败。
5.3 控制工具数量
一次请求发送太多工具定义会消耗大量 Token。建议:
- 普通场景:5-10 个工具
- 多工具场景:使用工具搜索策略
5.4 并发调用注意
AI Service 对同一个 @MemoryId 不支持并发调用,可能导致 ChatMemory 损坏。需要在高并发场景做好同步控制。
六、总结
| 需求 | 解决方案 |
|---|---|
| 基础工具调用 | @Tool + AiServices.tools() |
| 多个工具组合 | 注册多个工具对象,AI 自主选择 |
| 需要立即返回(不发回 LLM) | @Tool(returnBehavior = IMMEDIATE) |
| 减少 Token 消耗 | 工具搜索策略 / MCP 按需加载 |
| 接入社区工具 | MCP 协议集成 |
| 工具执行监控 | beforeToolExecution / afterToolExecution 钩子 |
- Title: LangChain4j 工具调用
- Author: 薛定谔的汪
- Created at : 2025-04-30 18:01:54
- Updated at : 2026-04-08 15:28:00
- Link: https://www.zhengyk.cn/2025/04/30/ai/langchain4j_04_tools/
- License: This work is licensed under CC BY-NC-SA 4.0.