Agent 4 — Vòng lặp tác tử & điều khiển: trái tim của harness
Vòng lặp là nơi harness thật sự sống
Ở bài 1 — Harness Engineering ta nói harness quan trọng hơn model; ở bài 2 — Thiết kế Tool ta dựng những "cửa" để agent chạm vào thế giới. Nhưng tool nằm im cho tới khi có thứ gọi chúng theo trình tự, đọc kết quả, và quyết định bước tiếp theo. Thứ đó là vòng lặp tác tử (agentic loop) — đoạn code trung tâm biến một mô hình ngôn ngữ thành một tác tử.
Nghe thì có vẻ ghê gớm, nhưng bản chất vòng lặp lại đơn giản đến bất ngờ: gọi model → xem model muốn gì → nếu muốn dùng tool thì chạy tool và đưa kết quả lại → lặp → dừng khi model bảo xong. Cái khó không nằm ở "vòng lặp" mà ở điều khiển nó: khi nào dừng, chống loop vô hạn, chống cháy quota, xử lý tool lỗi, chạy tool song song an toàn. Đó mới là phần kỹ thuật thực sự.
Cơ chế thật của Messages API
Với Anthropic SDK, một lượt gọi model là client.messages.create(...). Khi bạn khai báo tools=[...], model có thể trả về — trong danh sách content block — một block loại tool_use gồm id, name, và input (tham số model tự điền). Khi đó trường stop_reason == "tool_use".
Harness (không phải model, không phải Anthropic) chịu trách nhiệm thực thi tool đó, rồi gửi lại một message role=user chứa block tool_result với tool_use_id trỏ đúng vào id của lời gọi, và content là kết quả. Sau đó gọi model tiếp. Vòng lặp chạy tới khi stop_reason == "end_turn" — nghĩa là model đã nói xong và không cần tool nào nữa.
Điểm cốt tử: model không tự chạy tool. Nó chỉ đề nghị dùng tool. Toàn bộ việc thực thi, bắt lỗi, timeout, ghi audit… là code của bạn. Đây chính là lý do vòng lặp là phần harness bạn phải hiểu tường tận.
Các stop_reason và cách harness xử lý
Trường stop_reason cho biết vì sao model dừng lượt. Có sáu giá trị, và một harness nghiêm túc phải xử lý tất cả:
stop_reason | Ý nghĩa | Harness làm gì |
|---|---|---|
end_turn | Model nói xong tự nhiên | Kết thúc vòng lặp, trả lời cuối cho người dùng |
tool_use | Model đề nghị gọi ≥1 tool | Thực thi các tool, nối tool_result, lặp lại |
max_tokens | Chạm trần max_tokens của lượt | Đầu ra bị cắt giữa chừng → gọi tiếp để model "viết nốt" (continue), hoặc tăng max_tokens |
stop_sequence | Trúng một chuỗi dừng bạn khai báo | Coi như xong theo quy ước của bạn; xử lý phần đã sinh |
pause_turn | Lượt bị tạm dừng (tác vụ chạy dài, vd tool phía server) | Gọi lại với nguyên content đã trả để model tiếp tục |
refusal | Model từ chối vì lý do an toàn | Dừng an toàn: không lặp mù, ghi log, báo người dùng/nghiệp vụ |
Hai nhánh dễ bị bỏ quên nhất là max_tokens và refusal. Bỏ quên max_tokens khiến agent "cụt" câu mà không ai biết. Bỏ quên refusal (coi như lỗi rồi retry) có thể khiến agent lặp lại nỗ lực làm điều nó nên từ chối — cực nguy hiểm trong môi trường ngân hàng. pause_turn xuất hiện với các tác vụ dài; cách xử lý là gọi lại nguyên trạng để model nối tiếp.
Workflow hay Agent? "Start simple" trước đã
Trước khi viết một vòng lặp tự định hướng, hãy hỏi: bạn có thật sự cần agent không? Anthropic, trong bài "Building effective agents" (Engineering, 12/2024), phân biệt rạch ròi:
- Workflow: luồng do code định sẵn, các bước và nhánh cố định. Model chỉ là một mắt xích được orchestrate. Các mẫu tiêu biểu: prompt chaining (nối chuỗi prompt), routing (phân loại rồi rẽ nhánh), parallelization (chia phần — sectioning, hoặc bỏ phiếu — voting), evaluator–optimizer (một model tạo, một model chấm rồi lặp cải thiện).
- Agent: model tự định hướng vòng lặp — tự quyết dùng tool nào, theo thứ tự nào, khi nào dừng — dựa trên phản hồi từ môi trường.
Thông điệp lõi của Anthropic là "start simple": chỉ tăng độ phức tạp khi thật sự cần. Rất nhiều bài toán tưởng cần agent lại giải gọn bằng một workflow xác định — vừa rẻ, vừa dễ kiểm thử, vừa dễ audit (điều mà ngân hàng cực coi trọng). Anthropic gọi khối nền tảng là "augmented LLM": model + retrieval + tools + memory. Agent tự định hướng chỉ nên dùng khi không thể vẽ trước luồng, vì độ mở của bài toán quá lớn.
Quy tắc thực dụng cho NCB: nếu bạn viết được sơ đồ luồng cố định trên giấy, hãy làm workflow. Chỉ khi số nhánh bùng nổ và phụ thuộc dữ liệu thời gian chạy mới thả cho model tự lái bằng vòng lặp agent.
Điều khiển vòng lặp: phần khó thật sự
Một vòng lặp while True: gọi model; chạy tool chạy được trong demo nhưng sẽ cháy quota, treo, hoặc lặp vô hạn trong sản xuất. Dưới đây là các cơ chế điều khiển bắt buộc.
1. Điều kiện dừng rõ ràng
Vòng lặp phải có nhiều điều kiện dừng, không chỉ end_turn:
- Model báo xong (
end_turn) hoặc từ chối (refusal). - Chạm ngân sách bước (số vòng tối đa).
- Chạm ngân sách token (tổng token tích luỹ).
- Chạm timeout tổng của phiên.
Thiếu bất kỳ cái nào cũng để lại một cửa cho agent chạy mãi.
2. Ngân sách bước & ngân sách token
Đây là lá chắn chống loop vô hạn và cháy quota. Đặt MAX_STEPS (vd 8–12 vòng cho tác vụ phân tích) và một trần token cộng dồn từ response.usage. Khi chạm trần, đừng cắt phũ: chèn một message hệ thống bảo model kết luận với thông tin đang có, rồi gọi một lượt cuối không kèm tool để lấy câu trả lời. Cách này giữ agent luôn trả về thứ dùng được thay vì báo lỗi.
Đáng nhớ từ bài "Building a multi-agent research system" (Anthropic, 2025): agent dùng ~4× token so với chat, hệ multi-agent ~15× token so với chat, và token giải thích tới ~80% phương sai hiệu năng. Token là tài nguyên chính của agent — ngân sách token không phải tuỳ chọn mà là thiết kế cốt lõi.
3. Xử lý lỗi tool, retry & backoff
Tool sẽ lỗi: query timeout, mạng chập chờn, tham số model điền sai. Nguyên tắc từ "Writing effective tools for AI agents": trả lỗi có ý nghĩa để model tự sửa. Có hai tầng:
- Lỗi tạm thời (transient) — timeout DB, 5xx, rate limit: harness retry với backoff (vd 0.5s → 1s → 2s, có jitter), tối đa vài lần. Model không cần biết chuyện này.
- Lỗi logic — SQL sai cột, tham số ngoài miền: trả thông báo lỗi rõ ràng vào
tool_resultđể model sửa ở vòng sau (đổi câu SQL, đổi tham số). Nhớ đặt cờis_errorcho block khi thích hợp.
Đừng nuốt lỗi thành chuỗi rỗng — model sẽ tưởng tool thành công và lý luận sai.
4. Timeout
Mỗi lời gọi tool cần timeout riêng; cả phiên cần timeout tổng. Một query lỡ quét bảng lớn có thể treo cả agent. Với NCB, tool truy vấn read-replica luôn đặt statement_timeout để không lời gọi nào giữ kết nối quá lâu.
5. Gọi tool song song
Trong một lượt, model có thể trả nhiều block tool_use cùng lúc (ví dụ: đọc số dư và liệt kê giao dịch và tra hạn mức). Chúng độc lập → harness nên thực thi song song (thread/async) rồi gộp tất cả tool_result vào một message user kế tiếp. Đây là đòn giảm độ trễ lớn nhất và gần như miễn phí. Lưu ý: mỗi tool_result phải khớp đúng tool_use_id, và bạn phải trả đủ kết quả cho mọi tool_use model yêu cầu, nếu không API sẽ báo lỗi thiếu kết quả.
6. Idempotency để retry an toàn
Vì có retry, mọi thao tác thay đổi trạng thái phải idempotent — chạy hai lần cho cùng kết quả một lần. Với tác vụ chỉ đọc (SELECT trên read-replica) thì miễn phí. Với tác vụ ghi (tạo ticket, gửi cảnh báo), dùng khoá idempotency (một request_id duy nhất) để lần retry thứ hai không tạo bản ghi trùng. Không có idempotency thì backoff-retry trở thành máy nhân bản tác dụng phụ.
Vòng lặp trần vs Tool Runner của SDK
Bạn có hai cách viết vòng lặp:
| Vòng lặp trần (tự viết) | Tool runner của SDK | |
|---|---|---|
| Ai lặp | Bạn viết tay while | SDK tự lặp gọi–thực thi–nối |
| Kiểm soát | Toàn quyền: ngân sách, log, song song, dừng an toàn | Ít boilerplate, nhưng ít móc can thiệp hơn |
| Phù hợp | Sản xuất có ràng buộc chặt (ngân hàng), cần audit từng bước | Prototype, agent đơn giản, dựng nhanh |
Khuyến nghị: hiểu vòng lặp trần trước, kể cả khi cuối cùng bạn dùng tool runner. Vì mọi thứ tool runner làm ngầm — đọc stop_reason, nối tool_result, dừng ở end_turn — bạn phải hiểu để gỡ lỗi khi agent hành xử lạ. Claude Agent SDK cung cấp cả khung vòng lặp lẫn quản lý tool/sub-agent/quyền; nhưng bên dưới nó vẫn là đúng vòng lặp Messages API ở trên.
Một chi tiết dễ sai khi tự viết: giữ nguyên block thinking. Trên các model 4.6+ (gồm claude-opus-4-8), khi bật extended thinking bằng thinking={"type": "adaptive"}, model trả về block thinking trong content. Khi nối hội thoại cho vòng sau, bạn phải append nguyên cả response.content (bao gồm block thinking), không được lọc bỏ — nếu bỏ, model mất mạch lý luận giữa các bước. Lưu ý với model 4.6+ dùng adaptive, không dùng budget_tokens (sẽ bị từ chối).
Ví dụ Python đầy đủ (minh hoạ)
Dưới đây là một vòng lặp trần minh hoạ (không phải code sản xuất) với Anthropic SDK, model claude-opus-4-8, extended thinking adaptive, có ngân sách bước, xử lý stop_reason, thực thi nhiều tool_use song song, và bắt lỗi tool trả về cho model.
import concurrent.futures as cf
from anthropic import Anthropic
client = Anthropic()
TOOLS = [{
"name": "run_sql",
"description": "Chạy 1 câu SELECT chỉ-đọc trên read-replica NCB. "
"Trả lỗi rõ ràng nếu SQL sai để bạn tự sửa.",
"input_schema": {
"type": "object",
"properties": {"query": {"type": "string"}},
"required": ["query"],
},
}]
def execute_tool(block):
"""Thực thi 1 tool_use, luôn trả về 1 tool_result block."""
try:
if block.name == "run_sql":
rows = run_readonly_sql(block.input["query"], timeout_s=15) # có statement_timeout
return {"type": "tool_result", "tool_use_id": block.id,
"content": format_rows(rows)}
raise ValueError(f"tool không tồn tại: {block.name}")
except Exception as e:
# Lỗi logic -> trả cho model tự sửa ở vòng sau
return {"type": "tool_result", "tool_use_id": block.id,
"is_error": True, "content": f"Lỗi khi chạy tool: {e}"}
def agent_loop(user_msg, max_steps=8):
messages = [{"role": "user", "content": user_msg}]
for step in range(max_steps):
resp = client.messages.create(
model="claude-opus-4-8",
max_tokens=4096,
thinking={"type": "adaptive"},
tools=TOOLS,
messages=messages,
)
# GIỮ NGUYÊN cả content (gồm block thinking) khi nối
messages.append({"role": "assistant", "content": resp.content})
if resp.stop_reason == "end_turn":
return final_text(resp) # xong
if resp.stop_reason == "refusal":
return "[Model từ chối — dừng an toàn]" # KHÔNG retry mù
if resp.stop_reason == "max_tokens":
messages.append({"role": "user",
"content": "Hãy kết luận ngắn gọn với thông tin đang có."})
continue
if resp.stop_reason == "tool_use":
tool_uses = [b for b in resp.content if b.type == "tool_use"]
# Thực thi SONG SONG nhiều tool_use trong cùng một lượt
with cf.ThreadPoolExecutor() as pool:
results = list(pool.map(execute_tool, tool_uses))
# Gộp TẤT CẢ tool_result vào MỘT message user kế tiếp
messages.append({"role": "user", "content": results})
continue
# Chạm ngân sách bước: buộc kết luận, gọi 1 lượt cuối KHÔNG tool
messages.append({"role": "user",
"content": "Đã đạt giới hạn bước. Kết luận với dữ liệu hiện có."})
final = client.messages.create(model="claude-opus-4-8", max_tokens=1024,
thinking={"type": "adaptive"}, messages=messages)
return final_text(final)
Những điểm đáng chú ý trong đoạn trên: (1) mọi nhánh stop_reason đều được xử lý; (2) lỗi tool được gói thành tool_result có is_error để model tự sửa, không văng exception phá vòng lặp; (3) nhiều tool_use chạy song song rồi gộp một message; (4) chạm trần bước thì buộc kết luận thay vì báo lỗi trơ. run_readonly_sql và format_rows là hàm hạ tầng của bạn (kết nối read-replica, đặt statement_timeout, cắt gọn kết quả).
Máy trạng thái của vòng lặp
Use case thực tế
Bối cảnh. Đội Vận hành NCB cần một trợ lý phân tích giao dịch để cán bộ nghiệp vụ hỏi bằng tiếng Việt ("Chi nhánh Hà Nội tháng này có giao dịch bất thường nào không?") và nhận trả lời có số liệu. Trợ lý chạy trên read-replica (chỉ đọc), có tool run_sql, và một vòng lặp có ngân sách 8 bước.
Thiết kế điều khiển.
- Ngân sách bước = 8: đủ để model thăm dò (đếm tổng → khoanh vùng → soi chi tiết → đối chiếu) mà không lang thang. Chạm 8 → buộc kết luận.
- Retry SQL lỗi: khi model điền sai cột (ví dụ tưởng
transactionscócustomer_name), tool trảis_errorkèm thông báo "không có cột customer_name; JOIN customers để lấy tên". Model sửa ở vòng sau — thường mất thêm đúng 1 bước. - Dừng khi đủ: model tự phát
end_turnngay khi có đủ dữ kiện, không phung phí bước còn lại. - Timeout: mỗi query
statement_timeout = 15s; phiên tổng 90s.
Một bước điển hình — model muốn xem quy mô giao dịch theo loại tiền để khoanh vùng:
-- ▶ Chạy được
SELECT a.currency,
COUNT(*) AS so_gd,
ROUND(AVG(t.amount)::numeric, 2) AS gd_tb,
MAX(t.amount) AS gd_lon_nhat
FROM transactions t
JOIN accounts a ON a.id = t.account_id
GROUP BY a.currency
ORDER BY so_gd DESC;
Số liệu quan sát (ước lượng nội bộ, minh hoạ). Trên ~60 câu hỏi mẫu: phần lớn giải trong 3–5 bước, hiếm khi chạm trần 8. Khoảng 15% câu hỏi có ít nhất một lần SQL lỗi cột/kiểu, và nhờ thông báo lỗi rõ, model tự sửa thành công ~9/10 trong 1 bước kế. Nhờ gọi tool song song (đọc tổng quan + chi tiết cùng lượt), độ trễ trung bình mỗi phiên giảm rõ so với chạy tuần tự. Mỗi bước ghi audit log (câu SQL, thời gian chạy, số dòng) phục vụ tuân thủ — đúng tinh thần human-in-the-loop và truy vết ở bài context engineering.
Vì sao không dùng workflow? Vì tập câu hỏi mở: không vẽ trước được nên hỏi bảng nào, JOIN gì, khoanh vùng ra sao. Đây là đúng chỗ agent tự định hướng thắng workflow — nhưng vẫn bọc trong ngân sách chặt để an toàn và kiểm soát chi phí.
Ghi nhớ
- Vòng lặp = trái tim harness: gọi model → đọc
stop_reason→ nếutool_usethì thực thi tool, nốitool_result, lặp → dừng ởend_turn. Model đề nghị tool; harness thực thi. - Xử lý đủ 6
stop_reason:end_turn(xong),tool_use(lặp),max_tokens(viết nốt/continue),stop_sequence(theo quy ước),pause_turn(gọi lại),refusal(dừng an toàn, không retry mù). - Workflow trước, agent sau: theo Anthropic "start simple" — vẽ được luồng cố định thì dùng workflow (prompt chaining, routing, parallelization, evaluator–optimizer); chỉ thả agent tự lái khi bài toán quá mở.
- Điều khiển là phần khó: điều kiện dừng rõ ràng + ngân sách bước & token (chống loop vô hạn, cháy quota) + retry/backoff cho lỗi tạm thời + trả lỗi có nghĩa cho lỗi logic + timeout + gọi tool song song + idempotency cho retry an toàn.
- Token là tài nguyên chính: agent ~4× token so với chat, multi-agent ~15× (theo Anthropic) — ngân sách token là thiết kế, không phải tuỳ chọn.
- Song song đúng cách: nhiều
tool_usetrong một lượt → chạy song song, gộp mọitool_result(khớptool_use_id) vào một message kế tiếp. - Giữ nguyên block
thinkingkhi nối (thinkingadaptivetrênclaude-opus-4-8; không dùngbudget_tokens). - Hiểu vòng lặp trần trước rồi mới dùng tool runner của SDK — để gỡ lỗi khi agent hành xử lạ.
Nguồn tham khảo
- Anthropic — Building effective agents — phân biệt workflow vs agent, "start simple", augmented LLM, các mẫu prompt chaining/routing/parallelization/evaluator–optimizer.
- Anthropic — How we built our multi-agent research system — số liệu token của agent/multi-agent và vai trò của token trong hiệu năng.
- Anthropic — Writing effective tools for AI agents — trả lỗi có ý nghĩa để model tự sửa, thiết kế tool cho agent.
- Anthropic API — Tool use (function calling) — cơ chế
tool_use,tool_result,tool_use_id, gọi tool song song. - Anthropic API — Messages API reference — các giá trị
stop_reason(end_turn,tool_use,max_tokens,stop_sequence,pause_turn,refusal), cấu trúccontentblock,usage. - Yao et al. (2022), ReAct: Synergizing Reasoning and Acting in Language Models, arXiv:2210.03629 — nền tảng vòng lặp suy luận–hành động của tác tử LLM.
Tiếp theo — Agent 5: Bộ nhớ: vòng lặp đã chạy có kiểm soát; nhưng làm sao agent nhớ xuyên các phiên và các bước dài mà không tràn context?
Bài viết liên quan
Đặt nền cho chuỗi AI: phân biệt ba vòng tròn lồng nhau AI ⊃ ML ⊃ DL và khác biệt bản chất giữa lập trình truyền thống với học từ dữ liệu. Giới thiệu ba kiểu học máy (supervised, unsupervised, reinforcement), phân loại descriptive/predictive/prescriptive, quy trình ML end-to-end, chia train/validation/test, overfitting/underfitting và các thuật ngữ nền tảng, gắn với ứng dụng ngân hàng NCB.
Harness — lớp scaffolding quanh model (vòng lặp, tool, context, memory, verify, sub-agent) — mới là thứ quyết định agent chạy được hay chỉ là demo. Bài này mổ xẻ giải phẫu một harness, 7 kỹ năng cốt lõi khi xây agent, single vs multi-agent (kèm số liệu hiệu quả/chi phí), các repo nên dùng, và một quickstart Python dựng-là-chạy cho bối cảnh ngân hàng.
Hiểu LLM từ gốc: bản chất dự đoán token, ba giai đoạn huấn luyện (pretraining, fine-tuning, RLHF), token, context window và các tham số sinh (temperature, top-p). Nắm hiện tượng hallucination và kỹ thuật prompt engineering (vai trò, few-shot, chain-of-thought, ràng buộc đầu ra), kèm ví dụ gọi API model Claude mới nhất với adaptive thinking.
Vì sao dữ liệu quyết định chất lượng mô hình hơn cả thuật toán. Bài này đi qua toàn bộ pipeline chuẩn bị dữ liệu: phân loại dữ liệu, làm sạch (thiếu/ngoại lai/trùng lặp), mã hoá hạng mục, scaling, feature engineering, giảm chiều, và cách phòng data leakage — soi qua bài toán chấm điểm tín dụng.
Cảm nhận của bạn
Bình luận
Chưa có bình luận. Hãy là người đầu tiên chia sẻ!