基于 Spring Boot 3 + LangChain4j 快速构建企业级 AI 应用实战


基于 Spring Boot 3 + LangChain4j 快速构建企业级 AI 应用实战

摘要:本文将手把手教你如何在 Spring Boot 3 项目中集成 LangChain4j,实现智能对话、RAG 知识库检索、Function Calling 等核心能力,并给出完整的生产级代码和架构建议。


一、前言:为什么 Java 开发者需要关注 AI 集成?

2024-2025 年,大模型(LLM)已经从"玩具"变成了"生产工具"。但市面上 90% 的 AI 教程都是 Python 生态,这让广大 Java 开发者望而却步。

好消息是:LangChain4j 的出现彻底改变了这一局面。它是 LangChain 的 Java 版本,专为 JVM 生态设计,提供了:

  • 统一的 LLM 接入抽象(OpenAI、通义千问、文心一言、Ollama 本地模型等)
  • RAG(检索增强生成)完整链路
  • Function Calling(工具调用)
  • 内存管理与对话持久化

本文将基于 Spring Boot 3.2 + LangChain4j 0.35 版本,构建一个完整的 AI 客服系统。


二、环境准备

2.1 技术栈选型

组件 版本 说明
JDK 21 虚拟线程 + 模式匹配
Spring Boot 3.2.x 最新稳定版
LangChain4j 0.35.0 Java AI 框架
Ollama 0.3.x 本地大模型运行
Redis 7.x 向量存储 + 缓存
PostgreSQL 16 业务数据 + pgvector

2.2 项目初始化

bash 复制代码
# 使用 Spring Initializr 创建项目
curl https://start.spring.io/starter.zip \
  -d dependencies=web,lombok,data-jpa,postgresql,redis \
  -d javaVersion=21 \
  -d bootVersion=3.2.5 \
  -d baseDir=ai-service \
  -o ai-service.zip

三、核心依赖配置

3.1 Maven 依赖

xml 复制代码
<properties>
    <langchain4j.version>0.35.0</langchain4j.version>
</properties>

<dependencies>
    <!-- Spring Boot Starter -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    
    <!-- LangChain4j 核心 -->
    <dependency>
        <groupId>dev.langchain4j</groupId>
        <artifactId>langchain4j</artifactId>
        <version>${langchain4j.version}</version>
    </dependency>
    
    <!-- LangChain4j Spring Boot 集成 -->
    <dependency>
        <groupId>dev.langchain4j</groupId>
        <artifactId>langchain4j-spring-boot-starter</artifactId>
        <version>${langchain4j.version}</version>
    </dependency>
    
    <!-- OpenAI 适配器(也可替换为通义千问、文心等) -->
    <dependency>
        <groupId>dev.langchain4j</groupId>
        <artifactId>langchain4j-open-ai</artifactId>
        <version>${langchain4j.version}</version>
    </dependency>
    
    <!-- 本地模型 Ollama 适配器 -->
    <dependency>
        <groupId>dev.langchain4j</groupId>
        <artifactId>langchain4j-ollama</artifactId>
        <version>${langchain4j.version}</version>
    </dependency>
    
    <!-- 向量存储:Redis -->
    <dependency>
        <groupId>dev.langchain4j</groupId>
        <artifactId>langchain4j-redis</artifactId>
        <version>${langchain4j.version}</version>
    </dependency>
    
    <!-- 文档解析 -->
    <dependency>
        <groupId>dev.langchain4j</groupId>
        <artifactId>langchain4j-document-parser-apache-tika</artifactId>
        <version>${langchain4j.version}</version>
    </dependency>
</dependencies>

3.2 application.yml 配置

yaml 复制代码
spring:
  application:
    name: ai-customer-service
  datasource:
    url: jdbc:postgresql://localhost:5432/ai_service
    username: postgres
    password: your_password
  data:
    redis:
      host: localhost
      port: 6379

# LangChain4j 配置
langchain4j:
  open-ai:
    chat-model:
      api-key: ${OPENAI_API_KEY:sk-your-key}
      model-name: gpt-4o
      temperature: 0.7
      timeout: PT60S
  ollama:
    chat-model:
      base-url: http://localhost:11434
      model-name: qwen2.5:14b
      timeout: PT120S

# 自定义配置
ai:
  knowledge-base:
    enabled: true
    chunk-size: 500
    chunk-overlap: 50

四、核心架构设计

4.1 整体架构图

复制代码
┌─────────────────────────────────────────────────────────────┐
│                    Spring Boot Application                   │
│  ┌──────────────┐  ┌──────────────┐  ┌──────────────────┐  │
│  │  REST API    │  │  AI Service  │  │  Knowledge Base  │  │
│  │  Controller  │──│   Layer      │──│   Service        │  │
│  └──────────────┘  └──────────────┘  └──────────────────┘  │
│         │                 │                    │            │
│         └─────────────────┴────────────────────┘            │
│                           │                                  │
│              ┌────────────┴────────────┐                   │
│              ▼                         ▼                     │
│    ┌─────────────────┐      ┌─────────────────┐           │
│    │  LangChain4j    │      │  Vector Store   │           │
│    │  AI Services    │      │  (Redis/PG)     │           │
│    │                 │      │                 │           │
│    │  • ChatMemory   │      │  • Embeddings   │           │
│    │  • RAG Chain    │      │  • Similarity   │           │
│    │  • Tools        │      │    Search       │           │
│    └────────┬────────┘      └─────────────────┘           │
│             │                                                │
│    ┌────────┴────────┐                                      │
│    ▼                 ▼                                     │
│ ┌─────────┐    ┌──────────┐                               │
│ │ OpenAI  │    │  Ollama  │  (本地/云端模型切换)            │
│ │  GPT-4o │    │ Qwen2.5  │                               │
│ └─────────┘    └──────────┘                               │
└─────────────────────────────────────────────────────────────┘

4.2 领域模型设计

java 复制代码
package com.example.ai.entity;

import jakarta.persistence.*;
import lombok.Data;
import org.hibernate.annotations.CreationTimestamp;
import java.time.LocalDateTime;

@Data
@Entity
@Table(name = "chat_sessions")
public class ChatSession {
    
    @Id
    @GeneratedValue(strategy = GenerationType.UUID)
    private String id;
    
    @Column(name = "user_id", nullable = false)
    private String userId;
    
    @Column(name = "session_title")
    private String sessionTitle;
    
    @Column(name = "model_type")
    @Enumerated(EnumType.STRING)
    private ModelType modelType = ModelType.OPENAI;
    
    @CreationTimestamp
    @Column(name = "created_at")
    private LocalDateTime createdAt;
    
    public enum ModelType {
        OPENAI, OLLAMA, QIANWEN
    }
}

@Entity
@Table(name = "knowledge_docs")
@Data
public class KnowledgeDocument {
    
    @Id
    @GeneratedValue(strategy = GenerationType.UUID)
    private String id;
    
    @Column(name = "file_name", nullable = false)
    private String fileName;
    
    @Column(name = "content_type")
    private String contentType;
    
    @Column(name = "content_text", length = 10000)
    private String contentText;
    
    @Column(name = "embedding_status")
    @Enumerated(EnumType.STRING)
    private EmbeddingStatus status = EmbeddingStatus.PENDING;
    
    @CreationTimestamp
    private LocalDateTime uploadedAt;
    
    public enum EmbeddingStatus {
        PENDING, PROCESSING, COMPLETED, FAILED
    }
}

五、核心功能实现

5.1 AI 服务配置类

java 复制代码
package com.example.ai.config;

import dev.langchain4j.memory.chat.MessageWindowChatMemory;
import dev.langchain4j.model.chat.ChatLanguageModel;
import dev.langchain4j.model.openai.OpenAiChatModel;
import dev.langchain4j.model.ollama.OllamaChatModel;
import dev.langchain4j.rag.content.retriever.ContentRetriever;
import dev.langchain4j.rag.content.retriever.EmbeddingStoreContentRetriever;
import dev.langchain4j.store.memory.chat.redis.RedisChatMemoryStore;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.data.redis.core.StringRedisTemplate;
import java.time.Duration;

@Configuration
public class AiConfig {

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

    @Value("${langchain4j.ollama.chat-model.base-url}")
    private String ollamaBaseUrl;

    @Bean
    @Primary
    public ChatLanguageModel openAiModel() {
        return OpenAiChatModel.builder()
                .apiKey(openAiApiKey)
                .modelName("gpt-4o")
                .temperature(0.7)
                .timeout(Duration.ofSeconds(60))
                .build();
    }

    @Bean
    public ChatLanguageModel localModel() {
        return OllamaChatModel.builder()
                .baseUrl(ollamaBaseUrl)
                .modelName("qwen2.5:14b")
                .timeout(Duration.ofSeconds(120))
                .build();
    }

    /**
     * Redis 持久化对话记忆
     */
    @Bean
    public RedisChatMemoryStore chatMemoryStore(StringRedisTemplate redisTemplate) {
        return new RedisChatMemoryStore(redisTemplate.getConnectionFactory());
    }

    /**
     * 基于 Redis 的 RAG 内容检索器
     */
    @Bean
    public ContentRetriever contentRetriever(
            EmbeddingStoreContentRetriever embeddingStoreContentRetriever) {
        return embeddingStoreContentRetriever;
    }
}

5.2 智能对话服务(带历史记忆)

java 复制代码
package com.example.ai.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 dev.langchain4j.rag.content.retriever.ContentRetriever;
import dev.langchain4j.service.AiServices;
import dev.langchain4j.service.SystemMessage;
import dev.langchain4j.service.UserMessage;
import dev.langchain4j.service.V;
import dev.langchain4j.store.memory.chat.ChatMemoryStore;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

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

@Slf4j
@Service
@RequiredArgsConstructor
public class ChatService {

    private final ChatLanguageModel chatModel;
    private final ChatMemoryStore memoryStore;
    private final ContentRetriever contentRetriever;
    
    // 内存缓存会话级别的 AI Service 实例
    private final Map<String, CustomerSupportAgent> agentCache = new ConcurrentHashMap<>();

    /**
     * 定义 AI 客服代理接口
     */
    public interface CustomerSupportAgent {
        
        @SystemMessage("""
            你是一位专业的智能客服助手,名为"小智"。请遵循以下规则:
            1. 使用中文回答用户问题,语气友好专业
            2. 如果用户询问的是产品技术问题,优先使用知识库内容回答
            3. 如果知识库中没有相关信息,坦诚告知并建议转人工客服
            4. 对于敏感操作(如退款、修改订单),必须要求用户确认身份信息
            5. 每次回复控制在 300 字以内,重点突出
            
            当前时间:{{current_time}}
            用户等级:{{user_level}}
            """)
        String chat(@UserMessage String userMessage,
                   @V("current_time") String currentTime,
                   @V("user_level") String userLevel);
    }

