Azure OpenAI 통합
Azure OpenAI 통합
Azure에서 호스팅되는 OpenAI 모델(gpt-4, gpt-4o 등)을 LangChain4j에서 쓰는 방법이에요. 이 통합은 마이크로소프트의 Azure SDK를 쓰기 때문에, 고급 Azure 인증까지 포함한 MS 자바 스택에서 가장 잘 동작해요. AzureOpenAiChatModel로 대화형, AzureOpenAiStreamingChatModel로 스트리밍에 쓸 수 있어요.
LangChain4j는 OpenAI 채팅 모델을 위한 통합을 세 가지 제공하는데, 이 페이지가 그중 3번이에요.
- OpenAI — OpenAI REST API의 자바 사용자 구현으로, Quarkus·Spring에 잘 맞아요.
- OpenAI Official SDK — 공식 OpenAI 자바 SDK를 사용해요.
- Azure OpenAI — 마이크로소프트의 Azure SDK를 쓰고, 고급 Azure 인증을 포함한 MS 자바 스택에서 가장 잘 동작해요.
Azure OpenAI는 Azure OpenAI Java SDK를 사용해 OpenAI의 언어 모델(gpt-4, gpt-4o 등)을 Azure에 호스팅해서 제공해요.
출처: 공식문서
Azure OpenAI 문서
Maven 의존성
Plain Java
langchain4j-azure-open-ai 라이브러리는 Maven Central에 있어요.
<dependency>
<groupId>dev.langchain4j</groupId>
<artifactId>langchain4j-azure-open-ai</artifactId>
<version>1.20.0</version>
</dependency>
Spring Boot
langchain4j-azure-open-ai 라이브러리를 더 쉽게 구성할 수 있는 Spring Boot starter가 있어요.
<dependency>
<groupId>dev.langchain4j</groupId>
<artifactId>langchain4j-azure-open-ai-spring-boot4-starter</artifactId>
<version>1.20.0-beta30</version>
</dependency>
:::note
이 starter는 Spring Boot 4가 필요해요. Spring Boot 3에서는 langchain4j-azure-open-ai-spring-boot-starter를 쓰면 되고, 자세한 건 Spring Boot Integration 문서를 참고하세요.
:::
:::note Azure OpenAI 모델을 쓰기 전에 먼저 배포(deploy)해야 해요. :::
API 키로 AzureOpenAiChatModel 만들기
Plain Java
ChatModel model = AzureOpenAiChatModel.builder()
.endpoint(System.getenv("AZURE_OPENAI_URL"))
.apiKey(System.getenv("AZURE_OPENAI_KEY"))
.deploymentName("gpt-4o")
...
.build();
이 코드는 지정한 엔드포인트·API 키·배포 이름을 가진 AzureOpenAiChatModel 인스턴스를 만들어요. 다른 파라미터는 빌더에 값을 넣어 커스터마이즈할 수 있어요.
Spring Boot
application.properties에 추가해요:
langchain4j.azure-open-ai.chat-model.endpoint=${AZURE_OPENAI_URL}
langchain4j.azure-open-ai.chat-model.service-version=...
langchain4j.azure-open-ai.chat-model.api-key=${AZURE_OPENAI_KEY}
langchain4j.azure-open-ai.chat-model.non-azure-api-key=${OPENAI_API_KEY}
langchain4j.azure-open-ai.chat-model.deployment-name=gpt-4o
langchain4j.azure-open-ai.chat-model.max-completion-tokens=...
langchain4j.azure-open-ai.chat-model.max-tokens=...
langchain4j.azure-open-ai.chat-model.temperature=...
langchain4j.azure-open-ai.chat-model.top-p=
langchain4j.azure-open-ai.chat-model.logit-bias=...
langchain4j.azure-open-ai.chat-model.user=
langchain4j.azure-open-ai.chat-model.stop=...
langchain4j.azure-open-ai.chat-model.presence-penalty=...
langchain4j.azure-open-ai.chat-model.frequency-penalty=...
langchain4j.azure-open-ai.chat-model.seed=...
langchain4j.azure-open-ai.chat-model.strict-json-schema=...
langchain4j.azure-open-ai.chat-model.timeout=...
langchain4j.azure-open-ai.chat-model.max-retries=...
langchain4j.azure-open-ai.chat-model.log-requests-and-responses=...
langchain4j.azure-open-ai.chat-model.user-agent-suffix=
langchain4j.azure-open-ai.chat-model.custom-headers=...
langchain4j.azure-open-ai.chat-model.reasoningEffort=...
위 파라미터 중 일부의 설명은 여기에서 볼 수 있어요.
이 설정은 AzureOpenAiChatModel 빈(bean)(기본 모델 파라미터 사용)을 만들어 줘서, AI Service로 쓰거나 필요할 때 주입해서 쓸 수 있어요. 예를 들면:
@RestController
class ChatModelController {
ChatModel chatModel;
ChatModelController(ChatModel chatModel) {
this.chatModel = chatModel;
}
@GetMapping("/model")
public String model(@RequestParam(value = "message", defaultValue = "Hello") String message) {
return chatModel.chat(message);
}
}
Azure 자격 증명(Credentials)으로 AzureOpenAiChatModel 만들기
API 키는 보안 문제가 있을 수 있어요(커밋되거나 유출될 수 있고 등). 보안을 개선하고 싶다면 Azure Credentials를 쓰는 걸 권장해요. 그러려면 프로젝트에 azure-identity 의존성을 추가해야 해요.
<dependency>
<groupId>com.azure</groupId>
<artifactId>azure-identity</artifactId>
<scope>compile</scope>
</dependency>
그런 다음 DefaultAzureCredentialBuilder API로 AzureOpenAiChatModel을 만들 수 있어요.
ChatModel model = AzureOpenAiChatModel.builder()
.deploymentName("gpt-4o")
.endpoint(System.getenv("AZURE_OPENAI_URL"))
.tokenCredential(new DefaultAzureCredentialBuilder().build())
.build();
:::note Managed Identities로 모델을 배포해야 해요. 자세한 내용은 Azure CLI deployment script를 참고하세요. :::
Tools (툴)
Tools("Function Calling"이라고도 함)는 모델이 자바 코드 안의 메서드를 호출하게 해주고, 병렬 툴 호출도 지원해요. "Function Calling"은 OpenAI 문서에 여기에 설명돼 있어요.
:::note LangChain4j에서 "Function Calling"을 쓰는 완전한 튜토리얼은 여기 있어요. :::
함수는 ToolSpecification 클래스로 지정하거나, 더 간단하게 @Tool 애노테이션으로 지정할 수 있어요. 다음 예시를 볼게요:
class StockPriceService {
private Logger log = Logger.getLogger(StockPriceService.class.getName());
@Tool("Get the stock price of a company by its ticker")
public double getStockPrice(@P("Company ticker") String ticker) {
log.info("Getting stock price for " + ticker);
if (Objects.equals(ticker, "MSFT")) {
return 400.0;
} else {
return 0.0;
}
}
}
그런 다음 AI Assistant에서 StockPriceService를 이렇게 쓸 수 있어요:
interface Assistant {
String chat(String userMessage);
}
public class Demo {
String functionCalling(Model model) {
String question = "Is the current Microsoft stock higher than $450?";
StockPriceService stockPriceService = new StockPriceService();
Assistant assistant = AiServices.builder(Assistant.class)
.chatModel(model)
.tools(stockPriceService)
.build();
String answer = assistant.chat(question);
model.addAttribute("answer", answer);
return "demo";
}
}
Structured Outputs (구조화된 출력)
Structured Outputs는 모델의 응답이 JSON schema를 따르도록 보장해요.
:::note LangChain4j에서 Structured Outputs를 쓰는 문서는 여기 있고, 아래 섹션에서 Azure OpenAI 전용 정보를 볼 수 있어요. :::
JSON Schema 준수를 강제하려면 모델을 strictJsonSchema 파라미터를 true로 설정해 구성해야 해요:
ChatModel model = AzureOpenAiChatModel.builder()
.endpoint(System.getenv("AZURE_OPENAI_URL"))
.apiKey(System.getenv("AZURE_OPENAI_KEY"))
.deploymentName("gpt-4o")
.strictJsonSchema(true)
.supportedCapabilities(Set.of(RESPONSE_FORMAT_JSON_SCHEMA))
.build();
:::note
strictJsonSchema가 false이고 JSON Schema를 제공하면 모델은 여전히 스키마를 따르는 응답을 만들려고 하지만, 응답이 스키마를 따르지 않아도 실패하지는 않아요. 이렇게 하는 한 가지 이유는 성능 향상이에요.
:::
그런 다음 이 모델을 고수준 Assistant API나 저수준 ChatModel API 어느 쪽과도 쓸 수 있어요(아래 자세히 설명). 고수준 Assistant API와 쓸 때 supportedCapabilities(Set.of(RESPONSE_FORMAT_JSON_SCHEMA))를 구성해서 JSON schema로 구조화된 출력을 켜세요.
고수준 Assistant API 사용
이전 섹션의 Tools처럼, Structured Output도 AI Assistant로 자동 사용할 수 있어요.
interface PersonAssistant {
Person extractPerson(String message);
}
class Person {
private final String name;
private final List<String> favouriteColors;
public Person(String name, List<String> favouriteColors) {
this.name = name;
this.favouriteColors = favouriteColors;
}
public String getName() {
return name;
}
public List<String> getFavouriteColors() {
return favouriteColors;
}
}
이 Assistant는 응답이 Person 클래스에 대응하는 JSON schema를 따르게 해요. 다음 예시처럼요:
String question = "Julien likes the colors blue, white and red";
PersonAssistant assistant = AiServices.builder(PersonAssistant.class)
.chatModel(chatModel)
.build();
Person person = assistant.extractPerson(question);
저수준 ChatModel API 사용
고수준 API와 비슷한 과정인데, 이번에는 JSON schema를 수동으로 구성하고 JSON 응답을 자바 객체로 매핑해야 해요.
모델이 구성되면 JSON Schema는 요청마다 ChatRequest 객체에 지정해야 해요. 그러면 모델이 스키마를 따르는 응답을 만들어요. 다음 예시를 볼게요:
ChatRequest chatRequest = ChatRequest.builder()
.messages(UserMessage.from("Julien likes the colors blue, white and red"))
.responseFormat(ResponseFormat.builder()
.type(JSON)
.jsonSchema(JsonSchema.builder()
.name("Person")
.rootElement(JsonObjectSchema.builder()
.addStringProperty("name")
.addProperty("favouriteColors", JsonArraySchema.builder()
.items(new JsonStringSchema())
.build())
.required("name", "favouriteColors")
.build())
.build())
.build()
.build();
String answer = chatModel.chat(chatRequest).aiMessage().text();
이 예시에서 answer는 다음과 같아요.
{
"name": "Julien",
"favouriteColors": ["blue", "white", "red"]
}
이 JSON 응답은 보통 Jackson 같은 라이브러리로 자바 객체에 역직렬화(deserialize)돼요.
결과를 스트리밍하는 AzureOpenAiStreamingChatModel 만들기
이 구현은 위 AzureOpenAiChatModel과 비슷하지만, 응답을 토큰 단위로 스트리밍해요.
Plain Java
StreamingChatModel model = AzureOpenAiStreamingChatModel.builder()
.endpoint(System.getenv("AZURE_OPENAI_URL"))
.apiKey(System.getenv("AZURE_OPENAI_KEY"))
.deploymentName("gpt-4o")
...
.build();
Spring Boot
application.properties에 추가해요:
langchain4j.azure-open-ai.streaming-chat-model.endpoint=${AZURE_OPENAI_URL}
langchain4j.azure-open-ai.streaming-chat-model.service-version=...
langchain4j.azure-open-ai.streaming-chat-model.api-key=${AZURE_OPENAI_KEY}
langchain4j.azure-open-ai.streaming-chat-model.deployment-name=gpt-4o
langchain4j.azure-open-ai.streaming-chat-model.max-completion-tokens=...
langchain4j.azure-open-ai.streaming-chat-model.max-tokens=...
langchain4j.azure-open-ai.streaming-chat-model.temperature=...
langchain4j.azure-open-ai.streaming-chat-model.top-p=...
langchain4j.azure-open-ai.streaming-chat-model.logit-bias=...
langchain4j.azure-open-ai.streaming-chat-model.user=...
langchain4j.azure-open-ai.streaming-chat-model.stop=...
langchain4j.azure-open-ai.streaming-chat-model.presence-penalty=...
langchain4j.azure-open-ai.streaming-chat-model.frequency-penalty=...
langchain4j.azure-open-ai.streaming-chat-model.seed=...
langchain4j.azure-open-ai.streaming-chat-model.timeout=...
langchain4j.azure-open-ai.streaming-chat-model.max-retries=...
langchain4j.azure-open-ai.streaming-chat-model.log-requests-and-responses=...
langchain4j.azure-open-ai.streaming-chat-model.user-agent-suffix=...
langchain4j.azure-open-ai.streaming-chat-model.customHeaders=...
langchain4j.azure-open-ai.streaming-chat-model.reasoningEffort=...
오디오 전사 (Audio Transcription)
Azure OpenAI는 이제 오디오 전사를 지원해서, Azure에 호스팅된 최신 모델로 오디오 파일의 음성 언어를 텍스트로 바꿀 수 있어요.
Maven 의존성
오디오 전사 기능은 메인 langchain4j-azure-open-ai 패키지에 들어 있어요.
<dependency>
<groupId>dev.langchain4j</groupId>
<artifactId>langchain4j-azure-open-ai</artifactId>
<version>1.20.0</version>
</dependency>
Plain Java 사용법
AzureOpenAiAudioTranscriptionModel로 오디오 파일을 전사할 수 있어요.
import dev.langchain4j.data.audio.Audio;
import dev.langchain4j.model.audio.AudioTranscriptionRequest;
import dev.langchain4j.model.audio.AudioTranscriptionResponse;
import java.io.File;
import java.nio.file.Files;
AzureOpenAiAudioTranscriptionModel model = AzureOpenAiAudioTranscriptionModel.builder()
.endpoint(System.getenv("AZURE_OPENAI_URL"))
.apiKey(System.getenv("AZURE_OPENAI_KEY"))
.deploymentName("your-audio-model-deployment-name") // e.g., "whisper"
.build();
// Read audio file as binary data
File audioFile = new File("path/to/audio-file.wav");
byte[] audioData = Files.readAllBytes(audioFile.toPath());
// Create Audio object with binary data
Audio audio = Audio.builder()
.binaryData(audioData)
.build();
// Create transcription request
AudioTranscriptionRequest request = AudioTranscriptionRequest.builder()
.audio(audio)
.prompt("This is an audio file containing ...") // optional
.language("en") // optional
.temperature(0.0) // optional
.build();
// Transcribe audio
AudioTranscriptionResponse response = model.transcribe(request);
String transcript = response.text();
System.out.println(transcript);
주의사항 (Notes)
- 배포: Azure OpenAI 리소스에 오디오 전사 모델(예: Whisper)을 배포해야 해요. 자세한 내용은 Azure OpenAI 문서를 참고하세요.
- 지원 형식: WAV, MP3, FLAC 같은 일반적인 오디오 형식을 지원해요.
- 할당량과 가격: 오디오 전사는 Azure 구독의 리소스를 소비해요. Azure 포털에서 적용 가능한 할당량과 가격을 확인하세요.