springboot+LangChain4j 实战指南 DAY1

LangChain4j 实战指南

目标:3 天内从零跑通 Java AI 应用开发,建立信心,再去补理论基础。

技术栈:Java 17+ / Maven / LangChain4j / 硅基流动免费的模型api/

核心理念:先跑通,再理解。工程师的学习方式是动手 → 遇坑 → 理解原理。


源码地址:java ai learn

📅 三日路线总览

天数 主题 产出物
Day 1 环境搭建 + 第一次对话 可运行的 Spring Boot AI 对话接口
Day 2 多轮记忆 + 流式输出 带上下文记忆的流式聊天界面
Day 3 Function Calling + 简易 RAG 能调用外部工具、能查文档的智能助手

🛠️ Day 1:环境搭建 + 第一次对话

1.1 前置准备

JDK 确认
bash 复制代码
java -version
# 需要 JDK 17 或以上,推荐 JDK 21(LTS)

如果你还在用 JDK 8/11,强烈建议升级到 17+。LangChain4j 大量使用了现代 Java 特性(Record、Switch Pattern Matching、Sealed Classes 等)。

升级方式(推荐):

Maven 确认
bash 复制代码
mvn -version
# 需要 Maven 3.8+
1.2 获取硅基流动 API Key

地址:https://cloud.siliconflow.cn/

然后找免费的模型

建api key 供接口认证调用

1.3 完整项目结构

复制代码
java-ai-learn/
└── day1/
    ├── pom.xml
    └── src/main/java/com/day1/demo/
        ├── DemoApplication.java               # 启动类
        ├── config/
        │   ├── ChatModelConfig.java           # 对话模型 Bean(普通 + 流式)
        │   ├── LangChain4jConfig.java         # ChatMemory 全局配置
        │   ├── AssistantService.java          # @AiService 声明式助手
        │   └── ToolAssistantConfig.java       # Function Calling 配置(Day 3)
        ├── controller/
        │   ├── HelloController.java           # 健康检查
        │   ├── ChatController1.java           # 最简对话 + 系统提示词
        │   ├── ChatMemoryController1.java     # 带记忆多轮(手动)
        │   ├── ChatMemoryUseConfigController2.java  # 带记忆多轮(AiService)
        │   ├── SSEController1.java            # 流式 SSE 输出
        │   └── ToolAssistantController.java   # Function Calling 接口(Day 3)
        ├── service/
        │   ├── ChatService1.java              # 最简对话
        │   ├── ChatMemoryService1.java        # 手动记忆管理
        │   └── RagService.java                # RAG 检索增强(Day 3)
        ├── tool/
        │   └── WeatherTool.java               # 工具定义(Day 3)
        ├── param/
        │   └── ChatTestRequest.java           # POST 请求体
        └── resources/
            └── application.yml                # 配置文件