    /**
     * 执行对话
     */
    public ChatResponse chat(String sessionId, String userId, String message) {
        // 获取或创建带记忆的 AI Agent
        CustomerSupportAgent agent = agentCache.computeIfAbsent(sessionId, sid -> {
            ChatMemory chatMemory = MessageWindowChatMemory.builder()
                    .id(sid)
                    .maxMessages(20)  // 保留最近 20 轮对话
                    .chatMemoryStore(memoryStore)
                    .build();

            return AiServices.builder(CustomerSupportAgent.class)
                    .chatLanguageModel(chatModel)
                    .chatMemory(chatMemory)
                    .contentRetriever(contentRetriever)  // 接入 RAG
                    .build();
        });

        String currentTime = java.time.LocalDateTime.now()
                .format(java.time.format.DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm"));
        
        // 调用 AI(自动处理记忆、RAG 检索)
        String response = agent.chat(message, currentTime, "VIP");
        
        log.info("Session[{}] User: {} | AI: {}", sessionId, 
                message.substring(0, Math.min(50, message.length())), 
                response.substring(0, Math.min(100, response.length())));

        return new ChatResponse(response, sessionId, false);
    }

    /**
     * 清除会话记忆
     */
    public void clearSession(String sessionId) {
        agentCache.remove(sessionId);
        memoryStore.deleteMessages(sessionId);
    }

    public record ChatResponse(String content, String sessionId, boolean escalated) {}
}

5.3 RAG 知识库服务(文档上传与检索)

java 复制代码
package com.example.ai.service;

import dev.langchain4j.data.document.Document;
import dev.langchain4j.data.document.DocumentParser;
import dev.langchain4j.data.document.DocumentSplitter;
import dev.langchain4j.data.document.parser.apache.tika.ApacheTikaDocumentParser;
import dev.langchain4j.data.document.splitter.DocumentSplitters;
import dev.langchain4j.data.embedding.Embedding;
import dev.langchain4j.data.segment.TextSegment;
import dev.langchain4j.model.embedding.EmbeddingModel;
import dev.langchain4j.store.embedding.EmbeddingStore;
import dev.langchain4j.store.embedding.EmbeddingStoreIngestor;
import com.example.ai.entity.KnowledgeDocument;
import com.example.ai.repository.KnowledgeDocRepository;
import lombok.RequiredArgsConstructor;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import java.io.ByteArrayInputStream;
import java.util.List;

@Slf4j
@Service
@RequiredArgsConstructor
public class KnowledgeBaseService {

    private final EmbeddingStore<TextSegment> embeddingStore;
    private final EmbeddingModel embeddingModel;
    private final KnowledgeDocRepository docRepository;

    /**
     * 上传文档并构建向量索引
     */
    @SneakyThrows
    public String ingestDocument(MultipartFile file) {
        String docId = java.util.UUID.randomUUID().toString();
        
        // 1. 保存文档元数据
        KnowledgeDocument doc = new KnowledgeDocument();
        doc.setId(docId);
        doc.setFileName(file.getOriginalFilename());
        doc.setContentType(file.getContentType());
        doc.setStatus(KnowledgeDocument.EmbeddingStatus.PROCESSING);
        docRepository.save(doc);

        // 2. 异步处理文档向量化(生产环境建议用消息队列)
        new Thread(() -> processDocument(docId, file)).start();

        return docId;
    }

    @SneakyThrows
    private void processDocument(String docId, MultipartFile file) {
        try {
            // 解析文档(支持 PDF、Word、TXT、Markdown 等)
            DocumentParser parser = new ApacheTikaDocumentParser();
            Document document = parser.parse(new ByteArrayInputStream(file.getBytes()));
            document.metadata().add("doc_id", docId);
            document.metadata().add("file_name", file.getOriginalFilename());

            // 文档分块策略:按 500 token 分块,重叠 50 token
            DocumentSplitter splitter = DocumentSplitters.recursive(
                    500,   // max chunk size
                    50,    // overlap
                    new dev.langchain4j.model.openai.OpenAiTokenizer("gpt-4o")
            );

            // 构建 Ingestor 并执行向量化存储
            EmbeddingStoreIngestor ingestor = EmbeddingStoreIngestor.builder()
                    .documentSplitter(splitter)
                    .embeddingModel(embeddingModel)
                    .embeddingStore(embeddingStore)
                    .build();

            ingestor.ingest(document);

            // 更新状态
            updateStatus(docId, KnowledgeDocument.EmbeddingStatus.COMPLETED);
            log.info("文档 [{}] 向量化完成,共处理 {} 个片段", 
                    file.getOriginalFilename(), document.text().length());

        } catch (Exception e) {
            log.error("文档向量化失败: {}", e.getMessage(), e);
            updateStatus(docId, KnowledgeDocument.EmbeddingStatus.FAILED);
        }
    }

