API của bạn hiện có ba loại consumer: human developers xây dựng với chúng, application code gọi chúng tại runtime, và AI agents gọi chúng tự động trong quá trình thực thi task. Hai loại đầu tiên được hiểu rõ. Loại thứ ba sẽ phá vỡ API của bạn theo những cách bạn không thiết kế cho.

Đây không phải lý thuyết. Trong năm qua, các hệ thống tôi thấy thất bại trong môi trường production tích hợp agent đều có cùng nguyên nhân gốc rễ: API được thiết kế với giả định rằng một human developer đang ở đâu đó trong request path. Khi con người thoát ra và agent tiếp quản, các giả định bị phá vỡ. Một số thất bại đó gây bất tiện. Một số tốn kém. Một vài cái thảm khốc.

Đây là những gì thực sự quan trọng khi bạn thiết kế hoặc nâng cấp API để sẵn sàng cho agent.

Sự Khác Biệt Cơ Bản: Agent Không Có Judgment

Một human developer gọi API của bạn mang theo kiến thức ngầm mà spec API của bạn không document. Họ biết rằng một lệnh create_order có lẽ không nên retry nếu họ không chắc liệu cái đầu tiên đã thành công chưa. Họ biết rằng 403 Forbidden trên một bulk delete endpoint có nghĩa là nên dừng lại. Họ biết rằng khi API docs nói “idempotent,” nó có nghĩa cụ thể.

Một AI agent không có điều này. Nó có spec, response body cuối cùng, và bất kỳ context nào được cung cấp lúc bắt đầu task. Nó sẽ retry một non-idempotent endpoint khi timeout vì task nói cần tạo đơn hàng, và đơn hàng chưa được tạo. Nó sẽ diễn giải 403 dựa trên bất kỳ error handling logic nào nó có — có thể không khớp với ý định của bạn.

Đây không phải thất bại của AI capability — đây là design gap. API thiết kế cho human developers ủy thác judgment cho con người. API thiết kế cho AI agents cần encode judgment đó vào chính API.

Pattern 1: Mandatory Idempotency Keys

Đây là pattern quan trọng nhất và là pattern mà hầu hết API không có.

Một agent làm việc trên một task sẽ gặp timeout, lỗi mạng và các thất bại mơ hồ. Khi một request timeout, agent có hai lựa chọn: giả sử nó đã thành công (rủi ro: bỏ qua thao tác thực) hoặc retry (rủi ro: trùng lặp trên thao tác có side-effect). Không có idempotency keys, không có lựa chọn nào an toàn.

Idempotency keys cho agent lựa chọn thứ ba: retry an toàn, vì server sẽ phát hiện bản trùng lặp và trả về cùng kết quả như lần thực thi thành công đầu tiên.

POST /api/payments
Idempotency-Key: task-{task_id}-payment-{attempt_id}

{
  "amount": 4999,
  "currency": "USD",
  "customer_id": "cust_abc123"
}

Yêu cầu triển khai:

  • Nhận idempotency key dưới dạng header (không phải body field — cần xử lý được trước body)
  • Lưu request fingerprint (method + path + key) và response ít nhất 24 giờ
  • Trên duplicate key: nếu request body khớp, trả về response gốc; nếu body khác, trả về 422 với giải thích
  • Làm rõ key scope: per-customer, per-task, hay global

Định dạng key quan trọng với agent. Một key như task-{task_id}-step-{step_id}-{operation} giúp agent tạo keys có thể đoán trước, unique mà không cần duy trì external state. Các agent phải generate UUID ngẫu nhiên và nhớ chúng khó xây dựng hơn và khó debug hơn khi có sự cố.

Pattern 2: Machine-Readable Error Responses

Human-readable error messages dành cho kỹ sư đọc logs. Agent-consumable error responses dành cho hệ thống cần quyết định làm gì tiếp theo mà không hỏi con người.

Sự khác biệt là cấu trúc:

Human-readable (không agent-friendly):

{
  "error": "Payment failed because the card was declined by the issuer."
}

Agent-ready:

{
  "error": {
    "code": "CARD_DECLINED",
    "category": "terminal",
    "retry_safe": false,
    "human_message": "Payment failed because the card was declined by the issuer.",
    "suggested_action": "REQUEST_NEW_PAYMENT_METHOD",
    "context": {
      "decline_code": "insufficient_funds",
      "can_retry_with_different_amount": false
    }
  }
}

Các field quan trọng với agent:

  • code: định danh machine-readable ổn định, không phải string để hiển thị
  • category: transient (retry có thể hoạt động) | permanent (retry không giúp ích) | authorization (agent cần quyền cao hơn)
  • retry_safe: boolean rõ ràng — đừng để agent suy ra từ error code
  • suggested_action: agent nên làm gì tiếp theo, theo những thuật ngữ nó có thể hành động

Design này cũng có lợi cho human debugging. Machine-readable errors tốt hơn cho logs, alerting và dashboards so với chuỗi tự do.

Pattern 3: Context Anchors Trong Response

Agent làm việc trong sessions. Một session có thể liên quan đến hàng chục API call qua nhiều service, với agent xây dựng model về thế giới dựa trên những gì nó đã học. Khi một response cung cấp cho agent một tham chiếu có thể dùng để anchor các thao tác tương lai, bạn giảm khả năng agent drift hoặc bịa đặt state.

Cụ thể: mọi thao tác create hoặc update nên trả về full resource representation, không chỉ một ID.

Response yếu (buộc agent phải gọi thêm):

{
  "order_id": "ord_xyz789",
  "status": "created"
}

Context-anchored response:

{
  "order_id": "ord_xyz789",
  "status": "pending_payment",
  "total_amount": 4999,
  "items": [...],
  "next_steps": ["complete_payment", "cancel_order"],
  "payment_url": "https://checkout.example.com/ord_xyz789",
  "_links": {
    "self": "/api/orders/ord_xyz789",
    "payment": "/api/orders/ord_xyz789/payment",
    "cancel": "/api/orders/ord_xyz789/cancel"
  }
}

Mảng next_steps đặc biệt có giá trị với agent: nó liệt kê rõ ràng những gì agent được phép làm từ state này, thay vì để agent suy ra từ response payload.

Pattern 4: Rate Limits Với Budget Visibility

HTTP rate limit headers tồn tại, nhưng hầu hết API triển khai chúng theo cách làm cho agent rate limit management khó khăn.

Vấn đề: một agent làm việc trên một task phức tạp có thể thực hiện hàng trăm call. Không có khả năng hiển thị về rate limit budget hiện tại của mình, nó phát hiện giới hạn bằng cách chạm vào nó — tại thời điểm đó nó phải chờ hoặc hủy task.

Cách tiếp cận tốt hơn:

HTTP/1.1 200 OK
X-RateLimit-Limit: 1000
X-RateLimit-Remaining: 847
X-RateLimit-Reset: 1722844800
X-RateLimit-Window: 3600
X-Agent-Budget-Suggested-Pace: 14/min

Header X-Agent-Budget-Suggested-Pace cho agent biết call rate nào sẽ giữ nó trong budget cho reset window. Điều này cho phép agent được thiết kế tốt chủ động throttle bản thân thay vì phản ứng khi chạm giới hạn.

Pattern 5: Pagination Mà Agent Có Thể Drive

Pagination là nơi nhiều API design âm thầm thất bại với agent. Cursor-based pagination là ổn. Offset pagination là ổn. Vấn đề là pagination yêu cầu agent nhớ state giữa các trang.

Nếu một agent đang paginate qua 10,000 kết quả và xảy ra lỗi mạng ở trang 47, điều gì xảy ra? Nếu cursor là stateless (encode mọi thứ cần thiết để resume), agent có thể retry từ cursor thành công cuối cùng. Nếu cursor là server-side session state hết hạn, agent phải bắt đầu lại từ trang 1.

Yêu cầu cho agent-safe pagination:

  • Cursor nên là self-contained (base64 encoded offset hoặc timestamp, không phải server session key)
  • Bao gồm total_count nếu khả thi — agent lập kế hoạch task hưởng lợi từ việc biết phạm vi
  • Bao gồm has_more dưới dạng boolean rõ ràng, không phải được suy ra từ việc trang hiện tại có đầy không
  • Trả về cursor trong response, không phải dưới dạng response header mà agent có thể bỏ lỡ

Pattern 6: Align Với MCP Từ Đầu

Model Context Protocol (MCP) đang nhanh chóng trở thành interface layer chuẩn giữa AI agents và external tools. Nếu API của bạn có thể sẽ được AI agents consume — và trong năm 2026, hầu hết API đều như vậy — thiết kế cho MCP compatibility từ đầu tiết kiệm đáng kể công việc retrofit sau này.

MCP bọc API của bạn thành một tập hợp “tools” mà agents có thể discover và gọi. Mỗi tool có tên, mô tả và typed input schema. Agent gọi tool theo tên với typed arguments, và tool trả về kết quả mà agent có thể suy luận.

Điều này có nghĩa gì cho API design:

  • Verb-noun naming cho operations: create_order, get_order_status, cancel_order — không phải REST-style POST /orders. Agent suy luận về tên tool; REST paths là phụ.
  • Typed input schemas: JSON Schema cho mọi operation, với descriptions trên mọi field. Agent dùng những descriptions này để quyết định gọi tool nào và cách điền arguments.
  • Single-purpose operations: Tránh “smart” endpoints làm những thứ khác nhau dựa trên field nào bạn gửi. Agent làm tốt hơn với explicit operations có behavior rõ ràng, có ranh giới.
  • Result schemas: Trả về typed, structured results — không phải polymorphic responses.

Bạn không cần triển khai MCP native. Một MCP wrapper layer có thể dịch giữa MCP tool calls và REST hoặc GraphQL API hiện có của bạn. Nhưng nếu API của bạn có naming conventions, schema design và error handling được thiết kế cho MCP compatibility, wrapper trở nên gần như tự động.

Bài Kiểm Tra Thực Tế

Trước khi bạn ship một API mà agent sẽ consume, hãy chạy bài kiểm tra này: cho một agent chưa bao giờ thấy API của bạn MCP description của nó (hoặc chỉ OpenAPI spec), yêu cầu nó hoàn thành một task thực tế nhiều bước, và xem những gì bị phá vỡ.

Những gì bị phá vỡ là design API của bạn — không phải capability của agent.

Checklist:

  • Mọi write operation có idempotency key
  • Error responses có machine-readable codes và retry_safe booleans
  • Create/update responses trả về full resource representations với next_steps
  • Rate limit headers bao gồm forward-looking budget information
  • Pagination dùng stateless, self-contained cursors
  • Operations có verb-noun names với typed input/output schemas

Không có thay đổi nào trong số này là tốn kém. Hầu hết cũng cải thiện trải nghiệm human developer — machine-readable errors, full resource responses và stateless cursors là good API design bất kể agent có trong bức tranh không.

Các nhóm xây dựng agent-ready API ngay bây giờ sẽ có lợi thế đáng kể khi autonomous agents bắt đầu thực hiện phần lớn API call đến hệ thống của họ — điều này, dựa trên tốc độ tăng trưởng hiện tại, có lẽ gần hơn hầu hết các nhóm nghĩ.


Thuận Lương là Tech Lead với hơn 15 năm kinh nghiệm về .NET, kiến trúc cloud và hệ thống AI. Anh ấy viết về những bài học từ việc xây dựng các hệ thống production thực tế.

Xuất nội dung

Bình luận