A multi-agent system for finding and verifying statistics from reputable web sources using Go, built with omniagent-worker, Google ADK (Agent Development Kit), and Eino.
This project implements a sophisticated multi-agent architecture that leverages LLMs and web search to find verifiable statistics, prioritizing well-known and respected publishers. The system ensures accuracy through automated verification of sources.
The system implements a worker-based architecture using omniagent-worker with clear separation of concerns:
Architecture: Built with omniagent-worker for worker lifecycle and coordination. Workers implement the
Workerinterface and are orchestrated by aCoordinatorwith deterministic graph workflow and AgentOps tracing. See docs/architecture for complete details.
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β User Request β
β "Find climate change statistics" β
βββββββββββββββββββββ¬ββββββββββββββββββββββββββββββββββββββ
β
βΌ
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β COORDINATOR β
β (omniagent-worker.Coordinator) β
β β’ Coordinates worker workflow β
β β’ Manages retry logic β
β β’ AgentOps tracing via OpenTelemetry β
βββββββ¬ββββββββββββββ¬βββββββββββββββββ¬βββββββββββββββββββββ
β β β
βΌ βΌ βΌ
ββββββββββββββ ββββββββββββ βββββββββββββββββββ
β RESEARCH β βSYNTHESIS β β VERIFICATION β
β WORKER β β WORKER β β WORKER β
β β β β β β
β β’ Search ββββ’ Fetch ββββ’ Re-fetch URLs β
β Serper β β URLs β ββ’ Validate text β
β β’ Filter β ββ’ LLM β ββ’ Check numbers β
β Sources β β Extract β ββ’ Flag errors β
ββββββββββββββ ββββββββββββ βββββββββββββββββββ
β β β
βΌ βΌ βΌ
URLs only Statistics Verified Stats
The system uses omniagent-worker for worker lifecycle, coordination, and observability.
- No LLM required - Pure search functionality
- Implements
omniagent-worker.Workerinterface - Web search via Serper/SerpAPI integration
- Returns URLs with metadata (title, snippet, domain)
- Prioritizes reputable sources (
.gov,.edu, research orgs) - Output: List of
SearchResultobjects
- LLM-heavy extraction worker
- Implements
omniagent-worker.Workerinterface - Fetches webpage content from URLs
- Extracts numerical statistics using LLM analysis
- Finds verbatim excerpts containing statistics
- Creates
CandidateStatisticobjects with proper metadata
- LLM-light validation worker
- Implements
omniagent-worker.Workerinterface - Re-fetches source URLs to verify content
- Checks excerpts exist verbatim in source
- Validates numerical values match exactly
- Flags hallucinations and discrepancies
- Returns verification results with pass/fail reasons
- Built with
omniagent-worker.Coordinator - Deterministic graph-based workflow (no LLM for orchestration)
- Coordinates: Research β Synthesis β Verification
- Implements adaptive retry logic
- AgentOps tracing via OpenTelemetry
- Workflow: ValidateInput β Research β Synthesis β Verification β QualityCheck β Format
- β Multi-agent pipeline - Full verification workflow (Research β Synthesis β Verification) β RECOMMENDED
- β Real web search - Google search via Serper/SerpAPI (30 URLs searched by default) π
- β Comprehensive extraction - Processes 15+ pages, reads 30K chars per page for thorough coverage
- β Source verification - Validates excerpts and values match actual web pages
- β Human-in-the-loop retry - Prompts user when partial results found
- β Reputable source prioritization - Government, academic, research organizations
- β
Direct LLM mode - Fast but uses LLM memory (
β οΈ not recommended for statistics) - β
Hybrid mode - LLM discovery + web verification (
β οΈ low verification rate) - β OpenAPI documentation - Interactive Swagger UI for Direct agent (port 8005)
- β
ClaimsReport format - Export as structured-evaluation ClaimsReport via
?format=claims - β Source classification - Authoritative sources (WHO, CDC, NASA, etc.) classified as high reliability
- β Multi-LLM providers - Gemini, Claude, OpenAI, Ollama, xAI Grok via unified interface
- β omniagent-worker - Go-first multi-agent worker framework
- β Eino framework - Deterministic graph orchestration
- β A2A Protocol - Agent-to-Agent interoperability (Google standard) π
- β LLM Observability - OmniObserve integration (Opik, Langfuse, Phoenix) ποΈ
- β Huma v2 - OpenAPI 3.1 docs for Direct agent
- β MCP Server - Integration with Claude Code and other MCP clients
- β Docker deployment - Easy containerized setup π³
The system returns verified statistics in JSON format:
[
{
"name": "Global temperature increase since pre-industrial times",
"value": 1.1,
"unit": "Β°C",
"source": "IPCC Sixth Assessment Report",
"source_url": "https://www.ipcc.ch/...",
"excerpt": "Global surface temperature has increased by approximately 1.1Β°C since pre-industrial times...",
"verified": true,
"date_found": "2025-12-13T10:30:00Z"
}
]- name: Description of the statistic
- value: Numerical value (float32)
- unit: Unit of measurement (e.g., "Β°C", "%", "million", "billion")
- source: Name of source organization/publication
- source_url: URL to the original source
- excerpt: Verbatim quote containing the statistic
- verified: Whether the verification agent confirmed it
- date_found: Timestamp when statistic was found
- Go 1.21 or higher
- LLM API key for your chosen provider:
- Gemini (default): Google API key (set as
GOOGLE_API_KEYorGEMINI_API_KEY) - Claude: Anthropic API key (set as
ANTHROPIC_API_KEYorCLAUDE_API_KEY) - OpenAI: OpenAI API key (set as
OPENAI_API_KEY) - xAI Grok: xAI API key (set as
XAI_API_KEY) - Ollama: Local Ollama installation (default:
http://localhost:11434)
- Gemini (default): Google API key (set as
- Optional: API keys for search provider (Google Search, etc.)
- Clone the repository:
git clone https://github.com/plexusone/agent-team-stats.git
cd agent-team-stats- Install dependencies:
make install
# or
go mod download- Configure environment variables:
# For Gemini (default)
export GOOGLE_API_KEY="your-google-api-key"
# For Claude
export LLM_PROVIDER="claude"
export ANTHROPIC_API_KEY="your-anthropic-api-key"
# For OpenAI
export LLM_PROVIDER="openai"
export OPENAI_API_KEY="your-openai-api-key"
# For xAI Grok
export LLM_PROVIDER="xai"
export XAI_API_KEY="your-xai-api-key"
# For Ollama (local)
export LLM_PROVIDER="ollama"
export OLLAMA_URL="http://localhost:11434"
export LLM_MODEL="llama3:latest"
# Optional: Create .env file
cp .env.example .env
# Edit .env with your API keys- Build the agents:
make buildYou can run the system either with Docker (containerized) or locally. Choose the method that best fits your needs.
| Method | Best For | Command |
|---|---|---|
| Docker π³ | Production, quick start, isolated environment | docker-compose up -d |
| Local π» | Development, debugging, customization | make run-all-eino |
The fastest way to get started:
# Start all agents with Docker Compose
docker-compose up -d
# Test the orchestration endpoint
curl -X POST http://localhost:8000/orchestrate \
-H "Content-Type: application/json" \
-d '{"topic": "climate change", "min_verified_stats": 5}'
# View logs
docker-compose logs -f
# Stop
docker-compose downSee DOCKER.md for complete Docker deployment guide.
The coordinator runs all workers in-process using omniagent-worker:
# Build and run the coordinator
make build
./bin/stats-coordinator --port 8080
# With AgentOps tracing
./bin/stats-coordinator --port 8080 --agentops-dsn postgres://...The CLI supports three modes: Direct LLM search (fast, like ChatGPT), Direct + Verification (hybrid), and Multi-agent verification pipeline (thorough, verified).
Direct mode uses a single LLM call to find statistics from memory - similar to ChatGPT without web search:
# Start direct agent first
make run-direct
# Then query (fast but uses LLM memory)
./bin/stats-agent search "climate change" --directWhy Not Recommended for Statistics:
- β Uses LLM memory - Not real-time web search (training data up to Jan 2025)
- β Outdated URLs - LLM guesses URLs where stats came from
- β Low accuracy - Pages may have moved, changed, or be paywalled
β οΈ 0% verification rate - When combined with--direct-verify, most claims fail
When to Use:
- β General knowledge questions
- β Concept explanations
- β Quick brainstorming (accept unverified data)
For statistics, use Pipeline mode instead (see below)
Combines Direct mode with verification, but suffers from the same LLM memory issues:
# Start both agents
make run-direct-verify
# Then query
./bin/stats-agent search "climate change" --direct --direct-verifyWhy Not Recommended:
- β Low verification rate - Typically 0-30% of LLM claims verify
- β Same LLM memory problem - URLs are guessed, not from real search
β οΈ Slow with poor results - Verification overhead but few verified stats
For reliable statistics, use Pipeline mode instead
For verified, web-scraped statistics (requires agents running):
# Start agents first
make run-all-eino
# Then in another terminal:
# Basic search with verification pipeline
./bin/stats-agent search "climate change"
# Request specific number of verified statistics
./bin/stats-agent search "global warming" --min-stats 15
# Increase candidate search space
./bin/stats-agent search "AI trends" --min-stats 10 --max-candidates 100
# Only reputable sources
./bin/stats-agent search "COVID-19 statistics" --reputable-only
# JSON output only
./bin/stats-agent search "renewable energy" --output json
# Text output only
./bin/stats-agent search "climate data" --output textAdvantages of Multi-Agent Mode:
- β Verified sources - Actually fetches and checks web pages
- π Web search - Finds current statistics from the web
- π― Accuracy - Validates excerpts and values match
- π Human-in-the-loop - Prompts to continue if target not met
stats-agent search <topic> [options]
Options:
-d, --direct Use direct LLM search (fast, like ChatGPT)
--direct-verify Verify LLM claims with verification agent (requires --direct)
-m, --min-stats <n> Minimum statistics to find (default: 10)
-c, --max-candidates <n> Max candidates for pipeline mode (default: 50)
-r, --reputable-only Only use reputable sources
-o, --output <format> Output format: json, text, both (default: both)
--orchestrator-url Override orchestrator URL
-v, --verbose Show verbose debug information
--version Show version informationMode Comparison:
| Mode | Speed | Accuracy | Agents Needed | Client Needs API Key? | Best For |
|---|---|---|---|---|---|
--direct |
β‘β‘β‘ Fastest | Direct agent only | β No | Quick research, brainstorming | |
--direct --direct-verify |
β‘β‘ Fast | β Web-verified | Direct + Verification | β No | Balanced speed + accuracy |
| Pipeline (default) | β‘ Slower | β β Fully verified | All 4 agents | β No | Maximum reliability |
---
### Using with Claude Code (MCP Server)
The system can be used as an MCP server with Claude Code and other MCP clients:
```bash
# Build the MCP server
make build-mcp
# Configure in Claude Code's MCP settings (see MCP_SERVER.md)
See MCP_SERVER.md for detailed setup instructions.
You can call the coordinator via HTTP:
# Call coordinator (default port 8080)
curl -X POST http://localhost:8080/orchestrate \
-H "Content-Type: application/json" \
-d '{
"topic": "climate change",
"min_verified_stats": 10,
"max_candidates": 30,
"reputable_only": true
}'
# Get ClaimsReport format (structured-evaluation compatible)
curl -X POST "http://localhost:8080/orchestrate?format=claims" \
-H "Content-Type: application/json" \
-d '{"topic": "climate change", "min_verified_stats": 5}'See ClaimsReport Integration for detailed usage.
| Variable | Description | Default |
|---|---|---|
LLM_PROVIDER |
LLM provider: gemini, claude, openai, xai, ollama |
gemini |
LLM_MODEL |
Model name (provider-specific) | See defaults below |
LLM_API_KEY |
Generic API key (overrides provider-specific) | - |
LLM_BASE_URL |
Base URL for custom endpoints (Ollama, etc.) | - |
Provider-Specific API Keys:
| Variable | Description | Default |
|---|---|---|
GOOGLE_API_KEY / GEMINI_API_KEY |
Google API key for Gemini | Required for Gemini |
ANTHROPIC_API_KEY / CLAUDE_API_KEY |
Anthropic API key for Claude | Required for Claude |
OPENAI_API_KEY |
OpenAI API key | Required for OpenAI |
XAI_API_KEY |
xAI API key for Grok | Required for xAI |
OLLAMA_URL |
Ollama server URL | http://localhost:11434 |
Default Models by Provider:
- Gemini:
gemini-2.5-flash(orgemini-2.5-pro) - Claude:
claude-sonnet-4-20250514(orclaude-opus-4-1-20250805) - OpenAI:
gpt-4o(orgpt-5) - xAI:
grok-4-1-fast-reasoning(orgrok-4-1-fast-non-reasoning) - Ollama:
llama3:8b(ormistral:7b)
See LLM_CONFIGURATION.md for detailed LLM setup.
| Variable | Description | Default |
|---|---|---|
SEARCH_PROVIDER |
Search provider: serper, serpapi |
serper |
SERPER_API_KEY |
Serper API key (get from serper.dev) | Required for real search |
SERPAPI_API_KEY |
SerpAPI key (alternative provider) | Required for SerpAPI |
Note: Without a search API key, the research agent will use mock data. See SEARCH_INTEGRATION.md for setup details.
| Variable | Description | Default |
|---|---|---|
OBSERVABILITY_ENABLED |
Enable LLM observability | false |
OBSERVABILITY_PROVIDER |
Provider: opik, langfuse, phoenix |
opik |
OBSERVABILITY_API_KEY |
API key for the provider | - |
OBSERVABILITY_ENDPOINT |
Custom endpoint (optional) | Provider default |
OBSERVABILITY_PROJECT |
Project name for grouping traces | stats-agent-team |
Supported Providers:
- Comet Opik - LLM tracing and evaluation
- Langfuse - Open-source LLM observability
- Arize Phoenix - ML observability platform
| Variable | Description | Default |
|---|---|---|
COORDINATOR_PORT |
Coordinator HTTP port | 8080 |
AGENTOPS_DSN |
AgentOps tracing DSN (postgres) | - |
Workers can run in two modes:
| Mode | Description | Use Case |
|---|---|---|
| In-Process (default) | Workers run within the Coordinator process via Pool | Development, single-process deployment |
| HTTP Services | Workers run as separate HTTP services | Microservices, scaling individual workers |
Default Port (Coordinator): 8080
A2A Protocol Support:
GET /.well-known/agent-card.json- Agent discoveryPOST /invoke- JSON-RPC execution
Enable A2A with: A2A_ENABLED=true
agent-team-stats/
βββ workers/ # omniagent-worker based workers
β βββ research/ # Research worker (web search)
β β βββ worker.go
β βββ synthesis/ # Synthesis worker (LLM extraction)
β β βββ worker.go
β βββ verification/ # Verification worker (LLM validation)
β βββ worker.go
βββ coordinator/ # Workflow coordinator
β βββ coordinator.go # omniagent-worker.Coordinator implementation
βββ omniskill/ # OmniAgent skill integration
β βββ stats.go # Skill interface for omniagent
βββ cmd/
β βββ coordinator/ # Coordinator CLI entrypoint
β βββ main.go
βββ pkg/
β βββ config/ # Configuration management
β βββ direct/ # Direct LLM search service
β βββ llm/ # Multi-provider LLM factory (OmniLLM + OmniObserve)
β β βββ adapters/ # OmniLLM adapter for ADK integration
β βββ models/ # Shared data models
β βββ orchestration/ # Orchestration logic
βββ main.go # CLI entry point
βββ Makefile # Build and run commands
βββ go.mod # Go dependencies
βββ .env.example # Environment template
βββ README.md # This file
make buildmake testmake clean- Language: Go 1.21+
- Worker Framework:
- omniagent-worker - Go-first multi-agent worker framework β
- Agent Frameworks:
- Google ADK - LLM model interface + A2A protocol
- Eino - Workflow graph primitives
- LLM Integration:
- OmniLLM - Multi-provider LLM abstraction
- Supports: Gemini, Claude, OpenAI, xAI Grok, Ollama
- Observability:
- OmniObserve - Unified LLM observability
- AgentOps tracing via OpenTelemetry
- Supports: Comet Opik, Langfuse, Arize Phoenix
- Protocols:
- HTTP - Custom security, flexibility (ports 800x)
- A2A - Agent-to-Agent interoperability (ports 900x)
- Search:
- OmniSerp - Unified serp API abstraction
- Supports: Serper.dev, SerpAPI
- User Request: User provides a topic via CLI or API
- Coordination: Coordinator receives request and initiates workflow
- Research Phase: Research worker searches web for candidate URLs
- Synthesis Phase: Synthesis worker extracts statistics from URLs
- Verification Phase: Verification worker validates each statistic
- Quality Control: Coordinator checks if minimum verified stats met
- Retry Logic: If needed, request more candidates and verify
- Response: Return verified statistics in structured JSON format
The Eino orchestrator (pkg/orchestration/eino.go) implements steps 3β7
above as two composed, bounded loops rather than a single linear
pipeline with an ad-hoc retry, following the org's Loop
Engineering
REAL/VEAL patterns:
- REAL loop (discovery, up to 5 rounds): "find at least N verified statistics" is a mission β read the shortfall, search and extract a new batch, hand it to VEAL, loop until the mission is met.
- VEAL loop (verification, up to 3 attempts per batch): a read-only validator checks each candidate β including whether its source is a known low-trust aggregator, independent of whether the excerpt verifies β and a separate actor attempts a targeted fix (a primary-source replacement search for aggregator-sourced claims, a re-validation pass for transient fetch failures) before anything is counted as verified.
Domains VEAL rejects are excluded from REAL's next round, so a bad source doesn't keep resurfacing within the same request.
See REAL and VEAL Loops for the full design and why the two problems (finding enough candidates vs. making sure they're correct) are deliberately kept separate.
The research worker prioritizes these source types:
- Government Agencies: CDC, NIH, Census Bureau, EPA, etc.
- Academic Institutions: Universities, research journals
- Research Organizations: Pew Research, Gallup, McKinsey, etc.
- International Organizations: WHO, UN, World Bank, IMF, etc.
- Respected Media: With proper citations (NYT, WSJ, Economist, etc.)
- Source Unreachable: Marked as failed with reason
- Excerpt Not Found: Verification fails with explanation
- Value Mismatch: Flagged as discrepancy
- Insufficient Results: Automatic retry with more candidates
- Max Retries Exceeded: Returns partial results with warning
See ROADMAP.md for planned features including Perplexity integration, multi-language support, and browser extension.
Contributions welcome! Please:
- Fork the repository
- Create a feature branch
- Make your changes
- Add tests
- Submit a pull request
- Worker framework: omniagent-worker
- Agent frameworks: Google ADK, Eino
- Multi-LLM support: OmniLLM
- LLM observability: OmniObserve
- A2A protocol for agent interoperability
- Inspired by multi-agent collaboration frameworks