    private void updateStatus(String docId, KnowledgeDocument.EmbeddingStatus status) {
        docRepository.findById(docId).ifPresent(doc -> {
            doc.setStatus(status);
            docRepository.save(doc);
        });
    }

    /**
     * 相似度搜索(调试用)
     */
    public List<String> searchSimilar(String query, int maxResults) {
        Embedding queryEmbedding = embeddingModel.embed(query).content();
        
        return embeddingStore.findRelevant(queryEmbedding, maxResults)
                .stream()
                .map(match -> match.embedded().text())
                .toList();
    }
}

5.4 Function Calling(工具调用)实战

java 复制代码
package com.example.ai.tools;

import dev.langchain4j.agent.tool.Tool;
import dev.langchain4j.agent.tool.ToolMemoryId;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

import java.math.BigDecimal;
import java.time.LocalDate;
import java.util.List;

/**
 * AI 可调用的业务工具类
 */
@Slf4j
@Component
@RequiredArgsConstructor
public class CustomerServiceTools {

    private final OrderRepository orderRepository;
    private final UserRepository userRepository;

    /**
     * 查询订单信息
     * AI 在对话中识别到用户想查订单时,会自动调用此方法
     */
    @Tool("查询用户的订单信息,支持按订单号或日期范围查询")
    public List<OrderInfo> queryOrders(
            @ToolMemoryId String sessionId,  // 自动注入会话ID
            @dev.langchain4j.agent.tool.P("用户ID") String userId,
            @dev.langchain4j.agent.tool.P("订单号,可选") String orderNo,
            @dev.langchain4j.agent.tool.P("开始日期,格式 yyyy-MM-dd") String startDate,
            @dev.langchain4j.agent.tool.P("结束日期,格式 yyyy-MM-dd") String endDate) {
        
        log.info("[Session {}] AI 调用 queryOrders: userId={}, orderNo={}", 
                sessionId, userId, orderNo);
        
        // 实际业务查询逻辑
        return orderRepository.findByUserIdAndConditions(
                userId, orderNo, 
                startDate != null ? LocalDate.parse(startDate) : null,
                endDate != null ? LocalDate.parse(endDate) : null
        );
    }

    /**
     * 申请退款
     */
    @Tool("为用户申请订单退款,需要验证订单状态是否符合退款条件")
    public RefundResult applyRefund(
            @dev.langchain4j.agent.tool.P("订单号") String orderNo,
            @dev.langchain4j.agent.tool.P("退款原因") String reason,
            @dev.langchain4j.agent.tool.P("退款金额") BigDecimal amount) {
        
        // 业务校验:订单是否存在、是否已发货、是否在退款期内等
        Order order = orderRepository.findByOrderNo(orderNo)
                .orElseThrow(() -> new RuntimeException("订单不存在"));
        
        if (!order.canRefund()) {
            return new RefundResult(false, "该订单不符合退款条件:" + order.getStatus().getDesc());
        }

        // 执行退款逻辑...
        return new RefundResult(true, "退款申请已提交,预计 3-5 个工作日到账");
    }

    /**
     * 查询物流信息
     */
    @Tool("查询订单的物流跟踪信息")
    public LogisticsInfo queryLogistics(
            @dev.langchain4j.agent.tool.P("订单号") String orderNo) {
        
        // 调用第三方物流接口...
        return new LogisticsInfo("顺丰速运", "SF1234567890", 
                List.of(
                    new TrackNode("2024-05-01 10:30", "深圳市", "已揽收"),
                    new TrackNode("2024-05-01 18:00", "深圳市", "运输中"),
                    new TrackNode("2024-05-02 08:00", "北京市", "派送中")
                ));
    }

