ai(5) spring ai 单agent
- 上一篇
- ai agent
- 概念
- ai chat:用户输入,请求LLM(大模型), LLM返回答案。
- RAG(检索增强):知识分块 -》存入向量库。用户输入-》检索向量库-》请求LLM-》LLM返回数据
- Agent:用户输入-》LLM规划-》调用工具-》LLM规划-》调用工具。。。-》完成(闭环循环
- 大模型告诉你答案。rag引用资料说话。agent会说会做。
- 流程
- 开发工具:工具是什么,其实就是封装好的方法。比如封装一个天气的工具就是查询天气返回天气结果,封装一个查询订单的工具就是查询数据库返回数据。另外需要在方法上特别标注是做什么用,方便LLM快速找到想要的工具
- api调用:天气、股价、汇率等等
- 数据库查询:用户信息、订单、学生信息...
- 本地文件:读取配置、读日志、
- 知识库检索:RAG向量搜索
- 搜索引擎:es、日志、google等
- 数学计算:复杂公式、统计计算等
- 单位转换:货币、长度、重量等
- 时间处理:时区转换、日期计算等
- 数据统计:平均值、趋势分析等
- 文件操作:创建、移动、删除等
- 发送通知:邮件、短信、钉钉、企业微信等
- 执行命令:shell脚本、python脚本等
- 记忆实现
- 短期记忆:对话上下文
- 配置ChatMemory,主要包括储存和记录条数,短期记忆存储可以选择服务器内存、redis、数据库等
- 将ChatMemory注入到ChatClient中,ChatClient是ai sdk的一个接口或者方法。
- 会话id:conversationId,每次请求后端接口都需要一个会话id,来区分不同的用户和会话。通过会话id获取之前的记忆
- 长期记忆:Rag向量库
- 工具加载和调用
- java springboot框架中有专门的方法,将工具注册到对话模型上(别的语言应该一样)
- 调用的时候,LLM会根据工具的描述,遍历所有工具,找到匹配度最高的工具,然后决定调用这个工具,这个一般内置好的不用自己开发
- springboot会循环调用需要的工具处理数据
- 大模型处理
- 等大模型自动调用合适的工具处理好数据,然后组装数据返回给用户。
- 开发工具:工具是什么,其实就是封装好的方法。比如封装一个天气的工具就是查询天气返回天气结果,封装一个查询订单的工具就是查询数据库返回数据。另外需要在方法上特别标注是做什么用,方便LLM快速找到想要的工具
- 概念
- spring ai对接
- 首先开发对应的工具,例如开发一个查询天气的工具
import com.zwj.ai.core.ai.dto.GeoResponse;
import com.zwj.ai.core.ai.dto.WeatherResponse;
import com.zwj.ai.core.utils.HttpUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.ai.tool.annotation.Tool;
import org.springframework.ai.tool.annotation.ToolParam;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestClient;
import tools.jackson.databind.ObjectMapper;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Random;
import java.util.concurrent.ThreadLocalRandom;
/**
* 天气查询工具类
* <p>提供天气相关的 AI 工具方法,包括温度查询、湿度查询、天气状况和天气预报</p>
*
* @author ext.zhangwujie5
* @since 2026/6/6
*/
@Slf4j
@Service
public class WeatherTools {
private final RestClient restClient = RestClient.create("https://devapi.qweather.com");
private final ObjectMapper objectMapper = new ObjectMapper();
@Tool(description = "获取指定坐标的当前天气信息,包括温度等")
public double getCurrentTemperature(
@ToolParam(description = "纬度") double lat,
@ToolParam(description = "经度") double lon
) {
log.info("WeatherTools getCurrentTemperature start lat={} lon={}", lat, lon);
String forecastUrl = "https://api.open-meteo.com/v1/forecast?latitude=" + lat + "&longitude=" + lon + "¤t_weather=true&timezone=auto";
String s = HttpUtil.get(forecastUrl);
WeatherResponse response = objectMapper.readValue(s, WeatherResponse.class);
log.info("WeatherTools getCurrentTemperature start response={}", objectMapper.writeValueAsString(response));
if (response == null || response.getCurrentWeather() == null) {
throw new RuntimeException("无法获取温度数据");
}
return response.getCurrentWeather().getTemperature();
}
@Tool(description = "根据城市名称查询当前天气信息")
public String getWeatherByCity(@ToolParam(description = "城市名称,如:北京、上海") String cityName) {
try {
log.info("WeatherTools getWeatherByCity start cityName={}", cityName);
// 第一步:通过城市名获取坐标(Open-Meteo 内置地理编码)
String searchUrl = "https://geocoding-api.open-meteo.com/v1/search?name=" + cityName + "&count=1&language=zh";
GeoResponse geo = HttpUtil.get(searchUrl, GeoResponse.class);
if (geo == null || geo.getResults().isEmpty()) {
return "未找到城市:" + cityName;
}
double lat = geo.getResults().getFirst().getLatitude();
double lon = geo.getResults().getFirst().getLongitude();
String displayName = geo.getResults().getFirst().getName();
double currentTemperature = getCurrentTemperature(lat, lon);
return String.format("%s 当前温度: %.1f°C", displayName, currentTemperature);
} catch (Exception ex) {
log.error("WeatherTools getWeatherByCity catch error msg={}", ex.getMessage(), ex);
return "获取天气失败: " + ex.getMessage();
}
}
@Tool(description = "获取指城市的当温度,返回摄氏度")
public String getTemperature(@ToolParam(description = "城市名称") String city) {
log.info("WeatherTools getTemperature start city={}", city);
Map<String, Integer> temps = Map.of(
"北京", 10, "上海", 20, "深圳", 30, "广州", 40,
"成都", 50, "杭州", 60, "武汉", 70, "西安", 80
);
int temp = temps.getOrDefault(city, 21);
log.info("WeatherTools getTemperature temp={}", temp);
return String.format("%s当前温度 %d°C", city, temp);
}
@Tool(description = "获取指定城市的湿度")
public String getHumidity(@ToolParam(description = "城市名称") String city) {
log.info("WeatherTools getHumidity start city={}", city);
Map<String, Integer> humidity = Map.of(
"北京", 10, "上海", 20, "深圳", 30, "广州", 40,
"成都", 50, "杭州", 60, "武汉", 70, "西安", 80
);
int h = humidity.getOrDefault(city, 65);
log.info("WeatherTools getHumidity h={}", h);
return String.format("%s当前湿度 %d%%", city, h);
}
@Tool(description = "获取指定城市的天气状况(晴/雨/多云等)")
public String getWeatherCondition(@ToolParam(description = "城市名称") String city) {
log.info("WeatherTools getWeatherCondition start city={}", city);
List<String> conditions = List.of("晴朗☀️", "多云⛅", "小雨🌧️", "大雨🌧️", "雷阵雨⚡", "雾霾😷");
Random rand = new Random(city.hashCode());
String condition = conditions.get(rand.nextInt(conditions.size()));
return String.format("%s天气: %s", city, condition);
}
@Tool(description = "获取指定城市未来N天的天气预报")
public String getForecast(@ToolParam(description = "城市名称") String city,
@ToolParam(description = "天数(1-7)") int days) {
log.info("WeatherTools getForecast start city={}", city);
days = Math.min(days, 7);
List<String> forecasts = new ArrayList<>();
for (int i = 1; i <= days; i++) {
int temp = 20 + ThreadLocalRandom.current().nextInt(15);
forecasts.add(String.format("第%d天: %d°C", i, temp));
}
return String.format("%s未来%d天预报:\n%s", city, days, String.join("\n", forecasts));
}
} - 将写好的工具注册到对应的agent上
import com.zwj.ai.core.ai.tools.WeatherTools; import lombok.extern.slf4j.Slf4j; import org.springframework.ai.chat.client.ChatClient; import org.springframework.ai.chat.client.advisor.ToolCallAdvisor; import org.springframework.ai.ollama.OllamaChatModel; import org.springframework.ai.support.ToolCallbacks; import org.springframework.stereotype.Service; /** * 天气执行 Agent * <p>专门处理天气相关任务,集成温度查询、湿度查询、天气状况和天气预报等能力</p> */ @Slf4j @Service public class WeatherExecutorAgent { /** 天气查询 ChatClient,配置了天气工具 */ private final ChatClient weatherClient; public WeatherExecutorAgent( OllamaChatModel chatModel, WeatherTools weatherTools ) { this.weatherClient = ChatClient.builder(chatModel) .defaultSystem(""" 你是天气查询专家,专门处理所有与天气相关的问题。 你可以使用以下工具: 1. getTemperature - 获取指定城市的温度 2. getHumidity - 获取指定城市的湿度 3. getWeatherCondition - 获取指定城市的天气状况(晴/雨/多云等) 4. getForecast - 获取指定城市未来N天的天气预报 工作原则: - 仔细理解用户需要什么天气信息 - 如果用户问多个城市,分别查询每个城市 - 如果用户问未来天气,使用 getForecast 并指定天数 - 用友好、清晰的语言组织回答 """) .defaultToolCallbacks( ToolCallbacks.from( weatherTools ) ) .defaultAdvisors(ToolCallAdvisor.builder().build()) .build(); } /** * 执行天气查询任务 * * @param question 任务描述 * @return 执行结果 */ public String execute(String question) { log.info("WeatherExecutorAgent execute start question={}", question ); return weatherClient.prompt() .user(question) .call() .content(); } }
- 首先开发对应的工具,例如开发一个查询天气的工具
本文来自博客园,作者:zwjvzwj,转载请注明原文链接:https://www.cnblogs.com/zwjvzwj/p/22440313