Một trong những sai lầm phổ biến nhất khi xây dựng agentic loop (vòng lặp agentic) là chỉ tập trung vào việc agent bắt đầu task như thế nào, mà quên mất câu hỏi quan trọng hơn: khi nào agent nên dừng lại? Nếu không có cơ chế exit condition (điều kiện thoát) rõ ràng, agent có thể lặp đi lặp lại các bước không cần thiết, gọi lại các tool đã gọi trước đó, hoặc "suy nghĩ" lan man chỉ để cuối cùng đưa ra kết quả không tốt hơn kết quả nó đã có ở vòng lặp thứ ba. Mỗi vòng lặp dư thừa đó đều tiêu tốn token thật, tiền thật, và thời gian phản hồi thật.
Bài học này đi sâu vào cách thiết kế và triển khai các điều kiện dừng cho agentic loop — từ lý thuyết phân loại đến code thực tế trên các framework phổ biến như LangGraph, CrewAI và OpenAI Assistants API.
The Token Cost of Running Too Long — Cái Giá Của Việc Chạy Quá Lâu
Hãy tưởng tượng một agent được giao nhiệm vụ "tìm và sửa lỗi khiến test suite fail". Với một agentic loop không có exit condition tốt, kịch bản thường thấy là:
- Vòng 1-3: Agent đọc log lỗi, đọc file liên quan, đưa ra fix đầu tiên.
- Vòng 4-6: Test vẫn fail (vì fix chưa đúng), agent đọc lại gần như toàn bộ context cũ, thử fix khác.
- Vòng 7-10: Agent bắt đầu "loanh quanh" — thử lại các hướng đã thử, đọc lại các file đã đọc, vì nó không có tín hiệu nào cho biết "hướng đi này đã ngõ cụt, cần dừng và báo cáo".
Mỗi vòng lặp này không chỉ tốn token cho phần input mới, mà còn tốn gấp nhiều lần cho phần context history phải gửi lại toàn bộ ở lượt gọi sau (đây chính là hệ quả của cách agentic loop hoạt động: mỗi lượt gọi LLM đều phải kèm theo toàn bộ lịch sử hội thoại trước đó).
Hãy làm một phép tính cụ thể để thấy độ nghiêm trọng:
| Vòng lặp | Token input (bao gồm history) | Token output | Tổng token vòng này |
|---|---|---|---|
| 1 | 2,000 | 500 | 2,500 |
| 2 | 3,000 | 500 | 3,500 |
| 3 | 4,200 | 600 | 4,800 |
| 4 | 5,500 | 600 | 6,100 |
| 5 | 7,000 | 700 | 7,700 |
| ... | ... | ... | ... |
| 10 (nếu chạy runaway) | 14,000 | 900 | 14,900 |
Nếu agent chạy đến vòng 10 mới bị buộc dừng bởi timeout của hệ thống, tổng token tiêu thụ có thể lên đến 60,000-70,000 token cho một task mà lẽ ra chỉ cần 3 vòng (khoảng 10,800 token) là đã đủ dữ liệu để biết "cách này không hiệu quả, cần dừng và hỏi người dùng hoặc báo lỗi". Chênh lệch này không phải vài phần trăm — nó là 5-6 lần lượng token lãng phí, và với mức giá của các model cao cấp, một task đơn giản có thể tốn phí bằng cả chục task bình thường.
Vấn đề còn nghiêm trọng hơn ở quy mô production: nếu bạn chạy hàng nghìn agent instance mỗi ngày và chỉ 5-10% trong số đó rơi vào tình trạng "chạy dư" như trên, chi phí token bị lãng phí có thể chiếm phần lớn trong tổng chi phí vận hành hệ thống agentic — trong khi phần giá trị mang lại từ những vòng lặp dư đó gần như bằng không, thậm chí có thể khiến chất lượng kết quả cuối tệ hơn (agent "cố" sửa thêm và làm hỏng thứ đã đúng).
Mẹo: Luôn log lại số vòng lặp (iteration_count) và tổng token tiêu thụ theo từng task, kèm theo trạng thái exit cuối cùng (success, budget_exceeded, stuck, error). Sau một thời gian vận hành, bạn sẽ có dữ liệu thực tế để trả lời câu hỏi "task loại nào thường chạy runaway?" — từ đó tinh chỉnh exit condition cho đúng loại task đó, thay vì áp một ngưỡng chung cho tất cả.
Taxonomy of Exit Conditions — Phân Loại Các Điều Kiện Dừng
Để thiết kế exit condition hiệu quả, trước tiên cần phân loại rõ các "lý do" khiến một agentic loop nên dừng lại. Có bốn nhóm chính, và một hệ thống agentic trưởng thành nên triển khai đầy đủ cả bốn, không chỉ dựa vào một loại duy nhất.
1. Success Conditions — Điều Kiện Thành Công
Đây là nhóm lý tưởng nhất: agent đã hoàn thành mục tiêu và có thể tự xác nhận điều đó. Success condition thường được biểu diễn dưới dạng:
- Agent tự đưa ra tín hiệu hoàn thành (ví dụ output chứa
TASK_COMPLETEhoặc gọi một tool đặc biệt nhưsubmit_final_answer). - Một điều kiện có thể kiểm tra được từ bên ngoài đã đúng (test suite pass, file đã được tạo đúng định dạng, API trả về status 200).
- Người dùng (hoặc một agent giám sát khác) xác nhận kết quả đạt yêu cầu.
Điểm mấu chốt: success condition đáng tin cậy nhất khi nó không chỉ dựa vào lời tự nhận của agent, mà còn được xác minh bằng một cơ chế độc lập (ví dụ chạy lại test suite sau khi agent báo "đã fix xong").
2. Convergence Conditions — Điều Kiện Hội Tụ (Convergence)
Convergence (hội tụ) xảy ra khi agent không còn tạo ra thay đổi đáng kể nào giữa các vòng lặp — nó đang "đứng yên" về mặt nội dung dù vẫn tiếp tục sinh token. Đây là dấu hiệu quan trọng để dừng loop dù chưa đạt success, vì tiếp tục chạy thêm gần như chắc chắn không mang lại giá trị mới.
Các tín hiệu convergence phổ biến:
- Output của vòng lặp hiện tại giống (hoặc rất giống) output của vòng trước, đo bằng similarity score (điểm tương đồng văn bản).
- Agent liên tục gọi cùng một tool với cùng tham số.
- Độ dài hoặc cấu trúc của kế hoạch (plan) không thay đổi qua nhiều vòng.
3. Budget Conditions — Điều Kiện Ngân Sách
Đây là "lưới an toàn" cứng — không phụ thuộc vào việc agent có tự nhận biết được tình trạng của nó hay không. Budget condition đặt ra giới hạn cụ thể, ví dụ:
- Số vòng lặp tối đa (
max_iterations). - Tổng số token tối đa cho một task (
max_tokens_budget). - Thời gian chạy tối đa (
max_wall_clock_seconds). - Số lần gọi tool tối đa, hoặc số lần gọi một tool cụ thể tối đa.
Budget condition không thông minh, nhưng nó là điều kiện bắt buộc phải có trong mọi hệ thống production — nó là lớp bảo vệ cuối cùng khi tất cả các cơ chế phát hiện khác thất bại.
4. Failure Conditions — Điều Kiện Thất Bại
Failure condition phát hiện khi agent đang đi vào ngõ cụt hoặc gặp lỗi không thể tự phục hồi, và việc dừng sớm (thay vì cố "gỡ" thêm) là lựa chọn tốt hơn:
- Agent liên tục gặp lỗi từ cùng một tool (ví dụ 3 lần gọi API liên tiếp đều trả lỗi 500).
- Agent tự báo cáo rằng nó bị "kẹt" hoặc thiếu thông tin cần thiết để tiếp tục.
- Phát hiện vòng lặp logic (agent A gọi B, B gọi lại A với input gần như giống ban đầu).
- Chi phí ước tính để tiếp tục vượt quá giá trị kỳ vọng của việc hoàn thành task (một dạng phân tích cost-benefit đơn giản).
Mẹo: Đừng chỉ coi failure condition là "trường hợp xấu cần tránh". Một agent dừng đúng lúc với thông báo "tôi không thể tiếp tục vì thiếu quyền truy cập file X" có giá trị vận hành cao hơn nhiều so với một agent chạy thêm 5 vòng vô ích rồi mới báo lỗi tương tự — hãy thiết kế failure condition như một tính năng, không phải một lỗi cần che giấu.
Implementing Exit Conditions: From Concept to Code — Từ Ý Tưởng Đến Code
Sau khi đã hiểu rõ bốn loại exit condition, phần quan trọng nhất là triển khai chúng vào agentic loop thực tế. Dưới đây là ba phương pháp phổ biến, có thể kết hợp với nhau trong cùng một hệ thống.
Method 1: Stop Signal in Agent Output — Tín Hiệu Dừng Trong Output Của Agent
Cách đơn giản và phổ biến nhất: yêu cầu agent tự phát ra một tín hiệu rõ ràng khi nó cho rằng task đã hoàn thành, thường thông qua structured output (output có cấu trúc) hoặc một trường đặc biệt trong JSON response.
from dataclasses import dataclass
from typing import Optional
@dataclass
class AgentStepResult:
content: str
is_done: bool
reason: Optional[str] = None
def run_agent_step(llm_client, messages: list) -> AgentStepResult:
"""
Ask the LLM to respond, and require it to explicitly
mark whether the task is complete via a structured field.
"""
response = llm_client.chat.completions.create(
model="claude-sonnet-5",
messages=messages,
# Force the model to return a JSON object with an explicit
# "is_done" flag instead of relying on free-text parsing.
response_format={"type": "json_object"},
)
parsed = response.choices[0].message.parsed
return AgentStepResult(
content=parsed["content"],
is_done=parsed.get("is_done", False),
reason=parsed.get("reason"),
)
def agentic_loop(llm_client, initial_messages: list, max_iterations: int = 8):
messages = initial_messages
for step in range(max_iterations):
result = run_agent_step(llm_client, messages)
messages.append({"role": "assistant", "content": result.content})
if result.is_done:
print(f"Exiting at step {step}: {result.reason}")
return result # Success condition met, stop immediately.
print("Exiting due to max_iterations budget condition.")
return None
Điểm cần lưu ý: không nên tin tuyệt đối vào is_done do agent tự báo. Trong các task quan trọng (sửa code, xử lý giao dịch), hãy kết hợp thêm một bước xác minh độc lập (ví dụ chạy lại test) trước khi coi task là thực sự hoàn thành.
Method 2: Convergence Detection — Phát Hiện Hội Tụ
Khi agent không tự báo hoàn thành nhưng output của nó đã "đứng yên" qua nhiều vòng, ta cần một cơ chế đo độ tương đồng giữa các vòng lặp liên tiếp để chủ động dừng.
from difflib import SequenceMatcher
def similarity(a: str, b: str) -> float:
"""Return a 0-1 similarity ratio between two pieces of text."""
return SequenceMatcher(None, a, b).ratio()
class ConvergenceDetector:
def __init__(self, similarity_threshold: float = 0.92, patience: int = 2):
# patience: how many consecutive "no-change" rounds
# we tolerate before declaring convergence.
self.similarity_threshold = similarity_threshold
self.patience = patience
self.previous_output: str = ""
self.stagnant_rounds = 0
def check(self, current_output: str) -> bool:
"""Return True if the loop should exit due to convergence."""
if self.previous_output:
score = similarity(self.previous_output, current_output)
if score >= self.similarity_threshold:
self.stagnant_rounds += 1
else:
self.stagnant_rounds = 0
self.previous_output = current_output
return self.stagnant_rounds >= self.patience
detector = ConvergenceDetector()
for step in range(max_iterations):
result = run_agent_step(llm_client, messages)
if detector.check(result.content):
print("Exiting: output has converged, no meaningful change detected.")
break
Kỹ thuật này đặc biệt hữu ích với các task dạng "brainstorm", "viết lại", "tối ưu code" — những task mà agent có xu hướng lặp lại gần như y nguyên câu trả lời khi đã đạt đến giới hạn khả năng cải thiện.
Method 3: Tool-Call-Based Exit Triggers — Kích Hoạt Dừng Dựa Trên Lịch Sử Gọi Tool
Nhiều dấu hiệu "chạy runaway" thể hiện rõ nhất qua pattern gọi tool, không phải qua nội dung text. Ví dụ agent gọi cùng một tool với cùng tham số 3 lần liên tiếp — đó gần như luôn là dấu hiệu bị kẹt.
from collections import deque
class ToolCallExitTrigger:
def __init__(self, repeat_threshold: int = 3, error_threshold: int = 3):
self.repeat_threshold = repeat_threshold
self.error_threshold = error_threshold
self.recent_calls: deque = deque(maxlen=repeat_threshold)
self.consecutive_errors = 0
def record_call(self, tool_name: str, tool_args: dict, tool_error: bool):
call_signature = (tool_name, tuple(sorted(tool_args.items())))
self.recent_calls.append(call_signature)
self.consecutive_errors = (
self.consecutive_errors + 1 if tool_error else 0
)
def should_exit(self) -> Optional[str]:
# Trigger 1: same tool call repeated identically.
if (
len(self.recent_calls) == self.repeat_threshold
and len(set(self.recent_calls)) == 1
):
return "repeated_tool_call"
# Trigger 2: consecutive tool failures.
if self.consecutive_errors >= self.error_threshold:
return "consecutive_tool_errors"
return None
trigger = ToolCallExitTrigger()
for step in range(max_iterations):
result = run_agent_step(llm_client, messages)
for call in result.tool_calls:
tool_error = execute_tool_and_get_error_flag(call)
trigger.record_call(call.name, call.args, tool_error)
exit_reason = trigger.should_exit()
if exit_reason:
print(f"Exiting due to failure condition: {exit_reason}")
break
Cách này thuộc nhóm failure condition trong taxonomy đã nêu — nó không cần agent "tự nhận" gặp khó khăn, mà suy luận từ hành vi thực tế.
Mẹo: Kết hợp cả ba phương pháp trong cùng một loop theo thứ tự ưu tiên: kiểm tra success signal trước (Method 1), sau đó convergence (Method 2), cuối cùng là tool-call trigger và budget cứng (Method 3 + giới hạn max_iterations). Thứ tự này đảm bảo agent được dừng đúng lý do sớm nhất có thể, giúp việc debug và phân tích log sau này dễ dàng hơn nhiều.
Framework-Specific Early Termination — Triển Khai Theo Từng Framework
Các framework agentic phổ biến hiện nay đều có cơ chế riêng để hỗ trợ early termination (dừng sớm). Hiểu đúng cách từng framework xử lý sẽ giúp bạn tránh việc phải tự viết lại toàn bộ logic từ đầu.
LangGraph: Conditional Edges and State-Based Exits
LangGraph mô hình hóa agentic loop dưới dạng graph (đồ thị) với các node và edge (cạnh nối). Cơ chế dừng sớm tự nhiên nhất trong LangGraph là conditional edge (cạnh có điều kiện) — một hàm quyết định node kế tiếp dựa trên state hiện tại, bao gồm cả việc dẫn về END.
from langgraph.graph import StateGraph, END
from typing import TypedDict
class AgentState(TypedDict):
messages: list
iteration: int
is_done: bool
stagnant_rounds: int
def should_continue(state: AgentState) -> str:
"""
Conditional edge function: inspects the current state and
decides whether to loop back to 'agent' or exit to END.
"""
if state["is_done"]:
return "END"
if state["iteration"] >= 10:
return "END" # Budget condition.
if state["stagnant_rounds"] >= 2:
return "END" # Convergence condition.
return "agent"
graph = StateGraph(AgentState)
graph.add_node("agent", agent_node_fn)
graph.add_conditional_edges(
"agent",
should_continue,
{"agent": "agent", "END": END},
)
Ưu điểm của cách này: toàn bộ logic exit condition được tách riêng khỏi logic xử lý chính của agent, giúp code dễ đọc và dễ test độc lập (bạn có thể unit test hàm should_continue mà không cần chạy cả graph).
CrewAI: Max Iterations and Task Callbacks
CrewAI cung cấp cơ chế max_iter ở cấp độ Agent (budget condition cứng) kết hợp với callback ở cấp độ Task để phát hiện các tình huống hoàn thành sớm bất thường hoặc thất bại.
from crewai import Agent, Task, Crew
researcher = Agent(
role="Research Analyst",
goal="Find the three most relevant competitor pricing pages",
max_iter=6, # Stop after 6 internal reasoning/tool loops.
max_execution_time=180, # Also cap by wall-clock time (seconds).
)
def detect_premature_or_failed_completion(task_output):
"""
Callback invoked after the task finishes. Detects whether the
agent stopped too early (empty/short result) or clearly failed,
so the pipeline can flag it instead of silently accepting a bad result.
"""
text = task_output.raw or ""
if len(text.strip()) < 50:
raise ValueError(
"Task output looks incomplete (premature completion detected)."
)
if "unable to complete" in text.lower() or "error" in text.lower()[:200]:
raise ValueError("Task output indicates failure condition triggered.")
return task_output
pricing_task = Task(
description="Research competitor pricing and summarize findings.",
expected_output="A bullet list of 3 competitors with pricing tiers.",
agent=researcher,
callback=detect_premature_or_failed_completion,
)
crew = Crew(agents=[researcher], tasks=[pricing_task])
max_iter đóng vai trò budget condition, trong khi callback đóng vai trò lớp kiểm tra failure/success condition sau khi task hoàn tất — hai lớp này bổ trợ cho nhau: một chặn runaway trong khi chạy, một xác thực chất lượng sau khi dừng.
OpenAI Assistants API: Run Control
Với OpenAI Assistants API, vòng đời của một agentic loop được quản lý qua đối tượng Run, với các trạng thái (status) như completed, requires_action, expired, failed. Việc dừng sớm ở đây thường được thực hiện bằng cách chủ động gọi API hủy run (cancel) khi phát hiện điều kiện dừng ở phía client, kết hợp với tham số giới hạn thời gian như max_prompt_tokens và max_completion_tokens được set ngay khi tạo run.
Cách tiếp cận này khác biệt so với LangGraph hay CrewAI ở điểm: exit condition không nằm hoàn toàn "trong" framework, mà phần lớn logic giám sát (polling trạng thái, kiểm tra convergence, kiểm tra ngân sách token) nằm ở phía code client gọi API — bản thân Assistants API chỉ cung cấp các "van an toàn" cứng (token budget) và điểm neo (cancel) để client can thiệp kịp thời.
Mẹo: Khi làm việc với OpenAI Assistants API, luôn set max_prompt_tokens/max_completion_tokens ngay từ lúc tạo run, đừng chỉ dựa vào việc polling và tự tính token ở client — vì giữa hai lần poll, run vẫn tiếp tục tiêu token phía server, và bạn có thể phát hiện quá muộn.
Handling Partial Results on Early Termination — Xử Lý Kết Quả Dở Dang
Một sai lầm thường gặp: coi early termination đồng nghĩa với "hủy toàn bộ, không lấy gì cả". Trong thực tế, phần lớn các trường hợp dừng sớm (đặc biệt do budget hoặc convergence) vẫn để lại kết quả dở dang có giá trị — và việc trả về nó, kèm theo trạng thái rõ ràng, thường tốt hơn nhiều so với việc trả về lỗi trắng hoặc im lặng.
Nguyên tắc thiết kế nên áp dụng:
- Luôn giữ lại output tốt nhất đã có, không chỉ output của vòng lặp cuối. Có những trường hợp vòng lặp thứ 4 cho kết quả tốt hơn vòng lặp thứ 6 (agent "sửa" nhưng lại làm tệ hơn) — cần một cơ chế theo dõi "best-so-far" (kết quả tốt nhất tính đến hiện tại) thay vì chỉ lấy kết quả cuối cùng.
- Trả về metadata về lý do dừng (
exit_reason,iteration_count,confidence_level) cùng với kết quả, để hệ thống downstream (hoặc con người) biết cách xử lý kết quả này khác với kết quả "thành công hoàn toàn". - Phân loại mức độ tin cậy của kết quả dở dang — ví dụ kết quả dừng do đạt convergence thường đáng tin hơn kết quả dừng do budget exceeded (vì convergence nghĩa là agent đã "ổn định", còn budget exceeded có thể xảy ra giữa lúc agent vẫn đang cải thiện).
@dataclass
class PartialResult:
best_output: str
exit_reason: str
iteration_reached: int
confidence: str # "high", "medium", "low"
def finalize_on_early_exit(history: list, exit_reason: str) -> PartialResult:
# Pick the best-so-far output rather than blindly using the last one.
best = max(history, key=lambda h: h.get("quality_score", 0))
confidence = "high" if exit_reason in ("success", "convergence") else "low"
return PartialResult(
best_output=best["content"],
exit_reason=exit_reason,
iteration_reached=len(history),
confidence=confidence,
)
Mẹo: Đừng thiết kế hệ thống theo hướng nhị phân "thành công hoàn toàn" hoặc "thất bại hoàn toàn". Hãy để downstream (người dùng, hệ thống khác, hoặc một agent review) tự quyết định có chấp nhận kết quả confidence: "low" hay không — điều này giúp bạn tận dụng được phần công việc agent đã làm, thay vì vứt bỏ toàn bộ token đã chi.
Proactive vs. Reactive Exit Condition Design — Thiết Kế Chủ Động So Với Bị Động
Có hai triết lý thiết kế exit condition, và một hệ thống tốt cần kết hợp cả hai:
Reactive (bị động): Exit condition được kiểm tra sau khi mỗi vòng lặp đã chạy xong — ví dụ kiểm tra convergence sau khi đã có output, kiểm tra max_iterations sau khi vòng lặp đã tăng. Đây là cách phổ biến nhất vì dễ triển khai, nhưng nhược điểm là bạn luôn "trả giá" cho ít nhất một vòng lặp dư trước khi phát hiện ra cần dừng.
Proactive (chủ động): Exit condition được đánh giá trước khi thực thi vòng lặp tiếp theo, dựa trên dự đoán/ước lượng — ví dụ: ước tính số token còn lại trong budget trước khi cho phép agent thực hiện thêm một tool call tốn kém (như gọi một sub-agent khác), hoặc kiểm tra "liệu bước tiếp theo có khả năng tạo giá trị mới hay không" dựa trên pattern của các bước trước, thay vì để nó chạy rồi mới đánh giá.
Ví dụ minh họa cách kết hợp cả hai:
def estimate_next_step_cost(messages: list, avg_tokens_per_step: int) -> int:
"""Proactive check: estimate cost of the next step before running it."""
return len(messages) * 50 + avg_tokens_per_step # rough heuristic
def agentic_loop_with_proactive_guard(
llm_client, initial_messages: list, token_budget: int = 20000
):
messages = initial_messages
tokens_used = 0
avg_step_tokens = 1500
while True:
# Proactive: refuse to even start a step that would likely
# blow the budget, instead of discovering it reactively after.
if tokens_used + estimate_next_step_cost(messages, avg_step_tokens) > token_budget:
print("Exiting proactively: next step would exceed token budget.")
break
result = run_agent_step(llm_client, messages)
tokens_used += result.tokens_consumed # assume tracked on result
messages.append({"role": "assistant", "content": result.content})
if result.is_done:
break # Reactive: success condition checked after the step.
Trong thực tế, proactive design đặc biệt quan trọng khi mỗi vòng lặp có chi phí cao (ví dụ gọi một sub-agent phức tạp, hoặc gọi tool tính phí theo lượt) — bạn không muốn phát hiện "đã vượt budget" sau khi đã trả tiền cho vòng lặp đó.
Mẹo: Bắt đầu với reactive design cho hầu hết trường hợp (dễ làm, dễ debug), nhưng bổ sung proactive guard cho riêng những bước có chi phí cao hoặc không thể hoàn tác (gọi API tính phí bên ngoài, thực thi lệnh ghi dữ liệu) — đó là nơi việc "lỡ chạy một vòng dư" gây thiệt hại thực sự, không chỉ là token.
Summary — Tổng Kết
Exit condition không phải là một tính năng phụ được thêm vào sau cùng — nó là một phần thiết kế cốt lõi của bất kỳ agentic loop nào muốn vận hành hiệu quả về chi phí. Những điểm chính cần nhớ:
- Agentic loop không có exit condition rõ ràng có thể lãng phí 5-6 lần lượng token cần thiết, vì mỗi vòng lặp dư thừa đều kéo theo toàn bộ context history.
- Có bốn loại exit condition cần triển khai đầy đủ: success, convergence, budget, và failure — mỗi loại giải quyết một kiểu runaway khác nhau.
- Về mặt kỹ thuật, có thể triển khai qua stop signal trong output, convergence detection dựa trên độ tương đồng, hoặc theo dõi pattern gọi tool — và nên kết hợp nhiều phương pháp trong cùng một hệ thống.
- Mỗi framework (LangGraph, CrewAI, OpenAI Assistants API) có cách hỗ trợ riêng: conditional edge,
max_iter/callback, hoặc run control qua token budget — cần hiểu đúng để không phải tự viết lại từ đầu. - Khi dừng sớm, đừng vứt bỏ toàn bộ kết quả — hãy giữ lại "best-so-far" và gắn kèm metadata về độ tin cậy.
- Kết hợp cả reactive (kiểm tra sau khi chạy) và proactive (ước lượng trước khi chạy) để tối ưu cho cả trường hợp thông thường và trường hợp chi phí cao.
Nắm vững các nguyên tắc này giúp bạn xây dựng agentic system không chỉ "thông minh" mà còn "biết điểm dừng" — một yếu tố quyết định trực tiếp đến chi phí vận hành thực tế khi triển khai ở quy mô lớn.