Agent gọi điểm cuối chuyển mã video của bạn. Điểm cuối trả về 202 Accepted và một ID công việc. Agent, vốn không biết 202 có nghĩa gì trong hệ thống của bạn, báo cáo rằng việc chuyển mã đã hoàn tất và chuyển sang bước tiếp theo, bước này đọc một tệp chưa tồn tại.
Các hoạt động chạy dài làm hỏng agent theo một cách cụ thể. Một cuộc gọi đồng bộ có một hợp đồng rõ ràng: bạn gửi, bạn đợi, bạn nhận được câu trả lời. Một cuộc gọi không đồng bộ chia điều đó thành một phần bắt đầu và một phần kết thúc, và khoảng cách giữa chúng là nơi các agent bị nhầm lẫn. Chúng tuyên bố thành công sớm, chúng thăm dò một nghìn lần trong một vòng lặp chặt chẽ, hoặc chúng bị chặn trong sáu phút giữ một lượt hội thoại mở.
Hướng dẫn này trình bày cách thiết kế hợp đồng bất đồng bộ để agent có thể tuân theo, khi nào nên thăm dò và khi nào nên bàn giao, cách viết công cụ để mô hình hoạt động đúng, và cách kiểm tra toàn bộ quá trình bao gồm các trường hợp chậm và thất bại. Bài viết của chúng tôi về khôi phục lỗi agent bao gồm khía cạnh thất bại của các cuộc gọi API; bài viết này bao gồm những trường hợp thành công chậm.
Apidog phù hợp tại điểm mà bạn cần chứng minh rằng agent xử lý một công việc mất bốn phút rồi thất bại, điều này không phải là thứ bạn muốn khám phá trong môi trường sản xuất.
Tại sao agent xử lý sai bất đồng bộ
Ba thói quen gây ra hầu hết các rắc rối.
Các mô hình coi 2xx là đã hoàn tất. 202 có nghĩa là yêu cầu đã được chấp nhận để xử lý, và đặc tả ngữ nghĩa HTTP nói rõ rằng việc xử lý có thể chưa hoàn thành. Các mô hình được huấn luyện trên lưu lượng yêu cầu/phản hồi thông thường có xu hướng đọc bất kỳ 2xx nào là hoàn tất trừ khi phản hồi nói rõ ngược lại bằng lời.
Các vòng lặp tốn kém. Nếu một agent thăm dò bên trong vòng lặp suy luận của nó, mỗi lần kiểm tra sẽ tốn một lượt của mô hình cộng với các token của cuộc hội thoại trước đó. Thăm dò mỗi hai giây cho một công việc kéo dài bốn phút là 120 lượt, và quá trình chạy có thể làm cạn kiệt ngữ cảnh hoặc ngân sách. Bài viết của chúng tôi về giữ phản hồi công cụ ra khỏi cửa sổ ngữ cảnh giải thích tại sao điều đó lại tích lũy nhanh hơn mọi người mong đợi.
Agent mất dấu các công việc. Một công cụ bắt đầu công việc và trả về một ID công việc đã tạo ra trạng thái mà agent phải duy trì. Nếu ID nằm giữa một cuộc hội thoại dài, nó có thể bị nén đi, và agent quên mất rằng nó đang có một công việc đang thực hiện.
Thiết kế phản hồi để mô hình không thể đọc sai
Cách khắc phục hiệu quả nhất là cách diễn đạt, không phải kiến trúc. Bất kể mã trạng thái của bạn là gì, hãy làm cho phần thân phản hồi nói rõ ràng điều gì đã xảy ra và điều gì cần làm tiếp theo.
{
"status": "processing",
"job_id": "job_7f21c",
"message": "Quá trình chuyển mã đã BẮT ĐẦU và CHƯA hoàn tất. Đừng báo cáo thành công. Kiểm tra trạng thái bằng getJobStatus(job_id) sau ít nhất 30 giây.",
"poll_after_seconds": 30,
"estimated_duration_seconds": 240,
"status_url": "/v1/jobs/job_7f21c"
}
Điều đó có vẻ quá rõ ràng đối với một người tiêu dùng API. Nó được nhắm mục tiêu vào một mô hình, và các mô hình tuân theo các hướng dẫn rõ ràng trong phần thân phản hồi đáng tin cậy hơn nhiều so với việc chúng suy luận ý nghĩa từ mã trạng thái. Ba chi tiết thực hiện công việc: từ "chưa hoàn tất", công cụ tiếp theo được đặt tên và thời gian chờ tối thiểu.
AIP-151 của Google về các hoạt động chạy dài mô tả một hình dạng tài nguyên rõ ràng cho việc này, với một đối tượng Operation duy nhất mang các trường done, error và response. Sao chép cấu trúc đó mang lại cho bạn một bề mặt nhất quán trên mọi điểm cuối chậm, điều này quan trọng vì một agent học được một mẫu thăm dò có thể xử lý tất cả chúng.
Giữ phản hồi trạng thái cũng thẳng thắn:
{
"job_id": "job_7f21c",
"status": "processing",
"done": false,
"progress_percent": 45,
"elapsed_seconds": 108,
"poll_after_seconds": 45,
"message": "Vẫn đang xử lý. Không chuyển sang bước tiếp theo."
}
Và khi hoàn thành, trả về kết quả nội tuyến khi nó nhỏ, để agent không cần thực hiện cuộc gọi thứ ba:
{
"job_id": "job_7f21c",
"status": "succeeded",
"done": true,
"result": { "output_url": "https://cdn.example.com/out/7f21c.mp4", "duration_seconds": 372 }
}
Thăm dò bên ngoài mô hình, không phải bên trong nó
Lựa chọn triển khai quan trọng nhất: đặt việc chờ đợi vào trình bao bọc công cụ của bạn, không phải vào vòng lặp suy luận của agent.
import time
def start_and_await_transcode(client, source_url, max_wait=600):
job = client.post("/v1/transcode", json={"source_url": source_url}).json()
job_id = job["job_id"]
delay = job.get("poll_after_seconds", 5)
waited = 0
while waited < max_wait:
time.sleep(delay)
waited += delay
status = client.get(f"/v1/jobs/{job_id}").json()
if status.get("done"):
if status["status"] == "succeeded":
return {"status": "succeeded", "result": status["result"]}
return {"status": "failed", "error": status.get("error")}
delay = min(int(delay * 1.5), 60)
return {
"status": "timed_out",
"job_id": job_id,
"message": f"Still running after {max_wait}s. Job {job_id} continues in the background.",
}
Từ phía mô hình, đây là một lệnh gọi công cụ mất một thời gian và trả về câu trả lời cuối cùng. Không có vòng lặp thăm dò trong ngữ cảnh, không có ID công việc bị quên, không có 120 lượt. Việc lùi thời gian giúp giữ số lượng yêu cầu hợp lý, và giới hạn trên ngăn chặn một công việc bị kẹt làm treo quá trình chạy mãi mãi. Bài viết của Amazon về thời gian chờ, thử lại và lùi thời gian với jitter là tài liệu tham khảo đáng đọc trước khi bạn điều chỉnh các con số đó.
Hai quy tắc làm cho điều này an toàn. Luôn giới hạn thời gian chờ, và luôn trả về ID công việc khi hết thời gian chờ để agent hoặc con người có thể kiểm tra sau. Không bao giờ trả về kết quả mơ hồ: succeeded, failed, và timed_out là ba kết quả khác nhau và mô hình nên thấy ba từ khác nhau.
Đối với các công việc được đo bằng giờ thay vì phút, việc thăm dò trong trình bao bọc không còn hợp lý nữa. Khi đó, hình dạng đúng là hai công cụ, một để bắt đầu và một để kiểm tra, cộng với một bản ghi bền vững về các công việc đang thực hiện bên ngoài cuộc hội thoại để không có gì bị mất do nén. Lưu trữ job_id, nhiệm vụ mà nó thuộc về, và thời gian bắt đầu, và để agent đọc danh sách đó ở đầu mỗi lần chạy.
Khi nào webhook là câu trả lời tốt hơn
Thăm dò đơn giản và hoạt động ở mọi nơi. Callback hiệu quả hơn và tốn nhiều công sức hơn để chạy. Sự đánh đổi này đã được đề cập rõ trong so sánh webhook và thăm dò của chúng tôi, và phiên bản dành riêng cho agent thì hẹp hơn.
Sử dụng thăm dò khi công việc mất vài giây đến vài phút, khi agent đang chờ kết quả để tiếp tục, hoặc khi bạn không thể lưu trữ một điểm cuối công khai. Hầu hết các khối lượng công việc của agent đều nằm ở đây.
Sử dụng webhook khi công việc mất hàng giờ, khi agent kích hoạt công việc và chuyển sang việc khác, hoặc khi nhiều công việc chạy đồng thời và việc thăm dò từng công việc là lãng phí. Chi phí là có thật: bạn cần một bộ nhận công khai, xác minh chữ ký, xử lý thử lại và một cách để đánh thức agent khi callback đến. Các hướng dẫn của chúng tôi về thiết kế webhook đáng tin cậy và xác minh chữ ký webhook bao gồm những nền tảng đó.
Một lựa chọn trung gian đáng để biết. Truyền phát tiến độ công việc qua sự kiện do máy chủ gửi (server-sent events) mang lại cho bạn ngữ nghĩa đẩy mà không cần điểm cuối công khai, vì client giữ kết nối. Nó phù hợp với các agent tương tác nơi có con người đang theo dõi, và hướng dẫn của chúng tôi về truyền phát phản hồi API với SSE bao gồm việc triển khai.
Dù bạn chọn cách nào, đường dẫn hoàn tất phải là bất biến (idempotent). Webhook thử lại, các lần thăm dò cạnh tranh, và một agent nhìn thấy "thành công" hai lần không nên bắt đầu bước tiếp theo hai lần. Bài viết của chúng tôi về tính bất biến cho các agent AI bao gồm các khóa làm cho điều đó an toàn.
Kiểm tra đường dẫn chậm, không chỉ đường dẫn nhanh
Các lỗi bất đồng bộ bị ẩn đi vì môi trường kiểm thử nhanh. Một công việc mất bốn phút trong môi trường sản xuất hoàn thành trong 200 mili giây khi chạy với một stub cục bộ, vì vậy agent không bao giờ trải nghiệm trạng thái mà nó thực sự sẽ gặp phải.
Bốn kịch bản đáng để xây dựng một cách có chủ đích.
Công việc thực sự chậm. Giả lập điểm cuối trạng thái để nó trả về processing cho vài cuộc gọi đầu tiên và succeeded sau đó. Điều này chứng minh trình bao bọc thăm dò, lùi thời gian, và cuối cùng trả về. Trong Apidog bạn có thể điều khiển điều này bằng một mock thay đổi theo số lượng yêu cầu hoặc theo một tham số điều khiển, để cùng một thử nghiệm luôn chạy theo cùng một cách.

Công việc thất bại muộn. Trả về processing ba lần, sau đó failed với phần thân chứa lỗi. Agent phải báo cáo thất bại thay vì coi một lần thăm dò hoàn tất là một công việc đã hoàn thành. Đây là trường hợp gây mất dữ liệu âm thầm khi có lỗi.
Hết thời gian chờ (timeout). Giữ mock trả về processing vượt quá giới hạn của trình bao bọc và khẳng định công cụ trả về timed_out với ID công việc còn nguyên vẹn, không phải một ngoại lệ và không phải một thành công giả.
Hoàn thành trùng lặp. Gửi tín hiệu thành công hai lần, bằng cách thử lại webhook hoặc bằng một lần thăm dò cạnh tranh, và khẳng định bước tiếp theo chỉ chạy một lần.
Lưu cả bốn kịch bản này để chúng chạy trong CI. Chúng không tốn chi phí để chạy lại và chúng bắt lỗi hồi quy khi ai đó rút ngắn thời gian chờ hoặc bỏ qua một lỗi. Phương pháp tiếp cận rộng hơn nằm trong hướng dẫn kiểm thử hợp đồng API của chúng tôi.
Ba công việc làm lộ rõ vấn đề
Tạo báo cáo. Một agent tài chính yêu cầu xuất dữ liệu hàng quý. Việc này mất 90 giây. Với một công cụ đơn giản, agent nhận được ID công việc, thông báo báo cáo đã sẵn sàng, và sau đó đưa một liên kết tải xuống bị hỏng cho người dùng. Với một trình bao bọc chặn, nó đợi 90 giây và trả về URL thực. Cùng một API, kết quả đối lập, và sự khác biệt duy nhất là nơi việc chờ đợi xảy ra.
Nhập dữ liệu hàng loạt. Một agent vận hành tải lên 20.000 bản ghi. Quá trình nhập chạy trong tám phút và thất bại một phần ở hàng 14.000. Đây là trường hợp làm lộ rõ điểm yếu của việc kiểm tra thành công đơn giản: công việc đã hoàn thành, vì vậy trạng thái done là đúng, nhưng kết quả mang theo một danh sách các hàng bị từ chối. Trả về kết quả một phần một cách rõ ràng, kèm theo số lượng, và để agent đọc chúng trước khi nó chuyển sang bước tiếp theo.
Mô hình và đường ống xây dựng. Một agent kích hoạt một quá trình huấn luyện hoặc một bản dựng CI mất 40 phút. Việc thăm dò trong trình bao bọc không phù hợp ở đây; quá trình chạy sẽ giữ một lượt mở quá lâu. Bắt đầu công việc, ghi lại ID vào bộ lưu trữ bền vững, kết thúc lượt, và để một kiểm tra theo lịch hoặc một callback đánh thức bước tiếp theo. Bài viết của chúng tôi về bàn giao và truyền ngữ cảnh giữa nhiều agent bao gồm việc chuyển trạng thái đó giữa các lần chạy mà không làm mất nó.
Định hình kết quả một phần
Các công việc dài thường kết thúc ở đâu đó giữa thành công và thất bại, và một mô hình hai trạng thái buộc bạn phải nói dối về điều đó. Hãy làm cho trạng thái thứ ba trở nên rõ ràng:
{
"job_id": "job_a11f",
"status": "completed_with_errors",
"done": true,
"summary": { "processed": 20000, "succeeded": 19860, "failed": 140 },
"errors_url": "/v1/jobs/job_a11f/errors?limit=50",
"message": "Nhập dữ liệu hoàn tất. 140 hàng bị lỗi và không được ghi. Hãy xem xét lỗi trước khi báo cáo thành công."
}
Hai điều quan trọng trong payload đó. Các số đếm được đặt nội tuyến, vì vậy agent có thể quyết định mà không cần một cuộc gọi khác. Các hàng bị lỗi nằm sau một URL có giới hạn, vì vậy 140 đối tượng lỗi không xuất hiện trong ngữ cảnh mà không được mời.
Phải có người xem công việc bị đình trệ
Đường dẫn hết thời gian chờ kết thúc bằng một ID công việc và một thông báo cho biết công việc vẫn đang chạy. Đó là giá trị trả về chính xác, và nó chỉ hữu ích nếu nó đến được với một người.
Nếu agent là dịch vụ của riêng bạn, hãy định tuyến nó vào bất kỳ hàng đợi nào mà nhóm của bạn đang theo dõi. Nếu agent là một môi trường chạy mã đang xử lý các nhiệm vụ được giao, nền tảng chạy nó thường có nơi để thông báo này đến. Trong Sharkly, một lần chạy bị chặn vẫn nằm trên Nhiệm vụ của nó cùng với trạng thái thực thi và kết quả, và Hộp thư đến phân tách các mục cần phản hồi hoặc xem xét của con người khỏi các cập nhật thông thường. Vấn đề không phải là công cụ cụ thể. Vấn đề là "vẫn đang chạy, kiểm tra sau" cần một người chịu trách nhiệm, nếu không nó sẽ trở thành "không ai kiểm tra".

Danh sách kiểm tra ngắn gọn
- Mọi điểm cuối chậm đều trả về một ID công việc, một URL trạng thái và một thông báo bằng ngôn ngữ rõ ràng cho biết công việc chưa hoàn thành.
- Phản hồi trạng thái mang một trường boolean
done, không chỉ là một chuỗi mà mô hình phải giải thích. - Việc thăm dò nằm trong trình bao bọc công cụ với chiến lược lùi thời gian theo cấp số nhân và một giới hạn cứng.
- Thời gian chờ trả về ID công việc để công việc có thể được tiếp tục thay vì bị mất.
- Thành công, thất bại và hết thời gian chờ là ba giá trị trả về khác biệt.
- Các công việc đang thực hiện được ghi lại bên ngoài cuộc hội thoại đối với bất kỳ công việc nào dài hơn vài phút.
- Việc xử lý hoàn tất phải bất biến (idempotent), cho dù tín hiệu đến bằng thăm dò hay bằng callback.
- Tất cả các trường hợp hoàn thành chậm, thất bại muộn, hết thời gian chờ và hoàn thành trùng lặp đều có các bài kiểm thử đã lưu.
Viết đúng cách diễn đạt phản hồi và trình bao bọc, và các hoạt động chạy dài sẽ không còn là trường hợp đặc biệt đối với agent. Nó gọi một công cụ, đợi và nhận được câu trả lời, đó là hợp đồng mà nó xử lý tốt nhất. Tải xuống Apidog để xây dựng các mock cho công việc chậm cùng với các bài kiểm thử.
Các câu hỏi thường gặp
API có nên trả về 202 hay 200 cho một lần khởi động bất đồng bộ? 202 Accepted là mã chính xác và báo hiệu cho các client tiêu chuẩn rằng quá trình xử lý chưa hoàn tất. Đừng chỉ dựa vào nó cho các agent, vì phần thân phản hồi là thứ mô hình đọc đáng tin cậy nhất. Hãy sử dụng cả hai.
Trình bao bọc công cụ nên đợi bao lâu trước khi từ bỏ? Đặt giới hạn trên hơi cao hơn trường hợp xấu nhất thực tế của điểm cuối, thường là hai đến mười phút. Vượt quá thời gian đó, trình bao bọc sẽ chặn một lượt hội thoại quá lâu, và một công cụ kiểm tra sau sẽ là hình dạng tốt hơn.
Tôi nên sử dụng khoảng thời gian thăm dò nào? Bắt đầu từ gợi ý poll_after_seconds của máy chủ nếu có, sau đó lùi thời gian theo hệ số khoảng 1.5 với giới hạn khoảng 60 giây. Thăm dò cố định mỗi giây làm lãng phí yêu cầu và có thể gây ra giới hạn tỷ lệ, như đã đề cập trong hướng dẫn vượt quá giới hạn tỷ lệ của chúng tôi.
Agent có thể làm điều gì hữu ích trong khi chờ đợi không? Chỉ khi bộ điều phối của bạn hỗ trợ các lệnh gọi công cụ đồng thời. Nếu có, hãy bắt đầu công việc, thực hiện công việc độc lập, sau đó kiểm tra trạng thái. Nếu không, trình bao bọc chặn đơn giản và ít gây lỗi hơn so với một trình lập lịch tự chế.
Làm thế nào để tôi ngăn agent tuyên bố thành công sớm? Nói rõ ràng trong phần thân phản hồi, hiển thị một trường boolean done, và biến công cụ hoàn thành thành nơi duy nhất kết quả xuất hiện. Nếu phản hồi khởi động không chứa kết quả, mô hình sẽ không có gì để báo cáo là một kết quả.
Webhook có hoạt động với agent chạy trên máy tính xách tay không? Không trực tiếp, vì không có điểm cuối công khai. Sử dụng một đường hầm để phát triển, như trong hướng dẫn của chúng tôi về kiểm thử API localhost bằng dịch vụ webhook, hoặc kiên trì với việc thăm dò cho đến khi agent chạy ở một nơi có thể truy cập được.
