Khi hệ thống cũ có API, đây luôn là con đường tốt nhất. Nhưng API của legacy hiếm khi đẹp: có thể là SOAP/XML từ những năm 2000, phân trang lạ, mã lỗi khó hiểu, hoặc trả về hàng nghìn field. Nhiệm vụ của bạn là bọc nó thành một lớp công cụ (tool) sạch sẽ để agent gọi được an toàn.
Vì sao agent không nên gọi API legacy trực tiếp
Agent (LLM) sinh tham số dựa trên văn bản. Nếu bạn để nó tự lắp ráp XML SOAP 200 dòng, nó sẽ sai. Thay vào đó, ta dựng một wrapper: một hàm/endpoint nhỏ do bạn kiểm soát, nhận input đơn giản, xử lý toàn bộ phần "bẩn", trả về JSON gọn cho agent.
[Agent] --(JSON gọn)--> [Wrapper của bạn] --(SOAP/REST xấu)--> [Legacy API]
Ví dụ: bọc một CRM SOAP thành tool tra khách hàng
CRM cũ có endpoint SOAP GetCustomerByPhone. Ta viết wrapper:
import requests, xmltodict
def get_customer(phone: str) -> dict:
"""Tool cho agent: tra khach hang theo SDT. Tra JSON gon."""
envelope = f'''<soap:Envelope xmlns:soap="...">
<soap:Body><GetCustomerByPhone><phone>{phone}</phone>
</GetCustomerByPhone></soap:Body></soap:Envelope>'''
r = requests.post(CRM_URL, data=envelope,
headers={"Content-Type": "text/xml"}, timeout=8)
r.raise_for_status()
data = xmltodict.parse(r.text)
node = data["soap:Envelope"]["soap:Body"]["..."]["Customer"]
return { # chi tra field agent can
"name": node.get("FullName"),
"tier": node.get("MemberLevel"),
"debt": node.get("Outstanding"),
}
Agent chỉ thấy một tool get_customer(phone) trả về ba field. Toàn bộ XML, namespace, timeout được giấu đi.
Định nghĩa tool cho agent (function schema)
{
"name": "get_customer",
"description": "Tra thong tin khach hang theo so dien thoai",
"parameters": {
"type": "object",
"properties": {
"phone": {"type": "string", "description": "SDT 10 so"}
},
"required": ["phone"]
}
}
Mô tả rõ ràng, ít tham số, ràng buộc kiểu chặt — đó là cách giúp LLM gọi đúng.
Các bước xây lớp API wrapper
- Đọc tài liệu API legacy (hoặc dùng Postman/SoapUI dò thử nếu không có tài liệu).
- Xác thực: token, API key, hay session cookie? Lưu bí mật trong biến môi trường, không hardcode.
- Viết wrapper cho từng use case, mỗi hàm làm đúng một việc.
- Chuẩn hóa output về JSON tối giản — chỉ field agent cần.
- Thêm timeout, retry và mã lỗi rõ ràng (xem Bài 6).
- Viết function schema mô tả tự nhiên cho LLM.
- Test wrapper độc lập trước khi cho agent gọi.
Checklist một wrapper tốt
- [ ] Input đơn giản, có validate kiểu.
- [ ] Output là JSON phẳng, không lồng sâu.
- [ ] Timeout được đặt (không bao giờ để vô hạn).
- [ ] Bí mật nằm trong env, không trong code.
- [ ] Có log request/response để debug.
- [ ] Có phiên bản test không đụng dữ liệu thật.
Sai lầm thường gặp
- Cho agent tự sinh SOAP/XML: gần như chắc chắn sai cú pháp.
- Trả nguyên payload legacy về agent: tốn token, LLM bị nhiễu, dễ lộ dữ liệu nhạy cảm.
- Hardcode credential trong code wrapper → rò rỉ khi push git.
- Một wrapper làm quá nhiều việc (vừa tra vừa tạo vừa xóa) → khó test, khó kiểm soát quyền.
- Bỏ timeout: một API legacy treo sẽ làm cả agent đứng.
Khi API legacy phân trang hoặc trả về theo lô
API cũ thường trả kết quả theo trang (page/offset) hoặc giới hạn số bản ghi. Đừng để agent tự lặp qua từng trang — nó sẽ mất kiểm soát số vòng lặp. Thay vào đó, wrapper tự gom đủ dữ liệu (hoặc cắt ở một ngưỡng hợp lý như 50 bản ghi), rồi trả về một danh sách gọn kèm cờ has_more. Agent chỉ cần biết "có thêm hay không", không cần hiểu cơ chế phân trang bên dưới. Đây cũng là chỗ để bạn áp giới hạn, tránh một câu hỏi vô tình kéo về hàng vạn dòng làm ngốn token và làm chậm cả luồng.
Versioning và thay đổi từ nhà cung cấp
API legacy vẫn được nhà cung cấp cập nhật. Một field bị đổi tên hay bỏ đi sẽ âm thầm phá wrapper của bạn. Vì thế, hãy đọc output một cách phòng thủ: dùng .get() với giá trị mặc định thay vì truy cập trực tiếp, để khi thiếu field thì trả về null có kiểm soát thay vì ném lỗi giữa chừng. Ghi lại phiên bản API đang tích hợp, và sau mỗi lần nhà cung cấp thông báo cập nhật, chạy lại bộ test wrapper để bắt sớm sự thay đổi hình dạng dữ liệu.
Tổng kết
Khi có API, đừng để agent chạm trực tiếp. Hãy dựng một lớp wrapper sạch: input đơn giản, output tối giản, xử lý mọi phần bẩn của legacy — SOAP, phân trang, field thừa, thay đổi phiên bản — ở giữa. Đây là nền tảng cho mọi tích hợp bền vững.