Hướng dẫn sử dụng Microsoft Semantic Kernel với Python: Xây dựng AI Agent và Native Plugin cho doanh nghiệp

Artificial Intelligence tutorial - IT technology blog
Artificial Intelligence tutorial - IT technology blog

3 hướng đưa LLM vào backend doanh nghiệp: Chọn đường nào?

Nhúng LLM vào ERP, CRM hay hệ thống Helpdesk nội bộ chưa bao giờ đơn giản là gửi một prompt rồi nhận text. Trên thực tế, anh em dev thường cân nhắc giữa 3 phương án:

  • Gọi API trực tiếp (OpenAI SDK / REST): Viết code thô, tự parse JSON schema và tự dựng vòng lặp function calling bằng tay.
  • Dùng LangChain: Ecosystem đồ sộ, nhiều plugin có sẵn. Đổi lại, các lớp trừu tượng (abstraction) quá sâu thường khiến việc debug và kiểm soát schema dữ liệu trở thành ác mộng khi hệ thống phình to.
  • Dùng Microsoft Semantic Kernel (SK): Framework mã nguồn mở bám sát tư duy kiến trúc doanh nghiệp: dependency injection, type-safety cao, điều phối plugin rõ ràng và minh bạch.

So sánh thực tế giữa 3 lựa chọn

1. Gọi API thuần: Nhanh ban đầu, đuối về sau

Ưu điểm lớn nhất là nhẹ. Bạn nắm trọn từng byte của request payload mà không cần cài thêm dependency nặng nề.

Nhưng bài toán chỉ đẹp khi tool còn ít. Một khi hệ thống chạm mốc 20-30 business functions, hàng loạt vấn đề sẽ ập đến: retry logic, rate limit, context memory và prompt orchestration. Codebase lúc này dễ biến thành mớ spaghetti khó gỡ.

2. LangChain: Thích hợp thử nghiệm, cẩn trọng khi lên prod

LangChain rất tuyệt cho prototyping hoặc dựng luồng RAG cơ bản trong 1-2 ngày.

Dù vậy, khi đưa vào dự án enterprise chạy 24/7, đội ngũ phát triển thường gặp trở ngại vì các bản release đổi API liên tục (breaking changes). Hơn nữa, cơ chế tự động suy luận ngầm bên dưới gây nhiều khó khăn khi bạn cần ghi audit log chuẩn ISO hoặc truy vết lỗi bảo mật.

3. Microsoft Semantic Kernel: Chuẩn hóa cho enterprise

Semantic Kernel đi theo triết lý phần mềm truyền thống: tường minh, dễ đoán và kiểm soát chặt. Với cơ chế Native Plugins, bạn có thể biến các hàm Python thông thường thành tool cho Agent gọi an toàn chỉ với vài dòng type hints.

  • Ưu điểm: Tận dụng Pydantic và typing chuẩn chỉ của Python, hỗ trợ song song Semantic Functions (prompt template) lẫn Native Functions (Python code thuần). Cực kỳ dễ viết unit test bằng pytest và tích hợp liền mạch vào kiến trúc microservices.
  • Nhược điểm: Tài liệu Python SDK đi sau bản C#/.NET một nhịp. Cộng đồng mở rộng cũng chưa đông đảo bằng LangChain.

Khi nào nên chọn Semantic Kernel?

Cần demo gấp cho sếp xem vào ngày mai? Cứ dùng LangChain hoặc gọi API trực tiếp.

Nhưng nếu bạn đang xây dựng agent tương tác thẳng với dữ liệu nghiệp vụ — ví dụ trừ tiền trong ví, cập nhật 500 dòng database hay bắn email xác nhận đơn cho khách hàng — Semantic Kernel là bến đỗ an toàn hơn nhiều nhờ cơ chế validate tham số chặt chẽ.

Trong dự án ERP thực tế với hơn 40 API nội bộ, team mình từng gặp trường hợp agent truyền sai kiểu dữ liệu giữa string và int. Nhờ Semantic Kernel bắt lỗi ngay từ tầng schema type hint, hệ thống chặn đứng các truy vấn hỏng trước khi chúng kịp chạm vào database.

Từng bước triển khai Semantic Kernel và Native Plugin

Bước 1: Khởi tạo môi trường

Semantic Kernel yêu cầu Python từ 3.10 trở lên. Hãy tạo virtualenv sạch và cài đặt thư viện:

python3 -m venv venv
source venv/bin/activate
pip install semantic-kernel python-dotenv

Bước 2: Viết Native Plugin gắn logic nghiệp vụ

Native Plugin thực chất chỉ là một class Python. Bạn đánh dấu các hàm muốn cấp quyền cho AI bằng decorator @kernel_function.

Đặc biệt lưu ý: Phải khai báo docstring và type hint thật chi tiết qua Annotated. Semantic Kernel sẽ dùng chính các mô tả này để sinh ra function definition gửi đến mô hình.