    // 数据记录定义
    public record OrderInfo(String orderNo, LocalDate createDate, 
                           String status, BigDecimal amount, List<String> items) {}
    public record RefundResult(boolean success, String message) {}
    public record LogisticsInfo(String carrier, String trackingNo, List<TrackNode> tracks) {}
    public record TrackNode(String time, String location, String status) {}
}

5.5 在 AI Service 中注册工具

java 复制代码
// 修改 ChatService 中的 Agent 构建逻辑
CustomerSupportAgent agent = AiServices.builder(CustomerSupportAgent.class)
        .chatLanguageModel(chatModel)
        .chatMemory(chatMemory)
        .contentRetriever(contentRetriever)
        .tools(customerServiceTools)  // 注册工具!AI 会自动决策调用
        .build();

六、REST API 层

java 复制代码
package com.example.ai.controller;

import com.example.ai.service.ChatService;
import com.example.ai.service.KnowledgeBaseService;
import lombok.RequiredArgsConstructor;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import reactor.core.publisher.Flux;

@RestController
@RequestMapping("/api/v1/ai")
@RequiredArgsConstructor
public class AiController {

    private final ChatService chatService;
    private final KnowledgeBaseService kbService;

    /**
     * 普通对话(同步)
     */
    @PostMapping("/chat")
    public ResponseEntity<ChatService.ChatResponse> chat(
            @RequestBody ChatRequest request) {
        
        String sessionId = request.sessionId() != null ? 
                request.sessionId() : java.util.UUID.randomUUID().toString();
        
        var response = chatService.chat(sessionId, request.userId(), request.message());
        return ResponseEntity.ok(response);
    }

    /**
     * 流式对话(SSE)
     */
    @PostMapping(value = "/chat/stream", produces = MediaType.TEXT_EVENT_STREAM_VALUE)
    public Flux<String> chatStream(@RequestBody ChatRequest request) {
        // 使用 LangChain4j 的 StreamingChatLanguageModel 实现
        // 代码略,原理相同,返回 Flux<String>
        return Flux.empty(); 
    }

    /**
     * 上传知识库文档
     */
    @PostMapping("/knowledge/upload")
    public ResponseEntity<String> uploadKnowledge(
            @RequestParam("file") MultipartFile file) {
        
        String docId = kbService.ingestDocument(file);
        return ResponseEntity.accepted().body("文档处理中,ID: " + docId);
    }

    /**
     * 查询知识库状态
     */
    @GetMapping("/knowledge/{docId}/status")
    public ResponseEntity<?> getDocStatus(@PathVariable String docId) {
        // 返回处理状态
        return ResponseEntity.ok().build();
    }

    /**
     * 清除会话
     */
    @DeleteMapping("/session/{sessionId}")
    public ResponseEntity<Void> clearSession(@PathVariable String sessionId) {
        chatService.clearSession(sessionId);
        return ResponseEntity.noContent().build();
    }

    public record ChatRequest(String sessionId, String userId, String message) {}
}

七、生产环境优化建议

7.1 性能优化

优化点 方案 效果
首次加载慢 Ollama 模型预加载 + Keep-Alive 减少 5-10s 等待
向量检索慢 Redis 分片 + HNSW 索引 毫秒级响应
高并发 虚拟线程(JDK 21)+ 连接池 支撑万级并发
Token 消耗 对话摘要压缩(SummaryMemory) 降低 60% Token

7.2 安全与监控

java 复制代码
/**
 * AI 输入输出过滤器示例
 */
@Component
public class AiSafetyFilter {
    
    private static final List<String> BLOCKED_KEYWORDS = List.of(
            "密码", "身份证号", "银行卡", "验证码"
    );

    public String sanitizeInput(String input) {
        // 1. 敏感信息脱敏
        // 2. Prompt 注入检测
        // 3. 输入长度限制
        return input;
    }

    public boolean validateOutput(String output) {
        // 1. 检查是否泄露系统 Prompt
        // 2. 内容安全审核
        return true;
    }
}

7.3 多模型路由策略

java 复制代码
@Service
public class ModelRouter {
    
