A provider-agnostic GenAI observability & evaluation framework benchmarked on Mind2Web
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
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.
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:
| 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:
Evaluation dashboard β score distribution, pass/fail, tool-F1, and cost-vs-latency:
π These visuals come straight from the framework. See the full sample evaluation report β (Markdown) or the HTML executive summary β for the complete write-up.
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.
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β 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 β
ββββββββββββ΄ββββββββββββββββββ΄βββββββββββββββββββββββββββ΄βββββββββββββββββββββββ
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.
| 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 collectorReal 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.
| 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)
| 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_contentfor navigation,site_search β web_searchfor search.
| 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 |
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.
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 callsFindings 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.
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.
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.).
git clone https://github.com/minw0607/multi_agent_otel_eval.git
cd multi_agent_otel_eval
pip install -r requirements.txtcp .env.example .env
# Edit .env β uncomment the section for your provider and fill in credentialsThe 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.
jupyter notebook agentic_otel_demo_notebook.ipynbRun cells in order. The Mind2Web dataset streams from HuggingFace on first run and caches locally β subsequent runs skip the download.
β οΈ 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_VERSIONunset on Colab β it activates Azure mode, which won't connect.
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
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.
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.
- 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_MODELto 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.
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