from typing import Annotated
from semantic_kernel.functions import kernel_function

class InventoryPlugin:
    """Plugin phục vụ tra cứu và cập nhật kho hàng nội bộ."""

    @kernel_function(
        name="check_stock",
        description="Kiểm tra số lượng tồn kho của một mã sản phẩm (SKU)."
    )
    def check_stock(
        self,
        sku: Annotated[str, "Mã SKU của sản phẩm cần tra cứu, ví dụ: SKU-101"]
    ) -> str:
        # Giả lập query database nội bộ
        mock_db = {
            "SKU-101": 15,
            "SKU-202": 0,
            "SKU-303": 42
        }
        quantity = mock_db.get(sku.upper(), None)
        if quantity is None:
            return f"Không tìm thấy mã sản phẩm {sku} trong hệ thống kho."
        return f"Sản phẩm {sku} hiện còn {quantity} sản phẩm trong kho."

    @kernel_function(
        name="create_restock_ticket",
        description="Tạo phiếu đề xuất nhập kho cho sản phẩm đã hết hàng."
    )
    def create_restock_ticket(
        self,
        sku: Annotated[str, "Mã SKU cần nhập kho"],
        quantity: Annotated[int, "Số lượng đề xuất nhập thêm, ví dụ: 50"]
    ) -> str:
        return f"Đã tạo ticket nhập hàng #TK-{sku}-99 với số lượng {quantity} thành công."

Bước 3: Khởi tạo Kernel và bật Auto Function Invocation

Tạo file main.py. Ở ví dụ này chúng ta dùng OpenAI GPT-4o-mini, nhưng bạn hoàn toàn có thể trỏ về Azure OpenAI endpoint tương tự chỉ bằng việc đổi connector:

import asyncio
import os
from dotenv import load_dotenv
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

from inventory_plugin import InventoryPlugin

load_dotenv()

async def main():
    # 1. Khởi tạo Kernel điều phối
    kernel = Kernel()

    # 2. Đăng ký dịch vụ LLM
    chat_service = OpenAIChatCompletion(
        service_id="enterprise_agent",
        ai_model_id="gpt-4o-mini",
        api_key=os.getenv("OPENAI_API_KEY")
    )
    kernel.add_service(chat_service)

    # 3. Nạp Native Plugin vào Kernel
    kernel.add_plugin(InventoryPlugin(), plugin_name="inventory")

    # 4. Kích hoạt tính năng tự động gọi function (Auto Invocation)
    execution_settings = OpenAIChatPromptExecutionSettings(
        service_id="enterprise_agent",
        temperature=0.2,
        function_choice_behavior=FunctionChoiceBehavior.Auto(auto_invoke=True)
    )

    # 5. Thực thi câu lệnh yêu cầu phối hợp 2 function liên tiếp
    user_prompt = "Sản phẩm SKU-202 còn hàng không? Nếu hết, hãy tạo phiếu nhập kho 50 cái giúp tôi."
    print(f"User: {user_prompt}\n")

    response = await kernel.invoke_prompt(
        prompt=user_prompt,
        settings=execution_settings
    )

    print(f"Agent:\n{response}")

if __name__ == "__main__":
    asyncio.run(main())

4 kinh nghiệm thực chiến khi đưa lên Production

  1. Tuyệt đối không bỏ qua type hints: LLM không thể đoán mò kiểu dữ liệu. Hãy dùng Annotated[type, "mô tả"] rõ ràng, tránh tuyệt đối dùng kiểu Any khiến AI sinh tham số ngẫu hứng.
  2. Chặn rủi ro bằng FunctionInvocationFilter: Đừng cho agent toàn quyền ghi dữ liệu. Semantic Kernel cho phép gắn filter trước mỗi lệnh gọi hàm để kiểm tra quyền hạn người dùng (RBAC) hoặc yêu cầu phê duyệt từ con người (Human-in-the-loop) với các tác vụ nhạy cảm như chuyển tiền hay xóa tài khoản.
  3. Đảm bảo tính bất biến (Idempotency): Mạng chập chờn hoặc context thiếu sót có thể khiến LLM retry tool 2 lần. Mọi function làm thay đổi trạng thái (POST/UPDATE) phải có idempotency_key để ngăn chặn việc tạo trùng đơn hàng.
  4. Bắt toàn bộ exception bên trong Native Function: Đừng để một cú lỗi query DB làm sập toàn bộ tiến trình. Hãy bọc logic trong block try/except và trả về câu thông báo lỗi dạng chuỗi rõ ràng (như “Lỗi: Kho tạm ngắt kết nối, vui lòng thử lại sau”). AI sẽ đọc được lỗi này và khéo léo thông báo lại cho người dùng cuối.
Share: