Observability & Production Ops: Trace, Debugging & Governance
메뉴

AI Agent Engineering

Observability & Production Ops: Trace, Debugging & Governance

OpenTelemetry Distributed Tracing, Loop Debugging, Infinite Loop/Hallucination Detection, and Governance.

Observability & Production Ops: Trace, Debugging & Governance hero image

This post is Part 7 of the AI Agent Engineering series. It systematically covers observability, debugging, incident response, governance, and operational pipelines for AI agents executing nondeterministic and complex autonomous loops in production environments.


1. What to Observe in an Agent Run

In traditional web applications or single-prompt LLM API calls (Single Prompt Execution), the relationship between input and output is relatively intuitive. When an HTTP request arrives, the backend queries a database or executes static business logic to return a predictable response. Standard Application Performance Monitoring (APM) tools focusing on Latency, Throughput, and Error Rates are sufficient for detecting system anomalies.

An agent makes several model and tool calls within one request. A final response alone does not show which step caused a delay or failure.

Execution modelOrderLoop or exit
1. Traditional Backend API: Static & DeterministicUser Request → Static Logic / DB Query → Predictable ResponsePredictable response
2. Single-turn LLM Prompt: Single-turn I/OUser Prompt → LLM Completion Engine → Text / JSON ResponseOne input/output turn
3. Autonomous AI Agent: Nondeterministic Dynamic LoopUser Goal → State Evaluation → LLM Reasoner → Tool Execution → State Update & Memory StoreMemory Store → State Evaluation: Iteration Loop (N-turns). Separately, LLM Reasoner → Final Goal Completion

1.1 Comparison of Observability Characteristics by System Type

Metric CategoryTraditional Web APISingle-turn LLM CallAutonomous AI Agent
Execution PathStatic & DeterministicSingle I/O (Prompt → Completion)Nondeterministic Dynamic Loop
State ManagementDB / Session-based Static StateStatelessPer-iteration State Delta & Memory Store
Core Observability MetricsLatency, Throughput, HTTP 5xx RateToken Count, Time to First Token (TTFT)Span Hierarchy, Tool Call Accuracy, Step Count
Debugging ApproachStack Trace, APM LogInput/Output Prompt Pair LogCheckpoint Replay, Time-travel State Inspection
Primary Failure ModesNull Pointer Exception, DB TimeoutHallucination, Format ErrorInfinite Loop, Cascading Sub-agent Deadlock

In an agent runtime environment, unique engineering challenges arise:

  1. Nondeterministic Dynamic Execution Paths: Even when given the exact same goal, generated plans and tool invocation sequences can vary significantly based on environment state, LLM sampling, and external tool responses.
  2. Multi-turn Loop & State Transition: Rather than finishing in a single call, the agent iterates through $N$ or more turns, continually mutating its internal State. When a failure occurs, pinpointing "in which turn and tool call state corruption happened" is exceptionally difficult.
  3. Sub-agent Cascading Delegation: An N-tier hierarchical structure emerges where manager agents delegate tasks to worker agents, which in turn call external Model Context Protocol (MCP) servers or API tools.

The Necessity of Agent Observability Operating agents in production requires an engineering framework capable of tracking internal reasoning steps, tool input/output data, state mutation deltas, token costs, and safety guardrail triggers in real time, going far beyond simple log files or HTTP request metrics.


2. OpenTelemetry-Based Distributed Tracing & Hierarchical Span Design

The core pillar of AI agent observability is Distributed Tracing compliant with the OpenTelemetry (OTel) standard. A single full agent execution cycle forms a Root Span, while internal iterations, LLM Reasoner calls, Tool Executions, and Sub-agent calls form Child Spans with explicit Parent-Child relationships.

2.1 Span Hierarchy Tree Architecture

The agent runtime span structure is categorized into 5 primary layers:

  • Root Span (agent.run): Records the user's input goal, Session ID, Agent ID, execution start/end timestamps, and final success status.
  • Iteration Span (agent.iteration): Represents the $n$-th iteration of the agent loop, recording agent state deltas before and after entering the turn.
  • LLM Reasoner Span (llm.call): Records model ID, token usage, operation status, and elapsed time. Prompt contents, raw reasoning and tool-call arguments are excluded from default capture because they may include personal data or secrets.
  • Tool Execution Span (tool.execute): Records called tool name (tool_name), arguments (tool_args), execution output (tool_output), external API latency, and exception details on failure.
  • Sub-Agent Delegation Span (subagent.run): Propagates trace context (traceparent) when delegating to sub-agents, seamlessly linking parent and child agent traces into a unified distributed trace.

The OpenTelemetry Agent Span Hierarchy starts at Root Span: agent.run, with run_id: run_88f1a, agent_id: DataAnalyst. Repeated llm.call names identify separate children of their listed parents.

ScopeParent span → Child spanAttributes
Iteration 1 Spanagent.run → agent.iteration_1iteration: 1, status: OK
Iteration 1 Spanagent.iteration_1 → llm.callmodel: gpt-4o, prompt_tokens: 1240
Iteration 1 Spanagent.iteration_1 → tool.execute:sql_query_runnertool: sql_query_runner, latency: 120ms
Iteration 2 Spanagent.run → agent.iteration_2iteration: 2, status: OK
Iteration 2 Spanagent.iteration_2 → llm.callmodel: gpt-4o, prompt_tokens: 2890
Iteration 2 Spanagent.iteration_2 → subagent.runsubagent_id: CodeReviewer, traceparent: header
Sub-Agent Trace Context inside Iteration 2subagent.run → llm.callmodel: gpt-4o-mini, prompt_tokens: 680
Same Sub-Agent Trace Contextsubagent.run → tool.execute:git_diff_checktool: git_diff_check, latency: 85ms

2.2 OTel Semantic Conventions for Agent Execution

Standards review: October 30, 2026. The OpenTelemetry GenAI attribute registry lists the former gen_ai.system attribute as deprecated, replaced by gen_ai.provider.name. The standard also uses gen_ai.operation.name for chat or invoke_agent operation types and gen_ai.request.model for the requested model identifier.

Standard GenAI attributePurposeExample
gen_ai.provider.nameInstrumented provider flavoropenai, anthropic
gen_ai.operation.nameCall operationchat, invoke_agent
gen_ai.request.modelSelected request model IDgpt-4o
gen_ai.usage.input_tokens / output_tokensInput and output usage totalsInteger counts

The agent.run_id, agent.iteration, agent.tool.name and agent.circuit_breaker.triggered fields in the older table below are application-specific example attributes, not OpenTelemetry-standard GenAI field names.

Privacy and accounting boundary: Prompts, completions, raw reasoning, tool arguments and database outputs may contain secrets or personal data. Collect identifiers, result codes, timings and token totals by default; enable payload capture only under explicit access, redaction and retention policies. Avoid counting cached/reasoning tokens twice when they already belong to input or output totals. Record the semantic convention version emitted by the SDK.

Defining standard span attributes following OpenTelemetry LLM/GenAI Workgroup specifications and agent engineering standards is crucial.

OpenTelemetry GenAI Semantic Conventions Consistent Span Attribute keys help observability tools interpret the data. When changing backends, also check which fields are collected and how the exporter maps them.

Attribute NameTypeDescriptionExample
gen_ai.provider.namestringProvider telemetry convention (gen_ai.system is deprecated)openai, anthropic
gen_ai.request.modelstringFrontier model name used for requestgpt-4o, claude-3-5-sonnet
gen_ai.usage.input_tokensintPrompt tokens consumed for input1420
gen_ai.usage.output_tokensintCompletion tokens consumed for generation380
agent.run_idstringUnique identifier for a single agent execution unitrun-9a8f23
agent.iterationintCurrent agent execution loop count3
agent.tool.namestringUnique name of executed toolexecute_python_code
agent.tool.statusstringTool execution result statussuccess, error, blocked
agent.circuit_breaker.triggeredboolWhether safety guardrail tripped the circuit breakertrue, false

