Xây dựng Ứng dụng AI với Microsoft Semantic Kernel và Python: Plugins, Memory và Planning cho AI Agent Doanh nghiệp

AI tutorial - IT technology blog
AI tutorial - IT technology blog

Vấn đề với “Cứ Dùng LangChain Đi” trong Môi trường Doanh nghiệp

Hầu hết các hướng dẫn AI đều dẫn bạn thẳng đến LangChain. Tôi cũng vậy — dựng lên một Python service, ghép nối một vài tool, ship lên production rồi tưởng là xong. Sáu tháng sau, một lần bump minor version của LangChain đã phá vỡ một nửa tích hợp của chúng tôi. Code gần như không thể test được, và việc onboard một developer .NET từ team khác cảm giác như đưa cho họ một codebase hoàn toàn xa lạ.

Trải nghiệm đó đẩy tôi đến với Microsoft Semantic Kernel. Đây là SDK mã nguồn mở của Microsoft để xây dựng ứng dụng AI — và sau hơn một năm chạy trong production, tôi có thể nói đây là điều đáng học nếu bạn quan tâm đến độ tin cậy doanh nghiệp. Kiến trúc plugin rõ ràng, hệ thống planning minh bạch, và cùng một SDK chạy được trên Python, .NET và Java. Điểm cuối này quan trọng hơn vẻ ngoài của nó: việc onboard một developer .NET chỉ mất một buổi chiều thay vì cả tuần.

Hướng dẫn này đi qua việc xây dựng một AI agent hoạt động từ đầu — thiết lập kernel, native plugins, semantic plugins, vector memory và auto-invocation planning.

Các Khái niệm Cốt lõi Cần Nắm Trước

Kernel: Container DI cho AI của Bạn

Mọi thứ trong Semantic Kernel đều xoay quanh một đối tượng Kernel. Hãy nghĩ về nó như một dependency injection container — bạn đăng ký kết nối LLM, các plugin và memory store, rồi kernel điều phối tất cả. Thiết kế này giúp unit testing sạch sẽ: thay thế LLM thật bằng mock, chạy test, xong.

Plugins Thay thế Chains

Trong khi LangChain dùng “chains” và “tools,” Semantic Kernel sử dụng plugins. Có hai loại quan trọng:

  • Native plugins: Các hàm Python thông thường được trang trí bằng @kernel_function. Chúng chạy code thật — gọi API, truy vấn database, thực hiện tính toán.
  • Semantic plugins: Các prompt template được lưu dưới dạng text file. Bạn viết prompt, SK xử lý việc gọi LLM. Rất tốt cho các tác vụ ngôn ngữ như tóm tắt hay dịch thuật, và quản lý version sạch sẽ trong Git.

Planning: Auto-Invocation Thực sự Hoạt động

Planner của SK nhận mục tiêu của người dùng và tự xác định cần gọi những plugin nào, theo thứ tự nào. Trong SK 1.x, cách tiếp cận được khuyến nghị sử dụng khả năng gọi tool native của LLM thông qua FunctionChoiceBehavior. So với các thủ thuật chain-of-thought tùy chỉnh mà các framework trước đây dựa vào, nó đáng tin cậy hơn rõ rệt trong thực tế — ít hallucinate tool call hơn, xử lý tốt hơn các yêu cầu nhiều bước.

Thực hành: Xây dựng AI Agent Từng Bước

Cài đặt và Thiết lập

pip install semantic-kernel openai python-dotenv

Tạo file .env:

OPENAI_API_KEY=sk-...
OPENAI_CHAT_MODEL_ID=gpt-4o

Kernel Đầu tiên của Bạn

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

load_dotenv()

async def main():
    kernel = Kernel()
    kernel.add_service(OpenAIChatCompletion())

    result = await kernel.invoke_prompt(
        "Đâu là 3 lợi ích hàng đầu của Kubernetes cho microservices?"
    )
    print(result)

asyncio.run(main())

Chưa thú vị lắm — nhưng kiến trúc nền tảng này sẽ phát huy tác dụng ngay khi bạn thêm plugins.

Xây dựng Native Plugin

Đây là một plugin thực tế mô phỏng việc lấy số liệu server — loại bạn sẽ kết nối với Prometheus hoặc Datadog trong production:

import random
from semantic_kernel.functions import kernel_function

class ServerMetricsPlugin:

    @kernel_function(
        name="get_cpu_usage",
        description="Lấy phần trăm sử dụng CPU hiện tại cho một hostname server"
    )
    def get_cpu_usage(self, hostname: str) -> str:
        # Trong production: truy vấn Prometheus, Datadog, v.v.
        usage = random.uniform(10, 95)
        return f"Server {hostname} sử dụng CPU: {usage:.1f}%"

    @kernel_function(
        name="get_memory_usage",
        description="Lấy phần trăm sử dụng memory hiện tại cho một hostname server"
    )
    def get_memory_usage(self, hostname: str) -> str:
        usage = random.uniform(20, 90)
        return f"Server {hostname} sử dụng memory: {usage:.1f}%"

Kết nối Auto-Invocation Planning

from semantic_kernel import Kernel
from semantic_kernel.connectors.ai.open_ai import (
    OpenAIChatCompletion,
    OpenAIChatPromptExecutionSettings
)
from semantic_kernel.connectors.ai.function_choice_behavior import FunctionChoiceBehavior

async def main():
    kernel = Kernel()
    kernel.add_service(OpenAIChatCompletion())
    kernel.add_plugin(ServerMetricsPlugin(), plugin_name="ServerMetrics")

    settings = OpenAIChatPromptExecutionSettings(
        function_choice_behavior=FunctionChoiceBehavior.Auto()
    )

    result = await kernel.invoke_prompt(
        "Kiểm tra CPU và memory cho web-server-01. Đánh dấu bất kỳ điều gì đáng lo ngại.",
        settings=settings
    )
    print(result)

asyncio.run(main())

Phía sau, kernel tự xác định rằng nó cần cả get_cpu_usage lẫn get_memory_usage, gọi cả hai, rồi chuyển kết quả cho LLM để phân tích. Không cần chain thủ công. Không có định nghĩa chuỗi dễ vỡ.

Thêm Memory với Vector Search

Tầng memory của Semantic Kernel hoạt động với Qdrant, Pinecone, Azure AI Search và nhiều hơn nữa. Để prototyping, in-memory volatile store giúp bạn bắt đầu trong vài phút:

from semantic_kernel import Kernel
from semantic_kernel.connectors.ai.open_ai import OpenAIChatCompletion, OpenAITextEmbedding
from semantic_kernel.memory import SemanticTextMemory, VolatileMemoryStore

async def setup_memory():
    kernel = Kernel()
    kernel.add_service(OpenAIChatCompletion(service_id="chat"))
    kernel.add_service(OpenAITextEmbedding(service_id="embedding"))

    memory = SemanticTextMemory(
        storage=VolatileMemoryStore(),
        embeddings_generator=kernel.get_service(service_id="embedding")
    )

    await memory.save_information(
        collection="runbooks",
        id="restart-nginx",
        text="Khởi động lại nginx: 'sudo systemctl restart nginx'. "
             "Kiểm tra trạng thái: 'systemctl status nginx'."
    )

    await memory.save_information(
        collection="runbooks",
        id="disk-full",
        text="Đĩa đầy: kiểm tra với 'df -h', tìm file lớn với "
             "'du -sh /* | sort -rh | head -20', dọn /var/log."
    )

    results = await memory.search("runbooks", "server không khởi động được sau sự cố đĩa đầy")
    for r in results:
        print(f"[{r.relevance:.2f}] {r.text[:80]}...")

asyncio.run(setup_memory())

Sẵn sàng cho production? Thay VolatileMemoryStore bằng Qdrant hoặc Azure AI Search. Interface vẫn giữ nguyên — đó là abstraction đang làm đúng việc của nó.

Semantic Plugins: Prompts trong Version Control

Với các tác vụ ngôn ngữ, semantic plugins lưu prompts dưới dạng file thuần. Các thay đổi prompt hiện ra trong pull request như bất kỳ diff nào khác — có thể review, comment và dễ dàng rollback:

plugins/
  SummaryPlugin/
    SummarizeText/
      skprompt.txt
      config.json

Nội dung của skprompt.txt:

Tóm tắt đoạn văn bản sau trong 2-3 câu, tập trung vào những thông tin có thể hành động:

{{$input}}

Tóm tắt:

Nội dung của config.json:

{
  "schema": 1,
  "description": "Tóm tắt văn bản thành 2-3 câu có thể hành động",
  "execution_settings": {
    "default": {
      "max_tokens": 256,
      "temperature": 0.3
    }
  }
}

Load và gọi nó:

plugin = kernel.add_plugin(
    parent_directory="./plugins",
    plugin_name="SummaryPlugin"
)

result = await kernel.invoke(
    plugin["SummarizeText"],
    input="Nhập báo cáo sự cố hoặc văn bản log dài của bạn vào đây..."
)
print(result)

Semantic Kernel vs LangChain: So sánh Thẳng thắn

Đây không phải cuộc tranh luận về framework nào luôn thắng. Cả hai đều có điểm mạnh thực sự tùy theo ngữ cảnh của bạn:

  • Chọn Semantic Kernel khi bạn đang dùng Azure, team trải dài qua Python và .NET, bạn cần một API surface ổn định qua nhiều quý, hoặc bạn muốn các bước planning rõ ràng cho yêu cầu kiểm toán doanh nghiệp.
  • Tiếp tục dùng LangChain khi bạn cần tích hợp với các vector database thử nghiệm mới nhất, đang prototyping nhanh, hoặc team đã có phiên bản pinned ổn định và chuyên môn sâu.

Azure OpenAI, Azure AI Search, yêu cầu bảo mật doanh nghiệp — SK phù hợp với những tình huống đó tự nhiên hơn hầu hết các lựa chọn thay thế. Unit testing cũng là câu chuyện khác: bạn mock từng plugin riêng lẻ thay vì vật lộn với toàn bộ chain.

Bước Tiếp theo

Những gì bạn vừa xây dựng ở trên là một nền tảng vững chắc, có thể test được — không phải demo, mà là một pattern kiến trúc thực sự có thể mở rộng. Từ đây, ba bước tiếp theo có ý nghĩa. Kết nối một persistent vector store như Qdrant hoặc Azure AI Search cho các tác vụ RAG thực tế. Thêm authentication và rate limiting vào native plugins trước khi đưa bất kỳ thứ gì lên production. Và tìm hiểu về các pattern multi-agent, nơi các kernel riêng biệt chuyển giao công việc cho nhau.

Một khi kiến trúc plugin đã quen thuộc, việc xây dựng các workflow phức tạp trở nên dễ quản lý một cách đáng ngạc nhiên. Debug cũng là một trải nghiệm khác — bạn đang theo dõi từng lần gọi plugin riêng lẻ, không phải gỡ rối một chuỗi đối tượng mờ đục nơi trạng thái đã thay đổi đâu đó ở giữa.

Share: