Nhiều bạn mới làm AI agent hay dừng ở bước "chat với model". Bước tiếp theo, cho model gọi hàm thật trong hệ thống của mình, mới là chỗ agent bắt đầu có ích. Bài này mình đi qua một ví dụ nhỏ bằng Python: agent tra cứu trạng thái đơn hàng bằng tool use của Claude.

Tool use thực chất là gì

Model không tự chạy code của bạn. Bạn mô tả một danh sách tool (tên, mô tả, tham số). Khi cần, model trả về một yêu cầu kiểu "hãy gọi tool này với các tham số này". Code của bạn chạy hàm thật, rồi gửi kết quả ngược lại cho model để nó trả lời người dùng.

Nghe đơn giản, nhưng phần khó nằm ở chuyện vận hành: giới hạn tốc độ, chi phí và kiểm soát quyền khi gọi API ở quy mô doanh nghiệp. Mình đã tóm tắt phần này trong bài về Claude API enterprise nếu bạn định đưa agent vào hệ thống thật.

Cài đặt

pip install anthropic
export ANTHROPIC_API_KEY="sk-..."

Mình dùng SDK chính thức của Anthropic. Key lấy từ biến môi trường, đừng ghi thẳng vào code.

Định nghĩa tool

Một tool gồm tên, mô tả và JSON Schema cho tham số. Mô tả viết càng rõ thì model chọn tool càng đúng.

import anthropic

client = anthropic.Anthropic()

tools = [{
    "name": "get_order_status",
    "description": "Tra cứu trạng thái đơn hàng theo mã đơn.",
    "input_schema": {
        "type": "object",
        "properties": {
            "order_id": {"type": "string", "description": "Mã đơn hàng, ví dụ A1001"}
        },
        "required": ["order_id"],
    },
}]

def get_order_status(order_id: str) -> str:
    # Thay bằng truy vấn thật vào hệ thống đơn hàng
    data = {"A1001": "Đang giao", "A1002": "Đã hủy"}
    return data.get(order_id, "Không tìm thấy đơn hàng")

Vòng lặp gọi tool

Model có thể gọi tool một hoặc nhiều lần trước khi trả lời. Vì vậy ta cần một vòng lặp, và nên giới hạn số bước tối đa.

MAX_STEPS = 5
messages = [{"role": "user", "content": "Đơn A1001 của tôi đang ở đâu?"}]

for _ in range(MAX_STEPS):
    response = client.messages.create(
        model="claude-sonnet-5-5",
        max_tokens=1024,
        tools=tools,
        messages=messages,
    )
    if response.stop_reason != "tool_use":
        break

    messages.append({"role": "assistant", "content": response.content})
    results = []
    for block in response.content:
        if block.type == "tool_use":
            output = get_order_status(**block.input)
            results.append({
                "type": "tool_result",
                "tool_use_id": block.id,
                "content": output,
            })
    messages.append({"role": "user", "content": results})

answer = next(b.text for b in response.content if b.type == "text")
print(answer)

Điểm dễ sai nhất: phải gửi lại nguyên response.content của model dưới vai trò assistant, rồi mới gửi tool_result dưới vai trò user. Thiếu tool_use_id hoặc sai thứ tự là API trả lỗi ngay.

Khi có nhiều hơn một tool

Ví dụ trên chỉ có một tool, nhưng agent thật thường có năm, bảy tool. Lúc đó có vài thói quen giúp model chọn đúng. Đặt tên tool theo động từ rõ nghĩa, ví dụ get_order_status thay vì order. Trong mô tả, ghi luôn khi nào không nên dùng tool này. Chỉ đưa vào mỗi lượt gọi những tool thật sự liên quan, vì danh sách càng dài thì khả năng chọn nhầm càng cao.

Nếu có bước bắt buộc phải gọi một tool cụ thể, bạn có thể dùng tham số tool_choice để ép model, thay vì hy vọng nó tự chọn đúng. Chi tiết cách dùng nằm trong tài liệu chính thức của Anthropic, bạn nên đọc kỹ trước khi áp dụng.

Ba lỗi mình hay gặp

  • Mô tả tool mơ hồ. Hai tool có mô tả gần giống nhau thì model chọn nhầm. Hãy ghi rõ khi nào dùng và khi nào không dùng.
  • Không kiểm tra tham số. Đừng tin block.input tuyệt đối. Hãy validate trước khi chạy, nhất là với tool ghi dữ liệu.
  • Trả về lỗi dạng exception. Nếu tool lỗi, hãy trả về một chuỗi mô tả lỗi trong tool_result để model xử lý tiếp, thay vì để chương trình sập.

Trước khi đưa lên production

Ví dụ trên chỉ là bộ khung. Trước khi cho agent làm việc thật, mình luôn thêm bốn thứ: log đầy đủ mỗi lần gọi tool, giới hạn số lần gọi và chi phí cho mỗi phiên, bước xác nhận của con người với tool ghi hoặc xóa dữ liệu, và một bộ test nhỏ chạy lại mỗi khi đổi prompt hay đổi model.

Bạn đang cho agent của mình gọi những tool nào, và tool nào khiến bạn lo nhất? Mình rất muốn nghe kinh nghiệm của các bạn ở phần bình luận.

Mình là Darius Tran, làm việc về triển khai AI agent cho doanh nghiệp tại AI Hive.