Semantic Kernel 커널 이해하기
Semantic Kernel 커널 이해하기
출처: 공식문서
커널(kernel)은 Semantic Kernel의 중심 컴포넌트예요. 가장 단순하게 말하면, 커널은 AI 애플리케이션을 실행하는 데 필요한 모든 서비스와 플러그인을 관리하는 의존성 주입(Dependency Injection) 컨테이너예요. 모든 서비스와 플러그인을 커널에 제공하면, AI가 필요할 때 그대로 사용할 수 있어요.
커널이 중심에 있다
커널은 네이티브 코드와 AI 서비스를 실행하는 데 필요한 모든 서비스와 플러그인을 갖고 있기 때문에, Semantic Kernel SDK의 거의 모든 컴포넌트가 에이전트를 구동할 때 커널을 사용해요. 즉 Semantic Kernel에서 어떤 프롬프트나 코드를 실행하더라도, 커널은 항상 필요한 서비스와 플러그인을 꺼내 쓸 수 있게 준비돼 있어요.

이것은 매우 강력한데, 개발자가 AI 에이전트를 설정하고, 무엇보다 모니터링하는 단일 지점을 갖게 되기 때문이에요. 예를 들어 커널에서 프롬프트를 호출한다고 해 볼게요. 그럴 때 커널은...
- 프롬프트를 실행할 최적의 AI 서비스를 선택해요.
- 주어진 프롬프트 템플릿으로 프롬프트를 구성해요.
- 프롬프트를 AI 서비스에 보내요.
- 응답을 받아 파싱해요.
- 마지막으로 LLM의 응답을 애플리케이션에 반환해요.
이 전체 과정에서 각 단계마다 트리거되는 이벤트와 미들웨어를 만들 수 있어요. 로깅을 수행하거나, 사용자에게 상태 업데이트를 제공하거나, 무엇보다 책임 있는 AI(responsible AI)를 위한 동작을 하는 식이에요. 이 모든 걸 단일 지점에서 처리할 수 있어요.
서비스와 플러그인으로 커널 구성하기
커널을 구성하기 전에, 먼저 존재하는 두 가지 유형의 컴포넌트를 이해해야 해요.
| 컴포넌트 | 설명 |
|---|---|
| 서비스(Services) | AI 서비스(예: 채팅 완성)와 애플리케이션 실행에 필요한 기타 서비스(예: 로깅, HTTP 클라이언트)로 구성돼 있어요. 모든 언어에서 의존성 주입을 지원하도록 .NET의 Service Provider 패턴을 본떠 모델링했어요. |
| 플러그인(Plugins) | AI 서비스와 프롬프트 템플릿이 작업을 수행할 때 사용하는 컴포넌트예요. 예를 들어 AI 서비스는 플러그인을 사용해 데이터베이스에서 데이터를 조회하거나, 외부 API를 호출해 작업을 수행할 수 있어요. |
::: zone pivot="programming-language-csharp" 커널을 만들기 시작하려면 파일 상단에서 필요한 패키지를 가져와요.
:::code language="csharp" source="~/../semantic-kernel-samples/dotnet/samples/LearnResources/MicrosoftLearn/UsingTheKernel.cs" id="NecessaryPackages":::
다음으로 서비스와 플러그인을 추가할 수 있어요. 아래는 Azure OpenAI 채팅 완성, 로거, 시간 플러그인을 추가하는 예시예요.
// Create a kernel with a logger and Azure OpenAI chat completion service
var builder = Kernel.CreateBuilder();
builder.AddAzureOpenAIChatCompletion(modelId, endpoint, apiKey);
builder.Services.AddLogging(c => c.AddDebug().SetMinimumLevel(LogLevel.Trace));
builder.Plugins.AddFromType<TimePlugin>();
Kernel kernel = builder.Build();
::: zone-end
::: zone pivot="programming-language-python" 필요한 패키지를 가져와요.
from semantic_kernel import Kernel
from semantic_kernel.connectors.ai.open_ai import AzureChatCompletion
from semantic_kernel.core_plugins.time_plugin import TimePlugin
다음으로 커널을 만들 수 있어요.
# Initialize the kernel
kernel = Kernel()
마지막으로 필요한 서비스와 플러그인을 추가할 수 있어요. 아래는 Azure OpenAI 채팅 완성, 로거, 시간 플러그인을 추가하는 예시예요.
# Add the Azure OpenAI chat completion service
kernel.add_service(AzureChatCompletion(model_id, endpoint, api_key))
# Add a plugin
kernel.add_plugin(
TimePlugin(),
plugin_name="TimePlugin",
)
커널에서 MCP 서버 만들기
이제 Semantic Kernel 인스턴스에 등록한 함수에서 MCP 서버를 만드는 것을 지원해요.
이렇게 하려면 평소처럼 커널을 만든 다음,そこ에서 MCP 서버를 만들면 돼요.
from semantic_kernel import Kernel
from semantic_kernel.connectors.ai.open_ai import OpenAIChatCompletion
from semantic_kernel.functions import kernel_function
from semantic_kernel.prompt_template import InputVariable, PromptTemplateConfig
kernel = Kernel()
@kernel_function()
def echo_function(message: str, extra: str = "") -> str:
"""Echo a message as a function"""
return f"Function echo: {message} {extra}"
kernel.add_service(OpenAIChatCompletion(service_id="default"))
kernel.add_function("echo", echo_function, "echo_function")
kernel.add_function(
plugin_name="prompt",
function_name="prompt",
prompt_template_config=PromptTemplateConfig(
name="prompt",
description="This is a prompt",
template="Please repeat this: {{$message}} and this: {{$extra}}",
input_variables=[
InputVariable(
name="message",
description="This is the message.",
is_required=True,
json_schema='{ "type": "string", "description": "This is the message."}',
),
InputVariable(
name="extra",
description="This is extra.",
default="default",
is_required=False,
json_schema='{ "type": "string", "description": "This is the message."}',
),
],
),
)
server = kernel.as_mcp_server(server_name="sk")
위에서 만든 server 객체는 mcp 패키지에서 온 것이에요. 리소스나 다른 기능을 추가하는 식으로 더 확장할 수 있어요. 그런 다음 온라인으로 띄워서, 예를 들어 Stdio와 함께 사용할 수 있어요.
import anyio
from mcp.server.stdio import stdio_server
async def handle_stdin(stdin: Any | None = None, stdout: Any | None = None) -> None:
async with stdio_server() as (read_stream, write_stream):
await server.run(read_stream, write_stream, server.create_initialization_options())
anyio.run(handle_stdin)
또는 SSE와 함께 사용할 수 있어요.
import uvicorn
from mcp.server.sse import SseServerTransport
from starlette.applications import Starlette
from starlette.routing import Mount, Route
sse = SseServerTransport("/messages/")
async def handle_sse(request):
async with sse.connect_sse(request.scope, request.receive, request._send) as (read_stream, write_stream):
await server.run(read_stream, write_stream, server.create_initialization_options())
starlette_app = Starlette(
debug=True,
routes=[
Route("/sse", endpoint=handle_sse),
Mount("/messages/", app=sse.handle_post_message),
],
)
uvicorn.run(starlette_app, host="0.0.0.0", port=8000)
프롬프트 템플릿을 MCP 프롬프트로 노출하기
서로 다른 Semantic Kernel 프롬프트 템플릿을 MCP 프롬프트로 노출해서 활용할 수도 있어요. 이렇게 말이죠.
from semantic_kernel.prompt_template import InputVariable, KernelPromptTemplate, PromptTemplateConfig
prompt = KernelPromptTemplate(
prompt_template_config=PromptTemplateConfig(
name="release_notes_prompt",
description="This creates the prompts for a full set of release notes based on the PR messages given.",
template=template,
input_variables=[
InputVariable(
name="messages",
description="These are the PR messages, they are a single string with new lines.",
is_required=True,
json_schema='{"type": "string"}',
)
],
)
)
server = kernel.as_mcp_server(server_name="«redacted:sk_…»", prompts=[prompt])
::: zone-end
::: zone pivot="programming-language-java"
커널 구성하기
커널은 Kernel.builder()를 사용해 만들 수 있어요. 여기에 필요한 AI 서비스와 플러그인을 추가할 수 있어요.
Kernel kernel = Kernel.builder()
.withAIService(ChatCompletionService.class, chatCompletionService)
.withPlugin(lightPlugin)
.build();
::: zone-end
::: zone pivot="programming-language-csharp"
의존성 주입 사용하기
C#에서는 의존성 주입(Dependency Injection)을 사용해 커널을 만들 수 있어요. ServiceCollection을 만들고 거기에 서비스와 플러그인을 추가하는 방식이에요. 아래는 의존성 주입을 사용해 커널을 만드는 예시예요.
[!TIP] 커널은 트랜셔널(transient) 서비스로 만들어 매번 사용 후 폐기하는 걸 권장해요. 플러그인 컬렉션은 변경 가능(mutable)하기 때문이에요. 커널은 (서비스와 플러그인의 컨테이너일 뿐이라) 매우 가벼워서, 매번 새 커널을 만들어도 성능 문제가 되지 않아요.
using Microsoft.SemanticKernel;
var builder = Host.CreateApplicationBuilder(args);
// Add the OpenAI chat completion service as a singleton
builder.Services.AddOpenAIChatCompletion(
modelId: "gpt-4",
apiKey: ***
orgId: "YOUR_ORG_ID", // Optional; for OpenAI deployment
serviceId: "YOUR_SERVICE_ID" // Optional; for targeting specific services within Semantic Kernel
);
// Create singletons of your plugins
builder.Services.AddSingleton(() => new LightsPlugin());
builder.Services.AddSingleton(() => new SpeakerPlugin());
// Create the plugin collection (using the KernelPluginFactory to create plugins from objects)
builder.Services.AddSingleton<KernelPluginCollection>((serviceProvider) =>
[
KernelPluginFactory.CreateFromObject(serviceProvider.GetRequiredService<LightsPlugin>()),
KernelPluginFactory.CreateFromObject(serviceProvider.GetRequiredService<SpeakerPlugin>())
]
);
// Finally, create the Kernel service with the service provider and plugin collection
builder.Services.AddTransient((serviceProvider)=> {
KernelPluginCollection pluginCollection = serviceProvider.GetRequiredService<KernelPluginCollection>();
return new Kernel(serviceProvider, pluginCollection);
});
[!TIP] C#에서 의존성 주입을 사용하는 더 많은 샘플은 개념 샘플을 참고해요.
::: zone-end
::: zone pivot="programming-language-java"
::: zone-end
더 알아보기 (Learn more)
이제 커널을 이해했으니, 커널에 추가할 수 있는 다양한 AI 서비스에 대해 알아볼 수 있어요.