3. Structured Logging and Agent Loop Debugging

While distributed tracing visualizes the temporal and hierarchical flow of overall execution, Structured Logging handles fine-grained state mutation tracking and precision debugging.

3.1 Limitations of Plain Text Logging and Pydantic Event Schemas

Simply logging formatted strings like logger.info(f"Agent state: {state}") makes it difficult for log management platforms (Elasticsearch, Datadog, Loki, etc.) to query nested fields or configure automated alerts. Therefore, all agent events must be encoded and emitted using strict JSON schemas powered by Pydantic v2.

{  "timestamp": "2026-07-27T10:15:30.124Z",  "level": "INFO",  "event_type": "agent_tool_execution_completed",  "trace_id": "4bf92f3577b34da6a3ce929d0e0e4736",  "span_id": "00f067aa0ba902b7",  "agent_id": "DataAnalystAgent",  "run_id": "run-9a8f23",  "iteration": 2,  "payload": {    "tool_name": "query_database",    "execution_time_ms": 142.5,    "input_params": {"query": "SELECT count(*) FROM users;"},    "output_summary": {"row_count": 1, "status": "ok"},    "state_delta": {      "added_keys": ["db_result"],      "updated_keys": ["messages"]    }  }}

3.2 Replayability Checkpoints and Deterministic Replay Mode

When errors occur in non-deterministic production agents, the hardest issue to solve is: "The bug cannot be reproduced locally even with the exact same input prompt." To resolve this, the agent runtime must operate a Checkpoint Store that persists three critical elements for each iteration:

  1. Input Snapshot: Agent State and full Message History at loop entry.
  2. LLM Response Freeze: Raw text and function call JSON returned by the LLM.
  3. Tool Execution Result Freeze: Exact values returned by external APIs/tools.
StepFrom → ToMessage or operation
1User → Engineexecute_run(goal, input_state)
2Engine → StoreSave Checkpoint: Initial State Snapshot
3Engine → LLMStep 1: Prompt + History
4LLM → EngineToolCallRequest (e.g. query_db)
5Engine → StoreSave Checkpoint: LLM Completion Snapshot
6Engine → ToolExecute Tool (query_db)
7Tool → EngineRaw Tool Output (JSON)
8Engine → StoreSave Checkpoint: Tool Response & State Delta Snapshot
9Engine → UserRun Failure / Bug Detected (e.g. Invalid Parsing)
10Dev → Enginereplay_run(run_id, step=1)
11Engine → StoreFetch Checkpoint (State, LLM Output, Tool Response)
12Store → EngineHydrated Frozen State Snapshots
13Engine → EngineReplay Execution Step-by-Step with Mocked Input
14Engine → DevInspect State Mutation & Pinpoint Root Cause

The Value of Deterministic Replayability Production failures caused by agent non-determinism are nearly impossible to reproduce from raw logs alone. By freezing and locking snapshots of State, LLM Completions, and External API Responses for every iteration in a Checkpoint Store (e.g., Redis, PostgreSQL), developers can perform step-by-step offline replay debugging without triggering live external API calls.

3.3 Debugging Approach Comparison

Debugging ApproachExternal API CallsDeterminismDebug Speed & CostIdeal Failure Analysis Use Case
Plain Text Log AnalysisNone (Log query only)Very LowFast / $0 CostSimple syntax errors, server crash detection
Live Re-run (Re-execution)Live API re-callNon-deterministic (Varying results)Slow / Incurs API costTesting non-deterministic prompt improvements
Deterministic Checkpoint ReplayNone (Mocked replay)100% DeterministicExtremely Fast / $0 CostComplex loop state corruption, edge case analysis

4. Agent Failure Analysis & Real-Time Detection/Mitigation

Building real-time automatic mitigation (Circuit Breakers) for the 4 Major Production Agent Failure Patterns is essential for operating production agents.

4.1 Comparison of 4 Major Production Agent Failure Patterns

Failure PatternRoot CauseSystem ImpactMitigation & Circuit Breaker
Infinite Loop / RecursionRepeatedly calling the same tool with identical arguments / failing to convergeAPI hanging, resource exhaustion, stuck loopsDuplicate Tool Call Detector
(Trips circuit breaker if identical (tool, args) is called 3 consecutive times)
Hallucinated Tool CallCalling undefined tool names / argument type mismatchExecution runtime exceptionPydantic Guardrail & Retry Prompt
(Re-sends argument correction prompt once before fail-safe fallback)
Token Storm & Cost SpikeLarge tool outputs (500KB JSON) accumulating / prolonged loopsLLM API cost spikes, Context Window overflowContext Window Pruner & Budget Cap
(Enforces cumulative token budget limit & history summarization)
Cascading Sub-agent DeadlockUnhandled worker timeouts, cyclic delegation (Agent A → B → A)System-wide deadlock (Thread starvation)Cascading Timeout & Cycle Detector
(Delegation depth limiting & timeout propagation)

4.2 Circuit Breaker State Transition Architecture

Inside the agent runtime loop, Safety Middleware operating independently of LLM decisions is required to forcibly terminate execution or hand over control to Human-in-the-Loop workflows.

ScopeFrom → ToCondition or operation
Whole modelEntry → NormalExecutionStart Agent Iteration
Inside NormalExecutionEntry → CheckGuardrailsBegin internal checks
Inside NormalExecutionCheckGuardrails → LLMReasonerPass Limits
Inside NormalExecutionLLMReasoner → ValidateToolCallResponse Tool Call
Inside NormalExecutionValidateToolCall → ExecuteToolValid Schema
Outer connectionCheckGuardrails → TriggeredIteration Limit Exceeded OR Token Budget Exceeded
Outer connectionValidateToolCall → TriggeredTool Call Repeat Count >= 3
Outer connectionExecuteTool → TriggeredUnhandled Runtime Exception
Inside TriggeredEntry → LogCircuitBreakerEventStart circuit-breaker log
Inside TriggeredLogCircuitBreakerEvent → HumanInTheLoopHigh Risk / Action Required
Inside TriggeredLogCircuitBreakerEvent → FailSafeFallbackGraceful Shutdown
Outer connectionHumanInTheLoop → NormalExecutionApproved by Admin
Outer connectionHumanInTheLoop → TerminatedRejected
Outer connectionFailSafeFallback → TerminatedGraceful Abort
Outer connectionTerminated → EndReturn Partial Results & Error Trace

Key Guardrail Mechanisms:

  • Max Iteration Limit: Enforces maximum loop counts (e.g., immediate abort if exceeding 10 turns).
  • Duplicate Tool Call Detector: Aborts loop if identical (tool_name, tool_args) combinations repeat 3 or more times within recent $N$ iterations.
  • Context Window Pruner / Token Budget Cap: Blocks execution if cumulative token consumption per run exceeds designated budget (e.g., 100,000 Tokens).
  • Schema Validation Guardrail: Validates LLM tool call outputs using Pydantic. On validation failure, re-sends an argument correction prompt once; on second failure, gracefully returns an error.

Preventing API Cost Explosions from Unchecked Loops Infinite loops triggered by repeatedly invoking tools with identical arguments or retrying hallucinated tools can consume millions of tokens and trigger excessive external API queries within minutes. Circuit breakers are not optional features; they are an indispensable safety kill-switch for production runtimes.


5. Versioning, Regression Testing, Deployment & Governance

Agent software is a composite system combining standard application code with System Prompts, Tool Specifications, and LLM Model Versions.

5.1 Agent Specification Versioning Standard

When deploying agents, an explicit Agent Spec Version combining three core components must be maintained:

Agent Spec Version = [Code Release] + [Prompt Revision] + [Tool Specification Hash]Example: v2.4.0-p12.a9b1c3
ComponentIdentifier FormatMetadata IncludedImpact & Action
Code ReleasevX.Y.Z (SemVer)Agent runtime, orchestration engine, circuit breaker codeFull CI/CD test suite execution on Major/Minor updates
Prompt Revisionp1, p2, ...System Instruction, Few-shot Examples, Task ConstraintsMust pass Golden Evaluation Suite when prompts change
Tool Spec Hasha9b1c3 (SHA-256)MCP Server specification, Pydantic Tool Schema, API EndpointsAPI compatibility regression testing on Tool Signature change

If any single element changes, it constitutes a new Agent Spec Version and must undergo Regression Evaluation within the CI/CD pipeline.

5.2 CI/CD Regression Evaluation Flow

To prevent agent degradation when deploying new prompts or tools, automated evaluations against a Golden Dataset are executed.

  1. Trigger Phase: Git Push / Pull Request for a Prompt / Code / Tool Change enters Version Spec Verification.
  2. Automated CI Pipeline: Version Spec Verification (Code + Prompt + Tool Hash) → Load Golden Dataset (100+ Production Benchmark Tasks) → Parallel Agent Execution (Test Harness Matrix).
  3. Evaluation Engine & Metrics: parallel execution feeds each metric below, and each metric feeds All Metrics Passed?.
MetricTarget
Task Completion Rate>= 95%
Tool Selection Accuracy>= 98%
Step EfficiencyAvg Iterations <= 4.5
Token Cost DeltaCost Increase <= +5%
  1. Deployment Gatekeeper: NO → Block Deployment & Send Alert. YES → Approve PR & Trigger Deploy.
  2. CD & Production Monitoring: the approved path → Canary Deployment (10% Traffic Routing) → OTel Live Tracing & Metrics (Real-time Error Tracking) → 100% Production Rollout.

5.3 Core Agent Evaluation Metrics

Eval MetricTarget ThresholdEvaluation MethodDescription & Validation Content
Task Completion Rate$\ge 95%$Ground Truth Output comparison / LLM-as-a-JudgeVerifies whether agent successfully completes given goal
Tool Selection Accuracy$\ge 98%$Exact Schema Matching & Parameter CheckConfirms correct tools are invoked with valid argument formats
Step Efficiency$\le 4.5$ turnsAggregate iteration count (Avg Iteration Count)Average iterations spent per goal (detects unnecessary exploration)
Token Cost Efficiency$\le $0.05$/runOTel Token Span AggregateAverage dollar cost per execution run

5.4 Security & Compliance Governance

  • Human-in-the-Loop (HITL) Approval System: Destructive actions (DB deletions, payments, external emails, etc.) transition to a WAITING_FOR_APPROVAL pending state requiring admin authorization before execution.
  • Audit Log Immutability: All observability telemetry and tool execution history are immediately synchronized to an immutable Write-Once-Read-Many (WORM) audit log store.
  • PII / Secret Masking: Automatic redaction masking is applied to sensitive data (SSNs, credit cards, API keys) prior to sending OpenTelemetry spans and log events to exporters.

PII Protection and Destructive Action Governance LLM prompts and completions captured in traces and logs frequently contain sensitive customer data (SSNs, API keys, financial records). Passing telemetry through a PII Redaction Engine upstream of OTel Exporters is mandatory. Additionally, destructive tool calls (data deletion, payment execution) must transition into a WAITING_FOR_APPROVAL state to enforce Human-in-the-Loop approval.


6. Python Implementation: OpenTelemetry Agent Observability Runtime Core

The Python example combines OpenTelemetry SDK, Pydantic v2, and asyncio for hierarchical tracing, loop detection, and structured logging.

"""AI Agent Observability & Circuit Breaker Runtime Core Module(OpenTelemetry Distributed Tracing + Pydantic v2 + Safety Guardrails)""" import asyncioimport jsonimport loggingimport timefrom typing import Any, Dict, List, Optional, Tuplefrom pydantic import BaseModel, Field # OpenTelemetry Modulesfrom opentelemetry import tracefrom opentelemetry.trace import Status, StatusCode, SpanKindfrom opentelemetry.sdk.trace import TracerProviderfrom opentelemetry.sdk.trace.export import BatchSpanProcessor, ConsoleSpanExporter # OTel Tracer Setupprovider = TracerProvider()processor = BatchSpanProcessor(ConsoleSpanExporter())provider.add_span_processor(processor)trace.set_tracer_provider(provider) tracer = trace.get_tracer("agent.observability.core", "1.0.0")logger = logging.getLogger("AgentLogger")logging.basicConfig(level=logging.INFO, format="%(message)s") # ---------------------------------------------------------------------------# 1. Pydantic Schema Definitions# --------------------------------------------------------------------------- class ToolCallRequest(BaseModel):    tool_name: str = Field(description="Name of the tool to invoke")    tool_args: Dict[str, Any] = Field(default_factory=dict, description="Tool input parameters") class AgentState(BaseModel):    goal: str    messages: List[Dict[str, Any]] = Field(default_factory=list)    context_data: Dict[str, Any] = Field(default_factory=dict)    iteration_count: int = 0    is_completed: bool = False class AgentExecutionConfig(BaseModel):    max_iterations: int = 5    max_duplicate_tool_calls: int = 2    max_token_budget: int = 50000 class StructuredLogEvent(BaseModel):    """Structured event log schema powered by Pydantic v2"""    timestamp: str = Field(default_factory=lambda: time.strftime("%Y-%m-%dT%H:%M:%SZ", time.gmtime()))    event_type: str    trace_id: Optional[str] = None    span_id: Optional[str] = None    agent_id: str    run_id: str    iteration: int    payload: Dict[str, Any] = Field(default_factory=dict) # ---------------------------------------------------------------------------# 2. Circuit Breaker & Guardrail Classes# --------------------------------------------------------------------------- class AgentCircuitBreaker:    """Guardrail that detects infinite loops and agent failure patterns to abort execution"""     def __init__(self, config: AgentExecutionConfig):        self.config = config        self.tool_call_history: List[str] = []        self.total_tokens_used: int = 0     def check_guardrails(self, state: AgentState, pending_tool: Optional[ToolCallRequest] = None) -> None:        # 1. Max iteration limit check (abort if max_iterations exceeded)        if state.iteration_count > self.config.max_iterations:            raise RuntimeError(f"[CircuitBreaker] Exceeded max iterations ({self.config.max_iterations}). Forcibly terminating execution.")         # 2. Token budget check        if self.total_tokens_used >= self.config.max_token_budget:            raise RuntimeError(f"[CircuitBreaker] Exceeded allocated token budget ({self.config.max_token_budget}).")         # 3. Duplicate tool call check (Infinite Loop Detector)        if pending_tool:            tool_signature = f"{pending_tool.tool_name}:{json.dumps(pending_tool.tool_args, sort_keys=True)}"            same_calls = [sig for sig in self.tool_call_history if sig == tool_signature]            if len(same_calls) >= self.config.max_duplicate_tool_calls:                raise RuntimeError(                    f"[CircuitBreaker] Repeated tool invocation detected ({pending_tool.tool_name}). Aborting execution."                )            self.tool_call_history.append(tool_signature)     def record_tokens(self, tokens: int) -> None:        self.total_tokens_used += tokens # ---------------------------------------------------------------------------# 3. Observability Agent Runtime Engine# --------------------------------------------------------------------------- class ObservabilityAgentRuntime:    def __init__(self, agent_id: str, config: AgentExecutionConfig):        self.agent_id = agent_id        self.config = config     async def execute_run(self, run_id: str, goal: str) -> AgentState:        """Generates Root Run Span and executes agent main loop"""        state = AgentState(goal=goal)        circuit_breaker = AgentCircuitBreaker(self.config)         # 1. Create Root Span: agent.run        with tracer.start_as_current_span(            name="agent.run",            kind=SpanKind.SERVER,            attributes={                "agent.id": self.agent_id,                "agent.run_id": run_id,                "agent.goal": goal,            }        ) as root_span:            self._log_structured_event("agent_run_started", run_id, 0, {"goal": goal})             try:                while not state.is_completed:                    state.iteration_count += 1                     # 2. Create Child Span: agent.iteration                    with tracer.start_as_current_span(                        name=f"agent.iteration_{state.iteration_count}",                        attributes={"agent.iteration": state.iteration_count}                    ) as iter_span:                        # Check guardrail state                        circuit_breaker.check_guardrails(state)                         # Execute LLM reasoning step                        llm_decision, tokens_used = await self._step_llm_reasoner(run_id, state)                        circuit_breaker.record_tokens(tokens_used)                         # If tool call requested                        if llm_decision.get("type") == "tool_call":                            tool_req = ToolCallRequest(**llm_decision["payload"])                                                        # Re-verify guardrails before tool execution                            circuit_breaker.check_guardrails(state, pending_tool=tool_req)                             # Execute tool                            tool_result = await self._step_execute_tool(run_id, state.iteration_count, tool_req)                            state.messages.append({"role": "tool", "content": tool_result})                         elif llm_decision.get("type") == "finish":                            state.is_completed = True                            state.context_data["final_answer"] = llm_decision["payload"]["answer"]                            iter_span.set_attribute("agent.status", "completed")             except Exception as exc:                root_span.record_exception(exc)                root_span.set_status(Status(StatusCode.ERROR, str(exc)))                self._log_structured_event("agent_run_failed", run_id, state.iteration_count, {"error": str(exc)})                raise exc             root_span.set_status(Status(StatusCode.OK))            self._log_structured_event("agent_run_completed", run_id, state.iteration_count, {                "total_tokens": circuit_breaker.total_tokens_used,                "final_answer": state.context_data.get("final_answer")            })            return state     async def _step_llm_reasoner(self, run_id: str, state: AgentState) -> Tuple[Dict[str, Any], int]:        """LLM reasoning span and token usage aggregation"""        with tracer.start_as_current_span("llm.call") as span:            start_time = time.time()             # Simulated LLM processing            await asyncio.sleep(0.1)            prompt_tokens = 1500 + (state.iteration_count * 200)            completion_tokens = 150            total_tokens = prompt_tokens + completion_tokens             # Record OTel Attributes            span.set_attribute("gen_ai.provider.name", "openai")            span.set_attribute("gen_ai.request.model", "gpt-4o")            span.set_attribute("gen_ai.usage.input_tokens", prompt_tokens)            span.set_attribute("gen_ai.usage.output_tokens", completion_tokens)             # Simulated reasoning decision (completes on turn 3 after 2 tool calls)            if state.iteration_count < 3:                decision = {                    "type": "tool_call",                    "payload": {                        "tool_name": "fetch_user_analytics",                        "tool_args": {"user_id": "usr_9912", "period": "30d"}                    }                }            else:                decision = {                    "type": "finish",                    "payload": {"answer": "User analytics collection successfully completed."}                }             latency_ms = (time.time() - start_time) * 1000            self._log_structured_event("llm_call_completed", run_id, state.iteration_count, {                "prompt_tokens": prompt_tokens,                "completion_tokens": completion_tokens,                "latency_ms": latency_ms            })            return decision, total_tokens     async def _step_execute_tool(self, run_id: str, iteration: int, req: ToolCallRequest) -> str:        """Tool execution span recording and async execution"""        with tracer.start_as_current_span(f"tool.execute:{req.tool_name}") as span:            span.set_attribute("agent.tool.name", req.tool_name)            span.set_attribute("agent.tool.args", json.dumps(req.tool_args))             start_time = time.time()            try:                # Simulated tool execution                await asyncio.sleep(0.05)                output = f"Result for {req.tool_name} with args {req.tool_args}"                 span.set_attribute("agent.tool.status", "success")                latency_ms = (time.time() - start_time) * 1000                 self._log_structured_event("tool_execution_completed", run_id, iteration, {                    "tool_name": req.tool_name,                    "latency_ms": latency_ms,                    "status": "success"                })                return output            except Exception as e:                span.record_exception(e)                span.set_status(Status(StatusCode.ERROR, str(e)))                raise e     def _log_structured_event(self, event_type: str, run_id: str, iteration: int, payload: Dict[str, Any]) -> None:        """JSON structured log encoding and emission powered by Pydantic v2"""        current_span = trace.get_current_span()        ctx = current_span.get_span_context()         event = StructuredLogEvent(            event_type=event_type,            trace_id=format(ctx.trace_id, "032x") if ctx.is_valid else None,            span_id=format(ctx.span_id, "016x") if ctx.is_valid else None,            agent_id=self.agent_id,            run_id=run_id,            iteration=iteration,            payload=payload        )        logger.info(event.model_dump_json()) # ---------------------------------------------------------------------------# 4. Entrypoint Test# --------------------------------------------------------------------------- async def main():    agent_config = AgentExecutionConfig(max_iterations=5, max_duplicate_tool_calls=2)    runtime = ObservabilityAgentRuntime(agent_id="AnalyticsAgent_v1", config=agent_config)     print("=== [AI Agent Observability Runtime Test] ===")    result_state = await runtime.execute_run(run_id="run-test-1002", goal="Analyze recent 30-day data for user usr_9912")    print(f"\n[Final Execution Result]: {result_state.context_data.get('final_answer')}")     provider.shutdown() if __name__ == "__main__":    asyncio.run(main())

