Skip to content

Repository files navigation

Multi-Agent OTel Evaluation Framework

A provider-agnostic GenAI observability & evaluation framework benchmarked on Mind2Web

Open in Colab License: MIT Python 3.10+ OpenTelemetry Azure OpenAI OpenAI Ollama

Plug in any OpenAI-compatible LLM and run a rigorous, observable evaluation of single- and multi-agent web-navigation systems β€”
OpenTelemetry-compliant tracing Β· hybrid rule + LLM-judge scoring Β· tool-correctness metrics Β· cost & health monitoring Β· safety validation


What This Demo Showcases

As autonomous agents move into production, two questions become mission-critical: can you see what the agent did (observability), and can you prove it did the right thing (evaluation)? This demo is an end-to-end showcase of both, applied to a multi-agent web-navigation system on a real benchmark.

  • Observability β€” Every agent decision, LLM call, and tool invocation is captured as an OpenTelemetry-compliant span. The result is a portable, audit-ready trace tree you can ship to Datadog, Splunk, Phoenix, or Langfuse β€” the same instrumentation pattern you'd use to monitor agents in production.
  • Evaluation β€” A hybrid scoring engine (deterministic rules + LLM-as-judge), tool-selection correctness metrics, and safety validation quantify how well each agent performed β€” not just whether it finished.
  • Multi-agent architecture β€” A supervisor pattern (Planner β†’ Navigator β†’ Validator) is benchmarked head-to-head against a single-agent baseline, so you can see what orchestration buys you in quality, cost, and traceability.
  • Audit-grade reporting β€” A one-call generator turns the run into a structured Markdown report (executive summary, scope & compliance, section-by-section results, conclusion, audit trail) β€” deterministic by default, with optional LLM narratives clearly labeled πŸ€– AI Assessment. See a sample β†’

The notebook is deliberately coding-light: every component lives in src/, so the notebook reads as a clean narrative of the observability-and-evaluation workflow.


Sample Results

A 10-task run (single agent vs. multi-agent system) with real API token/cost accounting β€” your numbers will vary by model and sample, but the pattern is representative.

Single-Agent vs. Multi-Agent System β€” the multi-agent system lifted the pass rate substantially, at a measurable cost/latency premium:

Single vs Multi comparison

Metric Single Agent Multi-Agent Rating
Pass rate 60% 100% 🟒 High
Avg task score 0.697 0.809 🟒 High
Tool F1 0.399 0.462 🟑 Medium
Avg cost / task $0.0346 $0.0414 (1.2Γ—) 🟒 High
Median latency 8.3 s 19.5 s 🟑 Medium
Safety 100% 100% 🟒 High
Overall 🟒 High

(Cost reflects real API usage β€” counting every ReAct round-trip, not just the final output. Latency is the median, robust to occasional API stalls.)

OpenTelemetry trace tree β€” every task is a hierarchical span tree (task.execute β†’ planner β†’ navigator β†’ tool.execute β†’ validator) with per-agent cost, exported to OTLP JSON:

Multi-agent OTel trace tree

Evaluation dashboard β€” score distribution, pass/fail, tool-F1, and cost-vs-latency:

Evaluation dashboard

πŸ“„ These visuals come straight from the framework. See the full sample evaluation report β†’ (Markdown) or the HTML executive summary β†’ for the complete write-up.


Why This Framework

Most agent evaluation toolkits answer one question: "Did the agent complete the task?"

This framework answers five β€” and captures an OpenTelemetry-compliant trace that tells you how:

Question How
Did the agent complete the task? Hybrid rule-based + LLM-as-judge score
Did it pick the right tools? Precision / recall / F1 with flexible tool-equivalence mapping
Is it safe? PII, injection, harmful-content, and budget-violation checks
What does it cost to run? Per-call token + cost tracking, agent vs. judge separation
Is it healthy over time? Rolling-window success rate, latency percentiles, drift detection

Novel contributions: The full OpenTelemetry GenAI Semantic Convention span tree (portable to Datadog, Splunk, Phoenix, Langfuse) and the flexible tool-equivalence mapping are purpose-built for production agent observability β€” not found in standard evaluation toolkits.


At a Glance

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚                       Agent Evaluation Pipeline                              β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚  DATA    β”‚     AGENTS      β”‚       EXECUTION          β”‚      EVALUATION       β”‚
β”‚          β”‚                 β”‚                          β”‚                       β”‚
β”‚ Mind2Web β”‚ Single ReAct    β”‚ Hybrid real/mock tools   β”‚ Hybrid score          β”‚
β”‚ web-nav  β”‚ + multi-agent   β”‚ OTel span tracing        β”‚ (rule + LLM judge)    β”‚
β”‚ benchmarkβ”‚ supervisor      β”‚ token + cost tracking    β”‚ Tool correctness F1   β”‚
β”‚ (NeurIPS β”‚ (planner /      β”‚ health monitoring        β”‚ Safety validation     β”‚
β”‚  2023)   β”‚  navigator /    β”‚                          β”‚ Cost & latency        β”‚
β”‚          β”‚  validator)     β”‚                          β”‚ Audit-ready traces    β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

OpenTelemetry-Compliant Tracing

Every agent, LLM call, and tool invocation creates a span that follows the OpenTelemetry GenAI Semantic Conventions. Spans form a parent-child tree and export to OTLP JSON β€” portable to any observability backend (Datadog, Splunk, Phoenix, Langfuse, Jaeger).

task.execute                                  ← root span
β”œβ”€β”€ agent.planner.plan          (gen_ai.agent.role = task_decomposer)
β”œβ”€β”€ agent.navigator.execute     (gen_ai.agent.role = executor)
β”‚   β”œβ”€β”€ tool.execute            (gen_ai.tool.name = site_search)
β”‚   β”œβ”€β”€ tool.execute            (gen_ai.tool.name = filter_content)
β”‚   └── tool.execute            (gen_ai.tool.name = site_navigation)
└── agent.validator.validate    (gen_ai.evaluation.score = 0.82)

Standard attributes captured per span: gen_ai.system, gen_ai.request.model, gen_ai.usage.input_tokens, gen_ai.usage.output_tokens, gen_ai.agent.name, gen_ai.tool.name, gen_ai.usage.cost_usd, plus custom evaluation extensions.

Two tracing modes

Mode What it does When
Local (default) HierarchicalTracer records the span tree to JSONL + the offline trace-tree chart β€” zero extra dependencies Always on
Real OTel β†’ Phoenix setup_phoenix() registers the OpenTelemetry SDK and auto-instruments LangChain/LangGraph (OpenInference), streaming live spans to Arize Phoenix or any OTLP backend (Datadog, Jaeger, Grafana Tempo, Langfuse) One optional call
from src import setup_phoenix
setup_phoenix()                                  # local Phoenix UI at :6006
setup_phoenix(endpoint="http://collector:4317")  # or any OTLP collector

Real token & cost. Token counts come from actual API usage metadata (LangChain usage callbacks) whenever the provider returns it, falling back to a tiktoken estimate otherwise β€” the tokens_source field records which was used, so cost figures are honest rather than guessed.

πŸ“– New to OTel or want to wire up a specific backend? See the Observability Guide β†’ β€” a systematic walkthrough of OpenTelemetry concepts, how this framework emits spans, how to read a trace, and step-by-step setup for Phoenix, Jaeger, Grafana Tempo, Datadog, Splunk, Langfuse, and the generic OpenTelemetry Collector.


Evaluation Metrics

🎯 Task Completion (HybridEvaluator)

Component Method Weight
Length adequacy β‰₯ 40 words in the plan 0.2 (rule)
Specificity Contains numeric detail 0.1 (rule)
Goal alignment Task ↔ plan keyword overlap 0.3 (rule)
Structured format Uses action verbs (CLICK, TYPE, …) 0.2 (rule)
Action overlap Plan verbs ↔ reference verbs 0.2 (rule)
LLM judge Holistic 0.0–1.0 quality rating 0.6 (total)

total_score = 0.4 Γ— rule_score + 0.6 Γ— llm_score (weights configurable)

πŸ› οΈ Tool Correctness (ToolCorrectnessEval)

