当前位置: 首页 > news >正文

SpringAIAlibaba之基础功能和基础类源码解析(2)

一、序言

        SpringAIAlibaba系列的上一篇文章已经对SpringAIAlibaba做了一个入门,这里的入门就是知道SpringAIAlibaba是做什么的,然后也可以调通通义模型,本篇文章就再做一个入门PLUS吧,可以使用一些基础的功能,了解一些核心类实现。

二、基础功能

        使用 PromptTemplate 动态构建提示词可以让你的应用更灵活和可配置。以下是完整的实现方案:
1. YAML 配置文件
创建 src/main/resources/application.yml:

spring:ai:dashscope:api-key: ${DASHSCOPE_API_KEY:your-api-key}# 提示词模板配置
prompt:templates:chat:system: "你是一个专业的{role},擅长{expertise}。请用{style}的方式回答问题。"user: "用户问题:{question}\n背景信息:{context}\n请求类型:{requestType}"translation:system: "你是一个专业翻译,负责将{sourceLanguage}翻译成{targetLanguage}。"user: "请翻译以下内容:{content}"summary:system: "你是一个文档总结专家,能够提取关键信息并生成简洁的摘要。"user: "请总结以下内容,控制在{maxWords}字以内:\n{document}"# 默认参数
prompt:defaults:role: "AI助手"expertise: "回答各种问题"style: "友好专业"maxWords: "200"

2. 配置类

package com.example.yangai.config;import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;import java.util.Map;@Component
@ConfigurationProperties(prefix = "prompt")
public class PromptConfig {private Map<String, Map<String, String>> templates;private Map<String, String> defaults;// getters and setterspublic Map<String, Map<String, String>> getTemplates() {return templates;}public void setTemplates(Map<String, Map<String, String>> templates) {this.templates = templates;}public Map<String, String> getDefaults() {return defaults;}public void setDefaults(Map<String, String> defaults) {this.defaults = defaults;}
}

3. 提示词服务类

package com.example.yangai.service;import com.example.yangai.config.PromptConfig;
import org.springframework.ai.chat.prompt.Prompt;
import org.springframework.ai.chat.prompt.PromptTemplate;
import org.springframework.ai.chat.messages.SystemMessage;
import org.springframework.ai.chat.messages.UserMessage;
import org.springframework.stereotype.Service;import java.util.HashMap;
import java.util.Map;@Service
public class PromptService {private final PromptConfig promptConfig;public PromptService(PromptConfig promptConfig) {this.promptConfig = promptConfig;}/*** 构建聊天提示词*/public Prompt buildChatPrompt(Map<String, Object> variables) {return buildPrompt("chat", variables);}/*** 构建翻译提示词*/public Prompt buildTranslationPrompt(String sourceLanguage, String targetLanguage, String content) {Map<String, Object> variables = Map.of("sourceLanguage", sourceLanguage,"targetLanguage", targetLanguage,"content", content);return buildPrompt("translation", variables);}/*** 构建摘要提示词*/public Prompt buildSummaryPrompt(String document, Integer maxWords) {Map<String, Object> variables = Map.of("document", document,"maxWords", maxWords != null ? maxWords.toString() : promptConfig.getDefaults().get("maxWords"));return buildPrompt("summary", variables);}/*** 通用提示词构建方法*/public Prompt buildPrompt(String templateName, Map<String, Object> variables) {Map<String, String> template = promptConfig.getTemplates().get(templateName);if (template == null) {throw new IllegalArgumentException("Template not found: " + templateName);}// 合并默认参数和用户参数Map<String, Object> mergedVariables = new HashMap<>(promptConfig.getDefaults());mergedVariables.putAll(variables);// 构建系统消息SystemMessage systemMessage = null;if (template.containsKey("system")) {PromptTemplate systemTemplate = new PromptTemplate(template.get("system"));systemMessage = systemTemplate.createMessage(mergedVariables);}// 构建用户消息UserMessage userMessage = null;if (template.containsKey("user")) {PromptTemplate userTemplate = new PromptTemplate(template.get("user"));userMessage = userTemplate.createMessage(mergedVariables);}// 组合消息if (systemMessage != null && userMessage != null) {return new Prompt(List.of(systemMessage, userMessage));} else if (userMessage != null) {return new Prompt(userMessage);} else if (systemMessage != null) {return new Prompt(systemMessage);} else {throw new IllegalArgumentException("No valid template found");}}
}

4. 更新的 ChatModel 实现

package com.example.yangai.service;import com.alibaba.dashscope.aigc.generation.Generation;
import com.alibaba.dashscope.aigc.generation.GenerationParam;
import com.alibaba.dashscope.aigc.generation.GenerationResult;
import com.alibaba.dashscope.aigc.generation.models.QwenParam;
import com.alibaba.dashscope.common.Message;
import org.springframework.ai.chat.ChatClient;
import org.springframework.ai.chat.ChatResponse;
import org.springframework.ai.chat.prompt.Prompt;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;@Service
public class TongyiChatModel implements ChatClient {@Value("${spring.ai.dashscope.api-key}")private String apiKey;@Overridepublic ChatResponse call(Prompt prompt) {try {Generation gen = new Generation();// 转换消息格式List<Message> messages = prompt.getInstructions().stream().map(instruction -> Message.builder().role(mapRole(instruction.getMessageType().name())).content(instruction.getContent()).build()).collect(Collectors.toList());// 构建请求参数GenerationParam param = GenerationParam.builder().apiKey(apiKey).model(QwenParam.Model.QWEN_TURBO).messages(messages).resultFormat(GenerationParam.ResultFormat.MESSAGE).build();// 调用模型GenerationResult result = gen.call(param);String content = result.getOutput().getChoices().get(0).getMessage().getContent();// 转换为 Spring AI 格式org.springframework.ai.chat.Generation springGeneration = new org.springframework.ai.chat.Generation(content);return new ChatResponse(Arrays.asList(springGeneration));} catch (Exception e) {throw new RuntimeException("调用通义千问失败", e);}}private String mapRole(String messageType) {switch (messageType.toLowerCase()) {case "system": return "system";case "user": return "user";case "assistant": return "assistant";default: return "user";}}
}

5. 控制器使用示例

package com.example.yangai.controller;import com.example.yangai.service.PromptService;
import com.example.yangai.service.TongyiChatModel;
import org.springframework.ai.chat.ChatResponse;
import org.springframework.ai.chat.prompt.Prompt;
import org.springframework.web.bind.annotation.*;import java.util.Map;@RestController
@RequestMapping("/api/chat")
public class ChatController {private final PromptService promptService;private final TongyiChatModel chatModel;public ChatController(PromptService promptService, TongyiChatModel chatModel) {this.promptService = promptService;this.chatModel = chatModel;}/*** 通用聊天接口*/@PostMapping("/ask")public ChatResponse ask(@RequestBody Map<String, Object> request) {String question = (String) request.get("question");String context = (String) request.getOrDefault("context", "");String requestType = (String) request.getOrDefault("requestType", "一般询问");Map<String, Object> variables = Map.of("question", question,"context", context,"requestType", requestType,"role", request.getOrDefault("role", "AI助手"),"expertise", request.getOrDefault("expertise", "回答各种问题"),"style", request.getOrDefault("style", "友好专业"));Prompt prompt = promptService.buildChatPrompt(variables);return chatModel.call(prompt);}/*** 翻译接口*/@PostMapping("/translate")public ChatResponse translate(@RequestBody Map<String, String> request) {String sourceLanguage = request.get("sourceLanguage");String targetLanguage = request.get("targetLanguage");String content = request.get("content");Prompt prompt = promptService.buildTranslationPrompt(sourceLanguage, targetLanguage, content);return chatModel.call(prompt);}/*** 摘要接口*/@PostMapping("/summarize")public ChatResponse summarize(@RequestBody Map<String, Object> request) {String document = (String) request.get("document");Integer maxWords = (Integer) request.get("maxWords");Prompt prompt = promptService.buildSummaryPrompt(document, maxWords);return chatModel.call(prompt);}
}

6. 使用示例

聊天请求:

curl -X POST http://localhost:8088/api/chat/ask \-H "Content-Type: application/json" \-d '{"question": "如何学习Spring Boot?","context": "我是Java初学者","role": "编程导师","expertise": "Java和Spring框架","style": "循序渐进"}'

翻译请求:

curl -X POST http://localhost:8088/api/chat/translate \-H "Content-Type: application/json" \-d '{"sourceLanguage": "中文","targetLanguage": "英文","content": "你好,世界!"}'

三、基础类解析

        一次通信过程中涉及到的核心类的关系如下:

ChatResponse (最外层响应)
├── List<Generation> (多个候选回答)
│   ├── Generation (单个回答)
│   │   ├── AssistantMessage (消息内容)
│   │   └── GenerationMetadata (生成元数据)
│   └── ...
└── ChatResponseMetadata (响应级元数据)├── Usage (token使用统计)├── RateLimit (速率限制)└── 扩展字段

        其中最外层的类就是SpringAI的,最内层的类就是SpringAIAlibaba,这里也能清楚的看出来SpringAI是对所有的模型接入做了一层抽象,底层可以对接多种模型的api,SpringAIAlibaba就是对通义模型的api实现,所以做了一些适配转换逻辑。

四、总结

        本文通过一个具体的实践案例再次加深了对SpringAIAlibaba的使用,同时通过这个开发的过程也了解了过程中涉及到的核心响应类,以及基础关系,当然请求类也是相同的关系逻辑,后续继续介绍核心源码,以及框架的设计架构。

        欢迎关注、一起交流、一起进步。

http://www.dtcms.com/a/338956.html

相关文章:

  • 添加右键菜单项以管理员权限打开 CMD
  • JUC之CompletableFuture【中】
  • [ORACLE数据库] ORACLE 的 PL/SQL 块
  • 开通会话内容存档获取聊天记录
  • 机器学习中的「损失函数」:模型优化的核心标尺
  • 源雀SCRM开源版企微客服功能重磅升级
  • Linux 正则表达式
  • 【新启航】航空飞机起落架深孔型腔的内轮廓检测方法探究 - 激光频率梳 3D 轮廓检测
  • JavaScript 性能优化:new Map vs Array.find() 查找速度深度对比
  • 机器翻译60天修炼专栏介绍和目录
  • C语言:字符函数与字符串函数(1)
  • 从 IP编码地址困局到网络优化:VLSM 与 CIDR 如何破解地址浪费与路由难题
  • 使用 Resilience4j 实现 Spring Boot 服务限流:轻量级容错的最佳实践
  • Java算法之排序
  • Bot 流量“假阳性”调优笔记
  • ListBoxes使得在专为灵活性和易用性设计
  • 消费者API
  • 云电脑 vs 传统PC:全面对比3A游戏与AI训练的成本与性能
  • Leetcode 3654. Minimum Sum After Divisible Sum Deletions
  • 【多模态大模型的三化】
  • [PV]AXI R/W/RW带宽计算的tcl脚本
  • AI赋能商业数据分析:从海量数据挖掘到智能决策洞察,激活企业增长新动能
  • Redisson 分布式锁核心机制解析
  • Flink原理与实践:第一章大数据技术概述总结
  • 微软行业案例:英格兰足球超级联赛(Premier League)
  • 丝杆支撑座在自动化生产线中的关键支撑
  • arcgis-提取范围中最大占比面积的信息或唯一值
  • Jenkins服务器SSH公钥配置步骤
  • nodejs koa框架使用
  • 计算机大数据毕业设计推荐:基于Spark的气候疾病传播可视化分析系统【Hadoop、python、spark】