7. Production Operations Checklist

A comprehensive 4-domain operational checklist that engineering teams must review prior to deploying production agents.

DomainItemValidation DetailsStatus
Tracing & TelemetryOpenTelemetry Hierarchical SpansAre Parent-Child relationships between Root (agent.run), Iteration, LLM, and Tool Spans correctly formed?[ ]
GenAI OTel AttributesAre gen_ai.provider.name, gen_ai.operation.name, and gen_ai.usage.input_tokens/gen_ai.usage.output_tokens captured and distinguished from custom agent fields?[ ]
Cross-agent Context PropagationIs context propagated via Traceparent headers during sub-agent delegation to unify traces?[ ]
Debugging & ReplayStructured JSON LoggingAre JSON event logs containing Trace ID and Span ID transmitted to central log aggregators?[ ]
Checkpoint Store SetupAre per-iteration input State, LLM completions, and Tool outputs stored to enable offline Replay?[ ]
Guardrails & SafetyMax Iteration Circuit BreakerDoes the runtime automatically terminate when loop iteration limits are breached?[ ]
Duplicate Tool DetectorAre non-convergent, repeated tool calls with identical arguments detected and halted immediately?[ ]
Token & Cost Budget CapAre infrastructure-level kill-switches triggered when token thresholds per run or account are exceeded?[ ]
Governance & DeployAgent VersioningAre Code, Prompt Revision, and Tool Spec Hash tracked as a unified specification version?[ ]
Golden Eval SuiteIs automated regression evaluation performed in CI/CD, blocking deployment if benchmark scores fall short?[ ]
HITL & PII MaskingAre pre-approval mechanisms for risky tools and sensitive data (PII) redaction enabled?[ ]

8. Records to Keep for Operations

Connect execution flow, state changes, costs, and stop reasons when investigating an incident. Traces show call relationships and timing; structured logs record state changes; saved responses and checkpoints support replay. Start with one failure that is difficult to reproduce and check whether these records are available.

댓글

GitHub 계정으로 로그인하면 댓글을 남길 수 있습니다. 댓글은 GitHub Discussions를 통해 운영됩니다.

TOP