Cách Deploy Arize Phoenix trên Docker: Giám sát và Debug LLM, RAG, và AI Agent theo Thời gian Thực

AI tutorial - IT technology blog
AI tutorial - IT technology blog

Tại Sao Ứng Dụng LLM Khó Debug Khi Thiếu Observability

Deploy một ứng dụng LLM và mọi thứ trông có vẻ ổn ban đầu. Request đến, response trả về, log hiển thị 200 OK. Rồi một người dùng báo câu trả lời sai — và bạn đứng nhìn một đống text output mà không biết mọi thứ đã đi sai ở đâu.

Log truyền thống không đủ dùng. Bạn cần biết: prompt thực sự gửi đi là gì? Bước retrieval trả về gì? LLM có hallucinate không, hay nó nhận context kém từ RAG pipeline? Mỗi bước mất bao lâu?

Một RAG chatbot tôi deploy năm ngoái đã cho thấy điều này một cách đau đớn. Người dùng liên tục nhận được câu trả lời lỗi thời, nhưng log ứng dụng chỉ toàn hiển thị thành công. Mất nhiều giờ debug bằng print statement, thủ phạm hóa ra là vector search đang kéo về các embedding cũ từ một index chưa được refresh trong ba tháng. Hoàn toàn vô hình từ bên ngoài. Sự cố đó khiến LLM observability trở thành yêu cầu bắt buộc trong mọi dự án AI tôi xây dựng.

Arize Phoenix là một nền tảng observability mã nguồn mở được xây dựng đặc biệt cho vấn đề này. Hãy nghĩ nó như Jaeger hay Zipkin cho distributed tracing — nhưng được thiết kế riêng cho LLM, RAG pipeline và AI agent. Một giao diện duy nhất cho bạn thấy toàn bộ trace: prompt, completion, document được retrieved, latency từng bước, token count và điểm đánh giá.

Cài đặt

Phoenix đóng gói thành một Docker image duy nhất, nên tích hợp dễ dàng vào bất kỳ stack nào có sẵn. Tạo file docker-compose.yml:

version: "3.8"

services:
  phoenix:
    image: arizephoenix/phoenix:latest
    container_name: arize-phoenix
    ports:
      - "6006:6006"    # Giao diện web Phoenix
      - "4317:4317"    # Endpoint OTLP gRPC
      - "4318:4318"    # Endpoint OTLP HTTP
    volumes:
      - phoenix_data:/root/.phoenix
    restart: unless-stopped
    environment:
      - PHOENIX_WORKING_DIR=/root/.phoenix

volumes:
  phoenix_data:

Khởi động container:

docker compose up -d

Kiểm tra container đã chạy thành công:

docker compose ps
docker logs arize-phoenix

Mở http://localhost:6006 trên trình duyệt. Dashboard Phoenix sẽ hiện ra với chưa có project nào. Đang chạy trên server từ xa? Thay localhost bằng IP server của bạn và đảm bảo port 6006 đã được mở trong firewall hoặc security group.

Named volume phoenix_data tự động xử lý việc lưu trữ dữ liệu — trace sẽ tồn tại sau khi container khởi động lại mà không cần cấu hình thêm gì.

Cấu hình

Kết nối ứng dụng với Phoenix gồm ba bước: cài SDK, đăng ký tracer provider và instrument framework.

Cài đặt các Package

# Thư viện cốt lõi OTEL + Phoenix
pip install arize-phoenix-otel opentelemetry-sdk opentelemetry-exporter-otlp-proto-grpc

# Chọn gói instrumentation phù hợp với framework của bạn
pip install openinference-instrumentation-openai       # OpenAI
pip install openinference-instrumentation-langchain    # LangChain
pip install openinference-instrumentation-llama-index  # LlamaIndex

Đăng ký Tracer và Instrument OpenAI

from phoenix.otel import register
from openinference.instrumentation.openai import OpenAIInstrumentor

# Đăng ký Phoenix làm trace collector
tracer_provider = register(
    project_name="my-llm-app",
    endpoint="http://localhost:4317",  # OTLP gRPC
)

# Tự động instrument tất cả lời gọi OpenAI — không cần thay đổi code khác
OpenAIInstrumentor().instrument(tracer_provider=tracer_provider)

LangChain hoạt động tương tự — chỉ cần đổi instrumentor:

from phoenix.otel import register
from openinference.instrumentation.langchain import LangChainInstrumentor

tracer_provider = register(
    project_name="rag-pipeline",
    endpoint="http://localhost:4317",
)

LangChainInstrumentor().instrument(tracer_provider=tracer_provider)

Vậy là xong. Chạy ứng dụng bình thường — mọi lời gọi LLM, bước retrieval và chain execution đều được trace tự động.

Kết nối từ Container Docker Khác

Khi ứng dụng của bạn cũng chạy trong Docker, dùng tên service của container Phoenix thay vì localhost:

tracer_provider = register(
    project_name="my-llm-app",
    endpoint="http://arize-phoenix:4317",  # Tên service Docker
)

Thích HTTP hơn gRPC? Cách đó cũng được — tiện hơn khi đứng sau proxy không truyền gRPC qua được:

tracer_provider = register(
    project_name="my-llm-app",
    endpoint="http://arize-phoenix:4318/v1/traces",
    protocol="http/protobuf",
)

Xác minh & Giám sát

Gửi vài câu truy vấn thử qua ứng dụng, rồi mở http://localhost:6006. Một mục project sẽ xuất hiện cùng các trace đầu tiên của bạn.

Đọc Trace trên Giao diện

Click vào tab Traces và chọn bất kỳ trace nào để mở rộng thành cây span. Một RAG pipeline điển hình trông như sau:

  • Span cấp cao nhất: câu truy vấn đến từ người dùng
  • Span con: tạo embedding cho câu truy vấn
  • Span con: tìm kiếm vector cùng các đoạn tài liệu được retrieved
  • Span con: lời gọi LLM thực sự — toàn bộ prompt hiển thị ở đây, kể cả context được inject vào
  • Metadata trên mỗi span: latency, token count, tên model, lý do kết thúc

Đây chính xác là thứ tôi đã thiếu khi debug vấn đề embedding cũ. Với Phoenix đang chạy, các document chunk được retrieved hiển thị timestamp từ nhiều tháng trước — ngay trong trace. Điều mà trước đó mất nhiều giờ đoán mò, giờ chỉ cần chưa đến năm phút để xác định.

Chạy Đánh giá Chất lượng RAG

Phoenix có sẵn các evaluator tích hợp cho việc phát hiện hallucination và đánh giá độ liên quan của retrieval. Kéo các traced span thành dataframe và chạy đánh giá trên đó:

from phoenix.client import Client
from phoenix.evals import (
    HallucinationEvaluator,
    RelevanceEvaluator,
    run_evals,
)
from phoenix.evals import OpenAIModel

# Lấy các traced span
client = Client(endpoint="http://localhost:6006")
spans_df = client.get_spans_dataframe(project_name="rag-pipeline")

# Dùng model nhỏ để giảm chi phí đánh giá
eval_model = OpenAIModel(model="gpt-4o-mini")

results = run_evals(
    dataframe=spans_df,
    evaluators=[
        HallucinationEvaluator(eval_model),
        RelevanceEvaluator(eval_model),
    ],
    provide_explanation=True,
)

print(results[0].head())

Điểm số được ghi lại vào Phoenix và hiển thị trực tiếp trên từng span. Lọc danh sách trace theo điểm hallucination, sắp xếp theo độ liên quan thấp nhất, rồi click thẳng vào đúng cặp prompt-context đã gây ra vấn đề.

Giám sát AI Agent

Luồng làm việc agentic được xử lý tương tự. Phoenix trace mọi lời gọi tool như một span con. Một agent thực hiện bốn tìm kiếm web, fetch một URL và viết câu trả lời cuối cùng sẽ hiện ra dưới dạng sáu span trong cây — input, output và thời gian của từng span. Khả năng hiển thị đó thôi đã thay thế được hầu hết các đoạn print statement bạn vốn phải rải rác khắp nơi chỉ để hiểu agent đang làm gì.

Các Chỉ số Cần Theo dõi Thường xuyên

Sau khi có một tuần dữ liệu chạy vào, đây là ba tín hiệu đáng theo dõi thường xuyên:

  • P95 latency theo project — spike đột ngột thường chỉ đến bottleneck ở retrieval hoặc model timeout phía upstream
  • Xu hướng sử dụng token — phát hiện prompt phình to trước khi nó xuất hiện trên dashboard thanh toán
  • Tỷ lệ hallucination theo thời gian — tỷ lệ tăng dần gần như luôn có nghĩa là có gì đó đã thay đổi trong retrieval pipeline hoặc prompt template

Gắn Metadata Tùy chỉnh

Các thuộc tính OTEL tiêu chuẩn hoạt động ngay trong Phoenix. Gắn tag span với user ID và session ID giúp giảm đáng kể thời gian xử lý sự cố:

from opentelemetry import trace

tracer = trace.get_tracer(__name__)

with tracer.start_as_current_span("user-query") as span:
    span.set_attribute("user.id", user_id)
    span.set_attribute("session.id", session_id)
    span.set_attribute("query.type", "rag")
    # ... gọi LLM của bạn ở đây

Toàn bộ quá trình cài đặt — từ lúc chạy container đến trace đầu tiên — mất khoảng 20 phút. Sau đó, debug các vấn đề LLM giảm từ nhiều giờ đoán mò xuống chỉ vài phút click qua các trace. Chạy AI trên production mà không có observability là như đang bay mù. Hãy thêm Phoenix trước khi bạn ship tính năng tiếp theo.

Share: