채팅 완성(Chat completion)

채팅 완성(Chat completion)

채팅 완성(chat completion) 을 쓰면 AI 에이전트와 주고받는 대화를 시뮬레이션할 수 있어요. 당연히 채팅 봇을 만드는 데 유용하지만, 비즈니스 프로세스를 완료하거나 코드를 생성하는 자율 에이전트를 만드는 데도 쓰이죠. OpenAI·Google·Mistral·Amazon 등이 제공하는 대표적인 모델 유형답게, Semantic Kernel 프로젝트에 붙이는 AI 서비스 중에서도 가장 흔한 것이 바로 채팅 완성이에요.

출처: 공식문서

모델 고르기 전에 확인할 것

채팅 완성 모델을 고를 때는 네 가지를 따져 봐야 해요.

  • 모델이 지원하는 모달리티는 무엇인가 (예: 텍스트, 이미지, 오디오 등)?
  • 함수 호출(function calling) 을 지원하는가?
  • 토큰을 얼마나 빠르게 받고 생성하는가?
  • 토큰당 비용은 얼마인가?

이 중에서도 가장 중요한 것은 함수 호출 지원 여부예요. 지원하지 않으면 모델로 기존 코드를 호출할 수 없거든요. OpenAI·Google·Mistral·Amazon의 최신 모델은 대부분 함수 호출을 지원하지만, 소형 언어 모델의 지원은 아직 제한적이에요.

로컬 환경 준비하기

클라우드 서비스(Azure OpenAI·OpenAI·Mistral·Google·Hugging Face·Azure AI Inference·Anthropic·Amazon Bedrock)는 로컬 설정이 필요 없습니다. 로컬 호스팅이 가능한 건 Ollama와 ONNX예요. Ollama를 Docker로 띄우려면 이렇게 합니다(CPU용, GPU는 --gpus=all 추가).

docker run -d -v "c:\temp\ollama:/root/.ollama" -p 11434:11434 --name ollama ollama/ollama

컨테이너 터미널에서 필요한 모델을 내려받아요. 여기서는 phi3를 받고 있어요.

ollama pull phi3

ONNX는 모델 저장소를 클론합니다.

git clone https://huggingface.co/microsoft/Phi-3-mini-4k-instruct-onnx

필요한 패키지 설치하기

C# 프로바이더별 패키지는 이렇습니다.

  • Azure OpenAI: Microsoft.SemanticKernel.Connectors.AzureOpenAI
  • OpenAI: Microsoft.SemanticKernel.Connectors.OpenAI
  • Mistral: Microsoft.SemanticKernel.Connectors.MistralAI --prerelease
  • Google: Microsoft.SemanticKernel.Connectors.Google --prerelease
  • Hugging Face: Microsoft.SemanticKernel.Connectors.HuggingFace --prerelease
  • Azure AI Inference: Microsoft.SemanticKernel.Connectors.AzureAIInference --prerelease
  • Ollama: Microsoft.SemanticKernel.Connectors.Ollama --prerelease
  • Anthropic: Microsoft.SemanticKernel.Connectors.Amazon --prerelease (Anthropic 모델은 Amazon Bedrock 플랫폼에서 제공돼요)
  • Amazon Bedrock: Microsoft.SemanticKernel.Connectors.Amazon --prerelease
  • ONNX: Microsoft.SemanticKernel.Connectors.Onnx --prerelease

설치 예시(Azure OpenAI):

dotnet add package Microsoft.SemanticKernel.Connectors.AzureOpenAI

OpenAI 채팅 완성 API를 지원하는 다른 서비스(예: LLM Studio)라면 OpenAI 커넥터를 그대로 쓸 수 있어요.

채팅 완성 서비스 만들기

C#과 Python 두 SDK의 패턴을 함께 볼게요. 서비스를 만드는 방법은 크게 커넬에 직접 추가, 의존성 주입으로 등록, 독립 인스턴스 생성 세 가지예요.

