AI超级智能体学习笔记

AI恋爱大师

功能

① AI恋爱大师应用

② 自主规划能力的超级智能体 :(what) 能根据用户需求,自主推理和行动,直到完成目标

③ AI工具:联网搜索,文件操作,网页抓取,资源下载,终端操作,PDF生成

④ MCP服务: 在特定网站搜索图片

技术

Java21 + Springboot3

SpringAI + LangChain4j

RAG知识库

PGvector 向量数据库

Tool Calling 工具调用

MCP模型上下文协议

ReAct Agent 智能体构建

Serverless 计算服务

AI大模型开发平台百炼

Cursor AI 代码生成 + MCP

SearchAPI、Pexels API

Ollama 大模型部署

Jsoup 网页抓取

iText PDF生成

需求 - AI应用需求分析

获取需求 =》 细化需求 =》 确认需求

实例

markdown
复制代码
我要开发一个【恋爱大师】AI 应用,用户在恋爱过程中难免遇到各种难题,让 AI 为用户提供贴心情感指导。 请你帮我进行需求分析,满足我的目标。 == 我要开发一个【恋爱大师】AI 应用,用户在恋爱过程中难免遇到各种难题,让 AI 为用户提供贴心情感指导。 请你帮我进行需求分析,满足我的目标。 具体需要: 1. 分析目标用户群体及其核心需求 2. 提出主要功能模块和服务内容 3. 考虑产品的差异化竞争点 4. 分析可能的技术挑战和解决方案 === 咱们从服务对象、服务内容、产品特性等维度,来剖析“恋爱大师”AI应用的开发需求: ### 一、目标用户洞察 1. **年龄与身份**:18-35岁人群是恋爱活动的主力军,涵盖大学生、职场新人等。他们熟悉数字化生活,热衷借助AI解决恋爱问题。 2. **恋爱状态及需求** - **单身群体**:渴望打破社交壁垒,寻觅恋爱机会。他们需要拓展社交圈、提升自我魅力、学习搭讪技巧等方面的指导。 - **恋爱中人群**:重点关注如何处理情侣间的争吵矛盾,掌握沟通艺术,安排浪漫约会,进一步升温感情。 - **失恋人群**:急需摆脱失恋阴影,修复受伤的情感,重新建立自信,恢复正常生活节奏。 ### 二、功能板块规划 #### (一)问题识别与分类 1. **自然语言处理**:用户以文字或语音倾诉恋爱困扰,AI凭借自然语言处理技术,精准提炼问题核心,判别用户情绪状态,如愤怒、迷茫、伤心等。 2. **问题归类**:将收集到的问题,归入表白难题、约会安排、信任危机、分手应对等预设类别,为后续的个性化解答做好准备。 #### (二)个性化指导服务 1. **智能问答**:针对用户提出的问题,AI从海量的恋爱案例、心理学知识以及专业情感建议中,生成贴合实际的解决方案。比如,当用户纠结“该不该向喜欢的人表白”时,AI会依据用户描述的双方关系,给出不同策略。 2. **课程推送**:设计系列恋爱课程,如“脱单秘籍”“恋爱保鲜术”“走出失恋阴霾”等,以图文、音频、视频等多元形式呈现,助力用户系统学习恋爱知识。 3. **案例分享**:分享真实且具有代表性的恋爱故事,通过对成功与失败案例的复盘,为用户提供借鉴与启示。 #### (三)特色辅助功能 1. **聊天话术生成**:用户输入聊天场景或对方信息,AI创作富有吸引力、契合氛围的聊天话术,帮助用户提升沟通效果。 2. **恋爱规划制定**:依据用户的恋爱阶段和目标,制定专属恋爱计划,涵盖约会安排、礼物挑选、情感互动等细节。 #### (四)互动交流社区 1. **话题讨论**:搭建线上社区,用户可发布恋爱问题、分享经验心得,实现用户间的相互交流与支持。 2. **专家直播**:定期邀请情感专家进行直播,解答用户普遍关注的恋爱问题,分享前沿恋爱观念和技巧。 ### 三、非功能要求 1. **隐私安全**:在数据收集、存储和使用过程中,严格遵循相关法规,采取加密、匿名化等技术手段,保护用户隐私,让用户放心倾诉。 2. **情感陪伴感**:AI回复需富有情感,模拟真实交流场景,避免机械化回答,给予用户温暖贴心的陪伴。 3. **持续优化**:搭建反馈机制,收集用户评价和建议,持续优化AI算法和服务内容,提升服务质量。

扩展

本地部署AI大模型并接入

① 安装ollama https://ollama.com/

② 执行ollama 运行指令

ollama run xxx

接入spring ai ollama

③ 引入 依赖

xml
复制代码
<dependency> <groupId>org.springframework.ai</groupId> <artifactId>spring-ai-ollama-spring-boot-starter</artifactId> <version>1.0.0-M6</version> </dependency> <!-- 官方可能没发布到中央仓库 --> <repositories> <repository> <id>spring-milestones</id> <name>Spring Milestones</name> <url>https://repo.spring.io/milestone</url> <snapshots> <enabled>false</enabled> </snapshots> </repository> </repositories>

④ 配置本地ai地址,spring localhost:11434

yaml
复制代码
spring: ai: ollama: base-url: http://localhost:11434 chat: model: gemma3:1b

⑤ 编写spring ai 示例代码,把 ChatModel 的 实现dashscopeChatModel改成 ollamaChatModel

java
复制代码
// 取消注释即可在 SpringBoot 项目启动时执行 //@Component public class OllamaAiInvoke implements CommandLineRunner { @Resource private ChatModel ollamaChatModel; @Override public void run(String... args) throws Exception { AssistantMessage output = ollamaChatModel.call(new Prompt("你好,我是鱼皮")) .getResult() .getOutput(); System.out.println(output.getText()); } }

提示词工程

Authropic 提示词库

Midjourney 提示词库

Prompt Engineering Guide 提示工程指南

鱼皮提示词笔记

如何 写提示词 how?

  • 根据笔记,去优化prompt
    • 总结1:思维链提示法 =》 给出思考步骤
    • 总结2:少样本学习 =》 给出示例
    • 总结3:分步骤 =》 可管理的步骤
    • 总结4:自我评价和修正 =》对输出进行改进
    • 总结5:知识检索和引用 =》 明确引用信息的来源
    • 总结6:多视角分析 =》不同角度,立场,专业角度的分析
    • 总结7:多模态 =》 文字描述,图标结构,代码逻辑
  • 提示词调试与优化
    • 迭代式提示优化 =》 根据上面的优化方法,逐步对提示词的内容进行扩展
    • 边界测试 =》找出问题 =》 思考方法 =》 提供解题思路
    • 模板话 :=》 特定任务 一致性的提示词
    • 错误分析与修正:=》 给出错误问题,修正方法

示例

自定义Advisor

类似于拦截器,可以对AI的请求进行增强 what(when:调用AI前鉴权,调用AI后记录日志)

怎么做?how

1)实现接口 - CallAroundAdvisor(作用在prompt范围的) - StreamAroundAdvisor(作用于流式请求)

2)getName(自定义名称)getOrder(优先级) before,observeAfter(日志)

拦截器的应用

https://docs.spring.io/spring-ai/reference/api/advisors.html

1.日志拦截器

参考接口 SimpleLoggerAdvisor

重写aroundCall () and aroundStream()

2.自定义Re-Reading

重复阅读用户输入内容(prompt),why :增强推理能力,但是会消耗token

how : 可以用模板语法将map内容传给它

java
复制代码
Map<String, Object> advisedUserParams = new HashMap<>(advisedRequest.userParams()); advisedUserParams.put("re2_input_query", advisedRequest.userText()); return AdvisedRequest.from(advisedRequest) .userText(""" {re2_input_query} Read the question again: {re2_input_query} """) .userParams(advisedUserParams) .build();

结构化输出

将AI输出的文本 ===》 结构化(JSON,XML,Java等)的代码,可靠规律性强的结构

如何实现(没啥用)

调用前,加上附加格式指令(JSON,XML);调用后,将文本转换成结构化输出

  • JSON schema 库的导入

    xml
    复制代码
    <dependency> <groupId>com.github.victools</groupId> <artifactId>jsonschema-generator</artifactId> <version>4.38.0</version> </dependency>
  • Java 14 快速定义实体类 record

    java
    复制代码
    record LoveReport(String title, List<String> suggestions) { }
  • 喂给系统提示词(“每次对话后都要生成恋爱结果,标题为{用户名}的恋爱报告,内容为建议列表”)

  • 转换 实体类 entity(record xx)

对话记忆持久化

what 就是将对话数据存起来,要么是文件,要么是数据库

how 实现

  • 引入 Kyro 序列化库 (why:①对象转化为可输入的字节流input,②Message没有实现序列化接口)

    xml
    复制代码
    <dependency> <groupId>com.esotericsoftware</groupId> <artifactId>kryo</artifactId> <version>5.6.2</version> </dependency>
  • 实现ChatMemory

Prompt 模板

提示词特殊的模板功能,变量替换

java
复制代码
// 定义带有变量的模板 String template = "你好,{name}。今天是{day},天气{weather}。"; // 创建模板对象 PromptTemplate promptTemplate = new PromptTemplate(template); // 准备变量映射 Map<String, Object> variables = new HashMap<>(); variables.put("name", "鱼皮"); variables.put("day", "星期一"); variables.put("weather", "晴朗"); // 生成最终提示文本 String prompt = promptTemplate.render(variables); // 结果: "你好,鱼皮。今天是星期一,天气晴朗。"

RAG 实践与调优

  • 文档收集和切割 (优化原始文档,文档切片,元数据标注)
  • 向量转换和存储(补充元数据与标签keywordMeatadataEnricher 系统自动补全)
  • 文档过滤和检索(多查询扩展(全方面扩展语义),查询重写与翻译,检索器配置(过滤))
  • 查询增强与关联(错误处理机制(保底机制),)

Spring AI 工具调用

what : 用外部工具,做ai无法完成的事情。联网搜索,文件操作,网页抓取,资源下载,pdf下载,终端操作执行Python脚本

【自己的理解】:用户提出问题给大模型,大模型分析问题判断使用哪些工具,然后输出工具名称和参数,去执行工具,返回工具结果,大模型再用工具返回的结果生成回答返回给用户

how 基本上用Method方法(用Tool,Toolparam ),容易写。Function

java
复制代码
class WeatherTools { @Tool(description = "Get current weather for a location") public String getWeather(@ToolParam(description = "The city name") String city) { return "Current weather in " + city + ": Sunny, 25°C"; } } // 使用方式 ChatClient.create(chatModel) .prompt("What's the weather in Beijing?") .tools(new WeatherTools()) .call();

简单实现发送 Email 的方法

① 开通 qq 邮箱 SMTP 授权码

②配置host(smtp.qq.com) , 端口号(465),pass(授权码), ssl-enable(开启ssl) 等信息

xml
复制代码
mail: host: smtp.qq.com port: 465 from: 你的邮箱 user: 你的qq号 pass: 授权码 auth: true ssl-enable:true

③发送邮件

java
复制代码
@Tool(description = "send a email with given subject and content to given to address") public String sendMail(@ToolParam(description = "Address of the email to send") String address, @ToolParam(description = "Subject to be included in the email") String subject, @ToolParam(description = "Content to be included in the email")String content) { try { // 初始化邮箱账号 MailAccount account = initMailAccount(); // 发送邮件 sendingEmail(account, address, subject, content).send(); return "Email sent successfully to: " + address; } catch (Exception e) { return "Error sending email: " + e.getMessage(); } } public MailAccount initMailAccount() { MailAccount account = new MailAccount(); account.setHost(host); account.setPort(port); account.setFrom(from); account.setUser(user); account.setAuth(auth); account.setSslEnable(sslEnable); account.setPass(pass); return account; } public Mail sendingEmail (MailAccount mailAccount, String to, String subject, String content) { return Mail.create(mailAccount) .setTos(to) .setTitle(subject) .setContent(content); }

MySQL + Mybatis3 + SpringBoot3

pom 下载

①springboot3 需要使用 mybatis-spring-boot-starter 3以上

② springboot3 需要使用的mybatis-plus 需要使用mybatis-plus-spring-boot3-starter;而不是mybatis-plus-boot-starter。否则Mapper会无法注入

③ 3.5.9以上的mybatis-plus的版本分离了分页插件,需要导入mybatis-plus-jsqlparser

xml
复制代码
<dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <scope>runtime</scope> <version>8.0.33</version> </dependency> <!-- spring boot 3 以上 ,mybatis starter也要用3以上--> <!-- https://mvnrepository.com/artifact/org.mybatis.spring.boot/mybatis-spring-boot-starter --> <dependency> <groupId>org.mybatis.spring.boot</groupId> <artifactId>mybatis-spring-boot-starter</artifactId> <version>3.0.4</version> </dependency> <!-- https://mvnrepository.com/artifact/com.baomidou/mybatis-plus-boot-starter --> <dependency> <groupId>com.baomidou</groupId> <artifactId>mybatis-plus-spring-boot3-starter</artifactId> <version>3.5.12</version> </dependency> <!--分页,可能用不到:3.--> <dependency> <groupId>com.baomidou</groupId> <artifactId>mybatis-plus-jsqlparser</artifactId> <version>3.5.12</version> </dependency>

配置yml (数据源会和postgresql冲突)

yaml
复制代码
spring: datasource: driver-class-name: com.mysql.cj.jdbc.Driver url: jdbc:mysql://localhost:3306/reai username: root password: root mybatis-plus: configuration: map-underscore-to-camel-case: false log-impl: org.apache.ibatis.logging.stdout.StdOutImpl global-config: db-config: logic-delete-field: isDelete # 全局逻辑删除的实体字段名 logic-delete-value: 1 # 逻辑已删除值(默认为 1) logic-not-delete-value: 0 # 逻辑未删除值(默认为 0)

使用mybatisX-generator

配置main扫描

java
复制代码
@SpringBootApplication @MapperScan("com.rich.reaiagentbackennd.mapper") public class MainApplication {}

修改实体类

isDelete : 添加 TableLogic

修改MailMapper.xml namespace, resultMap.type

MCP协议

mcp 协议 是一种增强AI和外部系统交互能力的一种开放标准

how 基本使用

① 下载依赖

xml
复制代码
<!--spring ai mcp client--> <dependency> <groupId>org.springframework.ai</groupId> <artifactId>spring-ai-mcp-client-spring-boot-starter</artifactId> <version>1.0.0-M6</version> </dependency>

② 配置需要使用的mcp.json文件

json
复制代码
{ "mcpServers": { "amap-maps": { "command": "npx.cmd", "args": [ "-y", "@amap/amap-maps-mcp-server" ], "env": { "AMAP_MAPS_API_KEY": "your_apikey" } } } }

③ 配置 ymal(仅支持本地stdio)

yml
复制代码
spring: ai: mcp: client: stdio: servers-configuration: classpath:mcp-servers.json

④创建对话客户端

javaa
复制代码
// AI 调用MCP服务 @Resource private ToolCallbackProvider toolCallbackProvider; /** * AI 恋爱报告功能(调用MCP服务) * @param message * @param chatId * @return */ public String doChatWithMCP(String message, String chatId) { ChatResponse chatResponse = chatClient .prompt() .user(message) .advisors(spec -> spec.param(CHAT_MEMORY_CONVERSATION_ID_KEY, chatId) .param(CHAT_MEMORY_RETRIEVE_SIZE_KEY, 10)) // 开启日志,便于观察效果 .advisors(new MyLoggerAdvisor()) // 调用工具 .tools(toolCallbackProvider) .call() .chatResponse(); String content = chatResponse.getResult().getOutput().getText(); log.info("content: {}", content); return content; }

二。MCP服务端

①下载 xml依赖 mcp-server-webmvc

xml
复制代码
<dependency> <groupId>org.springframework.ai</groupId> <artifactId>spring-ai-mcp-server-webmvc-spring-boot-starter</artifactId> <version>1.0.0-M6</version> </dependency>

② 配置yml

yaml
复制代码
spring: ai: mcp: server: name: yu-image-search-mcp-server version: 0.0.1 type: SYNC # stdio stdio: true # stdio main: web-application-type: none banner-mode: off

③ 编写服务

java
复制代码
@Service public class ImageSearchTool { // 替换为你的 Pexels API 密钥(需从官网申请) private static final String API_KEY = APIKEY.SEARCH_API_KEY; // Pexels 常规搜索接口(请以文档为准) private static final String API_URL = "https://api.pexels.com/v1/search"; @Tool(description = "search image from web") public String searchImage(@ToolParam(description = "Search query keyword") String query) { try { return String.join(",", searchMediumImages(query)); } catch (Exception e) { return "Error search image: " + e.getMessage(); } } /** * 搜索中等尺寸的图片列表 * * @param query * @return */ public List<String> searchMediumImages(String query) { // 设置请求头(包含API密钥) Map<String, String> headers = new HashMap<>(); headers.put("Authorization", API_KEY); // 设置请求参数(仅包含query,可根据文档补充page、per_page等参数) Map<String, Object> params = new HashMap<>(); params.put("query", query); // 发送 GET 请求 String response = HttpUtil.createGet(API_URL) .addHeaders(headers) .form(params) .execute() .body(); // 解析响应JSON(假设响应结构包含"photos"数组,每个元素包含"medium"字段) return JSONUtil.parseObj(response) .getJSONArray("photos") .stream() .map(photoObj -> (JSONObject) photoObj) .map(photoObj -> photoObj.getJSONObject("src")) .map(photo -> photo.getStr("medium")) .filter(StrUtil::isNotBlank) .collect(Collectors.toList()); } }

④ 注入bean ToolCallbackProvider

java
复制代码
@Bean public ToolCallbackProvider imageSearchTools (ImageSearchTool imageSearchTool) { return MethodToolCallbackProvider.builder() .toolObjects(imageSearchTool) .build(); }

⑤ 打包jar


⑥ 配置本地 mcp-server.json 配置

json
复制代码
"re-image-search-mcp-server": { "command":"java", "args":[ "-Dspring.ai.mcp.server.stdio=true", "-Dspring.main.web-application-type=none", "-Dlogging.pattern.console=", "-jar", "re-image-search-mcp-server/target/re-image-search-mcp-server-0.0.1-SNAPSHOT.jar" ], "env": {} }

测试

java
复制代码
// 测试图片搜索MCP String message = "帮我搜索一些哄另一半开心的图片"; String answer = loveApp.doChatWithMCP(message, chatId); Assertions.assertNotNull(answer);

创建项目

jdk8 用 阿里的 镜像 https://start.aliyun.com

使用 jdk21 why: >17, 使用SpringBoot3 和 Spring AI,21 支持 虚拟线程 https://start.spring.io

导入通用工具

xml
复制代码
<!--spring web starter--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <!-- lombok --> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <version>1.18.38</version> <optional>true</optional> </dependency> <dependency> <groupId>cn.hutool</groupId> <artifactId>hutool-all</artifactId> <version>5.8.37</version> </dependency>

导入 api 校验插件 Knife4J (SpringBoot3)

① 加载依赖

xml
复制代码
<dependency> <groupId>com.github.xiaoymin</groupId> <artifactId>knife4j-openapi3-jakarta-spring-boot-starter</artifactId> <version>4.4.0</version> </dependency>

② 配置文件application.yml ,直接在官网复制即可

yml
复制代码
# springdoc-openapi项目配置 springdoc: swagger-ui: path: /swagger-ui.html tags-sorter: alpha operations-sorter: alpha api-docs: path: /v3/api-docs group-configs: - group: 'default' paths-to-match: '/**' packages-to-scan: {{{ **配置扫描文件,controller就行了** }}} #com.rich.reaiagentbackennd.controller # knife4j的增强配置,不需要增强可以不配 knife4j: enable: true setting: language: zh_cn

#配置端口和后端上下文路径/api(额外)

yml
复制代码
server: port: 8123 servlet: context-path: /api

通用代码

通用基础代码,① 自定义异常,②响应包装类,③全局异常处理器,④ 请求包装类,⑤ 全局跨域配置

调用AI大模型

如何接入?How

① 使用SDK接入,官方提供(推荐)

② HTTP接入, 发送http请求调用模型(官方没有提供SDK接入)

③ Spring AI 基于 Spring 生态的AI框架 (方便Spring)

④ LangChain4j, 构建LLM应用的Java框架 (比Spring AI灵活)

选择那种大模型?where : 阿里系对Java 友好

1. SDK接入

阿里云百联文档

创建 API key :https://bailian.console.aliyun.com/?tab=model#/api-key

① 导入maven https://help.aliyun.com/zh/model-studio/first-api-call-to-qwen?spm=a2c4g.11186623.help-menu-2400256.d_0_0_1.4906de53r5kWvZ&scm=20140722.H_2840915._.OR_help-T_cn~zh-V_1#a0d9906322g41

xml
复制代码
<dependency> <groupId>com.alibaba</groupId> <artifactId>dashscope-sdk-java</artifactId> <!-- 请将 'the-latest-version' 替换为最新版本号:https://mvnrepository.com/artifact/com.alibaba/dashscope-sdk-java --> <version>the-latest-version</version> </dependency>

示例代码

java
复制代码
import java.util.Arrays; import java.lang.System; 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.common.Message; import com.alibaba.dashscope.common.Role; import com.alibaba.dashscope.exception.ApiException; import com.alibaba.dashscope.exception.InputRequiredException; import com.alibaba.dashscope.exception.NoApiKeyException; public class Main { public static GenerationResult callWithMessage() throws ApiException, NoApiKeyException, InputRequiredException { Generation gen = new Generation(); Message systemMsg = Message.builder() .role(Role.SYSTEM.getValue()) .content("You are a helpful assistant.") .build(); Message userMsg = Message.builder() .role(Role.USER.getValue()) .content("你是谁?") .build(); GenerationParam param = GenerationParam.builder() // 若没有配置环境变量,请用阿里云百炼API Key将下行替换为:.apiKey("sk-xxx") .apiKey(System.getenv("DASHSCOPE_API_KEY")) .apiKey(xxx.apikey) // 模型列表:https://help.aliyun.com/zh/model-studio/getting-started/models .model("qwen-plus") .messages(Arrays.asList(systemMsg, userMsg)) .resultFormat(GenerationParam.ResultFormat.MESSAGE) .build(); return gen.call(param); } public static void main(String[] args) { try { GenerationResult result = callWithMessage(); System.out.println(result.getOutput().getChoices().get(0).getMessage().getContent()); } catch (ApiException | NoApiKeyException | InputRequiredException e) { System.err.println("错误信息:"+e.getMessage()); System.out.println("请参考文档:https://help.aliyun.com/zh/model-studio/developer-reference/error-code"); } System.exit(0); } }

2. HTTP 接入

为什么使用 why 官方不支持sdk,保持依赖的精简

cmd
复制代码
curl -X POST https://dashscope.aliyuncs.com/api/v1/services/aigc/text-generation/generation \ -H "Authorization: Bearer $DASHSCOPE_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "model": "qwen-plus", "input":{ "messages":[ { "role": "system", "content": "You are a helpful assistant." }, { "role": "user", "content": "你是谁?" } ] }, "parameters": { "result_format":"message" } }'

使用 cursor 的ask prompt

将下面代码转换为hutool 工具类的请求代码

java
复制代码
import cn.hutool.http.HttpRequest; import cn.hutool.json.JSONObject; import cn.hutool.json.JSONUtil; public class DashScopeClient { public String callQwenPlus(String apiKey, String userContent) { // 构建请求URL String url = "https://dashscope.aliyuncs.com/api/v1/services/aigc/text-generation/generation"; // 构建请求体 JSONObject requestBody = new JSONObject(); requestBody.set("model", "qwen-plus"); // 构建input部分 JSONObject input = new JSONObject(); JSONObject[] messages = new JSONObject[2]; // 添加system message messages[0] = new JSONObject(); messages[0].set("role", "system"); messages[0].set("content", "You are a helpful assistant."); // 添加user message messages[1] = new JSONObject(); messages[1].set("role", "user"); messages[1].set("content", userContent); input.set("messages", messages); requestBody.set("input", input); // 构建parameters部分 JSONObject parameters = new JSONObject(); parameters.set("result_format", "message"); requestBody.set("parameters", parameters); // 发送POST请求 String result = HttpRequest.post(url) .header("Authorization", "Bearer " + apiKey) .header("Content-Type", "application/json") .body(requestBody.toString()) .execute() .body(); return result; } // 使用示例 public static void main(String[] args) { String apiKey = {{ 使用 API key}}; DashScopeClient client = new DashScopeClient(); String response = client.callQwenPlus(apiKey, "你是谁?"); System.out.println(response); } }

3. Spring AI

一般支持OpenAI的国产大模型都支持Spring AI (推荐使用Spring AI Alibaba)

① 依赖注入

xml
复制代码
<dependency> <groupId>com.alibaba.cloud.ai</groupId> <artifactId>spring-ai-alibaba-starter</artifactId> <version>1.0.0-M6.1</version> </dependency> <!-- 如果依赖没有加载,可以使用下面的仓库地址250427--> <repositories> <repository> <id>spring-milestones</id> <name>Spring Milestones</name> <url>https://repo.spring.io/milestone</url> <snapshots> <enabled>false</enabled> </snapshots> </repository> </repositories>

② 配置文件

yaml
复制代码
spring: ai: dashscope: api-key: {{ api key }} chat: options: model: qwen-plus

③ 实例代码-使用ChatModel 简单的对话

什么是ChatModel? 是用户输入Prompt提示词,ai进行文字处理,返回response的接口

怎么用?how https://java2ai.com/docs/1.0.0-M6.1/tutorials/chat-model/?spm=5176.29160081.0.0.2856aa5cq6JshL

java
复制代码
// 普通方式 @RequestMapping("/chatWithPrompt") public String chatWithPrompt(String input) { Prompt prompt = new Prompt(input); ChatResponse response = chatModel.call(prompt); return response.getResult().getOutput().getContent(); } // stream 处理 @RequestMapping("/streamChat") public void streamChat(String input, HttpServletResponse response) throws IOException { response.setContentType("text/event-stream"); response.setCharacterEncoding("UTF-8"); Prompt prompt = new Prompt(input); chatModel.stream(prompt, new StreamHandler() { @Override public void onMessage(ChatMessage message) { try { response.getWriter().write("data: " + message.getContent() + "\n\n"); response.getWriter().flush(); } catch (IOException e) { e.printStackTrace(); } } @Override public void onComplete() { try { response.getWriter().write("event: complete\n\n"); response.getWriter().flush(); } catch (IOException e) { e.printStackTrace(); } } }); } // 结合 springboot 做项目启动时,一次性测试 @Component public class SpringAIInvoke implements CommandLineRunner { @Resource private ChatModel dashscopeChatModel; @Override public void run(String... args) throws Exception { AssistantMessage assistantMessage = dashscopeChatModel.call(new Prompt("你好,我是一个菜鸟程序员")) .getResult() .getOutput(); System.out.println(assistantMessage.getText()); } }

4. LangChain4j

针对大语言模型的java框架,不支持阿里云模型,但有个社区版本的整合包

https://docs.langchain4j.dev/integrations/language-models/dashscope/

导入依赖

xml
复制代码
<dependency> <groupId>dev.langchain4j</groupId> <artifactId>langchain4j-community-dashscope</artifactId> <version>1.0.0-beta2</version> </dependency>

②示例代码

java
复制代码
QwenChatModel model = QwenChatModel.builder() .apiKey(TestApiKey.apiKey) .modelName("qwen-max") .build(); String result = model.chat("你好"); System.out.println(result);

业务1 --- 多轮对话实现

什么是多轮对话,what ? 让AI对话功能有记忆能力

如何实现?how

必备概念

  • ChatClient

    • 支持更复杂灵活的链式调用(为什么使用它?why)
    • ①可以用建造者模式构建 builder().xx.build()(如何使用它?how)
    • ② 使用自动注入
    java
    复制代码
    private final ChatClient chatClient; public ChatService (ChatModel dashscopeChatModel ) chatClient = ChatClient.builder(dashscopeChatModel) .defaultSystem(SYSTEM_PROMPT) .defaultAdvisors( new MessageChatMemoryAdvisor(chatMemory) ) .build(); }
    • 响应格式
      • 获取 返回对象 ChatResponse,chatResponse()
      • 获取 返回实体对象 entity(Clazz) | entity(new ParameterizedTypeRference<List<T>>)
      • 流式 返回 stream().content()
    • 默认提示词
      • 初始化 defaultSystem()
      • 修改 system()
    • 拦截器 AdvisorsdefaultAdvisors()
      • 对话记忆拦截器 MyssageChatMemoryAdvisor(chatMemory)----多轮对话实现关键方法
        • 可以指定长度和idchatClient.prompt().advisors(ad -> ad.param(id/size))
        • chatMemory 负责历史对话的存储,可以保存,查询,清空
        • ① InMemoryChatMemory内存存储;② CassandraChatMemory :带过期。。
      • RAG 检索增强 RAG检索增强advisor(vectorStore)

业务2 -----RAG知识库

特定知识库 + AI 内容生成的结构 what

how ;

① RAG工作流程

  • 文档收集和切割
    • what 顾名思义,将文档切割成小片段
  • 向量转换和存储
    • what 使用Embedding模型将文本转成向量表示)
  • 文档过滤和检索
    • what 将用户的问题转成向量表示,再进行条件过滤,进行相似度搜索,组成连贯的上下文
  • 查询增强和关联 (检索到的文档再和用户问题进行组合增强)

② 实现

SpringAI +本地知识库

1.准备知识库文案,可以用AI 生成,或者其他

帮我生成 3 篇 Markdown 文章,主题是【恋爱常见问题和回答】,3 篇文章的问题分别针对单身、恋爱、已婚的状态,内容形式为 1 问 1 答,每个问题标题使用 4 级标题,每篇内容需要有至少 5 个问题,要求每个问题中推荐一个相关的课程,课程链接都是 https://www.codefather.cn

2.文档的读取Spring AI 支持ETL:(知识库文档处理,并保存到向量数据库中)

  • what (a.DocumentReader 文档读取. b, DucumentTransformer 文档转换;c、DocumentWriter 保存文档到内存)

支持的格式《=====支持的格式

1 依赖引入

xml
复制代码
<dependency> <groupId>org.springframework.ai</groupId> <artifactId>spring-ai-markdown-document-reader</artifactId> <version>1.0.0-M6</version> </dependency>

2 代码编写

① 加载markdown==》官方参考https://docs.spring.io/spring-ai/reference/api/etl-pipeline.html#_markdown

java
复制代码
@Component @Slf4j class LoveAppDocumentLoader { private final ResourcePatternResolver resourcePatternResolver; LoveAppDocumentLoader(ResourcePatternResolver resourcePatternResolver) { this.resourcePatternResolver = resourcePatternResolver; } public List<Document> loadMarkdowns() { List<Document> allDocuments = new ArrayList<>(); try { // 这里可以修改为你要加载的多个 Markdown 文件的路径模式 Resource[] resources = resourcePatternResolver.getResources("classpath:document/*.md"); for (Resource resource : resources) { String fileName = resource.getFilename(); MarkdownDocumentReaderConfig config = MarkdownDocumentReaderConfig.builder() .withHorizontalRuleCreateDocument(true) .withIncludeCodeBlock(false) .withIncludeBlockquote(false) .withAdditionalMetadata("filename", fileName) .build(); MarkdownDocumentReader reader = new MarkdownDocumentReader(resource, config); allDocuments.addAll(reader.get()); } } catch (IOException e) { log.error("Markdown 文档加载失败", e); } return allDocuments; } }

② 向量转换和存储

when(用在哪里,需求):本地的markdown知识库 转成向量数据库 ,官网好像没例子https://docs.spring.io/spring-ai/reference/api/vectordbs.html#api-overview

how (如何实现):官网提到VectorStore =》查看它源码

img《===参考实现代码、

embedding加载文档

image-20250501170148446

java
复制代码
@Configuration public class LoveAppVectorStoreConfig { @Resource private LoveAppDocumentLoader loveAppDocumentLoader; @Bean VectorStore loveAppVectorStore(EmbeddingModel dashscopeEmbeddingModel) { SimpleVectorStore simpleVectorStore = SimpleVectorStore.builder(dashscopeEmbeddingModel) .build(); // 加载文档 List<Document> documents = loveAppDocumentLoader.loadMarkdowns(); simpleVectorStore.add(documents); return simpleVectorStore; } }

③ 查询增强 使用QuestionAnswerAdivsor 官方文档https://docs.spring.io/spring-ai/reference/api/retrieval-augmented-generation.html#_questionansweradvisor

java
复制代码
@Resource private VectorStore loveAppVectorStore; public String doChatWithRag(String message, String chatId) { ChatResponse chatResponse = chatClient .prompt() .user(message) .advisors(spec -> spec.param(CHAT_MEMORY_CONVERSATION_ID_KEY, chatId) .param(CHAT_MEMORY_RETRIEVE_SIZE_KEY, 10)) // 开启日志,便于观察效果 .advisors(new MyLoggerAdvisor()) // 应用知识库问答 .advisors(new QuestionAnswerAdvisor(loveAppVectorStore)) .call() .chatResponse(); String content = chatResponse.getResult().getOutput().getText(); log.info("content: {}", content); return content; }

SpringAI + 云知识库服务

https://www.codefather.cn/course/1915010091721236482/section/1916804058325704706?type=#heading-30

①导入数据(应用数据)

②创建知识库

作业

利用 RAG 知识库,实现“通过用户的问题推荐可能的恋爱对象”功能。

1 生成知识库文档

帮我生成一个markdown的恋爱对象文档,恋爱对象文档内有30个用户信息,且男女均等,每行数据包含一位用户的基本信息,内容包括年龄,星座,职业,爱好,另一半的要求

使用PGStore

开通向量数据库:https://rdsnext.console.aliyun.com/dashboard/cn-hangzhou?spm=5176.6660585.rds_serverless_public_cn-top.i0.53ac7992UYENDM

配置xml

xml
复制代码
<!--https://mvnrepository.com/artifact/org.springframework.ai/spring-ai-starter-vector-store-pgvector--> <dependency> <groupId>org.springframework.ai</groupId> <artifactId>spring-ai-starter-vector-store-pgvector</artifactId> <version>1.0.0-M7</version> </dependency>

配置yml

yaml
复制代码
spring: datasource: url: jdbc:postgresql://改为你的公网地址/yu_ai_agent username: 改为你的用户名 password: 改为你的密码 ai: vectorstore: pgvector: index-type: HNSW dimensions: 1536 distance-type: COSINE_DISTANCE max-document-batch-size: 10000 # Optional: Maximum number of documents per batch

另一种方法:

配置xml

xml
复制代码
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-jdbc</artifactId> </dependency> <dependency> <groupId>org.postgresql</groupId> <artifactId>postgresql</artifactId> <scope>runtime</scope> </dependency> <dependency> <groupId>org.springframework.ai</groupId> <artifactId>spring-ai-pgvector-store</artifactId> <version>1.0.0-M6</version> </dependency>
java
复制代码
// 示例代码 List<Document> documents = List.of( new Document("菜鸟程序员学习spring AI", Map.of("meta1", "meta1")), new Document("21世纪学习编程还有出路吗?菜鸟学习编程就是等死"), new Document("Richard 真帅", Map.of("meta2", "meta2"))); // Add the documents to PGVector pgVectorVectorStore.add(documents); // Retrieve documents similar to a query List<Document> results = pgVectorVectorStore.similaritySearch(SearchRequest.builder().query("怎么学编程").topK(5).build()); Assertions.assertNotNull(results);

业务3 -------- 智能体构建

参考 openManus:

① 基础 Agent类 :定义了智能体基本信息,循环按步骤(step)执行的基本方法(思考,行动,观察)

② ReActAgent 类 :代理思考(think),行动(act )的两个关键步骤

③ ToolCallAgent 类:调用工具类,思考用什么工具(think ),执行调用工具(act) ,将结果返回给ai(observe)

④ ReManus类

一。定义数据模型

java
复制代码
/** * 代理执行状态的枚举类 */ public enum AgentState { /** * 空闲状态 */ IDLE, /** * 运行中状态 */ RUNNING, /** * 已完成状态 */ FINISHED, /** * 错误状态 */ ERROR }

一、基本代理

java
复制代码
/** * 抽象基础代理类,用于管理代理状态和执行流程。 * * 提供状态转换、内存管理和基于步骤的执行循环的基础功能。 * 子类必须实现step方法。 */ @Data @Slf4j public abstract class BaseAgent { // 核心属性 private String name; // 提示词 private String systemPrompt; private String nextStepPrompt; // 代理状态 private AgentState state = AgentState.IDLE; // 执行多步骤控制 private int currentStep = 0; private int maxSteps = 10; // LLM 大模型 private ChatClient chatClient; // Memory 记忆(需要自主维护会话上下文) private List<Message> messageList = new ArrayList<>(); /** * 运行代理 * @param userPrompt 用户提示词 * @return 执行结果 */ public String run (String userPrompt) { // 基础校验 if (this.state != AgentState.IDLE) { throw new RuntimeException("Cannot run agent from state: "+ this.state); } if (StrUtil.isBlank(userPrompt)) { throw new RuntimeException("Cannot run agent with empty user prompt"); } // 执行,更改状态 this.state = AgentState.RUNNING; // 记录消息上下文 messageList.add(new UserMessage(userPrompt)); // 保存结果列表 List<String> results = new ArrayList<>(); try { // 执行循环 for (int i = 0; i < maxSteps && state != AgentState.FINISHED; i++) { int stepNumber = i + 1; currentStep = stepNumber; log.info("Executing step {}/{}", stepNumber, maxSteps); // 单步执行 String stepResult = step(); String result = "Step " + stepNumber + ": " + stepResult; results.add(result); // 检查是否陷入循环 } // 检查是否超出步骤限制 if (currentStep >= maxSteps) { currentStep = 0; state = AgentState.FINISHED; results.add("Terminated: Reached max steps: (" + maxSteps + ")"); } return String.join("\n", results); } catch (Exception e) { state = AgentState.ERROR; log.error("error executing agent:", e); return "执行错误:" +e.getMessage(); } finally { // 清理资源 this.cleanup(); } } /** * 定义单个步骤 * @return */ public abstract String step(); /** * 清理资源 */ public void cleanup () { // 子类可以重写此方法清理资源 } }

二、思考,行动代理

java
复制代码
/** * ReAct (Reasoning and Acting) 模式的代理抽象类 * 实现了思考-行动的循环模式 */ @EqualsAndHashCode(callSuper = true) @Data public abstract class ReActAgent extends BaseAgent { /** * 处理当前状态并决定下一步行动 * * @return 是否需要执行行动,true表示需要执行,false表示不需要执行 */ public abstract boolean think(); /** * 执行决定的行动 * * @return 行动执行结果 */ public abstract String act(); /** * 执行单个步骤:思考和行动 * * @return 步骤执行结果 */ @Override public String step() { try { // 思考 boolean shouldAct = think(); if (!shouldAct) { //setState(AgentState.FINISHED); return "思考完成 - 无需行动"; } // 再执行 return act(); } catch (Exception e) { // 记录异常日志 e.printStackTrace(); return "步骤执行失败:" + e.getMessage(); } } }

三、工具调用

java
复制代码
/** * 处理工具调用的基础代理类,具体实现了 think 和 act 方法,可以用作创建实例的父类 */ @EqualsAndHashCode(callSuper = true) @Data @Slf4j public class ToolCallAgent extends ReActAgent{ // 可用的工具 private final ToolCallback[] availableTools; // 保存了工具调用信息的响应 private ChatResponse toolCallChatResponse; // 工具调用管理者 private final ToolCallingManager toolCallingManager; // 禁用内置的工具调用机制,自己维护上下文 private final ChatOptions chatOptions; public ToolCallAgent(ToolCallback[] availableTools) { super(); this.availableTools = availableTools; this.toolCallingManager = ToolCallingManager.builder().build(); this.chatOptions = DashScopeChatOptions.builder() .withProxyToolCalls(true) .build(); } /** * 处理当前状态并决定下一步行动 * * @return 是否需要执行行动 */ @Override public boolean think() { // 1. 校验提示词,拼接用户提示词 if (StrUtil.isNotBlank(getNextStepPrompt())) { UserMessage userMessage = new UserMessage(getNextStepPrompt()); getMessageList().add(userMessage); } List<Message> messageList = getMessageList(); Prompt prompt = new Prompt(messageList, this.chatOptions); try { ChatResponse chatResponse = getChatClient().prompt(prompt) .system(getSystemPrompt()) .tools(availableTools) .call() .chatResponse(); // 2. 调用AI大模型,获取工具调用结果 this.toolCallChatResponse = chatResponse; // 3. 解析工具调用结果,获取工具调用信息 // 助手信息 AssistantMessage assistantMessage = chatResponse.getResult().getOutput(); // 获取要调用的工具列表 List<AssistantMessage.ToolCall> toolCallList = assistantMessage.getToolCalls(); // 输出提示信息 String result = assistantMessage.getText(); log.info(getName() + "的思考:" +result); log.info(getName() + "选择了" + toolCallList.size() + "个工具来使用"); String toolCallInfo = toolCallList.stream() .map(toolCall -> String.format("工具名称:%s,工具参数:%s", toolCall.name(), toolCall.arguments())) .collect(Collectors.joining("\n")); log.info(toolCallInfo); // 如果不需要调用工具,返回false if (toolCallList.isEmpty()) { // 只有不调用工具时,才需要手动记录助手信息 getMessageList().add(assistantMessage); return false; } else { // 炫耀调用工具时,无需记录助手信息 return true; } } catch (Exception e) { log.error(getName() + "的思考过程遇到了问题", e.getMessage()); getMessageList().add(new AssistantMessage("处理时遇到了错误:" + e.getMessage())); return false; } } @Override public String act() { if (!toolCallChatResponse.hasToolCalls()) { return "没有工具需要调用"; } Prompt prompt = new Prompt(getMessageList(), this.chatOptions); // 调用工具 ToolExecutionResult toolExecutionResult = toolCallingManager.executeToolCalls(prompt, toolCallChatResponse); // 记录消息上下文 , conversationHistory 已经包含了助手信息和工具调用返回结果 setMessageList(toolExecutionResult.conversationHistory()); ToolResponseMessage toolResponseMessage = (ToolResponseMessage) CollUtil.getLast(toolExecutionResult.conversationHistory()); // 判断是否调用了终止工具 boolean terminateToolCalled = toolResponseMessage.getResponses().stream() .anyMatch(response -> response.name().equals("doTerminate")); if (terminateToolCalled) { // 任务结束,更改状态 setState(AgentState.FINISHED); } String results = toolResponseMessage.getResponses().stream() .map(response -> "工具" + response.name() + "返回的结果:" + response.responseData()) .collect(Collectors.joining("\n")); log.info(results); return results; } }

四、自定义manus

java
复制代码
@Component public class ReManus extends ToolCallAgent{ public ReManus(ToolCallback[] allTools, ChatModel dashscopeChatModel) { super(allTools); this.setName("ReManus"); String SYSTEM_PROMPT = """ You are ReManus, an all-capable AI assistant, aimed at solving any task presented by the user. You have various tools at your disposal that you can call upon to efficiently complete complex requests. """; this.setSystemPrompt(SYSTEM_PROMPT); String NEXT_STEP_PROMPT = """ Based on user needs, proactively select the most appropriate tool or combination of tools. For complex tasks, you can break down the problem and use different tools step by step to solve it. After using each tool, clearly explain the execution results and suggest the next steps. If you want to stop the interaction at any point, use the `terminate` tool/function call. """; this.setNextStepPrompt(NEXT_STEP_PROMPT); this.setMaxSteps(20); // 初始化AI对话客户端 ChatClient chatClient = ChatClient.builder(dashscopeChatModel) .defaultAdvisors(new MyLoggerAdvisor()) .build(); this.setChatClient(chatClient); } }

业务4 --------- AI接口

ChatClient流式输出steam() ,直接获取文本内容content()【而不是获取ChatResponse,内容太多,影响传输速率】。返回Flux

一 、 三种流式接口

Ⅰ、直接再GetMapping 中(produces) 添加 MediaType.TEXT_EVENT_STREAM_VALUE【优点:简单,方便】

java
复制代码
@GetMapping(value = "/love_app/chat/sse", produces = MediaType.TEXT_EVENT_STREAM_VALUE) public Flux<String> doChatWithLoveAppSSE (String message, String chatId) { return loveApp.doChatByStream(message, chatId); }

Ⅱ、在Flux中再封装一个ServerSentEvent泛型。Flux的map中可以使用ServerSentEvent构造器builder构造Flux<ServerSentEvent> 内容【优点:可以省略MediaType】

java
复制代码
@GetMapping(value = "/love_app/chat/server_send_event") public Flux<ServerSentEvent<String>> doChatWithLoveAppServerSendEvent (String message, String chatId) { return loveApp.doChatByStream(message, chatId) .map(chunk -> ServerSentEvent.<String>builder() .data(chunk) .build()); }

Ⅲ、使用SSEEmitter,通过send方法持续向SseEmitter发送信息【优点:可以定制化操作;缺点,麻烦】

① Flux 流中可以使用**subscribe()**的方法去处理每条信息

text
复制代码
@Nullable Consumer<? super T> consumer, @Nullable Consumer<? super Throwable> errorConsumer, @Nullable Runnable completeConsumer

参数1:处理每条信息,可以使用sseEmit.send() 处理每条信息

参数2:处理异常信息,可以使用sseEmit.completeWithError(),处理异常信息

参数3:处理完成时信息,可以使用sseEmit.complete(),处理完成时操作

② 可以使用new SseEmitter(timer) 创建超时的Emitter对象

java
复制代码
@GetMapping(value = "/love_app/chat/sse_emitter") public SseEmitter doChatWithLoveAppSseEmitter (String message, String chatId) { // 创建一个较长的超时时间 SseEmitter sseEmitter = new SseEmitter(180000L); // 3分钟超时 // 获取 Flux 响应数据流 平且直接通过订阅推送给SSE Emitter loveApp.doChatByStream(message, chatId) .subscribe(chunk -> { try { sseEmitter.send(chunk); } catch (IOException e) { sseEmitter.completeWithError(e); } }, sseEmitter::completeWithError, sseEmitter::complete); return sseEmitter; }

二、智能体接口开发

流式代理智能体

Ⅰ、需要设置一个线程异步处理CompleteFuture.runAsync(),避免阻塞主线程(IO流)

Ⅱ、创建emitter new SseEmitter(timer), 消息的发送,异常处理,完成时的操作

Ⅲ、超时的回调 emitter.onTimeout 和完成时的回调onCompletion

java
复制代码
/** * 运行代理(流式输出) * * @param userPrompt 用户提示词 * @return SseEmitter实例 */ public SseEmitter runStream(String userPrompt) { // 创建SseEmitter,设置较长的超时时间 SseEmitter emitter = new SseEmitter(300000L); // 5分钟超时 // 使用线程异步处理,避免阻塞主线程 CompletableFuture.runAsync(() -> { try { if (this.state != AgentState.IDLE) { emitter.send("错误:无法从状态运行代理: " + this.state); emitter.complete(); return; } if (StringUtil.isBlank(userPrompt)) { emitter.send("错误:不能使用空提示词运行代理"); emitter.complete(); return; } // 更改状态 state = AgentState.RUNNING; // 记录消息上下文 messageList.add(new UserMessage(userPrompt)); try { for (int i = 0; i < maxSteps && state != AgentState.FINISHED; i++) { int stepNumber = i + 1; currentStep = stepNumber; log.info("Executing step " + stepNumber + "/" + maxSteps); // 单步执行 String stepResult = step(); String result = "Step " + stepNumber + ": " + stepResult; // 发送每一步的结果 emitter.send(result); } // 检查是否超出步骤限制 if (currentStep >= maxSteps) { state = AgentState.FINISHED; emitter.send("执行结束: 达到最大步骤 (" + maxSteps + ")"); } // 正常完成 emitter.complete(); } catch (Exception e) { state = AgentState.ERROR; log.error("执行智能体失败", e); try { emitter.send("执行错误: " + e.getMessage()); emitter.complete(); } catch (Exception ex) { emitter.completeWithError(ex); } } finally { // 清理资源 this.cleanup(); } } catch (Exception e) { emitter.completeWithError(e); } }); // 设置超时和完成回调 emitter.onTimeout(() -> { this.state = AgentState.ERROR; this.cleanup(); log.warn("SSE connection timed out"); }); emitter.onCompletion(() -> { if (this.state == AgentState.RUNNING) { this.state = AgentState.FINISHED; } this.cleanup(); log.info("SSE connection completed"); }); return emitter; }

跨域

java
复制代码
/** * 全局跨域配置 */ @Configuration public class CorsConfig implements WebMvcConfigurer { @Override public void addCorsMappings(CorsRegistry registry) { // 覆盖所有请求 registry.addMapping("/**") // 允许发送 Cookie .allowCredentials(true) // 放行哪些域名(必须用 patterns,否则 * 会和 allowCredentials 冲突) .allowedOriginPatterns("*") .allowedMethods("GET", "POST", "PUT", "DELETE", "OPTIONS") .allowedHeaders("*") .exposedHeaders("*"); } }

AI生成前端提示词

1.原始需求,2 技术选项,3后端接口,4后端接口信息

markdown
复制代码
你是一位专业的前端开发,请帮我根据下列信息来生成对应的前端项目代码。 ## 需求 1)主页:用于切换不同的应用 2)页面 1:AI 恋爱大师应用。页面风格为聊天室,上方是聊天记录(用户信息在右边,AI 信息在左边),下方是输入框,进入页面后自动生成一个聊天室 id,用于区分不同的会话。通过 SSE 的方式调用 doChatWithLoveAppSse 接口,实时显示对话内容。 3)页面 2:AI 超级智能体应用。页面风格同页面 1,但是调用 doChatWithManus 接口,也是实时显示对话内容。 ## 技术选型 1. Vue3 项目 2. Axios 请求库 ## 后端接口信息 接口地址前缀:http://localhost:8123/api ## SpringBoot 后端接口代码 @RestController @RequestMapping("/ai") public class AiController { @GetMapping(value = "/love_app/chat/sse", produces = MediaType.TEXT_EVENT_STREAM_VALUE) public Flux<String> doChatWithLoveAppSse(String message, String chatId) { return loveApp.doChatByStream(message, chatId); } @GetMapping("/manus/chat") public SseEmitter doChatWithManus(String message) { YuManus yuManus = new YuManus(allTools, dashscopeChatModel); return yuManus.runStream(message); } }
0个评论
点击登录,快来和大家讨论吧~
表情
图片
暂无评论
李小钊
下载 APP