```xml

1.3 配置 pom.xml 依赖

打开 pom.xml,贴进去

java 复制代码
<?xml version="1.0" encoding="UTF-8"?>
<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>4.1.0</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.day1</groupId>
    <artifactId>demo</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>day1</name>
    <description>java ai learn</description>
    <url/>
    <licenses>
        <license/>
    </licenses>
    <developers>
        <developer/>
    </developers>
    <scm>
        <connection/>
        <developerConnection/>
        <tag/>
        <url/>
    </scm>
    <properties>
        <java.version>17</java.version>
    </properties>
    <dependencies>
        <!-- Spring Boot Web(已有则跳过)-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <!-- Lombok -->
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>

        <!-- Spring Boot Test -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>

        <dependency>
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-lang3</artifactId>
        </dependency>

        <!-- LangChain4j 核心依赖 -->
        <dependency>
            <groupId>dev.langchain4j</groupId>
            <artifactId>langchain4j</artifactId>
            <version>0.36.2</version>
        </dependency>

        <!-- LangChain4j Spring Boot Starter -->
        <dependency>
            <groupId>dev.langchain4j</groupId>
            <artifactId>langchain4j-spring-boot-starter</artifactId>
            <version>0.36.2</version>
        </dependency>

        <!-- LangChain4j OpenAI 集成(硅基流动兼容) -->
        <dependency>
            <groupId>dev.langchain4j</groupId>
            <artifactId>langchain4j-open-ai</artifactId>
            <version>0.36.2</version>
        </dependency>

        <!-- LangChain4j OpenAI Spring Boot Starter -->
        <dependency>
            <groupId>dev.langchain4j</groupId>
            <artifactId>langchain4j-open-ai-spring-boot-starter</artifactId>
            <version>0.36.2</version>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

</project>

版本说明 :LangChain4j 1.0+ 为正式稳定版,API 已趋于稳定。如果上述版本号有更新,可以去 Maven Central 查最新版本。

注意langchain4j-dashscope 模块在 LangChain4j 0.34 之前叫 langchain4j-community-dashscope,1.0 之后已并入主仓库。如果你用的是旧版本,请调整依赖名。

1.4 配置 application.yml

src/main/resources/ 下创建 application.yml

yaml 复制代码
# ========== 服务配置 ==========
server:
  port: 8080

spring:
  application:
    name: day1-demo

# ========== 硅基流动 AI 配置(OpenAI 兼容接口)==========
langchain4j:
  open-ai:
    # 从 https://cloud.siliconflow.cn/account/ak 获取
    api-key: ${SILICONFLOW_API_KEY:你的硅基流动api key}
    # 硅基流动 API 地址
    base-url: https://api.siliconflow.cn/v1
    # 免费模型推荐:
    #   Qwen/Qwen2.5-7B-Instruct(通用对话)
    #   Qwen/Qwen3-8B(更强推理)
    #   deepseek-ai/DeepSeek-V3(最强免费)
    model-name: Qwen/Qwen2.5-7B-Instruct

安全提示:不要把 API Key 硬编码在代码里!推荐两种方式:

  1. 环境变量:export DASHSCOPE_API_KEY=sk-xxxxx
  2. 使用 .env 文件(需配合 spring-dotenv 等库)

务必把 API Key 加入 .gitignore

1.5 编写代码

1.5.1 启动类
java 复制代码
package com.day1.demo;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class DemoApplication {
    public static void main(String[] args) {
        SpringApplication.run(DemoApplication.class, args);
    }
}
1.5.2 模型配置
java 复制代码
package com.day1.demo.config;

import dev.langchain4j.model.chat.ChatLanguageModel;
import dev.langchain4j.model.openai.OpenAiChatModel;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import java.time.Duration;

@Configuration
public class ChatModelConfig {

    @Value("${langchain4j.open-ai.api-key}")
    private String apiKey;

    @Value("${langchain4j.open-ai.base-url}")
    private String baseUrl;

    @Value("${langchain4j.open-ai.model-name:Qwen/Qwen2.5-7B-Instruct}")
    private String modelName;

    @Bean
    public ChatLanguageModel chatLanguageModel() {
        return OpenAiChatModel.builder()
                .apiKey(apiKey)
                .baseUrl(baseUrl)
                .modelName(modelName)
                .timeout(Duration.ofSeconds(60))
                .build();
    }
}
1.5.3 最简对话 Service
java 复制代码
package com.day1.demo.service;

import dev.langchain4j.model.chat.ChatLanguageModel;
import org.springframework.stereotype.Service;

@Service
public class ChatService1 {

    private final ChatLanguageModel chatModel;

    public ChatService1(ChatLanguageModel chatModel) {
        this.chatModel = chatModel;
    }

    public String chat(String prompt) {
        return chatModel.generate(prompt);
    }
}
1.5.4 Hello 接口 + 对话接口
java 复制代码
// HelloController.java --- 健康检查
@RestController
public class HelloController {
    @GetMapping("/hello")
    public Map<String, Object> hello(@RequestParam(defaultValue = "World") String name) {
        return Map.of(
            "message", "Hello, " + name + "!",
            "timestamp", LocalDateTime.now().toString()
        );
    }
}

// ChatController1.java --- 第一个对话接口
@RestController
@RequestMapping("/chat")
public class ChatController1 {

    private final ChatService1 chatService1;

    public ChatController1(ChatService1 chatService1) {
        this.chatService1 = chatService1;
    }

    /** GET /chat/chatTest?prompt=用一句话介绍你自己 */
    @GetMapping("/chatTest")
    public String chat(@RequestParam String prompt) {
        return chatService1.chat(prompt);
    }

    /** POST /chat/systemPrompt  --- 带系统提示词 */
    @PostMapping("/systemPrompt")
    public String chatWithSystem(@RequestBody ChatTestRequest request) {
        String fullPrompt = request.getSystemPrompt() + "\n\n用户问题:" + request.getQuestion();
        return chatService1.chat(fullPrompt);
    }
}

1.6 启动 & 测试

bash 复制代码
mvn spring-boot:run -DskipTests
bash 复制代码
# 健康检查
curl http://localhost:8080/hello

# 第一次 AI 对话 🎉
curl "http://localhost:8080/chat/chatTest?prompt=用一句话介绍Java"

🧠 Day 2:多轮记忆 + 流式输出

Day 1 每个请求都是"全新"的------大模型不记得你上句话说了什么。Day 2 我们解决两个核心问题:

  1. 对话记忆:让 AI 记住上下文,实现多轮对话
  2. 流式输出:逐字返回,不用等完整结果

2.1 为什么需要对话记忆?

text 复制代码
用户: 我叫张三
 AI:  你好张三!
用户: 我叫什么名字?   ← 没有记忆的话,AI 无法回答这个问题

本质上,大模型是"无状态"的------每次请求都独立。ChatMemory 的原理就是把历史消息拼进下一次请求的 prompt 里

2.2 手动管理记忆

java 复制代码
package com.day1.demo.service;

import dev.langchain4j.data.message.AiMessage;
import dev.langchain4j.data.message.UserMessage;
import dev.langchain4j.memory.ChatMemory;
import dev.langchain4j.memory.chat.MessageWindowChatMemory;
import dev.langchain4j.model.chat.ChatLanguageModel;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;

import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

@Service
@RequiredArgsConstructor
public class ChatMemoryService1 {

    private final ChatLanguageModel chatLanguageModel;

    // 每个用户独立的记忆空间
    private final Map<String, ChatMemory> memoryMap = new ConcurrentHashMap<>();

    public String chat(String userId, String message) {
        // 获取或创建该用户的记忆(首次自动创建)
        ChatMemory memory = memoryMap.computeIfAbsent(userId, id ->
            MessageWindowChatMemory.builder()
                .maxMessages(20)  // 保留最近 20 条消息 ≈ 10 轮对话
                .build()
        );

        // 1. 把用户消息存入记忆
        memory.add(UserMessage.from(message));

        // 2. 用所有历史消息 + 当前消息生成回复
        String answer = chatLanguageModel
                .generate(memory.messages())
                .content()
                .text();

        // 3. 把 AI 回复也存入记忆
        memory.add(AiMessage.from(answer));
        return answer;
    }

    public void clear(String userId) {
        memoryMap.remove(userId);
    }
}

关键参数 maxMessages(20)

  • 值太小 → AI 记不住上下文,"失忆"
  • 值太大 → token 消耗暴增,费用飙升,且可能超出模型上下文窗口
  • 推荐 20 条(约 10 轮对话),适合大多数场景
接口
java 复制代码
@RestController
@RequestMapping("/chatMemory")
@RequiredArgsConstructor
public class ChatMemoryController1 {

    private final ChatMemoryService1 chatMemoryService;

    @GetMapping("/chat1")
    public Map<String, String> chat(
            @RequestParam(defaultValue = "default-user") String userId,
            @RequestParam String message) {
        String answer = chatMemoryService.chat(userId, message);
        return Map.of("userId", userId, "answer", answer);
    }

    @GetMapping("/deleteMemory")
    public Map<String, String> clearMemory(@RequestParam String userId) {
        chatMemoryService.clear(userId);
        return Map.of("message", "记忆已清空");
    }
}

测试多轮记忆:

bash 复制代码
# 第一轮:告诉 AI 你的名字
curl "http://localhost:8080/chatMemory/chat1?userId=user1&message=我叫张三"

# 第二轮:问 AI 你的名字(它应该记住)
curl "http://localhost:8080/chatMemory/chat1?userId=user1&message=我叫什么名字"

# 换个用户,记忆隔离
curl "http://localhost:8080/chatMemory/chat1?userId=user2&message=我叫什么名字"
# 👆 AI 不知道 user2 叫什么,因为 user1 和 user2 的记忆是隔离的

2.3 AiService 声明式记忆(推荐)

上面手动管理记忆虽然直观,但代码量大。LangChain4j 提供了 @AiService 注解,只需定义接口,框架自动生成实现:

自定义系统提示词 AssistantService
java 复制代码
package com.day1.demo.config;

import dev.langchain4j.service.MemoryId;
import dev.langchain4j.service.SystemMessage;
import dev.langchain4j.service.UserMessage;
import dev.langchain4j.service.spring.AiService;

@AiService
public interface AssistantService {

    @SystemMessage("""
        你是一个专业的 Java 技术助手,名字叫"码哥"。
        回答问题时遵循以下规则:
        1. 先给出简洁的结论
        2. 再补充关键细节
        3. 如有必要给出代码示例
        4. 语气轻松专业,像一个资深架构师
        """)
    String chat(@MemoryId String userId, @UserMessage String message);
}
全局记忆配置
java 复制代码
package com.day1.demo.config;

import dev.langchain4j.memory.chat.ChatMemoryProvider;
import dev.langchain4j.memory.chat.MessageWindowChatMemory;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class LangChain4jConfig {

    @Bean
    public ChatMemoryProvider chatMemoryProvider() {
        return memoryId -> MessageWindowChatMemory.builder()
                .id(memoryId)
                .maxMessages(20)
                .build();
    }
}
接口调用
java 复制代码
@RestController
@RequestMapping("/assistant")
@RequiredArgsConstructor
public class ChatMemoryUseConfigController2 {

    private final AssistantService assistant;

    @GetMapping("/assistantTest")
    public String chat(
            @RequestParam(defaultValue = "user1") String userId,
            @RequestParam String message) {
        return assistant.chat(userId, message);
    }
}
bash 复制代码
curl "http://localhost:8080/assistant/assistantTest?userId=user1&message=介绍一下Spring Boot"

三种对话模式对比:

方式 代码量 记忆 系统提示词 适用场景
ChatService1 极少 单次问答、翻译
ChatMemoryService1 中等 ✅ (手动) 需要灵活控制记忆
AssistantService (@AiService) 极少 ✅ (自动) 推荐,生产首选

2.4 流式输出 SSE

普通对话要等大模型生成完整回复才返回,可能等 5-10 秒。流式输出像 ChatGPT 一样逐字"打字",体验好得多。

添加流式模型 Bean

ChatModelConfig 中增加:

java 复制代码
@Bean
public StreamingChatLanguageModel streamingChatLanguageModel() {
    return OpenAiStreamingChatModel.builder()
            .apiKey(apiKey)
            .baseUrl(baseUrl)
            .modelName(modelName)
            .timeout(Duration.ofSeconds(120))
            .build();
}
SSE 流式接口
java 复制代码
@RestController
@RequestMapping("/stream")
@RequiredArgsConstructor
public class SSEController1 {

    private final StreamingChatLanguageModel streamingChatLanguageModel;

    @GetMapping(value = "/streamChat", produces = MediaType.TEXT_EVENT_STREAM_VALUE)
    public SseEmitter streamChat(@RequestParam String message) {
        SseEmitter emitter = new SseEmitter(120_000L);  // 2 分钟超时

        streamingChatLanguageModel.generate(
            java.util.List.of(UserMessage.from(message)),
            new StreamingResponseHandler<AiMessage>() {
                @Override
                public void onNext(String token) {
                    try {
                        emitter.send(SseEmitter.event().data(token));
                    } catch (IOException e) {
                        emitter.completeWithError(e);
                    }
                }

                @Override
                public void onComplete(Response<AiMessage> response) {
                    emitter.complete();
                }

                @Override
                public void onError(Throwable error) {
                    emitter.completeWithError(error);
                }
            }
        );

        return emitter;
    }
}

测试流式输出:

bash 复制代码
# 浏览器直接打开(原生支持 SSE)
http://localhost:8080/stream/streamChat?message=讲一个冷笑话

# 或命令行
curl.exe -N "http://localhost:8080/stream/streamChat?message=讲一个冷笑话"

流式输出原理:

复制代码
时间线 →
[我] [是] [一] [个] [AI] [助] [手] ...
  ↑    ↑    ↑    ↑    ↑    ↑    ↑
  每个 token 到达立即推送给前端,不等完整结果

以下功能暂未本地实现,需要自行测试

🚀 Day 3:Function Calling + 简易 RAG

Day 2 的 AI 能聊天但能力有限。Day 3 让 AI 能:

  1. 调用外部工具(Function Calling)--- 查天气、算数学、调接口
  2. 查本地文档(RAG)--- 让 AI 回答它"不知道"的知识

3.1 Function Calling 是什么?

让大模型"学会调用函数"。比如问"北京今天天气怎么样?",AI 会自动调用 getWeather("北京") 拿到真实数据,再生成回复。

text 复制代码
用户:北京今天天气怎么样?
  ↓
AI 识别意图 → 调用 getWeather("北京") → 拿到 {"temp": 25, "desc": "晴"}
  ↓
AI 生成回复:北京今天晴,气温 25°C

3.2 定义工具

java 复制代码
package com.day1.demo.tool;

import dev.langchain4j.agent.tool.Tool;
import org.springframework.stereotype.Component;

import java.util.Map;

@Component
public class WeatherTool {

    @Tool("查询指定城市的天气")
    public String getWeather(String city) {
        // 模拟数据,实际应调用天气 API
        Map<String, String> mockWeather = Map.of(
            "北京", "晴,25°C,湿度 40%",
            "上海", "多云,28°C,湿度 65%",
            "深圳", "阵雨,30°C,湿度 80%"
        );
        return mockWeather.getOrDefault(city, "暂无" + city + "的天气数据");
    }

    @Tool("简单的数学四则运算")
    public double calculate(
            @dev.langchain4j.agent.tool.P("第一个操作数") double a,
            @dev.langchain4j.agent.tool.P("第二个操作数") double b,
            @dev.langchain4j.agent.tool.P("运算类型:add/subtract/multiply/divide") String operation) {
        return switch (operation) {
            case "add" -> a + b;
            case "subtract" -> a - b;
            case "multiply" -> a * b;
            case "divide" -> a / b;
            default -> throw new IllegalArgumentException("不支持的运算: " + operation);
        };
    }
}

3.3 配置 Function Calling 大模型--(后面代码我还未本地测试,仅作参考)

java 复制代码
package com.day1.demo.config;

import dev.langchain4j.agent.tool.Tool;
import dev.langchain4j.memory.chat.MessageWindowChatMemory;
import dev.langchain4j.model.openai.OpenAiChatModel;
import dev.langchain4j.service.AiServices;
import dev.langchain4j.service.MemoryId;
import dev.langchain4j.service.UserMessage;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import java.time.Duration;

@Configuration
public class ToolAssistantConfig {

    @Value("${langchain4j.open-ai.api-key}")
    private String apiKey;

    @Value("${langchain4j.open-ai.base-url}")
    private String baseUrl;

    @Value("${langchain4j.open-ai.model-name:Qwen/Qwen2.5-7B-Instruct}")
    private String modelName;

    /**
     * 带工具的 AI 助手(代码组装方式)
     */
    @Bean
    public ToolAssistant toolAssistant(WeatherTool weatherTool) {
        return AiServices.builder(ToolAssistant.class)
                .chatLanguageModel(OpenAiChatModel.builder()
                        .apiKey(apiKey)
                        .baseUrl(baseUrl)
                        .modelName(modelName)
                        .timeout(Duration.ofSeconds(60))
                        .build())
                .tools(weatherTool)      // 注入工具
                .chatMemoryProvider(memoryId ->
                    MessageWindowChatMemory.builder()
                        .id(memoryId)
                        .maxMessages(20)
                        .build())
                .build();
    }

    /**
     * 工具助手接口
     */
    public interface ToolAssistant {
        String chat(@MemoryId String userId, @UserMessage String message);
    }
}

3.4 工具助手接口

java 复制代码
@RestController
@RequestMapping("/tool")
@RequiredArgsConstructor
public class ToolAssistantController {

    private final ToolAssistantConfig.ToolAssistant toolAssistant;

    @GetMapping("/chat")
    public String chat(
            @RequestParam(defaultValue = "user1") String userId,
            @RequestParam String message) {
        return toolAssistant.chat(userId, message);
    }
}
bash 复制代码
# AI 会自动调用 getWeather 工具
curl "http://localhost:8080/tool/chat?userId=user1&message=北京今天天气怎么样"

# AI 会自动调用 calculate 工具
curl "http://localhost:8080/tool/chat?userId=user1&message=计算 3.14 乘以 2.5"

3.5 RAG --- 让 AI 回答私有知识

大模型的训练数据有截止日期,也不知道你公司的内部文档。RAG(Retrieval-Augmented Generation)解决这个问题:

text 复制代码
1. 把你的文档切成小块(chunk)
2. 每块用嵌入模型转成向量
3. 存入向量数据库(PGVector / Redis)
4. 用户提问 → 向量搜索找到最相关的文档块
5. 把文档块拼进 prompt 发给大模型 → 生成答案
添加依赖
xml 复制代码
<!-- PGVector(需要 PostgreSQL) -->
<dependency>
    <groupId>dev.langchain4j</groupId>
    <artifactId>langchain4j-pgvector</artifactId>
    <version>0.36.2</version>
</dependency>

<!-- 嵌入模型(硅基流动免费) -->
<dependency>
    <groupId>dev.langchain4j</groupId>
    <artifactId>langchain4j-embeddings</artifactId>
    <version>0.36.2</version>
</dependency>
RAG Service 骨架
java 复制代码
@Service
public class RagService {

    @Value("${langchain4j.open-ai.api-key}")
    private String apiKey;

    @Value("${langchain4j.open-ai.base-url}")
    private String baseUrl;

    /**
     * 1. 加载文档
     * 2. 切片
     * 3. 向量化存入 PGVector
     */
    @PostConstruct
    public void initDocument() {
        // TODO: 实现文档加载 & 向量化
        // DocumentLoader loader = new FileSystemDocumentLoader();
        // List<Document> docs = loader.load("docs/");
        // embeddingStore.addAll(docs);
    }

    /**
     * 检索增强生成
     */
    public String ask(String question) {
        // 1. 向量搜索找到相关文档
        // List<TextSegment> relevant = embeddingStore.search(question, 3);

        // 2. 拼进 prompt
        // String context = relevant.stream()
        //     .map(TextSegment::text)
        //     .collect(Collectors.joining("\n\n"));

        // 3. 发给大模型
        // return chatModel.generate("基于以下知识回答问题:\n" + context + "\n\n问题: " + question);
        return "RAG 待实现 --- Day 3 习题";
    }
}

💡 Day 3 的完整 RAG 实战(包括 Docker PostgreSQL + PGVector 部署、文档加载、向量化、检索)作为扩展练习,基础架构已就绪。


复制代码
## 🔧 启动 & 全部接口测试

```bash
# 启动
cd day1
mvn spring-boot:run -DskipTests

# === Day 1 ===
curl http://localhost:8080/hello
curl "http://localhost:8080/chat/chatTest?prompt=用一句话介绍Java"
curl -X POST http://localhost:8080/chat/systemPrompt \
  -H "Content-Type: application/json" \
  -d '{"systemPrompt":"你是一个幽默的程序员", "question":"什么是OOM"}'

# === Day 2 ===
curl "http://localhost:8080/chatMemory/chat1?userId=user1&message=我叫张三"
curl "http://localhost:8080/chatMemory/chat1?userId=user1&message=我叫什么名字"
curl "http://localhost:8080/assistant/assistantTest?userId=user1&message=介绍Spring Boot"
# 流式:浏览器打开 http://localhost:8080/stream/streamChat?message=讲个笑话

# === Day 3 ===
curl "http://localhost:8080/tool/chat?userId=user1&message=北京天气"
curl "http://localhost:8080/tool/chat?userId=user1&message=算一下 3.14 * 2.5"

📚 API 速查表

方法 路径 功能 天数
GET /hello 健康检查 Day 1
GET /chat/chatTest?prompt= 最简对话 Day 1
POST /chat/systemPrompt 带系统提示词 Day 1
GET /chatMemory/chat1?userId=&message= 多轮记忆(手动) Day 2
GET /chatMemory/deleteMemory?userId= 清空记忆 Day 2
GET /assistant/assistantTest?userId=&message= 多轮记忆(AiService) Day 2
GET /stream/streamChat?message= 流式 SSE Day 2
GET /tool/chat?userId=&message= Function Calling Day 3

🧩 技术栈

组件 版本 说明
Spring Boot 4.1.0 应用框架
Java 17 LTS 长期支持
LangChain4j 0.36.2 LLM 集成框架
硅基流动 Qwen2.5-7B-Instruct 免费大模型(OpenAI 兼容)
Lombok --- 简化代码
Maven 3.9+ 构建工具

📖 延伸阅读