Xây dựng Trợ lý AI Y tế với Spring Boot 3, LangChain4j, MongoDB và Elasticsearch 8

Giới thiệu

Bài viết này hướng dẫn cách tích hợp Spring Boot 3 với LangChain4j để xây dựng một trợ lý AI y tế, sử dụng MongoDB để lưu trữ bộ nhớ cuộc trò chuyện và Elasticsearch 8 để lưu trữ và truy xuất dữ liệu vector.

Các công nghệ chính được sử dụng:

  • Spring Boot 3.2.6
  • LangChain4j 1.0.0-beta3
  • DeepSeek, Ollama, Qwen (Aliyun) - các mô hình ngôn ngữ lớn
  • MongoDB - lưu trữ bộ nhớ cuộc trò chuyện
  • Elasticsearch 8 - lưu trữ vector và RAG
  • Function Calling - tùy chỉnh logic kinh doanh
  • Đầu ra luồng - phản hồi thời gian thực

Cấu hình dự án Spring Boot 3 và LangChain4j

Môi trường JDK 17

Spring Boot 3 yêu cầu JDK 17 trở lên. Hãy đảm bảo bạn đã cài đặt JDK 17.

Thêm dependency vào pom.xml

<properties>
    <maven.compiler.source>17</maven.compiler.source>
    <maven.compiler.target>17</maven.compiler.target>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <spring-boot.version>3.2.6</spring-boot.version>
    <langchain4j.version>1.0.0-beta3</langchain4j.version>
</properties>

<dependencies>
    <!-- Web core -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <!-- Testing -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-test</artifactId>
        <scope>test</scope>
    </dependency>
</dependencies>

<dependencyManagement>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-dependencies</artifactId>
            <version>${spring-boot.version}</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>
    </dependencies>
</dependencyManagement>

Cấu hình application.properties

# Cổng
server.port=8080

Lớp khởi động

package com.example.ai;

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

@SpringBootApplication
public class MedicalAssistantApplication {
    public static void main(String[] args) {
        SpringApplication.run(MedicalAssistantApplication.class, args);
        System.out.println("Ứng dụng đã khởi động thành công!");
    }
}

Tích hợp các mô hình ngôn ngữ lớn (LLM)

DeepSeek

Đăng ký tài khoản trên trang web DeepSeek và lấy API key.

Cấu hình application.properties

# DeepSeek API
DEEP_SEEK_API_KEY=sk-cf1a************94674e7e9
langchain4j.open-ai.chat-model.base-url=https://api.deepseek.com
langchain4j.open-ai.chat-model.api-key=${DEEP_SEEK_API_KEY}
langchain4j.open-ai.chat-model.model-name=deepseek-chat

Ollama

Tải và cài đặt Ollama, sau đó tải mô hình DeepSeek: `ollama run deepseek-r1:1.5b`.

Dependency và Cấu hình

<!-- Ollama -->
<dependency>
    <groupId>dev.langchain4j</groupId>
    <artifactId>langchain4j-ollama-spring-boot-starter</artifactId>
</dependency>

# Ollama
langchain4j.ollama.chat-model.base-url=http://localhost:11434
langchain4j.ollama.chat-model.model-name=deepseek-r1:1.5b

Qwen (Aliyun)

Đăng ký tài khoản trên Aliyun và lấy API key.

Dependency và Cấu hình

<!-- Aliyun Qwen -->
<dependency>
    <groupId>dev.langchain4j</groupId>
    <artifactId>langchain4j-community-dashscope-spring-boot-starter</artifactId>
</dependency>

# Aliyun Qwen
DASH_SCOPE_API_KEY=sk-3f0ebccc3*******c5a728e8974
langchain4j.community.dashscope.chat-model.api-key=${DASH_SCOPE_API_KEY}
langchain4j.community.dashscope.chat-model.model-name=qwen-max

Bộ nhớ cuộc trò chuyện (Chat Memory)

Bộ nhớ trong (In-memory)

Sử dụng `MessageWindowChatMemory` để lưu trữ một số lượng tin nhắn nhất định.

@Configuration
public class ChatMemoryConfig {
    @Bean
    ChatMemory chatMemory() {
        return MessageWindowChatMemory.withMaxMessages(10);
    }
}

Bộ nhớ được phân lập theo ID cuộc trò chuyện

Sử dụng `ChatMemoryProvider` để tạo bộ nhớ riêng cho mỗi cuộc trò chuyện.

@Configuration
public class IsolatedChatMemoryConfig {
    @Bean
    ChatMemoryProvider chatMemoryProvider() {
        return memoryId -> MessageWindowChatMemory.builder()
                .id(memoryId)
                .maxMessages(10)
                .build();
    }
}

Lưu trữ bộ nhớ vào MongoDB

Tạo một lớp implements `ChatMemoryStore` để lưu trữ và truy xuất dữ liệu từ MongoDB.

@Component
public class MongoChatMemoryStore implements ChatMemoryStore {
    @Autowired
    private MongoTemplate mongoTemplate;

    @Override
    public List<ChatMessage> getMessages(Object memoryId) {
        // ... logic to retrieve messages from MongoDB
    }

    @Override
    public void updateMessages(Object memoryId, List<ChatMessage> messages) {
        // ... logic to update messages in MongoDB
    }

    @Override
    public void deleteMessages(Object memoryId) {
        // ... logic to delete messages from MongoDB
    }
}

Template Prompt và System Message

Sử dụng `@SystemMessage` để định nghĩa vai trò và hành vi của AI, và `@UserMessage` để nhận đầu vào từ người dùng.

@AiService(wiringMode = EXPLICIT, chatModel = "qwenChatModel", chatMemoryProvider = "chatMemoryProvider")
public interface MedicalAssistant {
    @SystemMessage(fromResource = "medical-assistant-prompt.txt")
    String chat(@MemoryId Long memoryId, @UserMessage String userMessage);
}

Tệp `medical-assistant-prompt.txt` chứa hướng dẫn cho AI:

Bạn là một trợ lý y tế chuyên nghiệp. Hãy trả lời các câu hỏi y tế một cách chính xác và hữu ích.

Function Calling (Công cụ tùy chỉnh)

Định nghĩa các công cụ để AI có thể gọi các hàm kinh doanh.

Ví dụ: Công cụ đặt lịch hẹn

@Component
public class AppointmentTools {
    @Autowired
    private AppointmentService appointmentService;

    @Tool(name = "Đặt lịch hẹn", value = "Đặt lịch hẹn cho bệnh nhân")
    public String bookAppointment(Appointment appointment) {
        // Logic to book an appointment
    }

    @Tool(name = "Hủy lịch hẹn", value = "Hủy lịch hẹn của bệnh nhân")
    public String cancelAppointment(Appointment appointment) {
        // Logic to cancel an appointment
    }
}

Lưu trữ Vector với Elasticsearch 8

Cài đặt Elasticsearch 8

Tải và cài đặt Elasticsearch 8. Cấu hình `elasticsearch.yml` để tắt bảo mật nếu cần.

Tạo Index Vector

PUT medical-knowledge
{
  "mappings": {
    "properties": {
      "vector": {
        "type": "dense_vector",
        "dims": 1024,
        "index": true,
        "similarity": "l2_norm"
      },
      "text": { "type": "text" }
    }
  }
}

Tích hợp Elasticsearch trong dự án

<!-- Elasticsearch -->
<dependency>
    <groupId>dev.langchain4j</groupId>
    <artifactId>langchain4j-elasticsearch</artifactId>
</dependency>

<dependency>
    <groupId>co.elastic.clients</groupId>
    <artifactId>elasticsearch-java</artifactId>
    <version>8.17.0</version>
</dependency>

# Elasticsearch
es.host=127.0.0.1
es.port=9200
es.index-name=medical-knowledge

Cấu hình Content Retriever

@Configuration
public class RAGConfig {
    @Autowired
    private RestClient restClient;
    @Autowired
    private EmbeddingModel embeddingModel;

    @Bean
    ContentRetriever contentRetriever() {
        ElasticsearchEmbeddingStore embeddingStore = ElasticsearchEmbeddingStore.builder()
                .restClient(restClient)
                .indexName("medical-knowledge")
                .build();

        return EmbeddingStoreContentRetriever.builder()
                .embeddingModel(embeddingModel)
                .embeddingStore(embeddingStore)
                .maxResults(1)
                .minScore(0.4)
                .build();
    }
}

Đầu ra luồng (Streaming Output)

Sử dụng WebFlux để cung cấp phản hồi theo thời gian thực.

Dependency

<!-- WebFlux và Reactor -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-webflux</artifactId>
</dependency>
<dependency>
    <groupId>dev.langchain4j</groupId>
    <artifactId>langchain4j-reactor</artifactId>
</dependency>

Cấu hình và Controller

@AiService(
    wiringMode = EXPLICIT,
    streamingChatModel = "qwenStreamingChatModel",
    chatMemoryProvider = "chatMemoryProvider",
    tools = "appointmentTools",
    contentRetriever = "contentRetriever"
)
public interface MedicalAssistant {
    Flux<String> chat(@MemoryId Long memoryId, @UserMessage String userMessage);
}

@RestController
@RequestMapping("/api/assistant")
public class AssistantController {
    @Autowired
    private MedicalAssistant medicalAssistant;

    @PostMapping("/chat")
    public Flux<String> chat(@RequestBody ChatRequest request) {
        return medicalAssistant.chat(request.getMemoryId(), request.getMessage());
    }
}

Thẻ: springboot3 langchain4j MongoDB Elasticsearch8 AI

Đăng vào ngày 14 tháng 7 lúc 09:46