Getting started with Semantic Kernel: a practical guide

open-source入门20 分钟阅读2026/7/11

I was building a content processing tool a few months ago—something that could take raw meeting transcripts, extract action items, and then automatically draft follow-up emails. I started with direct API calls to OpenAI, and within a week, my code was a mess of string concatenation, manual JSON parsing, and fragile prompt templates scattered across a dozen files. Every time I needed to add a new step to the pipeline, I had to wire up another API call, handle another set of errors, and figure out how to pass context between steps.

That's when I stumbled onto Semantic Kernel. Microsoft built it as an orchestration layer—a way to structure how your code talks to AI models without turning your codebase into spaghetti. It gives you a kernel object that manages AI services, a plugin system for organizing your prompts and functions, and planners that can chain multiple steps together automatically. After spending a weekend refactoring my tool with it, I was sold. Let me walk you through getting it set up so you can see for yourself.

Step 1: Install the SDK and Set Up Keys

I work primarily in Python, so I'll focus there, but Semantic Kernel also supports C# and Java. The Python install is straightforward:

pip install semantic-kernel

For C#, it's:

dotnet add package Microsoft.SemanticKernel

Now, you need API keys. Semantic Kernel supports OpenAI and Azure OpenAI out of the box. I use Azure OpenAI in production, but for getting started, regular OpenAI is simpler. Create a .env file in your project root:

OPENAI_API_KEY=sk-your-key-here
OPENAI_ORG_ID=your-org-id-if-applicable

If you're using Azure OpenAI instead, your .env looks different:

AZURE_OPENAI_API_KEY=your-azure-key
AZURE_OPENAI_ENDPOINT=https://your-resource.openai.azure.com
AZURE_OPENAI_CHAT_DEPLOYMENT_NAME=gpt-4

Here's my first mistake: I initially hardcoded my API key directly in the script. It worked, obviously, but when I pushed to GitHub later that day—yeah. I had to rotate the key. Use environment variables from the start. Semantic Kernel can read from .env automatically if you use python-dotenv.

Step 2: Create Your First Kernel and Have a Conversation

The kernel is the core object. It manages your AI services and plugins. Here's how to get a basic back-and-forth conversation going:

import asyncio
from semantic_kernel import Kernel
from semantic_kernel.connectors.ai.open_ai import OpenAIChatCompletion

async def main():
    # Initialize the kernel
    kernel = Kernel()

    # Add an AI service
    kernel.add_service(
        OpenAIChatCompletion(
            service_id="chat",
            ai_model_id="gpt-4o",
        )
    )

    # Simple chat invocation
    from semantic_kernel.contents import ChatHistory
    from semantic_kernel.connectors.ai.chat_completion_client_base import ChatCompletionClientBase

    chat_service = kernel.get_service(type=ChatCompletionClientBase)
    history = ChatHistory()
    history.add_user_message("I have a meeting transcript. Can you help me extract action items?")

    response = await chat_service.get_chat_message_contents(
        chat_history=history,
        settings=chat_service.get_prompt_execution_settings_from_service_id("chat"),
    )

    print(response[0].content)

asyncio.run(main())

When I first ran this, I got an error about missing API keys because I forgot to load my .env file. Add from dotenv import load_dotenv and call load_dotenv() at the top of your script. After that, it worked—GPT-4o responded with a helpful message about extracting action items.

This is fine for a demo, but it's not much better than calling the OpenAI API directly. The real power comes next.

Step 3: Give the AI the Ability to Run Your Code

This is where Semantic Kernel clicked for me. You can write regular Python functions, decorate them, and the AI can call them during a conversation. These are called "native functions" or plugins.

from semantic_kernel.functions import kernel_function

class ActionItemsPlugin:
    @kernel_function(
        description="Extract action items from meeting text",
        name="extract_actions"
    )
    def extract_actions(self, text: str) -> str:
        # In reality, you'd do something more sophisticated here
        # This could hit a database, call another API, etc.
        lines = text.split(".")
        action_items = [line.strip() for line in lines if "need to" in line.lower() or "will" in line.lower()]
        return "\n".join(f"- {item}" for item in action_items)