커넬에 직접 추가하기 (C#)

AddAzureOpenAIChatCompletion 같은 확장 메서드로 커넬의 내부 서비스 프로바이더에 추가합니다.

Azure OpenAI 예시:

using Microsoft.SemanticKernel;

IKernelBuilder kernelBuilder = Kernel.CreateBuilder();
kernelBuilder.AddAzureOpenAIChatCompletion(
    deploymentName: "NAME_OF_YOUR_DEPLOYMENT",
    apiKey: ***
    endpoint: "YOUR_AZURE_ENDPOINT",
    modelId: "gpt-4", // Optional name of the underlying model if the deployment name doesn't match the model name
    serviceId: "YOUR_SERVICE_ID", // Optional; for targeting specific services within Semantic Kernel
    httpClient: new HttpClient() // Optional; if not provided, the HttpClient from the kernel will be used
);
Kernel kernel = kernelBuilder.Build();

OpenAI 예시:

using Microsoft.SemanticKernel;

IKernelBuilder kernelBuilder = Kernel.CreateBuilder();
kernelBuilder.AddOpenAIChatCompletion(
    modelId: "gpt-4",
    apiKey: ***
    orgId: "YOUR_ORG_ID", // Optional
    serviceId: "YOUR_SERVICE_ID", // Optional; for targeting specific services within Semantic Kernel
    httpClient: new HttpClient() // Optional; if not provided, the HttpClient from the kernel will be used
);
Kernel kernel = kernelBuilder.Build();

확장 메서드 이름은 프로바이더마다 다르지만 받는 인자(배포명·모델명·엔드포인트·apiKey·serviceId 등)는 비슷해요. Mistral은 AddMistralChatCompletion, Google은 AddGoogleAIGeminiChatCompletion, Hugging Face는 AddHuggingFaceChatCompletion, Azure AI Inference는 AddAzureAIInferenceChatCompletion, Ollama는 AddOllamaChatCompletion, Anthropic/Amazon Bedrock은 AddBedrockChatCompletionService, ONNX는 AddOnnxRuntimeGenAIChatCompletion이에요.

실험(experimental) 커넥터(Mistral·Google·Hugging Face·Azure AI Inference·Ollama·Bedrock·ONNX)는 #pragma warning disable SKEXP0070이 필요하고, OpenAI 커넥터에 커스텀 엔드포인트를 쓸 때는 SKEXP0010이 필요해요.

의존성 주입으로 등록하기 (C#)

의존성 주입 환경이라면 AI 서비스를 서비스 프로바이더에 직접 등록하는 게 좋아요. AI 서비스의 싱글턴을 만들어 일시적(transient) 커넬들에서 재사용하려는 경우에 특히 유용하죠.

using Microsoft.SemanticKernel;

var builder = Host.CreateApplicationBuilder(args);

builder.Services.AddAzureOpenAIChatCompletion(
    deploymentName: "NAME_OF_YOUR_DEPLOYMENT",
    apiKey: ***
    endpoint: "YOUR_AZURE_ENDPOINT",
    modelId: "gpt-4", // Optional name of the underlying model if the deployment name doesn't match the model name
    serviceId: "YOUR_SERVICE_ID" // Optional; for targeting specific services within Semantic Kernel
);

builder.Services.AddTransient((serviceProvider)=> {
    return new Kernel(serviceProvider);
});

독립 인스턴스 만들기 (C#)

서비스 인스턴스를 직접 만들어, 나중에 커넬에 넣거나 코드에서 곧바로 사용할 수도 있어요.

using Microsoft.SemanticKernel.Connectors.OpenAI;

OpenAIChatCompletionService chatCompletionService = new (
    modelId: "gpt-4",
    apiKey: ***
    organization: "YOUR_ORG_ID", // Optional
    endpoint: new Uri("YOUR_ENDPOINT"), // Used to point to your service
    httpClient: new HttpClient() // Optional; if not provided, the HttpClient from the kernel will be used
);

Ollama는 OllamaApiClient를 확장 메서드로 서비스로 변환해요.

using Microsoft.SemanticKernel.ChatCompletion;
using OllamaSharp;

#pragma warning disable SKEXP0070
using var ollamaClient = new OllamaApiClient(
    uriString: "YOUR_ENDPOINT"    // E.g. "http://localhost:11434" if Ollama has been started in docker as described above.
    defaultModel: "NAME_OF_MODEL" // E.g. "phi3" if phi3 was downloaded as described above.
);

IChatCompletionService chatCompletionService = ollamaClient.AsChatCompletionService();

Python으로 만들기

Python은 먼저 프로바이더별 패키지를 설치해요. Azure OpenAI(AzureChatCompletion)와 OpenAI(OpenAIChatCompletion)는 semantic-kernel 패키지에 기본 포함돼 있어 추가 설치가 필요 없고, 나머지는 이렇게 설치합니다.

pip install semantic-kernel[azure]      # Azure AI Inference
pip install semantic-kernel[anthropic]  # Anthropic
pip install semantic-kernel[aws]        # Amazon Bedrock
pip install semantic-kernel[google]     # Google AI / Vertex AI
pip install semantic-kernel[mistralai]
pip install semantic-kernel[ollama]
pip install semantic-kernel[onnx]

AI 서비스에 필요한 정보(api_key·endpoint 등)는 생성자에 직접 넘기거나, 환경변수를 설정하거나, 프로젝트에 .env 파일을 만들어 채울 수 있어요. 각 프로바이더가 요구하는 환경변수 전체 목록은 python/samples/concepts/setup/ALL_SETTINGS.md에서 찾을 수 있어요.

Azure OpenAI 예시:

from semantic_kernel.connectors.ai.open_ai import AzureChatCompletion

chat_completion_service = AzureChatCompletion(
    deployment_name="my-deployment",  
    api_key="my-api-key",
    endpoint="my-api-endpoint", # Used to point to your service
    service_id="my-service-id", # Optional; for targeting specific services within Semantic Kernel
)

# You can do the following if you have set the necessary environment variables or created a .env file
chat_completion_service = AzureChatCompletion(service_id="my-service-id")

참고) AzureChatCompletionAzureAIInferenceChatCompletion은 API 키 없이도 Microsoft Entra 인증을 지원해요. API 키를 안 주면 Entra 토큰으로 인증을 시도합니다.

주의할 점 하나 — OpenAIChatCompletion, AzureChatCompletion, AzureAIInferenceChatCompletioninstruction_role 키워드 인자를 설정할 수 있어요. 시스템 지시를 모델에 어떻게 전달할지 제어하는 인자로 "system" 또는 "developer"를 받아요. reasoning 모델을 쓸 때는 instruction_role="developer" 설정해야 하며, ChatHistory 안의 system 역할 메시지는 모델에 요청을 보내기 전에 자동으로 developer 역할로 매핑돼요.

다른 프로바이더도 패턴은 비슷해요. AnthropicChatCompletion, BedrockChatCompletion, GoogleAIChatCompletion, VertexAIChatCompletion, MistralAIChatCompletion, OllamaChatCompletion, OnnxGenAIChatCompletion 식으로 가져와 생성하면 돼요. Amazon Bedrock은 API 키를 받지 않으니 환경 설정 가이드를, Google의 Gemini 모델은 Google AI Studio 또는 Vertex 플랫폼으로 접근하니 README 가이드를 참고하세요.

만든 서비스는 즉시 쓸 수도 있고, 커넬에 추가할 수도 있어요.

from semantic_kernel import Kernel

# Initialize the kernel
kernel = Kernel()

# Add the chat completion service created above to the kernel
kernel.add_service(chat_completion_service)

Java로 만들기

Java에서는 클라이언트를 먼저 만들고, 빌더로 서비스를 생성한 뒤 커넬에 등록해요.

import com.azure.ai.openai.OpenAIAsyncClient;
import com.azure.ai.openai.OpenAIClientBuilder;
import com.microsoft.semantickernel.Kernel;
import com.microsoft.semantickernel.services.chatcompletion.ChatCompletionService;

// Create the client
OpenAIAsyncClient client = new OpenAIClientBuilder()
    .credential(openAIClientCredentials)
    .buildAsyncClient();

// Create the chat completion service
ChatCompletionService openAIChatCompletion = OpenAIChatCompletion.builder()
    .withOpenAIAsyncClient(client)
    .withModelId(modelId)
    .build();

// Initialize the kernel
Kernel kernel = Kernel.builder()
    .withAIService(ChatCompletionService.class, openAIChatCompletion)
    .build();

채팅 완성 서비스 가져오기

커넬에 서비스를 추가했다면 get service 메서드로 꺼내 쓸 수 있어요.

  • C#: var chatCompletionService = kernel.GetRequiredService<IChatCompletionService>();
  • Python: chat_completion_service = kernel.get_service(type=ChatCompletionClientBase) (또는 service_id="my-service-id"로 가져옴). kernel.get_prompt_execution_settings_from_service_id("my-service-id")로 기본 inference 설정도 얻을 수 있어요.
  • Java: ChatCompletionService chatCompletionService = kernel.getService(ChatCompletionService.class);

커넬 안의 다른 서비스가 필요 없다면 굳이 커넬에 추가하지 않고 코드에서 직접 사용해도 괜찮아요.

채팅 완성 서비스 사용하기

채팅 완성 서비스로 답변을 생성하는 방식은 크게 두 가지예요.

  • 비스트리밍(Non-streaming): 서비스가 전체 응답을 생성한 뒤 사용자에게 돌려줘요.
  • 스트리밍(Streaming): 응답 조각(chunk)이 생성되는 대로 사용자에게 전달돼요.

참고) Python에서 커넬에 서비스를 등록하지 않았다면, 쓰기 전에 실행 설정(execution settings) 인스턴스를 직접 만들어야 해요. OpenAIChatPromptExecutionSettings처럼 각 프로바이더별 *ChatPromptExecutionSettings 클래스를 import 하면 됩니다. 실행 설정에서 뭘 바꿀 수 있는지는 소스 코드나 API 문서에서 확인할 수 있어요.

비스트리밍

C#:

ChatHistory history = [];
history.AddUserMessage("Hello, how are you?");

var response = await chatCompletionService.GetChatMessageContentAsync(
    history,
    kernel: kernel
);

Python:

chat_history = ChatHistory()
chat_history.add_user_message("Hello, how are you?")

response = await chat_completion_service.get_chat_message_content(
    chat_history=history,
    settings=execution_settings,
)

Java:

ChatHistory history = new ChatHistory();
history.addUserMessage("Hello, how are you?");

InvocationContext optionalInvocationContext = null;

List<ChatMessageContent<?>> response = chatCompletionService.getChatMessageContentsAsync(
    history,
    kernel,
    optionalInvocationContext
);

스트리밍

C#:

ChatHistory history = [];
history.AddUserMessage("Hello, how are you?");

var response = chatCompletionService.GetStreamingChatMessageContentsAsync(
    chatHistory: history,
    kernel: kernel
);

await foreach (var chunk in response)
{
    Console.Write(chunk);
}

Python:

chat_history = ChatHistory()
chat_history.add_user_message("Hello, how are you?")

response = chat_completion_service.get_streaming_chat_message_content(
    chat_history=history,
    settings=execution_settings,
)

async for chunk in response:
    print(chunk, end="")

참고) Java용 Semantic Kernel은 스트리밍 응답 모델을 지원하지 않아요.

다음 단계

더 알아보기 (Learn more)