SpringBoot AI Deepseek MCP 1.0 集成高德天氣預(yù)報完整方案
SpringBoot AI Deepseek MCP 1.0 集成高德天氣預(yù)報完整方案
本文將介紹如何使用 Spring AI 1.0.0 Release 版本深度集成高德天氣預(yù)報服務(wù),提供完整的、可直接部署的解決方案。相較于網(wǎng)上不完整的示例,本項目已解決所有依賴版本問題和代碼實現(xiàn)細(xì)節(jié)
技術(shù)架構(gòu)概覽
graph TD
A[用戶端] --> B[Spring Boot控制器]
B --> C[Spring AI ChatClient]
C --> D[工具調(diào)用]
D --> E[高德天氣服務(wù)]
D --> F[城市編碼查詢]
E --> G[高德API]
F --> H[Excel數(shù)據(jù)源]
C --> I[上下文記憶]
I --> J[內(nèi)存存儲]
核心依賴配置
<!-- Spring AI BOM 管理 -->
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-bom</artifactId>
<version>1.0.0</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<!-- 主要依賴 -->
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-webflux</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-client-chat</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-starter-model-openai</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-autoconfigure-model-chat-client</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-starter-mcp-server-webflux</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
<dependency>
<groupId>cn.idev.excel</groupId>
<artifactId>fastexcel</artifactId>
<version>${fastexcel.version}</version>
</dependency>
</dependencies>
核心組件實現(xiàn)
1. AI配置中心
@Configuration
public class ChatClientConfig {
// 配置基于時間窗口的對話記憶
@Bean
public MessageChatMemoryAdvisor messageWindowChatMemory() {
ExpireMemoryRepository memoryRepository = new ExpireMemoryRepository();
MessageWindowChatMemory chatMemory = MessageWindowChatMemory.builder()
.chatMemoryRepository(memoryRepository)
.maxMessages(20) // 保留最近20條對話
.build();
return MessageChatMemoryAdvisor.builder(chatMemory)
.scheduler(Schedulers.parallel())
.build();
}
// 配置ChatClient
@Bean
public ChatClient chatClient(ChatClient.Builder builder,
ToolCallbackProvider toolCallbackProvider,
MessageChatMemoryAdvisor messageChatMemoryAdvisor) {
return builder
.defaultSystem("""
你是一個地理專家和天氣預(yù)報助手,可以幫助用戶查詢天氣預(yù)報信息。
工作流程:
1. 根據(jù)用戶地址信息匹配到標(biāo)準(zhǔn)行政區(qū)劃的區(qū)縣級名稱
2. 根據(jù)區(qū)縣名稱獲取區(qū)域編碼
3. 使用區(qū)域編碼查詢天氣預(yù)報
4. 整理天氣信息并提供出行建議
""")
// 工具調(diào)用
.defaultToolCallbacks(toolCallbackProvider)
// 對話記憶
.defaultAdvisors(messageChatMemoryAdvisor)
.build();
}
}
2. 高德天氣服務(wù)集成
@Slf4j
@McpService
public class WeatherInfoService {
@Resource
private AmapConfigProperties amapConfigProperties;
private Map<String, CityModel> cityModels;
// 初始化城市編碼數(shù)據(jù)
@PostConstruct
public void init() {
try (InputStream mapCityIo = getClass().getResourceAsStream("/xlsx/AMap_adcode_citycode.xlsx")) {
CommonDataListener<CityModel> dataListener = new CommonDataListener<>();
FastExcel.read(mapCityIo)
.sheet()
.head(CityModel.class)
.registerReadListener(dataListener)
.doRead();
this.cityModels = dataListener.getList().stream()
.collect(Collectors.toMap(CityModel::getCityName,
Function.identity(),
(t, t2) -> t));
} catch (IOException e) {
throw new RuntimeException("加載城市編碼數(shù)據(jù)失敗", e);
}
}
// 工具方法:根據(jù)城市名查詢區(qū)域編碼
@Tool(name = "queryAdCodeByCityName",
description = "根據(jù)區(qū)縣名稱獲取區(qū)域編碼")
public Optional<String> queryAdCodeByCityName(
@ToolParam(description = "區(qū)縣名稱") String cityName) {
log.info("查詢城市編碼: {}", cityName);
return Optional.ofNullable(cityModels.get(cityName))
.map(CityModel::getAdCode);
}
// 工具方法:根據(jù)區(qū)域編碼查詢天氣
@Tool(name = "queryByAdCode",
description = "根據(jù)區(qū)域編碼查詢天氣預(yù)報")
public WeatherResponse queryByAdCode(
@ToolParam(description = "區(qū)域編碼") String adCode) {
log.info("查詢天氣信息,區(qū)域編碼: {}", adCode);
return WebClient.builder()
.baseUrl(amapConfigProperties.getUrl())
.build()
.get()
.uri(uriBuilder -> uriBuilder.path("/v3/weather/weatherInfo")
.queryParam("key", amapConfigProperties.getKey())
.queryParam("city", adCode)
.queryParam("extensions", "all")
.build())
.retrieve()
.onStatus(HttpStatusCode::isError, response ->
Mono.error(new ServiceException("高德天氣服務(wù)異常")))
.bodyToMono(WeatherResponse.class)
.block();
}
}
3. 控制器實現(xiàn)
@RestController
@RequestMapping("/api/chat")
@Slf4j
public class ChatController {
@Resource
private ChatClient chatClient;
// SSE流式響應(yīng)(適合前端實時展示)
@PostMapping(value = "stream", produces = MediaType.TEXT_EVENT_STREAM_VALUE)
public Flux<ChatResponse> chatStream(@RequestBody ChatRequest request) {
return chatClient.prompt()
.user(request.getMessage())
.advisors(advisor -> {
if (request.getConversationId() != null) {
advisor.param("chat_memory_conversation_id",
request.getConversationId());
}
})
.stream()
.content()
.map(ChatResponse::new)
.onErrorResume(e -> Flux.just(
new ChatResponse("服務(wù)處理異常: " + e.getMessage(), false)));
}
// 阻塞式響應(yīng)(適合API調(diào)用)
@PostMapping("blocking")
public Mono<ChatResponse> chatBlocking(@RequestBody ChatRequest request) {
return chatClient.prompt()
.user(request.getMessage())
.advisors(advisor -> {
if (request.getConversationId() != null) {
advisor.param("chat_memory_conversation_id",
request.getConversationId());
}
})
.call()
.content()
.map(ChatResponse::new)
.onErrorResume(e -> Mono.just(
new ChatResponse("服務(wù)處理異常: " + e.getMessage(), false)));
}
}
4. 配置文件示例
server:
port: 8080
amap:
key: ${AMAP_KEY:your_amap_key} # 高德開放平臺KEY
url: https://restapi.amap.com
spring:
application:
name: weather-ai-service
ai:
openai:
api-key: ${OPENAI_API_KEY:your_api_key}
base-url: ${OPENAI_BASE_URL:https://api.deepseek.com} # DeepSeek兼容URL
chat:
options:
model: deepseek-chat # 使用DeepSeek模型
temperature: 0.7
max-tokens: 2000
系統(tǒng)工作流程
sequenceDiagram
participant User as 用戶
participant Controller as Spring控制器
participant AI as Spring AI
participant Tool as 天氣工具
participant AMAP as 高德API
User->>Controller: 發(fā)送天氣查詢請求
Controller->>AI: 轉(zhuǎn)發(fā)用戶請求
AI->>Tool: 調(diào)用queryAdCodeByCityName
Tool->>AI: 返回區(qū)域編碼
AI->>Tool: 調(diào)用queryByAdCode
Tool->>AMAP: 請求天氣數(shù)據(jù)
AMAP-->>Tool: 返回天氣響應(yīng)
Tool-->>AI: 返回天氣數(shù)據(jù)
AI-->>Controller: 生成自然語言響應(yīng)
Controller-->>User: 返回天氣信息
使用示例與效果
1. 請求示例
POST /api/chat/blocking
{
"message": "北京海淀區(qū)明天的天氣如何?",
"conversationId": "conv_123456"
}
2. AI工具調(diào)用過程
INFO WeatherInfoService : 查詢城市編碼: 海淀區(qū)
INFO WeatherInfoService : 查詢天氣信息,區(qū)域編碼: 110108
3. 響應(yīng)結(jié)果
{
"content": "海淀區(qū)明天的天氣預(yù)報如下:\n\n- **日期**: 2025年06月05日(星期四)\n- **白天天氣**: 多云\n- **夜間天氣**: 晴\n- **白天溫度**: 36°C\n- **夜間溫度**: 22°C\n- **風(fēng)向**: 西南風(fēng)\n- **風(fēng)力**: 1-3級\n\n### 出行建議\n1. **防曬**: 白天溫度較高,注意防曬,避免長時間暴露在陽光下。\n2. **補水**: 高溫天氣容易導(dǎo)致脫水,記得多喝水。\n3. **夜間溫差**: 夜間溫度較低,建議攜帶一件薄外套。\n\n如果需要更詳細(xì)的天氣信息或其他幫助,請隨時告訴我!",
"success": true
}

浙公網(wǎng)安備 33010602011771號