Metric Method
Precision / Recall / F1 Predicted vs. reference tools, flexible equivalence
Exact Match No missing or extra tools
Order Accuracy Longest common subsequence vs. reference order

Flexible tool equivalence recognizes that Mind2Web's basic action set (CLICK, TYPE) maps to the agent's richer toolset β€” site_navigation β‰ˆ site_search β‰ˆ filter_content for navigation, site_search β‰ˆ web_search for search.

πŸ›‘οΈ Safety (SafetyValidator)

Check Detects
PII SSN, credit card, email, phone
Injection XSS, SQL injection, code injection
Harmful content Jailbreak / bypass / exploit keywords
Financial Prices exceeding a stated budget

Single-Agent vs. Multi-Agent System (the core story)

The demo runs the same tasks through two architectures and puts the trade-off side by side β€” when is orchestration worth it?

Architecture Pattern Specialists Models
Single Agent One ReAct loop with all tools 1 AGENT_MODEL
Multi-Agent System Supervisor β†’ Planner β†’ Navigator β†’ Validator 4 per-role (configurable)

In the MAS, work is divided: the Planner decomposes the task, the Navigator executes it with tools, and the Validator independently checks the result. This decomposition tends to lift task quality on complex, multi-step tasks β€” at the cost of more tokens and latency (4 LLM roles vs. 1).

Each specialist gets its own model (set PLANNER_MODEL, NAVIGATOR_MODEL, SUPERVISOR_MODEL, VALIDATOR_MODEL in .env) and its own OTel span with per-agent cost attribution. The notebook produces a comparison table, a 3-panel chart, and an auto-generated interpretation of which system won and why.

Takeaway: simple lookups favor the single agent; complex, multi-step tasks favor the MAS. The framework lets you measure exactly where that line is for your tasks and models.


Audit-Grade Reporting

The final step generates a structured Markdown evaluation report (src/report.py) suitable for model-risk review:

evaluation_report_<timestamp>.md
β”œβ”€β”€ 1. Executive Summary        β€” key findings & observations
β”œβ”€β”€ 2. Testing Scope            β€” what we test Β· Mind2Web data Β· regulations & compliance
β”œβ”€β”€ 3. Testing Approach         β€” hybrid sandbox method Β· scoring stack Β· judge model
β”œβ”€β”€ 4. Testing Results          β€” section-by-section assessment + embedded visualization
β”‚      4.1 Task completion   4.2 Tool correctness   4.3 Safety
β”‚      4.4 Cost & performance 4.5 Single-vs-multi   4.6 Observability
β”œβ”€β”€ 5. Conclusion               β€” recommendation from the cost/quality trade-off
└── 6. Appendices               β€” artifacts Β· per-task audit trail Β· AI disclosure

Hybrid, audit-safe assessment. All tables, metrics, pass/fail decisions, and the audit trail are computed deterministically (rule-based) and are audit-safe.

Selective LLM judge (default-on, used only when needed). The LLM judge is enabled by default but invoked only where deterministic interpretation is genuinely ambiguous β€” borderline scores, mixed cost/quality trade-offs, or safety violations. Clear-cut sections stay rule-based, which is cheaper, faster, and fully reproducible. Every LLM narrative is labeled πŸ€– AI Assessment with a disclosure notice, so LLM inference is never confused with the deterministic record (mapping to NIST AI RMF transparency).

generate_report(..., use_llm=True,  llm_selective=True)   # default β€” AI only when ambiguous
generate_report(..., use_llm=True,  llm_selective=False)  # AI narrative on every section
generate_report(..., use_llm=False)                       # fully deterministic, no LLM calls

Findings are numbered (F1–F7) in the Executive Summary and cross-referenced from each results section, so a reviewer can trace every headline claim back to its underlying metric and assessment. Each finding carries a 🟒 High / 🟑 Medium / πŸ”΄ Low rating, and the report rolls these up into a single overall testing rating (from task completion, quality, and safety). Model names render as friendly labels (e.g. GPT 5-4 (Azure)), not raw deployment IDs.

πŸ“₯ Download a sample report β†’ (with embedded charts) to see the full output before running anything.


Hybrid Real + Mock Tool Environment

The industry-standard approach for safe pre-deployment agent evaluation:

READ tools     (real when API keys present, mock fallback)
  web_search Β· site_search Β· get_price_info Β· check_availability
  site_navigation Β· filter_content Β· get_page_info

WRITE tools    (ALWAYS mocked β€” no real-world side effects)
  book_reservation Β· make_phone_call Β· submit_form Β· make_purchase

COMPUTE        (always real)
  budget_calculator

This balances rigor (real agent behavior, real web data via Tavily) with safety (no real bookings, purchases, or form submissions). Set TAVILY_API_KEY to enable live web search; without it, READ tools return realistic mock data.


Quickstart

Recommended: run locally with Jupyter. This demo is designed to run on your own machine. The reference Azure OpenAI setup uses IP-allowlist access (no interactive login), which is the smoothest path for uninterrupted evaluation runs β€” but it means Google Colab will not work with Azure (Colab's Google Cloud IPs are not on corporate allowlists). Colab remains available for users who bring a non-Azure provider (OpenAI, Groq, Together, etc.).

Option A β€” Local Setup (recommended)

1. Clone and install

git clone https://github.com/minw0607/multi_agent_otel_eval.git
cd multi_agent_otel_eval
pip install -r requirements.txt

2. Configure your LLM provider

cp .env.example .env
# Edit .env β€” uncomment the section for your provider and fill in credentials

The provider is auto-detected from OPENAI_API_VERSION:

  • Set (e.g. 2025-04-01-preview) β†’ Azure OpenAI (AzureChatOpenAI)
  • Blank β†’ OpenAI direct, Ollama, Groq, or any compatible endpoint (ChatOpenAI)

See docs/provider-setup.md for step-by-step instructions per provider.

3. Run the demo notebook

jupyter notebook agentic_otel_demo_notebook.ipynb

Run cells in order. The Mind2Web dataset streams from HuggingFace on first run and caches locally β€” subsequent runs skip the download.


Option B β€” Google Colab (non-Azure providers only)

⚠️ Not compatible with the reference Azure OpenAI setup (IP allowlisting blocks Colab). Use this only with OpenAI, Groq, Together, or another IP-independent provider.

Click the Open in Colab badge at the top of this README, then add your credentials as Colab Secrets (πŸ”‘ in the left sidebar) and run all cells:

Secret name Example value
OPENAI_API_KEY sk-...
OPENAI_BASE_URL https://api.openai.com/v1
AGENT_MODEL gpt-4o
JUDGE_MODEL gpt-4o
TAVILY_API_KEY tvly-... (optional β€” enables real web search)

Leave OPENAI_API_VERSION unset on Colab β€” it activates Azure mode, which won't connect.


Repo Structure

multi_agent_otel_eval/
β”œβ”€β”€ README.md
β”œβ”€β”€ requirements.txt
β”œβ”€β”€ .env.example                    ← Copy to .env and fill in credentials (never committed)
β”œβ”€β”€ .gitignore
β”œβ”€β”€ LICENSE
β”‚
β”œβ”€β”€ agentic_otel_demo_notebook.ipynb             ← β˜… Start here β€” coding-light, all heavy lifting in src/
β”œβ”€β”€ Enhanced_Agentic_Framework_Multi_Agent.ipynb   ← Original monolithic research notebook
β”‚
β”œβ”€β”€ src/                            ← Importable Python modules
β”‚   β”œβ”€β”€ config.py                   ← Provider-agnostic LLM factory, reads from .env
β”‚   β”œβ”€β”€ tracer.py                   ← Local OTel-shaped spans (HierarchicalTracer) + ExecutionTrace
β”‚   β”œβ”€β”€ otel.py                     ← Real OpenTelemetry β†’ Phoenix + real token/cost callbacks
β”‚   β”œβ”€β”€ monitors.py                 ← CostTracker + HealthMonitor (rolling window)
β”‚   β”œβ”€β”€ safety.py                   ← PII, injection, harmful-content, budget checks
β”‚   β”œβ”€β”€ tools.py                    ← Hybrid real/mock web-navigation tools
β”‚   β”œβ”€β”€ dataset.py                  ← Mind2Web streaming loader with local cache
β”‚   β”œβ”€β”€ agents.py                   ← Baseline ReAct + multi-agent supervisor pipeline
β”‚   β”œβ”€β”€ runner.py                   ← evaluate_batch() β€” runs N tasks through either system
β”‚   β”œβ”€β”€ evaluator.py                ← HybridEvaluator + ToolCorrectnessEval
β”‚   β”œβ”€β”€ visualizer.py               ← Eval dashboard, trace tree, telemetry, comparison charts
β”‚   └── report.py                   ← Audit-grade Markdown report generator
β”‚
β”œβ”€β”€ docs/
β”‚   β”œβ”€β”€ provider-setup.md           ← Step-by-step setup for Azure, OpenAI, Ollama, Groq
β”‚   └── observability.md            ← OTel concepts + backend setup (Phoenix/Datadog/Jaeger/…)
β”‚
└── outputs/                        ← Results, traces, charts, reports (gitignored)
    β”œβ”€β”€ traces/                     ← OTLP JSON span exports
    β”œβ”€β”€ data/                       ← Cached Mind2Web dataset
    β”œβ”€β”€ baseline_vs_multi.png
    β”œβ”€β”€ single_agent_*.csv / multi_agent_*.csv
    └── evaluation_report_*.md      ← Audit-grade report

Provider Compatibility

The framework auto-detects your provider from .env β€” no code changes required.

OPENAI_API_VERSION Provider LangChain class
Set (e.g. 2025-04-01-preview) Azure OpenAI AzureChatOpenAI
Blank OpenAI / Ollama / Groq / etc. ChatOpenAI

Supported providers:

Provider OPENAI_BASE_URL Notes
Azure OpenAI https://<resource>.openai.azure.com Set OPENAI_API_VERSION
OpenAI (direct) https://api.openai.com/v1 Default
Ollama (local) http://localhost:11434/v1 Free, no API key
Groq https://api.groq.com/openai/v1 β€”
Together AI https://api.together.xyz/v1 β€”
LM Studio http://localhost:1234/v1 β€”

See docs/provider-setup.md for step-by-step setup and troubleshooting.


About the Mind2Web Dataset

Mind2Web is the first large-scale benchmark for evaluating AI agents that perform web-navigation tasks from natural language instructions. Published at NeurIPS 2023 (Spotlight) by The Ohio State University, it spans 2,000+ tasks across 137 real websites and 31 domains.

This framework streams the lightweight text metadata (task descriptions, websites, reference action sequences) from the osunlp/Multimodal-Mind2Web HuggingFace dataset, skipping the heavy HTML and screenshot fields.


Limitations

  • LLM-as-judge bias: When the agent and judge use the same model, self-evaluation biases toward higher scores. A separate judge model is preferable when budget allows β€” set JUDGE_MODEL to a different model.
  • Hypothetical-plan scoring: The evaluator scores the agent's plan (intended actions), not live browser execution. Mind2Web tasks run against mock/scraped data, not the live target site.
  • Tool-equivalence mapping: The flexible mapping is tuned for Mind2Web's basic action set. Custom toolsets may need their own equivalence rules in evaluator.py.
  • Synchronous execution: The evaluation loop is single-threaded. For large runs (>100 tasks), parallelise at the process level.

Citation

If you use this framework, please cite the Mind2Web benchmark:

@inproceedings{deng2023mind2web,
  title={Mind2Web: Towards a Generalist Agent for the Web},
  author={Deng, Xiang and Gu, Yu and Zheng, Boyuan and Chen, Shijie and
          Stevens, Samuel and Wang, Boshi and Sun, Huan and Su, Yu},
  booktitle={NeurIPS},
  year={2023}
}

And the OpenTelemetry GenAI Semantic Conventions:

https://opentelemetry.io/docs/specs/semconv/gen-ai/

Made with ❀️ for rigorous, observable agent evaluation
Open an issue Β· Provider setup Β· Observability guide

About

Enterprise-grade GenAI observability and evaluation framework using OpenTelemetry conventions, with multi-agent orchestration tested on the Mind2Web benchmark.

Topics

Resources

Stars

Watchers

Forks

Releases

Packages

Contributors

Languages