Xây dựng Agent Python tự hành với Claude SDK

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

Vấn đề: AI của bạn thông minh nhưng “bất lực”

Tất cả chúng ta đều đã từng gặp tình huống này: bạn dành hàng giờ để hoàn thiện system prompt cho Claude. Nó viết mã Python tinh tế, tóm tắt các tệp PDF 50 trang trong vài giây và mô phỏng giọng điệu thương hiệu của bạn một cách hoàn hảo. Nhưng ngay khi bạn yêu cầu nó thực sự làm điều gì đó—như kiểm tra cơ sở dữ liệu kho hàng theo thời gian thực hoặc gửi thông báo vào kênh Slack—nó ngay lập tức vấp phải rào cản.

Hầu hết các nhà phát triển đều bị kẹt trong “Bẫy Chatbox”. Bạn gửi một tin nhắn, API trả về văn bản và giao dịch kết thúc. AI sống trong một môi trường chân không. Việc lấp đầy khoảng cách này bằng mã thủ công thường dẫn đến một cơn ác mộng if/else dài 200 dòng nhằm cố gắng đoán xem khi nào AI muốn chạy một hàm. Nó rất mong manh và sẽ hỏng ngay khi Claude thay đổi cách diễn đạt dù chỉ một từ.

Tại sao các tích hợp LLM tiêu chuẩn lại không hiệu quả

Sự thất vọng bắt nguồn từ một sự mất kết nối đơn giản: suy luận không phải là thực thi. Một mô hình ngôn ngữ lớn (LLM) là một công cụ dự đoán văn bản đẳng cấp thế giới, chứ không phải là một quản trị viên hệ thống. Bản thân nó không hiểu về trạng thái (state) hoặc các tác dụng phụ (side effects). Nếu bạn yêu cầu một chatbot thông thường “lưu trữ các bản log cũ”, nó sẽ tự tin trả lời: “Tôi đã lưu trữ các bản log”, trong khi dung lượng đĩa máy chủ của bạn vẫn ở mức 99%.

Trong môi trường production, việc chuyển từ một chatbot thụ động sang một agent chủ động là điểm khác biệt giữa một dự án sở thích cuối tuần và một công cụ xử lý 5.000 yêu cầu người dùng mỗi giờ. Các rào cản kỹ thuật chính bao gồm:

  • Trôi ngữ cảnh (Context Drift): Mất mạch cuộc hội thoại trong các tác vụ nhiều bước.
  • Tham số ảo (Hallucinated Parameters): AI tự tạo ra các đối số cho hàm của bạn mà không tồn tại trong schema.
  • Rủi ro bảo mật: Ngăn chặn agent diễn giải lệnh “xóa tài khoản của tôi” thành “xóa toàn bộ cơ sở dữ liệu production”.

So sánh các chiến lược Agent

Claude Agent SDK so với các phương pháp cũ như thế nào? Hãy nhìn vào các con số và quy trình làm việc.

Phương pháp Độ tin cậy Công sức phát triển
Phân tích cú pháp Regex Thấp (~60% thành công) Cao; yêu cầu bảo trì liên tục logic phân tích cú pháp.
LangChain / Framework nặng Trung bình Cao; các trừu tượng “hộp đen” khiến việc debug trở thành một thử thách kéo dài 3 giờ.
Claude Agent SDK / Tool Use Cao (95%+) Thấp; hỗ trợ JSON schema gốc đảm bảo kết quả đầu ra có thể dự đoán được.

Claude SDK cung cấp một quy trình bắt tay có cấu trúc. Thay vì đoán mò, Claude nói rõ với mã của bạn rằng: “Dừng lại. Tôi cần bạn chạy hàm get_inventory_count(item_id='sku_123'). Tôi sẽ đợi kết quả trước khi tiếp tục nói chuyện.”

Bản thiết kế: Xây dựng vòng lặp Agent có kiểm soát

Cách mạnh mẽ nhất để xây dựng một agent là mô hình Tool Use (Sử dụng công cụ). Điều này tạo ra một vòng lặp nơi Claude suy nghĩ, hành động, quan sát kết quả và sau đó tinh chỉnh bước tiếp theo.

1. Thiết lập môi trường

Lấy API key từ Anthropic Console. Chúng ta sẽ sử dụng thư viện anthropic chính thức, hiện đã xử lý các tương tác phức tạp này một cách tự nhiên.

pip install anthropic python-dotenv

2. Định nghĩa Schema cho công cụ

Một công cụ là một hàm Python tiêu chuẩn đi kèm với một JSON schema. Schema này đóng vai trò như một cuốn hướng dẫn sử dụng cho AI. Hãy xây dựng một công cụ kiểm tra trạng thái tài khoản người dùng.

import anthropic
import os
from dotenv import load_dotenv

load_dotenv()
client = anthropic.Anthropic(api_key=os.getenv("ANTHROPIC_API_KEY"))

def get_user_status(user_id):
    # Mô phỏng một truy vấn tới instance PostgreSQL hoặc Redis thực tế
    mock_db = {
        "user_123": "Đang hoạt động",
        "user_456": "Bị tạm ngưng"
    }
    return mock_db.get(user_id, "Không tìm thấy người dùng")

tools = [
    {
        "name": "get_user_status",
        "description": "Trả về trạng thái tài khoản cho một ID người dùng cụ thể. Sử dụng công cụ này để xác minh xem người dùng có được phép mua hàng hay không.",
        "input_schema": {
            "type": "object",
            "properties": {
                "user_id": {"type": "string", "description": "ID duy nhất, ví dụ: user_123"}
            },
            "required": ["user_id"]
        }
    }
]

3. Triển khai vòng lặp thực thi

Agent cần một “vòng lặp tư duy”. Nó gửi một prompt cho Claude, kiểm tra xem có yêu cầu gọi công cụ nào không, thực thi mã Python và đưa kết quả trở lại mô hình. Quá trình này tiếp tục cho đến khi tác vụ hoàn thành.

def run_agent(user_prompt):
    messages = [{"role": "user", "content": user_prompt}]
    
    response = client.messages.create(
        model="claude-3-5-sonnet-20240620",
        max_tokens=1024,
        tools=tools,
        messages=messages
    )

    # Vòng lặp xử lý suy luận đa bước
    while response.stop_reason == "tool_use":
        messages.append({"role": "assistant", "content": response.content})
        
        # Trích xuất yêu cầu công cụ
        tool_use = next(block for block in response.content if block.type == "tool_use")
        tool_name = tool_use.name
        tool_input = tool_use.input
        
        print(f"[Agent] Đang thực thi: {tool_name}({tool_input})")

        if tool_name == "get_user_status":
            result = get_user_status(tool_input["user_id"])

        messages.append({
            "role": "user",
            "content": [
                {
                    "type": "tool_result",
                    "tool_use_id": tool_use.id,
                    "content": str(result),
                }
            ],
        })

        # Truy vấn lại Claude với dữ liệu mới
        response = client.messages.create(
            model="claude-3-5-sonnet-20240620",
            max_tokens=1024,
            tools=tools,
            messages=messages
        )

    return response.content[0].text

print(run_agent("Người dùng user_456 có thể đặt hàng không?"))

Những bài học kinh nghiệm về độ tin cậy của Agent

Xây dựng một agent hoạt động trên terminal thì dễ. Xây dựng một agent không gặp lỗi ảo giác (hallucination) trong môi trường production thì khó hơn nhiều. Đây là những gì tôi đã học được khi triển khai các hệ thống này ở quy mô lớn:

  • Mô tả chính là Prompt: Trường description trong schema công cụ của bạn là đoạn mã quan trọng nhất mà bạn viết. Đừng chỉ nói “lấy dữ liệu”. Hãy dùng: “Chỉ sử dụng công cụ này khi người dùng yêu cầu rõ ràng về chu kỳ thanh toán hoặc gói đăng ký của họ.”
  • Xử lý lỗi khéo léo: Nếu lệnh gọi API của bạn bị timeout, đừng chỉ để nó crash. Hãy gửi chuỗi thông báo lỗi ngược lại cho Claude dưới dạng tool_result. Claude thường có thể xin lỗi người dùng và gợi ý một giải pháp thay thế hoặc thử lại.
  • “Bộ ngắt mạch” (Circuit Breaker): Luôn thiết lập giới hạn vòng lặp tối đa (ví dụ: 5 vòng lặp). Nếu không có điều này, hai công cụ có thể vô tình kích hoạt lẫn nhau trong một vòng lặp vô tận, làm tiêu tốn 50 USD phí API chỉ trong vài phút.
  • Kiểm soát cá tính (Persona): Sử dụng system prompt để xác định ranh giới. Hãy nói với agent: “Bạn là một trợ lý hỗ trợ chỉ có quyền đọc. Không bao giờ cố gắng sửa đổi dữ liệu người dùng trừ khi người dùng cung cấp mã xác nhận 6 chữ số.”

Vượt xa các truy vấn đơn giản

Khi bạn đã nắm vững vòng lặp cơ bản, các khả năng sẽ mở rộng đáng kể. Bạn có thể cung cấp cho Claude một công cụ search_web để vượt qua giới hạn kiến thức cũ hoặc công cụ write_to_file để tạo báo cáo. Bằng cách sử dụng Claude SDK, bạn chuyển từ việc xây dựng một chatbot chỉ biết nói về công việc sang xây dựng một agent thực sự thực hiện công việc đó. Đó là sự chuyển đổi từ tạo văn bản sang tính hữu dụng thực thụ.

Share: