MistralAI 통합

MistralAI 통합

LangChain4j에서 Mistral AI 모델을 쓰는 방법을 다룰게요. MistralAiChatModel로 대화형(채팅), MistralAiStreamingChatModel로 스트리밍, 그리고 코드 완성용 MistralAiFimModel까지 쓸 수 있어요. Mistral AI는 오픈소스 모델과 상용 모델을 나눠서 운영하는데, 성능과 비용 트레이드오프에 따라 모델을 선택하게 돼요.

출처: 공식문서

프로젝트 설정

프로젝트에 langchain4j를 설치하려면 다음 의존성을 추가해요.

Maven 프로젝트 pom.xml:


<dependency>
    <groupId>dev.langchain4j</groupId>
    <artifactId>langchain4j</artifactId>
    <version>1.20.0</version>
</dependency>

<dependency>
    <groupId>dev.langchain4j</groupId>
    <artifactId>langchain4j-mistral-ai</artifactId>
    <version>1.20.0</version>
</dependency>

Gradle 프로젝트 build.gradle:

implementation 'dev.langchain4j:langchain4j:1.20.0'
implementation 'dev.langchain4j:langchain4j-mistral-ai:1.20.0'

API 키 설정

Mistral AI API 키를 프로젝트에 추가해요. 다음 코드로 ApiKeys.java 클래스를 만들 수 있어요.

public class ApiKeys {
    public static final String MISTRALAI_API_KEY = System.getenv("MISTRAL_AI_API_KEY");
}

API 키를 환경변수로 설정하는 걸 잊지 마세요.

export MISTRAL_AI_API_KEY=your-api-key #For Unix OS based
SET MISTRAL_AI_API_KEY=your-api-key #For Windows OS

Mistral AI API 키를 얻는 자세한 방법은 여기에서 확인할 수 있어요.

모델 선택

MistralAiChatModelNameMistralAiFimModelName 자바 enum을 사용해 사용 사례에 맞는 모델 이름을 찾을 수 있어요. Mistral AI는 성능과 비용 트레이드오프에 따라 새로운 모델 선택·분류를 갱신했어요.

Model name Deployment or available from Description
open-mistral-7b - Mistral AI La Plateforme.
- Cloud platforms (Azure, AWS, GCP).
- Hugging Face.
- Self-hosted (On-premise, IaaS, docker, local).
OpenSource
The first dense model released by Mistral AI,
perfect for experimentation,
customization, and quick iteration.

Max tokens 32K

Java Enum
MistralAiChatModelName.OPEN_MISTRAL_7B
open-mixtral-8x7b - Mistral AI La Plateforme.
- Cloud platforms (Azure, AWS, GCP).
- Hugging Face.
- Self-hosted (On-premise, IaaS, docker, local).
OpenSource
Ideal to handle multi-languages operations,
code generationand fine-tuned.
Excellent cost/performance trade-offs.

Max tokens 32K

Java Enum
MistralAiChatModelName.OPEN_MIXTRAL_8x7B
open-mixtral-8x22b - Mistral AI La Plateforme.
- Cloud platforms (Azure, AWS, GCP).
- Hugging Face.
- Self-hosted (On-premise, IaaS, docker, local).
OpenSource
It has all Mixtral-8x7B capabilities plus strong maths
and coding natively capable of function calling

Max tokens 64K.

Java Enum
MistralAiChatModelName.OPEN_MIXTRAL_8X22B
open-mistral-nemo - Mistral AI La Plateforme.
- Cloud platforms (Azure, AWS, GCP).
- Hugging Face.
- Self-hosted (On-premise, IaaS, docker, local).
OpenSource
A 12B model built in collaboration with NVIDIA.
Its reasoning, world knowledge, and coding accuracy are state-of-the-art in its size category.

Max tokens 128K.

Java Enum
MistralAiChatModelName.OPEN_MISTRAL_NEMO
open-codestral-mamba - Mistral AI La Plateforme.
- Cloud platforms (Azure, AWS, GCP).
- Hugging Face.
- Self-hosted (On-premise, IaaS, docker, local).
OpenSource
A Mamba2 language model specialised in code generation.
It was trained with advanced code and reasoning capabilities, enabling it to perform on par with SOTA transformer-based models.

Max tokens 256K.

Java Enum
MistralAiFimModelName.OPEN_CODESTRAL_MAMBA
mistral-small-latest - Mistral AI La Plateforme.
- Cloud platforms (Azure, AWS, GCP).
Commercial
Suitable for simple tasks that one can do in bulk
(Classification, Customer Support, or Text Generation).

Max tokens 32K

Java Enum
MistralAiChatModelName.MISTRAL_SMALL_LATEST
mistral-medium-latest - Mistral AI La Plateforme.
- Cloud platforms (Azure, AWS, GCP).
Commercial
Ideal for intermediate tasks that require moderate
reasoning (Data extraction, Summarizing,
Writing emails, Writing descriptions.

Max tokens 32K

Java Enum
MistralAiChatModelName.MISTRAL_MEDIUM_LATEST
mistral-large-latest - Mistral AI La Plateforme.
- Cloud platforms (Azure, AWS, GCP).
Commercial
Ideal for complex tasks that require large reasoning
capabilities or are highly specialized
(Text Generation, Code Generation, RAG, or Agents).

Max tokens 128K

Java Enum
MistralAiChatModelName.MISTRAL_LARGE_LATEST
mistral-embed - Mistral AI La Plateforme.
- Cloud platforms (Azure, AWS, GCP).
Commercial
Converts text into numerical vectors of
embeddings in 1024 dimensions.
Embedding models enable retrieval and RAG applications.

Max tokens 8K

Java Enum
MistralAiEmbeddingModelName.MISTRAL_EMBED
codestral-latest - Mistral AI La Plateforme.
- Cloud platforms (Azure, AWS, GCP).
- Hugging Face.
- Self-hosted (On-premise, IaaS, docker, local).
OpenSource (Non-production license) and Commercial
A cutting-edge generative model that has been specifically designed
and optimized for code generation tasks, including fill-in-the-middle and code completion.

Max tokens 32K

Java Enum
MistralAiFimModelName.CODESTRAL_LATEST

표를 보면 분류가 두 갈래로 나뉘는데요. 실험·커스터마이즈에 좋은 오픈소스 계열(open-mistral-7b, open-mixtral-8x7b, open-mistral-nemo, open-codestral-mamba)과, 분류·고객지원 같은 단순 작업에 적합한 상용 계열(mistral-small-latest, mistral-medium-latest, mistral-large-latest)이에요. 코드 생성 특화 모델은 codestral-latest예요.

@Deprecated 모델:

  • mistral-tiny (@Deprecated)
  • mistral-small (@Deprecated)
  • mistral-medium (@Deprecated)

각 Mistral 모델과 사용 사례 유형에 대한 자세한 내용은 여기에서 찾을 수 있어요.

채팅 완성 (Chat Completion)

채팅 모델은 대화 데이터로 미세조정된 모델로 인간 같은 응답을 생성하게 해줘요.

동기(Synchronous)

클래스를 만들고 다음 코드를 추가해요.

import dev.langchain4j.model.chat.ChatModel;
import dev.langchain4j.model.mistralai.MistralAiChatModel;

public class HelloWorld {
    public static void main(String[] args) {
        ChatModel model = MistralAiChatModel.builder()
                .apiKey(ApiKeys.MISTRALAI_API_KEY)
                .modelName(MistralAiChatModelName.MISTRAL_SMALL_LATEST)
                .build();

        String response = model.chat("Say 'Hello World'");
        System.out.println(response);
    }
}

프로그램을 실행하면 다음과 비슷한 출력이 나와요.

Hello World! How can I assist you today?

스트리밍(Streaming)

클래스를 만들고 다음 코드를 추가해요.

import dev.langchain4j.data.message.AiMessage;
import dev.langchain4j.model.chat.response.StreamingChatResponseHandler;
import dev.langchain4j.model.mistralai.MistralAiStreamingChatModel;
import dev.langchain4j.model.output.Response;

import java.util.concurrent.CompletableFuture;

public class HelloWorld {
    public static void main(String[] args) {
        MistralAiStreamingChatModel model = MistralAiStreamingChatModel.builder()
                .apiKey(ApiKeys.MISTRALAI_API_KEY)
                .modelName(MistralAiChatModelName.MISTRAL_SMALL_LATEST)
                .build();

        CompletableFuture<ChatResponse> futureResponse = new CompletableFuture<>();         
        model.chat("Tell me a joke about Java", new StreamingChatResponseHandler() {
            
            @Override
            public void onPartialResponse(String partialResponse) {
                System.out.print(partialResponse);
            }

            @Override
            public void onCompleteResponse(ChatResponse completeResponse) {
                futureResponse.complete(completeResponse);
            }

            @Override
            public void onError(Throwable error) {
                futureResponse.completeExceptionally(error);
            }    
        });

        futureResponse.join();
    }
}

LLM이 생성하는 각 텍스트 청크(토큰)를 onPartialResponse 메서드에서 받아요. 아래 출력이 실시간으로 스트리밍되는 걸 볼 수 있어요.

"Why do Java developers wear glasses? Because they can't C#"

물론 Mistral AI 채팅 완성을 Set Model ParametersChat Memory 같은 다른 기능과 결합해 더 정확한 응답을 얻을 수 있어요.

Chat Memory에서 채팅 히스토리를 전달하는 방법을 배울 수 있어요. 그러면 LLM이 이전에 말한 내용을 알 수 있어요. 이 간단한 예시처럼 채팅 히스토리를 전달하지 않으면 LLM은 이전에 말한 내용을 알 수 없어서 두 번째 질문('What did I just ask?')에 올바르게 답하지 못해요.

timeout, 모델 타입, 모델 파라미터 같은 많은 파라미터가 내부적으로 설정돼요. Set Model Parameters에서 이 파라미터를 명시적으로 설정하는 방법을 배울 수 있어요.

함수 호출 (Function Calling)

Function calling은 Mistral 채팅 모델(동기·스트리밍)이 외부 툴에 연결하게 해줘요. 예를 들어 Mistral AI 함수 호출 튜토리얼에 나온 것처럼 Tool을 호출해 결제 트랜잭션 상태를 가져올 수 있어요.

지원되는 mistral 모델은?

:::note 현재 함수 호출은 다음 모델에서 사용할 수 있어요.

  • Mistral Small MistralAiChatModelName.MISTRAL_SMALL_LATEST
  • Mistral Large MistralAiChatModelName.MISTRAL_LARGE_LATEST
  • Mixtral 8x22B MistralAiChatModelName.OPEN_MIXTRAL_8X22B
  • Mistral Nemo MistralAiChatModelName.OPEN_MISTRAL_NEMO :::

1. Tool 클래스 정의와 결제 데이터 가져오기

이런 결제 트랜잭션 데이터셋이 있다고 가정해 볼게요. 실제 애플리케이션에서는 데이터 소스를 주입하거나 REST API 클라이언트로 데이터를 가져와야 해요.

import java.util.*;

public class PaymentTransactionTool {

   private final Map<String, List<String>> paymentData = Map.of(
            "transaction_id", List.of("T1001", "T1002", "T1003", "T1004", "T1005"),
            "customer_id", List.of("C001", "C002", "C003", "C002", "C001"),
            "payment_amount", List.of("125.50", "89.99", "120.00", "54.30", "210.20"),
            "payment_date", List.of("2021.20.05", "2021.20.06", "2021.20.07", "2021.20.05", "2021.20.08"),
            "payment_status", List.of("Paid", "Unpaid", "Paid", "Paid", "Pending"));
   
    ...
}

다음으로 Tool 클래스에서 결제 상태와 결제 날짜를 가져올 retrievePaymentStatusretrievePaymentDate 두 메서드를 정의해요.

// Tool to be executed to get payment status
@Tool("Get payment status of a transaction") // function description
String retrievePaymentStatus(@P("Transaction id to search payment data") String transactionId) {
    return getPaymentData(transactionId, "payment_status");
}

// Tool to be executed to get payment date
@Tool("Get payment date of a transaction") // function description
String retrievePaymentDate(@P("Transaction id to search payment data") String transactionId) {
   return getPaymentData(transactionId, "payment_date");
}

private String getPaymentData(String transactionId, String data) {
    List<String> transactionIds = paymentData.get("transaction_id");
    List<String> paymentData = paymentData.get(data);

    int index = transactionIds.indexOf(transactionId);
    if (index != -1) {
        return paymentData.get(index);
    } else {
        return "Transaction ID not found";
    }
}

함수 설명을 정의하는 @Tool 애노테이션과 파라미터 설명을 정의하는 @P 애노테이션을 dev.langchain4j.agent.tool.* 패키지에서 써요. 자세한 내용은 여기를 참고하세요.

2. 채팅 메시지를 보내는 agent 인터페이스 정의

PaymentTransactionAgent 인터페이스를 만들어요.

import dev.langchain4j.service.SystemMessage;

interface PaymentTransactionAgent {
    @SystemMessage({
            "You are a payment transaction support agent.",
            "You MUST use the payment transaction tool to search the payment transaction data.",
            "If there a date convert it in a human readable format."
    })
    String chat(String userMessage);
}

3. Mistral AI 채팅 모델과 대화하는 main 애플리케이션 클래스 정의

import dev.langchain4j.memory.chat.MessageWindowChatMemory;
import dev.langchain4j.model.chat.ChatModel;
import dev.langchain4j.model.mistralai.MistralAiChatModel;
import dev.langchain4j.model.mistralai.MistralAiChatModelName;
import dev.langchain4j.service.AiServices;

public class PaymentDataAssistantApp {

    ChatModel mistralAiModel = MistralAiChatModel.builder()
            .apiKey(System.getenv("MISTRAL_AI_API_KEY")) // Please use your own Mistral AI API key
            .modelName(MistralAiChatModelName.MISTRAL_LARGE_LATEST) // Also you can use MistralAiChatModelName.OPEN_MIXTRAL_8X22B as open source model
            .logRequests(true)
            .logResponses(true)
            .build();
    
    public static void main(String[] args) {
        // STEP 1: User specify tools and query
        PaymentTransactionTool paymentTool = new PaymentTransactionTool();
        String userMessage = "What is the status and the payment date of transaction T1005?";

        // STEP 2: User asks the agent and AiServices call to the functions
        PaymentTransactionAgent agent = AiServices.builder(PaymentTransactionAgent.class)
                .chatModel(mistralAiModel)
                .tools(paymentTool)
                .chatMemory(MessageWindowChatMemory.withMaxMessages(10))
                .build();
        
        // STEP 3: User gets the final response from the agent
        String answer = agent.chat(userMessage);
        System.out.println(answer);
    }
}

그러면 이런 답을 기대할 수 있어요.

The status of transaction T1005 is Pending. The payment date is October 8, 2021.

JSON 모드

JSON 형식으로 응답을 받으려면 JSON 모드도 쓸 수 있어요. 그러려면 MistralAiChatModel 빌더 또는 MistralAiStreamingChatModel 빌더에서 responseFormat 파라미터를 ResponseFormat.JSON으로 설정하면 돼요.

동기 예시:

ChatModel model = MistralAiChatModel.builder()
                .apiKey(System.getenv("MISTRAL_AI_API_KEY")) // Please use your own Mistral AI API key
                .responseFormat(ResponseFormat.JSON)
                .build();

String userMessage = "Return JSON with two fields: transactionId and status with the values T123 and paid.";
String json = model.chat(userMessage);

System.out.println(json); // {"transactionId":"T123","status":"paid"}

스트리밍 예시:

StreamingChatModel streamingModel = MistralAiStreamingChatModel.builder()
                .apiKey(System.getenv("MISTRAL_AI_API_KEY")) // Please use your own Mistral AI API key
                .responseFormat(MistralAiResponseFormatType.JSON_OBJECT)
                .build();

String userMessage = "Return JSON with two fields: transactionId and status with the values T123 and paid.";

CompletableFuture<ChatResponse> futureResponse = new CompletableFuture<>();

streamingModel.chat(userMessage, new StreamingChatResponseHandler() {

    @Override
    public void onPartialResponse(String partialResponse) {
        System.out.print(partialResponse);
    }

    @Override
    public void onCompleteResponse(ChatResponse completeResponse) {
        futureResponse.complete(completeResponse);
    }

    @Override
    public void onError(Throwable error) {
        futureResponse.completeExceptionally(error);
    }
});

String json = futureResponse.get().content().text();

System.out.println(json); // {"transactionId":"T123","status":"paid"}

구조화된 출력 (Structured Outputs)

Structured Outputs는 모델의 응답이 JSON schema를 따르도록 보장해요.

:::note LangChain4j에서 Structured Outputs를 쓰는 문서는 여기 있고, 아래 섹션에서 MistralAI 전용 정보를 볼 수 있어요. :::

원한다면 모델에 기본 JSON Schema를 구성할 수 있는데, 요청에 스키마가 없을 때 폴백으로 사용돼요.

ChatModel model = MistralAiChatModel.builder()
        .apiKey(System.getenv("MISTRAL_AI_API_KEY"))
        .modelName(MISTRAL_SMALL_LATEST)
        .supportedCapabilities(Set.of(Capability.RESPONSE_FORMAT_JSON_SCHEMA)) // Enable structured outputs
        .responseFormat(ResponseFormat.builder() // Set the fallback JSON Schema (optional)
                .type(ResponseFormatType.JSON)
                .jsonSchema(JsonSchema.builder().rootElement(JsonObjectSchema.builder()
                                .addProperty("name", JsonStringSchema.builder().build())
                                .addProperty("capital", JsonStringSchema.builder().build())
                                .addProperty(
                                        "languages",
                                        JsonArraySchema.builder()
                                                .items(JsonStringSchema.builder().build())
                                                .build())
                                .required("name", "capital", "languages")
                                .build())
                        .build())
                .build())
        .strictJsonSchema(true)
        .build();

Guardrailing

Guardrails는 모델이 유해하거나 원치 않는 콘텐츠를 생성하지 못하게 동작을 제한하는 방법이에요. MistralAiChatModel 빌더 또는 MistralAiStreamingChatModel 빌더에서 선택적으로 safePrompt 파라미터를 설정할 수 있어요.

동기 예시:

ChatModel model = MistralAiChatModel.builder()
                .apiKey(System.getenv("MISTRAL_AI_API_KEY"))
                .safePrompt(true)
                .build();

String userMessage = "What is the best French cheese?";
String response = model.chat(userMessage);

스트리밍 예시:

StreamingChatModel streamingModel = MistralAiStreamingChatModel.builder()
                .apiKey(System.getenv("MISTRAL_AI_API_KEY"))
                .safePrompt(true)
                .build();

String userMessage = "What is the best French cheese?";

CompletableFuture<ChatResponse> futureResponse = new CompletableFuture<>();

streamingModel.chat(userMessage, new StreamingChatResponseHandler() {
    
    @Override
    public void onPartialResponse(String partialResponse) {
        System.out.print(partialResponse);
    }

    @Override
    public void onCompleteResponse(ChatResponse completeResponse) {
        futureResponse.complete(completeResponse);
    }

    @Override
    public void onError(Throwable error) {
        futureResponse.completeExceptionally(error);
    }
});

futureResponse.join();

안전 프롬프트를 켜면 메시지 앞에 다음 @SystemMessage가 붙어요.

Always assist with care, respect, and truth. Respond with utmost utility yet securely. Avoid harmful, unethical, prejudiced, or negative content. Ensure replies promote fairness and positivity.

요청별 파라미터 (Per-Request Parameters)

Mistral 전용 옵션(safePrompt, randomSeed, sendThinking, returnThinking)은 MistralAiChatRequestParameters로 요청별로도 설정할 수 있어요. 모델 빌더에 설정된 값을 덮어써요. 이러면 하나의 공유 모델 인스턴스로 호출마다 옵션을 바꿀 수 있는데, 예를 들어 재현 가능한 완성을 위해 한 요청에만 safePrompt를 켜거나 randomSeed를 설정할 때, 두 번째 모델을 만들지 않고 처리할 수 있어요.

ChatModel model = MistralAiChatModel.builder()
        .apiKey(System.getenv("MISTRAL_AI_API_KEY"))
        .modelName("mistral-small-latest")
        .build();

MistralAiChatRequestParameters parameters = MistralAiChatRequestParameters.builder()
        .safePrompt(true)
        .randomSeed(42)
        .build();

ChatRequest chatRequest = ChatRequest.builder()
        .messages(UserMessage.from("What is the best French cheese?"))
        .parameters(parameters)
        .build();

ChatResponse chatResponse = model.chat(chatRequest);

Thinking / Reasoning

MistralAiChatModelMistralAiStreamingChatModel 둘 다 Magistral reasoning 모델로 reasoning을 지원해요.

다음 파라미터로 구성해요.

  • returnThinking — 켜면 모델이 만든 reasoning 텍스트를 API 응답에서 파싱해 AiMessage.thinking()에 저장해요. 스트리밍에선 StreamingChatResponseHandler.onPartialThinking()TokenStream.onPartialThinking() 콜백도 호출돼요. 기본 비활성.
  • sendThinking — 켜면 이전 응답의 reasoning 텍스트(AiMessage.thinking()에 저장됨)를 후속 요청에 포함해요. 기본 비활성.

reasoning을 구성하는 예시예요.

ChatModel model = MistralAiChatModel.builder()
        .apiKey(System.getenv("MISTRAL_AI_API_KEY"))
        .modelName(MistralAiChatModelName.MAGISTRAL_MEDIUM_LATEST)
        .returnThinking(true)
        .sendThinking(true)
        .build();

Moderation

텍스트에서 유해한 콘텐츠를 감지하는 데 쓰는 분류 모델이에요.

Moderation 예시:

ModerationModel model = new MistralAiModerationModel.Builder()
    .apiKey(System.getenv("MISTRAL_AI_API_KEY"))
    .modelName(MistralAiModerationModelName.MISTRAL_MODERATION_LATEST)
    .logRequests(true)
    .logResponses(false)
    .build();
// I want to check if the text contains harmful content
Moderation moderation = model.moderate("I want to kill them.").content();

코드 완성 (Code Completion)

Fill-in-the-Middle(FIM) 모델은 코드 완성을 생성하게 해줘요. prompt로 코드의 시작점을, 선택적 suffix로 끝점, 선택적 stop을 정의할 수 있어요.

FIM 동기(Synchronous)

채팅 완성과 마찬가지로 FIM 엔드포인트도 동작해요. 다음 코드를 추가해 테스트할 수 있어요.

import dev.langchain4j.model.mistralai.MistralAiFimModel;
import dev.langchain4j.model.output.Response;

public class HelloWorld {
    public static void main(String[] args) {
        MistralAiFimModel codestral = MistralAiFimModel.builder()
                .apiKey(System.getenv("MISTRAL_AI_API_KEY"))
                .modelName(MistralAiFimModelName.CODESTRAL_LATEST)
                .stop(List.of("}")) // must stop at the first occurrence of "}"
                .build();
        
        // I want to generate a code completion for a simple hello world program using MistralAI of LangChain4j framework.
        String codePrompt = """
                  public static void main(String[] args) {
                      // Create a function to multiply two numbers
                """;
        String suffix = """
                    System.out.println(result);
                  }
                """;

        // Asking to Codestral model to complete the code with given prompt and suffix
        Response<String> response = codestral.generate(prompt, suffix);
        
        System.out.println(
                String.format(
                        "%s%s%s",
                        prompt, // print code prompt (prefix)
                        response.content(), // print code filled-in-the-middle
                        suffix)); // print code suffix
    }
}

프로그램을 실행하면 다음 출력이 나와요.

public static void main(String[] args) {
      // Create a function to multiply two numbers
      int result = multiply(5, 3);
      System.out.println(result);
  }

FIM 스트리밍

클래스를 만들고 다음 코드를 추가해요.

import dev.langchain4j.model.StreamingResponseHandler;
import dev.langchain4j.model.language.StreamingLanguageModel;
import dev.langchain4j.model.mistralai.MistralAiStreamingFimModel;
import dev.langchain4j.model.output.Response;

import java.util.concurrent.CompletableFuture;

public class HelloWorld {
    public static void main(String[] args) {
        StreamingLanguageModel codestralStream = MistralAiStreamingFimModel.builder()
                .apiKey(ApiKeys.MISTRALAI_API_KEY)
                .modelName(MistralAiFimModelName.CODESTRAL_LATEST)
                .build();

        // I want to generate a code completion for a simple hello world program.
        String prompt = "public static void main(String[] args) {";

        CompletableFuture<Response<String>> futureResponse = new CompletableFuture<>();
        codestral.generate(prompt, new StreamingResponseHandler() {
            @Override
            public void onNext(String token) {
                System.out.print(token);
            }

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

            @Override
            public void onError(Throwable error) {
                futureResponse.completeExceptionally(error);
            }
        });

        futureResponse.join();
    }
}

LLM이 생성하는 각 텍스트 청크(토큰)를 onNext 메서드에서 받아요. 아래 출력이 실시간으로 스트리밍되는 걸 볼 수 있어요.

public static void main(String[] args) {

        int[] arr = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
        int sum = 0;

        for (int i = 0; i < arr.length; i++) {
            sum += arr[i];
        }

        System.out.println("Sum of all elements in the array: " + sum);
    }
}

raw HTTP 응답과 Server-Sent Events(SSE) 접근

MistralAiChatModel을 쓸 때 raw HTTP 응답에 접근할 수 있어요.

SuccessfulHttpResponse rawHttpResponse = ((MistralAiChatResponseMetadata) chatResponse.metadata()).rawHttpResponse();
System.out.println(rawHttpResponse.body());
System.out.println(rawHttpResponse.headers());
System.out.println(rawHttpResponse.statusCode());

MistralAiStreamingChatModel을 쓸 때는 raw HTTP 응답(위 참고)과 raw Server-Sent Events에 접근할 수 있어요.

List<ServerSentEvent> rawServerSentEvents = ((MistralAiChatResponseMetadata) chatResponse.metadata()).rawServerSentEvents();
System.out.println(rawServerSentEvents.get(0).data());
System.out.println(rawServerSentEvents.get(0).event());

배치 처리 (Batch Processing)

MistralAiBatchChatModel은 핵심 BatchChatModel 인터페이스를 구현해 Mistral Batch API로 많은 채팅 요청을 표준 토큰당 가격의 **50%**로 비동기 처리해요. 배치 안의 모든 요청은 배치 모델에 구성된 단일 모델로 실행돼요.

배치를 제출하고 종료 상태가 될 때까지 폴링한 뒤 요청별 결과를 읽어요(제출 순서 보존):

MistralAiBatchChatModel batchModel = MistralAiBatchChatModel.builder()
        .apiKey(System.getenv("MISTRAL_AI_API_KEY"))
        .modelName("mistral-small-latest")
        .build();

BatchResponse<ChatResponse> submitted = batchModel.submit(new BatchRequest<>(List.of(
        ChatRequest.builder().messages(UserMessage.from("What is the capital of France?")).build(),
        ChatRequest.builder().messages(UserMessage.from("What is the capital of Germany?")).build())));

String batchId = submitted.batchId();

// Poll until the batch reaches a terminal state (SUCCEEDED, FAILED, CANCELLED, EXPIRED).
BatchResponse<ChatResponse> batch = batchModel.retrieve(batchId);
while (!batch.state().isTerminal()) {
    Thread.sleep(Duration.ofSeconds(30).toMillis());
    batch = batchModel.retrieve(batchId);
}

for (BatchItemResult<ChatResponse> result : batch.results()) {
    if (result.isSuccess()) {
        System.out.println(result.response().aiMessage().text());
    } else {
        System.out.println("Failed: " + result.error().message());
    }
}

실행 중인 배치는 취소할 수 있고, 기존 배치는 페이지네이션으로 나열할 수 있어요.

batchModel.cancel(batchId);

BatchPage<ChatResponse> page = batchModel.list(new BatchPagination(20, null));

예시

더 알아보기