    public ChatLanguageModel route(AiTaskType taskType) {
        return switch (taskType) {
            case SIMPLE_QA -> localModel;      // 简单问答用本地模型
            case COMPLEX_REASONING -> openAiModel; // 复杂推理用 GPT-4o
            case CODE_GENERATION -> codeModel;   // 代码专用模型
            case SUMMARIZATION -> localModel;    // 摘要本地处理
        };
    }
}

八、完整项目结构

复制代码
ai-customer-service/
├── src/main/java/com/example/ai/
│   ├── AiApplication.java
│   ├── config/
│   │   ├── AiConfig.java          # AI 模型配置
│   │   ├── RedisConfig.java       # Redis 向量存储配置
│   │   └── SecurityConfig.java    # 安全配置
│   ├── controller/
│   │   └── AiController.java      # REST API
│   ├── service/
│   │   ├── ChatService.java       # 对话服务
│   │   ├── KnowledgeBaseService.java  # RAG 服务
│   │   └── ModelRouter.java       # 模型路由
│   ├── tools/
│   │   └── CustomerServiceTools.java  # AI 工具
│   ├── entity/
│   │   ├── ChatSession.java
│   │   └── KnowledgeDocument.java
│   └── repository/
│       └── KnowledgeDocRepository.java
├── src/main/resources/
│   ├── application.yml
│   └── prompts/
│       └── system_prompt.txt      # 可外部化的 Prompt
├── docker-compose.yml             # 一键启动依赖
└── README.md

九、总结与展望

本文完整演示了如何在 Spring Boot 3 中集成 LangChain4j,实现了:

多模型支持 :OpenAI / Ollama 本地模型无缝切换

对话记忆 :Redis 持久化,支持长期上下文

RAG 检索 :文档上传 → 分块 → 向量化 → 语义检索

Function Calling :AI 自主调用业务工具

生产级设计:异步处理、安全过滤、模型路由

下一步可以探索

  1. Multi-Agent 架构 :用 LangChain4j 的 AgentExecutor 实现多智能体协作
  2. MCP 协议集成:接入 Model Context Protocol 生态
  3. A2A 协议:实现 Agent 之间的标准化通信
  4. 本地知识库:结合 DeepSeek + Ollama 实现完全离线部署

🔗 产品体验入口:https://www.ipdatacloud.com/

📖 API文档参考:https://www.ipdatacloud.com/doc/

🔗 产品体验入口:https://www.ipdatacloud.com/

📖 API文档参考:https://www.ipdatacloud.com/doc/## 参考资源


📌 GitHub 源码https://github.com/yourname/ai-customer-service(示例链接)

💬 讨论区:欢迎在评论区交流生产环境踩坑经验!


相关推荐
weixin_446260853 小时前
赋能未来生产力:AI技术如何重塑工作流与产业格局的宏观纲要
人工智能
风落无尘3 小时前
第一章《废土》完整学习资料
人工智能
CCC:CarCrazeCurator3 小时前
DeepSeek V4 大模型技术评估
人工智能
水如烟3 小时前
孤能子视角:重看“劳动,创造美“
人工智能
AI产品测评官3 小时前
2026年AI招聘工具深度测评:世纪云猎与递航AI技术路线与应用场景全景解析
人工智能
AI医影跨模态组学3 小时前
如何将多模态CT深度学习特征与肿瘤微环境中的免疫相关生物学过程建立关联,并进一步解释其与非小细胞肺癌新辅助免疫化疗后的pCR机制联系
人工智能·深度学习·论文·医学·医学影像·影像组学
2zcode3 小时前
基于深度学习的香梨产量预测系统设计与实现
人工智能·深度学习
txg6663 小时前
VulCNN:多视图图表征驱动的可扩展漏洞检测体系
人工智能·深度学习·安全·网络安全
码点滴3 小时前
告别显存焦虑:PagedAttention 如何将大模型吞吐量提升 4 倍?
人工智能·架构·kubernetes·大模型·pagedattention