
Trace agent ADK trên Vertex AI: 5 lỗi khiến span biến mất
Bật enable_tracing mà Cloud Trace vẫn trống: năm nguyên nhân im lặng trên Vertex AI Agent Engine, kiểm chứng trên google-adk 2.7.0, kèm lệnh kiểm tra.
Bạn bật enable_tracing=True cho agent chạy trên Vertex AI Agent Engine, deploy lại, và Cloud Trace vẫn trống trơn. Agent trả lời đúng, latency bình thường, log ứng dụng sạch — không có gì để lần.
Đó là kiểu hỏng khó chịu nhất: hỏng im lặng. Bài viết của một kỹ sư trên Dev.to hôm qua liệt kê năm chỗ gây ra nó, kiểm chứng trên google-adk 2.7.0 và google-cloud-aiplatform 1.165.1. Dưới đây là năm chỗ đó, kèm lệnh kiểm tra cho từng chỗ.
Mọi lỗi ở đây đều im lặng vì một lý do: theo tác giả, SDK xem telemetry là best-effort. Cấu hình sai khiến bạn mất observability, không bao giờ mất availability — đúng cho production, rất tệ cho người đang debug.
1. Span không gửi tới Cloud Trace API
Phản xạ đầu tiên là bật cloudtrace.googleapis.com rồi coi như xong. Theo bài viết, span không đi đường đó. Exporter là OTLP/HTTP trỏ tới Telemetry API — endpoint mặc định trong mã nguồn là https://telemetry.googleapis.com/v1/traces, và span được POST lên đó bằng credential từ google.auth.default().
SDK có thăm dò API lúc khởi động và in cảnh báo rằng telemetry.googleapis.com chưa được bật trong project, kèm dòng "telemetry data will not be stored". Nhưng kiểm tra đó nằm trong một khối except trống và cố ý không gây lỗi — container vẫn boot, vẫn phục vụ request, còn cảnh báo thì trôi qua trong log khởi động.
gcloud services list --enabled --project=my-project \
--filter="config.name:(telemetry.googleapis.com OR cloudtrace.googleapis.com)" \
--format="value(config.name)"
Bạn cần thấy cả hai tên trong output. Giữ cloudtrace.googleapis.com vì đó là thứ phục vụ phía đọc và console, nhưng chỉ bật mỗi nó thì đường ghi vẫn chết.
2. Lỗi IAM là một dòng 403 trong log bạn không mở
Bật API, deploy lại, vẫn không có gì. Lỗi có tồn tại nhưng không nằm ở chỗ bạn đang nhìn: không trong log Cloud Run service, không trong output ứng dụng, mà trong log tài nguyên Reasoning Engine, dạng Failed to export span batch code: 403. Batch span processor ghi lỗi rồi bỏ cả batch.
gcloud logging read \
'resource.type="aiplatform.googleapis.com/ReasoningEngine" AND textPayload=~"Failed to export span batch"' \
--project=my-project --freshness=1h --limit=20
Quyền cần có là telemetry.traces.write. Hai role cấp quyền này và cách đặt tên dễ gây nhầm: roles/cloudtrace.agent là tập cha, đã bao gồm Telemetry API dù tên nghe có vẻ cũ, nên gán kèm roles/telemetry.tracesWriter là thừa.
Một đặc điểm hữu ích của lỗi này: theo tác giả, sau khi sửa IAM, các dòng 403 dừng tại một mốc thời gian rõ ràng mà không cần deploy lại. Thấy lỗi đến thời điểm T rồi trace xuất hiện sau T nghĩa là binding đã lan tới nơi.
3. Đừng tự set ADK_CAPTURE_MESSAGE_CONTENT_IN_SPANS
Mặc định ADK ghi prompt, phản hồi model và tham số tool vào span, và mặc định của biến ADK_CAPTURE_MESSAGE_CONTENT_IN_SPANS là bật. Ghim giá trị đó trong config deploy nghe hợp lý, nhưng trên Agent Engine là vô nghĩa: AdkApp.set_up() ghi đè biến này vô điều kiện theo giá trị enable_tracing.
Hệ quả là một quyết định bảo mật, không phải chi tiết cấu hình: bật tracing đồng nghĩa toàn bộ prompt và payload tool nằm trong trace, và bạn không thể tắt phần nội dung qua biến môi trường này. Nếu agent xử lý dữ liệu nhạy cảm, hãy quyết định trước ai được đọc trace. Bài viết lưu ý thêm: CLI adk deploy có inject giá trị false, nhưng chỉ khi bạn deploy qua đúng CLI đó — tạo engine từ SDK hay công cụ IaC thì đoạn inject không bao giờ chạy.
4. enable_tracing không phải công tắc duy nhất
Tracing là phép AND của hai điều khiển. Bảng chân trị nằm ngay trong mã nguồn SDK:
| enable_tracing | enable_telemetry (env) | Tracing thực tế |
|---|---|---|
| true | false | false |
| true | true | true |
| true | None | true |
| None (mặc định) | true | adk_version >= 1.17 |
| None (mặc định) | None | false |
enable_telemetry đến từ biến GOOGLE_CLOUD_AGENT_ENGINE_ENABLE_TELEMETRY — cũng chính là thứ mà công tắc trên Cloud Console ghi vào. Đặt nó false thì enable_tracing=True của bạn chết ngay từ đầu; để trống thì không sao.
Một điểm cần chính xác: SDK chỉ deprecate enable_tracing=False, không phải cả tham số. Muốn tắt tracing thì bỏ hẳn tham số và dùng biến môi trường, vì truyền False làm công tắc trên Console lệch khỏi thực tế.
5. Root span không tên là invoke_agent
Bạn đi tìm invoke_agent ở gốc và không thấy. ADK có hai phiên bản schema telemetry, và Agent Engine mặc định dùng v2, nhận biết qua sự hiện diện của biến GOOGLE_CLOUD_AGENT_ENGINE_ID. Dưới v2, gốc là invoke_workflow, còn invoke_agent {name} là node con; execute_tool mang tên tool; nội dung nằm trên call_llm dưới dạng gcp.vertex.agent.llm_request và llm_response.
Thêm một cái bẫy khi đọc: danh sách trace mặc định sắp theo trace ID chứ không theo thời gian. Không đặt filter thì bạn nhận một lát cắt tùy ý và dễ kết luận nhầm là không có gì được ghi.
Một request không phải là một trace
Đây là phần đổi cách bạn thiết kế, không chỉ cách cấu hình. Mỗi cặp create_session() + stream_query() là một invocation độc lập và sinh trace riêng. Handler nào fan-out ba lời gọi song song cho cùng một bản ghi nghiệp vụ sẽ nhận ba trace không liên quan nhau, vì trace context không vượt qua ranh giới Agent Engine.
Các thuộc tính chuẩn của ADK là invocation_id, session_id và event_id — đều là định danh nội bộ, không trỏ về đối tượng nghiệp vụ của bạn, và user_id thì không được export. Cách tác giả xử lý là gắn thuộc tính riêng bằng một BasePlugin chạy trong context của root span, rồi truy vấn theo app.record_id để gom cả ba trace về một tập.
Bốn chi tiết trong plugin đó đều có thể làm hỏng việc nếu bỏ qua: callback phải là async def; phải trả về None, vì giá trị khác None bị coi là tín hiệu thoát sớm và cắt ngang cả lượt chạy; phải bọc try/except, vì exception trong plugin không được chặn mà bị bọc thành RuntimeError và ném tiếp — một bug gắn nhãn span đủ sức hạ cả lượt chạy agent; và user_id là property chứ không phải field, nên không xuất hiện khi bạn soi model_fields.
Suy ra điều đáng nhớ nhất: user_id là kênh dùng chung duy nhất để mang dữ liệu tương quan qua ranh giới Agent Engine, vì bạn kiểm soát nó lúc create_session(). Hãy mã hóa nó cẩn thận và giữ phần encode với decode trong cùng một module.
Kiểm tra theo thứ tự này
- Chạy lệnh
gcloud services list --enabledở mục 1 trước mọi thứ khác. Đây là nguyên nhân phổ biến nhất. - Đọc log Reasoning Engine tìm
Failed to export span batchtrước khi nghi ngờ code của mình. - Quyết định ai được đọc trace trước khi bật tracing trên agent chạm dữ liệu khách hàng.
- Lọc theo
root:invoke_workflow, đừng tìminvoke_agentở gốc. - Nếu một request sinh nhiều invocation, gắn khóa nghiệp vụ vào span ngay từ đầu — về sau không ghép lại được.
Không spam, hủy đăng ký bất kỳ lúc nào.
Bài viết liên quan

Chống prompt injection cho AI agent: checklist 6 nhóm
10 thg 10, 2026
Benchmark 100 câu hỏi: RAG 48%, GraphRAG 69%, agentic 99%
09 thg 10, 2026