Bạn không thể debug thứ bạn không nhìn thấy. Với agent, "nhìn thấy" nghĩa là trace: bản ghi đầy đủ từng bước suy nghĩ → hành động → kết quả trong một lần chạy. Không có trace, mỗi lần agent sai bạn chỉ biết "output xấu" mà không biết ở đâu và tại sao. Bài này dựng hệ thống logging thực dụng, bật được ngay hôm nay.
Trace là gì và cần chứa gì
Một trace ghi lại một phiên (session/run) của agent, gồm nhiều span (bước). Tối thiểu mỗi bước phải có:
step_id,timestamptype:llm_call|tool_call|tool_result|final_answerinput: prompt/messages gửi vào (kèm system prompt)output: agent quyết định gì (text hoặc lời gọi tool + tham số)latency_ms,tokens(in/out),costerror(nếu có)
Ví dụ: một trace tối thiểu ở dạng JSON Lines
{"run_id":"r-88","step":1,"type":"llm_call","output":{"tool":"lookup_order","args":{"id":"A123"}},"latency_ms":820,"tokens_in":540,"tokens_out":40}
{"run_id":"r-88","step":2,"type":"tool_result","tool":"lookup_order","output":{"eta":"2026-07-12"},"latency_ms":130}
{"run_id":"r-88","step":3,"type":"final_answer","output":"Đơn A123 sẽ giao ngày 12/07/2026.","tokens_out":22}
Nhìn trace này bạn biết ngay: agent gọi đúng tool, nhận đúng dữ liệu, trả lời khớp. Nếu ở bước 3 nó ghi ngày khác dữ liệu tool → phát hiện hallucination tức thì.
Cách gắn logging tự động (pattern decorator)
Đừng rải print khắp nơi. Bọc mỗi lời gọi LLM và tool bằng một lớp ghi log tập trung:
import time, json
def log_step(run_id, step_type, inp, out, err=None, t0=None):
rec = {
"run_id": run_id, "type": step_type,
"input": inp, "output": out, "error": err,
"latency_ms": int((time.time()-t0)*1000) if t0 else None,
}
with open("traces.jsonl", "a") as f:
f.write(json.dumps(rec, ensure_ascii=False) + "\n")
def traced_tool(fn, run_id):
def wrapper(**kwargs):
t0 = time.time()
try:
out = fn(**kwargs)
log_step(run_id, "tool_result", {"tool": fn.__name__, "args": kwargs}, out, t0=t0)
return out
except Exception as e:
log_step(run_id, "tool_error", {"tool": fn.__name__, "args": kwargs}, None, str(e), t0)
raise
return wrapper
Các bước triển khai logging trong dự án của bạn
- Gán
run_idduy nhất cho mỗi phiên (dùnguuid4) — để gộp mọi bước của một lần chạy lại với nhau. - Bọc lời gọi LLM: log system prompt (hoặc hash của nó), messages, và output thô (bao gồm cả lời gọi tool).
- Bọc mọi tool: log tên tool, tham số, kết quả và lỗi. Tool error thường là gốc rễ của loop.
- Ghi ra JSON Lines (
.jsonl), mỗi dòng một bước — dễ append, dễ đọc bằngjq, dễ đổ vào DataFrame. - Đừng log dữ liệu nhạy cảm dạng thô: che (mask) số điện thoại, token, mật khẩu trước khi ghi.
- Thêm
parent_run_idnếu có multi-agent, để dựng lại cây gọi giữa các agent.
Đọc trace nhanh bằng jq
# Đếm số lời gọi mỗi tool trong 1 run
grep '"run_id":"r-88"' traces.jsonl | jq -r '.output.tool // empty' | sort | uniq -c
# Tìm mọi bước có lỗi tool trong toàn bộ file
jq -c 'select(.type=="tool_error")' traces.jsonl
Ba cấp độ trace — chọn theo giai đoạn dự án
- Cấp 1 (file JSONL local): đúng cho lúc phát triển. Rẻ, không phụ thuộc dịch vụ ngoài,
grep/jqlà đủ. Đây là nơi bạn nên bắt đầu hôm nay. - Cấp 2 (tự host DB/log store): khi có nhiều phiên, cần truy vấn theo thời gian, theo tool, theo lỗi. Đổ trace vào SQLite/Postgres hoặc một bảng phân tích.
- Cấp 3 (nền tảng observability chuyên dụng cho LLM): khi lên production thật, cần dashboard, so phiên bản, và gắn feedback người dùng vào trace. Đừng vội lên cấp này khi chưa cần.
run_id + từng bước) giống nhau ở cả 3 cấp — nên bắt đầu từ JSONL rồi nâng cấp mà không phải viết lại.Khung tư duy: "5 câu hỏi mọi trace phải trả lời"
- Agent quyết định làm gì ở mỗi bước? (WHAT)
- Vì sao nó quyết vậy? (input/prompt nào dẫn tới)
- Tool trả về gì — đúng hay lỗi?
- Mất bao lâu / tốn bao nhiêu token?
- Nó dừng ở đâu và vì sao dừng?
Sai lầm thường gặp
- Chỉ log input & output cuối: Mất toàn bộ phần "ở giữa" — chính là nơi agent đi lạc. Phải log từng bước.
- Không log lỗi tool: Agent nuốt lỗi rồi loop; không có log tool_error bạn sẽ mò kim đáy bể.
- Không có
run_id: Log của nhiều phiên trộn lẫn, không dựng lại được câu chuyện. - Log prompt khổng lồ dạng thô mỗi bước: Tốn dung lượng; nên log hash system prompt + phần thay đổi.
- Quên che dữ liệu nhạy cảm: Rủi ro lộ PII trong file log.
Checklist kết bài
- [ ] Mỗi phiên có
run_idduy nhất. - [ ] Log đủ: llm_call, tool_call, tool_result, tool_error, final_answer.
- [ ] Ghi JSON Lines, che PII.
- [ ] Đọc lại được 1 trace và kể lại "câu chuyện" agent đã làm gì.
Học xong bài này rồi?
Tạo tài khoản miễn phí để lưu lại — lần sau vào là biết ngay đang dở ở đâu,
và học hết khóa thì có chứng chỉ.
Lưu tiến độ của tôi