最近美国向全球加征关税,对全球经济贸易产生巨大影响,2025-04-07日,对全球来说都是黑色星期一,这两天相信大家都在刷各种金融资讯小作文。而AI作为本次技术革命先锋,最近各大金融公司也相继进行金融+AI的落地实践,积极拥抱新技术。我们也在积极探索尝试AI程序员、AI投资顾问落地应用。
一、前言背景
二、向deepseek明确具体需求
三、项目结构
四、配置参数启动
五、最终demo实例
六、总结和展望
七、项目源码
一、前言背景
最近AI程序员非常火热,在AI coding rank上,国际大模型排名靠前的是claude 3.7 sonnet、gemini-2.5、还有deepseek v3。在编程领域,国内的混元、通义、豆包背后的金主也在积极布局AI coding 助手。未来万物皆可AI的局面将百花齐放,大幅提升各行各业的效率。
IT人员已经开始尝试一键AI生成系统项目代码,或者对系统新功能直接一键生成。
今天通过一句话让deepseek生成基于Spring A+DeepseekI实现的在线AI chatbot助手。大模型给出的代码0修改,只修改了pom,就直接启动可用。最终效果界面:
二、向deepseek明确具体需求
Spring AI 1.0已经集成支持目前主流的各种大模型还有AI实践框架技术。我们熟悉的RAG、MCP、prompts、语音、图片、视频、向量数据库、AI大模型基本都及时集成支持,方便大家应用到系统实践。
今天通过一小段话,明确实现一个Springboot项目,提供一个在线AI聊天助手。具体内容如下:
【你是一个java研发人员,现在有一个Springboot项目需要你去完整实现,主要通过集成Spring ai 和deepseek,提供一个在线可视化聊天机器人系统。最终提供一个界面支持用户输入聊天内容,并响应展示deepseek返回内容。】
在prompt及其简略的前提下,deepseek依靠自身强大的推理能力依然可以给出超预期基本可直接运行的源码,并推荐使用Spring initialize去初始化项目。
三、项目结构
deepseek最终给出的项目架构是JDK17+Spring AI+thymeleaf+Spring web来实现。
具体项目源码内容有:
1、pom.xml详细配置(这里存在唯一一个bug)。deepseek 给的depenency用的是
spring-ai-ollama-spring-boot-starter,最后调整为spring-ai-bom才成功。
2、deepseek客户端,通过restClient调用deepseek api的bean,以及Service层的逻辑处理。
3、请求响应的model DeepSeekRequest.java+DeepSeekResponse.java+ChatMessage.java (模型)。
4、chat接口,支持前端界面录入聊天内容并返回。
5、前端界面实现templates/chat.html。
四、配置参数启动
在deepseek提供源码application.properties基础上,deepseek的答案也完整提示,在application继续新增与deepseek api相关的两个参数配置进去。
deepseek.api.key=your-deepseek-api-key
deepseek.api.url=https://api.deepseek.com/v1/chat/completions
然后启动 Springboot 应用程序,访问localhost:8080就可以访问。
五、最终demo实例
界面虽然很简陋,后端功能也没有实现上下文记忆能力。但是这种一键生成项目系统源码,0代码修改,只需要简单配置就可以直接运行的感觉,不得不佩服AI强大的能力。
六、总结和展望
除了尝试这种prompt方式去获得AI提供的系统源码能力,还尝试了其他几种agent方式。总体而言,针对一键生成UI设计、数据处理分析任务、完整系统项目源码生成、量化研究任务几种场景,近期尝试过多个大模型,以及多个agent。但是总体感觉通用大模型还是不够智能,尤其是编程环境的复杂依赖、版本兼容冲突问题解决还不尽如意,然而智能IDE目前国内支持的还很少,值得期待。当然单纯的智能补齐、代码分析、单测编写已经非常成熟好用。
所以AI替换程序员的话题,个人觉得还有很大一段距离。而AI提升编程效率改变编程的时代,已经来临。
七、项目源码
7.1 pom.xml
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>3.2.0</version> <relativePath/> <!-- lookup parent from repository --> </parent> <groupId>com.example</groupId> <artifactId>ai-chatbot</artifactId> <version>0.0.1-SNAPSHOT</version> <name>ai-chatbot</name> <description>Demo project for Spring Boot with DeepSeek AI</description> <properties> <java.version>17</java.version> <spring-ai.version>0.8.1</spring-ai.version> </properties> <dependencies> <!-- Spring Boot Starters --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-thymeleaf</artifactId> </dependency> <dependency> <groupId>org.springframework.ai</groupId> <artifactId>spring-ai-bom</artifactId> <version>1.0.0-SNAPSHOT</version> <type>pom</type> <scope>import</scope> </dependency> <!-- Other dependencies --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-devtools</artifactId> <scope>runtime</scope> <optional>true</optional> </dependency> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <optional>true</optional> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> </dependencies> <repositories> <repository> <id>spring-snapshots</id> <name>Spring Snapshots</name> <url>https://repo.spring.io/snapshot</url> <releases> <enabled>false</enabled> </releases> </repository> <repository> <name>Central Portal Snapshots</name> <id>central-portal-snapshots</id> <url>https://central.sonatype.com/repository/maven-snapshots/</url> <releases> <enabled>false</enabled> </releases> <snapshots> <enabled>true</enabled> </snapshots> </repository> </repositories> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> <configuration> <excludes> <exclude> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> </exclude> </excludes> </configuration> </plugin> </plugins> </build> </project>
7.2 application.properties
spring.application.name=ai-chatbot # Server port server.port=8080 # Spring AI - DeepSeek configuration # Note: As of my knowledge cutoff, Spring AI doesn't have direct DeepSeek support # We'll implement a custom client for DeepSeek API # Thymeleaf configuration spring.thymeleaf.cache=false spring.thymeleaf.prefix=classpath:/templates/ spring.thymeleaf.suffix=.html spring.thymeleaf.mode=HTML spring.thymeleaf.encoding=UTF-8 deepseek.api.key=你的deepseek api key替换 deepseek.api.url=https://api.deepseek.com/v1/chat/completions
7.3 DeepSeekConfig.java
package com.example.config; import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.web.client.RestClient; public class DeepSeekConfig { "${deepseek.api.key}") ( private String apiKey; "${deepseek.api.url}") ( private String apiUrl; public RestClient deepSeekRestClient() { return RestClient.builder() .baseUrl(apiUrl) .defaultHeader("Authorization", "Bearer " + apiKey) .defaultHeader("Content-Type", "application/json") .build(); } }
7.4 model 模型
ChatMessage.java、DeepSeekRequest.java 、DeepSeekResponse.java
package com.example.model; import java.util.List; public class DeepSeekResponse { private String id; private String object; private long created; private String model; private List<Choice> choices; private Usage usage; // Getters and setters public String getId() { return id; } public void setId(String id) { this.id = id; } public String getObject() { return object; } public void setObject(String object) { this.object = object; } public long getCreated() { return created; } public void setCreated(long created) { this.created = created; } public String getModel() { return model; } public void setModel(String model) { this.model = model; } public List<Choice> getChoices() { return choices; } public void setChoices(List<Choice> choices) { this.choices = choices; } public Usage getUsage() { return usage; } public void setUsage(Usage usage) { this.usage = usage; } public static class Choice { private int index; private Message message; private String finish_reason; // Getters and setters public int getIndex() { return index; } public void setIndex(int index) { this.index = index; } public Message getMessage() { return message; } public void setMessage(Message message) { this.message = message; } public String getFinish_reason() { return finish_reason; } public void setFinish_reason(String finish_reason) { this.finish_reason = finish_reason; } } public static class Message { private String role; private String content; // Getters and setters public String getRole() { return role; } public void setRole(String role) { this.role = role; } public String getContent() { return content; } public void setContent(String content) { this.content = content; } } public static class Usage { private int prompt_tokens; private int completion_tokens; private int total_tokens; // Getters and setters public int getPrompt_tokens() { return prompt_tokens; } public void setPrompt_tokens(int prompt_tokens) { this.prompt_tokens = prompt_tokens; } public int getCompletion_tokens() { return completion_tokens; } public void setCompletion_tokens(int completion_tokens) { this.completion_tokens = completion_tokens; } public int getTotal_tokens() { return total_tokens; } public void setTotal_tokens(int total_tokens) { this.total_tokens = total_tokens; } } }
package com.example.model; import java.util.ArrayList; import java.util.List; public class DeepSeekRequest { private String model = "deepseek-chat"; private List<Message> messages; private double temperature = 0.7; private int max_tokens = 2000; public DeepSeekRequest(String prompt) { this.messages = new ArrayList<>(); this.messages.add(new Message("user", prompt)); } // Getters and setters public String getModel() { return model; } public void setModel(String model) { this.model = model; } public List<Message> getMessages() { return messages; } public void setMessages(List<Message> messages) { this.messages = messages; } public double getTemperature() { return temperature; } public void setTemperature(double temperature) { this.temperature = temperature; } public int getMax_tokens() { return max_tokens; } public void setMax_tokens(int max_tokens) { this.max_tokens = max_tokens; } public static class Message { private String role; private String content; public Message(String role, String content) { this.role = role; this.content = content; } // Getters and setters public String getRole() { return role; } public void setRole(String role) { this.role = role; } public String getContent() { return content; } public void setContent(String content) { this.content = content; } } }
package com.example.model; public class ChatMessage { private String role; // "user" or "ai" private String content; public ChatMessage() { } public ChatMessage(String role, String content) { this.role = role; this.content = content; } // Getters and setters public String getRole() { return role; } public void setRole(String role) { this.role = role; } public String getContent() { return content; } public void setContent(String content) { this.content = content; } }
7.5 DeepSeekService.java
package com.example.service; import com.example.model.DeepSeekRequest; import com.example.model.DeepSeekResponse; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import org.springframework.web.client.RestClient; public class DeepSeekService { private final RestClient deepSeekRestClient; public DeepSeekService(RestClient deepSeekRestClient) { this.deepSeekRestClient = deepSeekRestClient; } public String generateResponse(String prompt) { DeepSeekRequest request = new DeepSeekRequest(prompt); DeepSeekResponse response = deepSeekRestClient.post() .body(request) .retrieve() .body(DeepSeekResponse.class); return response != null ? response.getChoices().get(0).getMessage().getContent() : "No response from DeepSeek"; } }
7.6 ChatController.java
package com.example.controller; import com.example.model.ChatMessage; import com.example.service.DeepSeekService; import org.springframework.stereotype.Controller; import org.springframework.ui.Model; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.ModelAttribute; import org.springframework.web.bind.annotation.PostMapping; import java.util.ArrayList; import java.util.List; public class ChatController { private final DeepSeekService deepSeekService; private List<ChatMessage> chatHistory = new ArrayList<>(); public ChatController(DeepSeekService deepSeekService) { this.deepSeekService = deepSeekService; } "/") ( public String chat(Model model) { model.addAttribute("chatMessage", new ChatMessage()); model.addAttribute("chatHistory", chatHistory); return "chat"; } "/send") ( public String sendMessage( ChatMessage chatMessage, Model model) { // Add user message to chat history chatHistory.add(new ChatMessage("user", chatMessage.getContent())); // Get response from DeepSeek String response = deepSeekService.generateResponse(chatMessage.getContent()); // Add AI response to chat history chatHistory.add(new ChatMessage("ai", response)); model.addAttribute("chatMessage", new ChatMessage()); model.addAttribute("chatHistory", chatHistory); return "chat"; } }
7.7 前端实现templates/chat.html
<html xmlns:th="http://www.thymeleaf.org"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>DeepSeek Chatbot</title> <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet"> <style> .chat-container { max-width: 800px; margin: 0 auto; padding: 20px; border: 1px solid #ddd; border-radius: 10px; box-shadow: 0 0 10px rgba(0,0,0,0.1); } .chat-history { height: 500px; overflow-y: auto; margin-bottom: 20px; padding: 10px; border: 1px solid #eee; border-radius: 5px; } .user-message { background-color: #e3f2fd; padding: 10px; border-radius: 10px; margin-bottom: 10px; max-width: 80%; margin-left: auto; } .ai-message { background-color: #f5f5f5; padding: 10px; border-radius: 10px; margin-bottom: 10px; max-width: 80%; } .message-time { font-size: 0.8em; color: #666; margin-top: 5px; } </style> </head> <body> <div class="container mt-5"> <div class="chat-container"> <h2 class="text-center mb-4">DeepSeek Chatbot</h2> <div class="chat-history" id="chatHistory"> <div th:each="message : ${chatHistory}"> <div th:class="${message.role == 'user' ? 'user-message' : 'ai-message'}"> <strong th:text="${message.role == 'user' ? 'You:' : 'AI:'}"></strong> <div th:text="${message.content}"></div> <div class="message-time" th:text="${#temporals.format(#temporals.createNow(), 'HH:mm')}"></div> </div> </div> </div> <form th:action="@{/send}" th:object="${chatMessage}" method="post"> <div class="input-group mb-3"> <input type="text" class="form-control" th:field="*{content}" placeholder="Type your message here..." autocomplete="off"> <button class="btn btn-primary" type="submit">Send</button> </div> </form> </div> </div> <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"></script> <script> // Scroll to bottom of chat history window.onload = function() { var chatHistory = document.getElementById('chatHistory'); chatHistory.scrollTop = chatHistory.scrollHeight; }; </script> </body> </html>