Domain 1: Agentic Architecture & Orchestration·Task 1.1
Vòng lặp agent và stop_reason
Agent gọi Claude, chạy tool, gửi kết quả rồi gọi tiếp. Bài này giúp bạn biết khi nào vòng lặp phải chạy tiếp, khi nào dừng, và những cách dừng sai hay gặp.
- 8 phút đọc
- Đối chiếu docs 02/11/2026
- 5 nguồn
Đọc xong bạn nắm được
- Biết khi nào vòng lặp phải gọi Claude tiếp, khi nào dừng
- Gửi kết quả tool về đúng cách để Claude dùng được ở lượt sau
- Phân biệt agent tự chọn bước tiếp theo với quy trình viết sẵn trong code
- Nhận ra ba cách dừng vòng lặp nghe hợp lý nhưng sai
Khi bạn cho Claude dùng tool, Claude không tự chạy tool đó. Nó chỉ trả lời kiểu "tôi muốn gọi tool này, với tham số này". Việc chạy tool, gửi kết quả lại cho Claude và gọi Claude thêm lần nữa là việc của code bạn viết. Đoạn code lặp đi lặp lại như vậy gọi là vòng lặp agent, tiếng Anh là agentic loop.
Câu hỏi quan trọng nhất của bài: làm sao code biết lúc nào lặp tiếp, lúc nào dừng? Câu trả lời nằm ở một field trong phản hồi của Claude, tên là stop_reason.
Ví dụ xuyên suốt: agent đặt phòng họp
Giả sử công ty bạn có một agent đặt phòng họp, được cho dùng hai tool:
find_rooms: tìm phòng còn trống theo ngày, giờ, số người và thiết bị cần có.book_room: giữ một phòng và trả về mã đặt phòng.
Một nhân viên nhắn: "Đặt giúp mình phòng cho 6 người, chiều thứ Năm 14h–15h, cần máy chiếu."
Agent sẽ chạy qua ba lượt:
| Lượt | Claude trả về | stop_reason | Code của bạn làm gì |
|---|---|---|---|
| 1 | Yêu cầu gọi find_rooms | tool_use | Chạy find_rooms, gửi kết quả cho Claude: phòng P302 và P305 còn trống |
| 2 | Yêu cầu gọi book_room cho phòng P302 | tool_use | Chạy book_room, gửi kết quả cho Claude: mã đặt BK-0412 |
| 3 | Câu trả lời: "Mình đã đặt phòng P302…" | end_turn | Dừng, gửi câu trả lời cho nhân viên |
Để ý là trong code không có dòng nào viết "tìm phòng xong thì đặt phòng". Claude tự quyết định lượt 2 làm gì sau khi thấy kết quả của lượt 1.
Vòng lặp chạy thế nào
Mỗi vòng có bốn bước:
- Gửi cho Claude toàn bộ cuộc hội thoại từ đầu tới giờ, kèm danh sách tool.
- Xem
stop_reasontrong phản hồi. - Nếu là
tool_use, nghĩa là Claude muốn gọi tool: chạy tool đó, rồi thêm kết quả vào cuộc hội thoại. - Quay lại bước 1. Nếu là
end_turn, nghĩa là Claude đã trả lời xong: dừng.
Viết bằng TypeScript, vòng lặp trông như sau. Bạn chỉ cần để ý những chữ in đậm:
const messages: MessageParam[] = [
{ role: "user", content: "Đặt phòng cho 6 người, chiều thứ Năm 14h–15h, cần máy chiếu" },
];
while (true) {
const response = await client.messages.create({ model, max_tokens: 1024, tools, messages });
messages.push({ role: "assistant", content: response.content });
if (response.stop_reason !== "tool_use") return response;
const results: ToolResultBlockParam[] = [];
for (const block of response.content) {
if (block.type !== "tool_use") continue;
results.push({
type: "tool_result",
tool_use_id: block.id,
content: await runTool(block.name, block.input),
});
}
messages.push({ role: "user", content: results });
}Cho gọn, dòng return ở trên coi mọi giá trị khác tool_use là dừng. Khi viết thật, bạn nên xử lý riêng từng giá trị, xem mục cuối bài.
Gửi kết quả tool về cho đúng
Claude không có trí nhớ giữa các lần gọi. Nó chỉ biết những gì nằm trong danh sách messages bạn gửi lên. Nếu bạn quên thêm kết quả của find_rooms vào đó, ở lượt sau Claude sẽ không biết P302 còn trống, và sẽ gọi lại find_rooms hoặc đoán bừa.
Khi gửi kết quả tool về, bạn cần làm đúng mấy điều sau, nếu không API sẽ báo lỗi hoặc Claude sẽ hiểu sai:
- Trước tiên, lưu nguyên phản hồi của Claude vào
messages(vaiassistant), rồi mới thêm kết quả. - Message chứa kết quả phải nằm ngay sau message có yêu cầu gọi tool. Không chen message nào khác vào giữa.
- Mỗi yêu cầu gọi tool có một
idriêng. Kết quả gửi về phải ghi đúngidđó trong fieldtool_use_id, để Claude biết kết quả nào thuộc yêu cầu nào. Thiếu kết quả cho mộtidthì API báo lỗi. - Trong message kết quả, các khối
tool_resultphải đứng đầu tiên. Đặt chữ lên trước thì API trả lỗi 400. - Tool chạy bị lỗi thì vẫn gửi
tool_result, thêmis_error: truevà mô tả lỗi, để Claude biết mà tìm cách khác.
Claude có thể yêu cầu gọi nhiều tool cùng lúc, ví dụ tìm phòng ở hai tầng một lượt. Khi đó bạn chạy hết, rồi gửi tất cả kết quả trong một message duy nhất.
Để Claude chọn bước tiếp theo, hay viết sẵn trong code
Có hai cách để một hệ thống biết bước tiếp theo làm gì. Đề thi gọi cách thứ nhất là model-driven decision-making, cách thứ hai là pre-configured decision trees hay tool sequences:
| Để Claude tự chọn | Viết sẵn thứ tự trong code | |
|---|---|---|
| Ai quyết định bước tiếp theo | Claude, dựa vào kết quả vừa nhận | Code, theo thứ tự đã định |
Khi find_rooms không tìm thấy phòng nào | Claude có thể tìm khung giờ khác, hoặc hỏi lại người dùng | Code vẫn gọi book_room và lỗi, hoặc dừng luôn |
| Hợp với | Yêu cầu đa dạng, khó đoán trước | Quy trình cố định, lần nào cũng giống nhau |
Vòng lặp agent đi theo cách thứ nhất. Còn khi một bước bắt buộc phải làm trước bước khác, ví dụ phải xác minh danh tính rồi mới được hoàn tiền, thì nên chặn bằng code thay vì chỉ dặn trong prompt. Phần đó nằm ở bài 1.4.
Ba cách dừng vòng lặp nghe hợp lý nhưng sai
Có ba cách quyết định "đã xong chưa" mà nhiều người hay dùng, tiếng Anh gọi chung là anti-pattern (cách làm sai nhưng phổ biến). Trong đề thi, chúng thường nằm ở các đáp án sai, nên bạn cần nhận ra ngay. Mỗi cách có kèm cách đề thi tiếng Anh mô tả nó:
- Đọc nội dung câu trả lời để đoán đã xong (parsing natural language signals to determine loop termination). Ví dụ code dò thấy trong câu trả lời có chữ "đã đặt phòng xong" thì dừng. Câu đó chỉ là lời Claude nói với người dùng, không phải tín hiệu gì của API. Claude có thể viết câu đó mà vẫn còn muốn gọi thêm tool, hoặc lần sau diễn đạt khác đi.
- Đặt số vòng tối đa làm cách dừng chính (setting arbitrary iteration caps as the primary stopping mechanism). Ví dụ "chạy tối đa 5 vòng". Việc cần 6 vòng sẽ bị cắt giữa chừng, còn agent đang lặp vô ích vẫn chạy đủ 5 vòng mới chịu dừng.
- Thấy phản hồi có chữ là coi như xong (checking for assistant text content as a completion indicator). Một phản hồi có thể vừa có chữ ("Để mình tìm phòng trước nhé") vừa có yêu cầu gọi tool. Có chữ không có nghĩa là hết việc.
Đặt số vòng tối đa vẫn có ích, nhưng chỉ để phòng hờ agent chạy không dứt. Agent SDK của Anthropic có tuỳ chọn max_turns cho việc này. Mặc định nó không giới hạn, và khi chạm ngưỡng thì kết quả trả về báo lỗi error_max_turns. Agent dừng bình thường là nhờ stop_reason; giới hạn số vòng chỉ để chặn trường hợp bất thường.
Các giá trị khác của stop_reason
Đề thi chủ yếu hỏi tool_use và end_turn. Khi viết agent thật, bạn sẽ gặp thêm vài giá trị nữa. Biết qua để không coi nhầm chúng là "đã xong":
| Giá trị | Nghĩa là | Nên làm gì |
|---|---|---|
max_tokens | Câu trả lời bị cắt vì chạm giới hạn max_tokens bạn đặt | Tăng max_tokens hoặc cho Claude viết tiếp |
stop_sequence | Claude gặp một chuỗi dừng mà bạn tự đặt | Xem field stop_sequence để biết chuỗi nào |
pause_turn | Tool chạy phía Anthropic (như web search) đã lặp tới giới hạn, mặc định 10 lượt | Gửi lại nguyên phản hồi để Claude làm tiếp |
refusal | Claude từ chối trả lời | Xem stop_details để biết lý do, có thể thử lại bằng model khác |
model_context_window_exceeded | Câu trả lời lấp đầy giới hạn ngữ cảnh của model | Coi như câu trả lời bị cắt |
- stop_reason là tool_use?Chạy tool, gửi kết quả, gọi Claude tiếp
- pause_turn?Gửi lại nguyên phản hồi để Claude làm tiếp
- max_tokens hoặc model_context_window_exceeded?Câu trả lời bị cắt: tăng max_tokens hoặc cho viết tiếp
- refusal?Xem stop_details, thử model khác hoặc báo người dùng
- Còn lạiend_turn hoặc stop_sequence: dừng, dùng câu trả lời
Anthropic Exam Pro