Yugen UI

Minh bạch tiến trình với Trace

Khi hệ thống làm việc thay người dùng — agent AI, pipeline, tác vụ nền — hãy cho họ thấy từng bước: đang làm gì, mất bao lâu, sai ở đâu và có thể làm gì tiếp.

Vì sao cần minh bạch

Một spinner “Đang xử lý…” kéo dài 20 giây khiến người dùng nghi ngờ, bấm lại, hoặc bỏ đi. Một danh sách bước đang tiến triển thì không.

  • Niềm tin — người dùng thấy AI đã đọc tài liệu nào, gọi công cụ nào trước khi tin vào câu trả lời.
  • Quyền kiểm soát — biết đang ở bước nào thì mới quyết định chờ, dừng hay thử lại.
  • Gỡ lỗi — khi sai, bước lỗi và log nằm ngay đó, không phải mở tab khác.

Sáu trạng thái

Mỗi trạng thái có icon riêng, màu token riêng và nhãn chữ (đọc được bởi trình đọc màn hình) — màu không bao giờ là tín hiệu duy nhất.

Trạng tháiNhãnKhi nàoMàu
pendingĐang chờĐã lên kế hoạch, chưa bắt đầu.text-foreground-3
runningĐang chạyĐang thực hiện — đồng hồ chạy trực tiếp.text-brand-foreground-1
successHoàn tấtXong, có thời lượng.text-success-foreground-1
errorLỗiThất bại — tự mở chi tiết, nói nguyên nhân.text-danger-foreground-1
skippedBỏ quaKhông cần chạy (điều kiện không thoả, cache trúng).text-foreground-3
cancelledĐã huỷBị dừng bởi người dùng hoặc vì bước trước lỗi.text-warning-foreground-1

Chọn độ chi tiết

Một bước = một việc người dùng hiểu được. Chi tiết kỹ thuật nằm trong phần mở rộng, không nằm trên dòng tiêu đề.

Tạo báo cáo tháng 10

Đang chờ

Thời lượng: 9.6s
  • 2.1s
    sales_db12 480 dòng
  • 3.4s
  • Viết nhận xét, Hoàn tất
    4.1s
    sakura-12.1k token
  • Tiêu đề bước là động từ + đối tượng (“Lấy dữ liệu bán hàng”); tên hàm / công cụ để trong metadata hoặc details.
  • Lồng tối đa 2 cấp. Agent gọi 30 lệnh nhỏ → gộp thành một bước cha “Đọc 30 tệp” với bước con thu gọn.
  • metadata cho thông tin quét nhanh: công cụ, model, số token, số dòng, nhánh git.
  • details (log, JSON, CodeBlock) mặc định thu gọn; bước lỗi và bước đang chạy tự mở.

Cập nhật trực tiếp

Trace là component hiển thị thuần: bạn giữ danh sách bước trong state và cập nhật theo sự kiện từ agent.

// Sự kiện từ agent (SSE / WebSocket) → props của TraceStep
type AgentEvent =
  | { type: "step_started"; id: string; title: string; at: number }
  | { type: "step_finished"; id: string; at: number; tokens?: number }
  | { type: "step_failed"; id: string; at: number; error: string };

function reduce(steps: Step[], e: AgentEvent): Step[] {
  switch (e.type) {
    case "step_started":
      return [...steps, { id: e.id, title: e.title, status: "running", startedAt: e.at }];
    case "step_finished":
      return steps.map((s) => s.id === e.id ? { ...s, status: "success", duration: e.at - s.startedAt } : s);
    case "step_failed":
      return steps.map((s) => s.id === e.id ? { ...s, status: "error", error: e.error } : s);
  }
}

<Trace title="Agent" startedAt={runStartedAt}>
  {steps.map((s) => (
    <TraceStep
      key={s.id}
      title={s.title}
      status={s.status}
      startedAt={s.startedAt}
      duration={s.duration}
      details={s.error && <TraceLog intent="error">{s.error}</TraceLog>}
    />
  ))}
</Trace>
Prop · KiểuMặc địnhMô tả
statusTraceStatusMặc định: "pending"Đổi status là đủ — icon, màu, đồng hồ, thông báo tự theo.
startedAtnumberMặc định: —Mốc bắt đầu từ server để đồng hồ chính xác; bỏ trống thì tính từ lúc chuyển sang running.
durationnumber (ms)Mặc định: —Thời lượng thật khi xong.
Trace.startedAt / durationnumberMặc định: —Đồng hồ tổng khi đang chạy; tổng thời lượng khi xong.
Trace.announceChangesbooleanMặc định: trueGộp các thay đổi cùng nhịp thành một thông báo polite.

Khi có lỗi

Bấm Chạy: bước get_order sẽ hết thời gian chờ ở lần đầu. Các bước sau chuyển sang Đã huỷ, và phần đầu đưa ra hành động tiếp theo.

Trợ lý: kiểm tra đơn hàng #A1023

Đang chờ

  • Phân tích câu hỏi, Đang chờ
  • search_docs("đổi trả"), Đang chờ
  • get_order("#A1023"), Đang chờ
  • Soạn câu trả lời, Đang chờ
  • Mô tả lỗi bằng ngôn ngữ người dùng (“không phản hồi sau 5 giây”); log kỹ thuật nằm trong details.
  • Đánh dấu các bước phụ thuộc là cancelled — đừng để chúng ở pending như thể vẫn sẽ chạy.
  • Cho thử lại từ bước lỗi thay vì chạy lại tất cả khi có thể.

Khả năng tiếp cận

Khía cạnhCách Trace xử lý
Ngữ nghĩaVùng <section> có tên (tiêu đề); các bước là role=list / listitem, bước con là danh sách lồng.
Trạng tháiMỗi bước có chữ ẩn “, Hoàn tất” / “, Lỗi”… ngay trong tên — không chỉ dựa vào icon hay màu.
Mở rộngTiêu đề bước có details / bước con là nút disclosure với aria-expanded + aria-controls; Enter / Space để mở.
Thông báoMột vùng role=status polite đọc “Tên bước: trạng thái”; thay đổi cùng nhịp được gộp làm một.
Chuyển độngSpinner đứng yên và bước mới không mờ dần khi người dùng bật giảm chuyển động.
LogTraceLog luôn dir="ltr", focus được bằng Tab để cuộn bằng bàn phím.

Đặt title của TraceStep là chuỗi (hoặc truyền announceLabel) để thông báo trạng thái có nội dung.

Nên & không nên

Nên
  • Hiện bước ngay khi agent bắt đầu nó, không đợi xong mới in ra.
  • Ghi thời lượng cho từng bước để người dùng biết chậm ở đâu.
  • Mở sẵn bước lỗi, kèm nguyên nhân và hành động thử lại.
  • Dùng Trace size small, thu gọn, trong tin nhắn của trợ lý AI.
Không nên
  • Không giả lập tiến độ bằng các bước bịa — chỉ hiện việc thật sự xảy ra.
  • Không để bước phụ thuộc ở pending khi pipeline đã dừng.
  • Không đưa dữ liệu nhạy cảm (token, mật khẩu) vào metadata hay log hiển thị.