AI Agents Trong Production

Observability, tracing, evaluation và quản lý chi phí khi deploy agent thực tế

Thách Thức Production

Chạy agent ở local thì dễ. Chạy ở production thì khác:

  • Observability: Agent đang làm gì? Tại sao nó chọn tool này?
  • Cost: Mỗi LLM call tốn tiền. Multi-step agents = nhiều calls
  • Latency: Users không muốn đợi 30 giây cho mỗi response
  • Reliability: Agent fail rate bao nhiêu? Recovery strategy?

Tracing & Observability

Trace Anatomy

Trace (1 user request)
├── Span: User input processing
├── Span: LLM call #1 (planning)
│   ├── Token usage: 500 input, 200 output
│   └── Duration: 1.2s
├── Span: Tool call: searchDocuments
│   └── Duration: 0.8s
├── Span: LLM call #2 (with tool results)
│   ├── Token usage: 1500 input, 300 output
│   └── Duration: 2.1s
└── Span: Response generation

Tích Hợp Langfuse

import { Langfuse } from "langfuse";
import { generateText } from "ai";
import { openai } from "@ai-sdk/openai";

const langfuse = new Langfuse({
  publicKey: process.env.LANGFUSE_PUBLIC_KEY!,
  secretKey: process.env.LANGFUSE_SECRET_KEY!,
  baseUrl: process.env.LANGFUSE_BASE_URL
});

async function tracedAgent(userMessage: string, userId: string) {
  // Tạo trace
  const trace = langfuse.trace({
    name: "agent-response",
    userId,
    metadata: { source: "web-app" }
  });

  // Span cho planning
  const planSpan = trace.span({ name: "planning" });

  const result = await generateText({
    model: openai("gpt-4o-mini"),
    tools: { /* ... */ },
    maxSteps: 5,
    prompt: userMessage,
    // Callback cho mỗi step
    onStepFinish: (step) => {
      trace.span({
        name: step.toolCalls?.[0]?.toolName || "llm-generation",
        input: step.toolCalls?.[0]?.args,
        output: step.toolResults?.[0]?.result,
        metadata: {
          tokenUsage: step.usage,
          model: "gpt-4o-mini"
        }
      });
    }
  });

  planSpan.end();

  // Log final output
  trace.generation({
    name: "final-response",
    input: userMessage,
    output: result.text,
    usage: {
      promptTokens: result.usage.promptTokens,
      completionTokens: result.usage.completionTokens
    }
  });

  // Score quality (optional)
  trace.score({ name: "response-quality", value: 0.9 });

  await langfuse.shutdownAsync();
  return result.text;
}

Key Metrics

Metrics Bắt Buộc

MetricMô tảTarget
Latency P9595th percentile response time< 10s
Token UsageTokens/request trung bìnhMonitor trend
Error Rate% requests thất bại< 5%
Tool Call Success% tool calls thành công> 95%
Cost per RequestChi phí trung bình/requestMonitor trend

Dashboard Setup

// Custom metrics tracking
interface AgentMetrics {
  requestId: string;
  userId: string;
  timestamp: Date;
  totalLatencyMs: number;
  llmCalls: number;
  toolCalls: number;
  totalTokens: number;
  estimatedCost: number;
  success: boolean;
  errorType?: string;
}

async function logMetrics(metrics: AgentMetrics) {
  // Lưu vào Supabase cho dashboard
  await supabase.from("agent_metrics").insert(metrics);
}

Cost Management

Token Cost Calculator

const PRICING = {
  "gpt-4o": { input: 2.50 / 1_000_000, output: 10.00 / 1_000_000 },
  "gpt-4o-mini": { input: 0.15 / 1_000_000, output: 0.60 / 1_000_000 }
};

function calculateCost(
  model: keyof typeof PRICING,
  inputTokens: number,
  outputTokens: number
): number {
  const pricing = PRICING[model];
  return inputTokens * pricing.input + outputTokens * pricing.output;
}

Chiến Lược Giảm Cost

1. Model Routing

// Dùng model nhỏ cho tasks đơn giản
function selectModel(taskComplexity: "simple" | "medium" | "complex") {
  switch (taskComplexity) {
    case "simple": return openai("gpt-4o-mini");
    case "medium": return openai("gpt-4o-mini");
    case "complex": return openai("gpt-4o");
  }
}

2. Prompt Caching

// Cache system prompts (OpenAI tự xử lý)
// Giảm input tokens bằng cách reuse prefix
const cachedSystemPrompt = `
[Dài, chi tiết system prompt]
Prompt này sẽ được cache sau lần gọi đầu tiên.
`;

3. Token Budget

// Giới hạn tokens cho mỗi request
const result = await generateText({
  model: openai("gpt-4o-mini"),
  maxTokens: 500,  // Giới hạn output
  maxSteps: 3,     // Giới hạn vòng lặp
  prompt: userMessage
});

Error Handling & Recovery

async function resilientAgent(message: string) {
  const maxRetries = 3;

  for (let attempt = 1; attempt <= maxRetries; attempt++) {
    try {
      const result = await generateText({
        model: openai("gpt-4o-mini"),
        prompt: message,
        // Timeout
        abortSignal: AbortSignal.timeout(30000)
      });

      return result.text;
    } catch (error) {
      console.error(`Attempt ${attempt} failed:`, error);

      if (attempt === maxRetries) {
        // Fallback response
        return "Xin lỗi, tôi đang gặp sự cố. Vui lòng thử lại sau.";
      }

      // Exponential backoff
      await new Promise(r => setTimeout(r, 1000 * Math.pow(2, attempt)));
    }
  }
}

Tổng Kết

  • Tracing mọi bước của agent với Langfuse
  • Monitor 5 metrics chính: latency, tokens, errors, tool success, cost
  • Cost management: model routing, prompt caching, token budgets
  • Error recovery: retries với exponential backoff, fallback responses
  • Production agents cần observability first — bạn không thể fix cái bạn không thấy