class EmailPlugin:
    @kernel_function(
        description="Draft a follow-up email based on action items",
        name="draft_email"
    )
    def draft_email(self, action_items: str, recipient: str) -> str:
        return f"Hi {recipient},\n\nHere are the action items from our meeting:\n{action_items}\n\nBest regards"

# Add plugins to the kernel
kernel.add_plugin(ActionItemsPlugin(), plugin_name="actions")
kernel.add_plugin(EmailPlugin(), plugin_name="email")

The @kernel_function decorator is what makes the magic happen. The description parameter tells the AI what the function does. When you enable function calling (also called tool calling), the AI can decide on its own when to invoke these functions based on the user's request.

Here's how to enable that:

from semantic_kernel.connectors.ai.function_choice_behavior import FunctionChoiceBehavior

settings = chat_service.get_prompt_execution_settings_from_service_id("chat")
settings.function_choice_behavior = FunctionChoiceBehavior.Auto()

response = await chat_service.get_chat_message_contents(
    chat_history=history,
    settings=settings,
    kernel=kernel,  # Pass the kernel so it knows about available functions
)

With FunctionChoiceBehavior.Auto(), the AI looks at the available plugin functions, decides which ones to call based on the user's message, and calls them automatically. When I sent "Extract action items from this transcript and draft an email to Sarah," the AI called both extract_actions and draft_email in sequence, passing the output of the first into the second. That's orchestration without me writing any glue code.

Step 4: Watch the AI Create Plans on the Fly

The function calling above handles simple chains. For more complex scenarios, Semantic Kernel has planners. The planner takes a goal and figures out which plugin functions to call, in what order, with what parameters.

I'll be honest—when I first tried the planner, I was skeptical. The idea of an AI deciding which of my functions to run felt risky. But for well-scoped tasks with clear function descriptions, it works surprisingly well.

from semantic_kernel.connectors.ai.open_ai import OpenAIPromptExecutionSettings

# Create a goal
goal = "Take this meeting transcript, extract action items, and draft a follow-up email to the team lead"

# The planner will use the AI to figure out which functions to call
# and in what order to achieve the goal

The newer versions of Semantic Kernel lean heavily into the function calling approach for planning rather than the older Handlebars planner. This is actually better—it's more reliable because the AI is using structured tool calls rather than generating freeform text that gets parsed.

One surprise I hit: the planner sometimes calls functions in a weird order if your descriptions are vague. I had extract_actions described as "process text" and the AI tried to feed raw transcript into the email drafter first. Be specific in your @kernel_function descriptions. They're prompts for the AI, not just documentation for humans.

Practical Tips and Honest Limitations

After using Semantic Kernel for a few months, here's what I've learned:

Be specific with function descriptions. The AI relies entirely on your description to decide when and how to call a function. "Extract action items from meeting text" is way better than "process text." I spent an hour debugging a weird planning failure that was entirely caused by a vague description.

Start with function calling, not planners. The FunctionChoiceBehavior.Auto() approach is more predictable and easier to debug than the full planner. Move to planners only when you have complex multi-step workflows that genuinely need dynamic orchestration.

Test your plugins independently. Write unit tests for your plugin functions just like any other code. The AI layer is a consumer of your functions—if the functions are buggy, the AI will pass buggy results downstream.

Watch your token usage. When function calling is enabled, every function schema gets sent with each request. If you have dozens of plugins with complex parameter types, your token count balloons fast. I hit rate limits sooner than expected because my function definitions were eating up context window space.

The documentation is still catching up. Semantic Kernel is evolving fast, and some tutorials you find online are already outdated. The official Microsoft docs are the best source, but even they lag behind the latest releases. Check the GitHub repo's examples folder for current patterns.

It's not a silver bullet. If you're making simple API calls with no orchestration needs, Semantic Kernel adds complexity without much benefit. I still use raw OpenAI API calls for one-off scripts. Semantic Kernel shines when you have reusable functions, multi-step workflows, and need to swap between different AI providers.

The biggest win for me was the plugin system. Instead of scattering prompts and API calls throughout my codebase, everything is organized into plugins with clear interfaces. When I needed to switch from GPT-4o to a different model for cost reasons, I changed one line—the kernel configuration—and all my plugins kept working. That alone made the learning curve worth it.

相关 Agent

O

OpenClaw

开源 AI Agent 框架,用于构建自主工作流

了解更多 →