Inspiration

Financial misinformation destroys real people's wealth. In Latin America, Ponzi schemes disguised as "unique opportunities", Telegram gurus promising "guaranteed" returns, and manipulated alarmist headlines circulate without any filter. Traditional fact-checkers rarely cover financial content in Spanish. We wanted to change that with an agent that acts — not just responds.

What it does

VeritasAgent receives a financial headline, an investment promise, or a suspicious URL and runs an autonomous 8-step pipeline before issuing a verdict:

  • [0] Semantic triage — searches Elastic to check if the claim was already verified. If the kNN score ≥ 0.92, it returns the cached result in under 2 seconds (early-exit). This proves real database usage, not just chat.
  • [1] Extractor — scrapes the URL live using Bright Data MCP.
  • [2] Claim parser — Gemini 2.5 Flash extracts atomic claims as JSON.
  • [3] Source checker — validates against 21 regulated financial domains (Reuters, Bloomberg, local regulators).
  • [4] Cross-reference — matches against Elastic memory + open web search.
  • [5] Linguistic — detects alarmism, clickbait, and Ponzi red flags.
  • [6] Verdict — Gemini consolidates everything: label + confidence + evidence.
  • [7] Persist — indexes the verdict in Elastic with 768-dimension embeddings to enrich the agent's memory.

The agent never opines or gives investment advice. It cites sources, identifies red flags, and warns when something smells like fraud.

How we built it

The agent's core runs on Google ADK with Gemini 2.5 Flash as the reasoning engine. We implemented two modes that coexist:

Reactive mode (/analizar): an LlmAgent from Google ADK decides in real time which tools to use — Google Search, URL Context, Elastic MCP, or Bright Data MCP.

Deterministic multi-step mode (/analizar/multipaso): a custom orchestrator runs the 8 steps in fixed order with guaranteed early-exit. This mode is the demo's highlight because it makes every agent action on real external services fully visible.

Elastic MCP is the hackathon's track partner: we use it for semantic triage with hybrid kNN + BM25 search, persistent verdict memory with configurable TTL, and text-embedding-004 embeddings (768 dimensions). The agent learns from every analysis it performs.

The backend is FastAPI with 5 actionable endpoints. The frontend is Streamlit. Gemini authentication is dual: Vertex AI ADC for production or direct API key for local demos.

Challenges we ran into

  • Triage calibration: kNN and BM25 scores operate on different scales. We had to design independent thresholds (≥ 0.92 for kNN only) to avoid false positives that would poison the semantic cache.
  • Dual auth: Google Cloud organizations can block API keys. We built automatic auth mode detection so the agent works in any environment without changing code.
  • MCP in deterministic pipeline: Google ADK's MCPToolsets are designed for reactive agents. We built a direct client (brightdata_client.py) to use them in synchronous pipeline steps.

Accomplishments that we're proud of

  • Early-exit semantic cache: a claim already verified returns in under 2 seconds — no LLM call, no scraping, no cost. Pure vector memory doing real work.
  • Hybrid kNN + BM25 triage: two retrieval strategies with independently calibrated thresholds, working together without polluting each other's scores.
  • Dual auth with zero code changes: the agent detects Vertex AI ADC or API key automatically — the same codebase runs in production and in a judge's laptop.
  • MCP beyond reactive agents: we made Bright Data MCP work inside a synchronous deterministic pipeline, something Google ADK doesn't support out of the box.
  • 8 real actions before one word: every analysis touches Elastic, Bright Data, and Vertex AI before the agent speaks. Not a chatbot.

  • Hybrid kNN + BM25 triage with Elastic MCP: the triage step runs two retrieval strategies simultaneously against the verified_claims index. kNN finds semantically similar claims using text-embedding-004 vectors of 768 dimensions — so "Bitcoin guaranteed 300% return" matches a previously verified "crypto promises 250% profit" even with completely different wording. BM25 catches exact keyword matches that dense vectors sometimes miss. Both scores are computed independently with separately calibrated thresholds: kNN ≥ 0.92 triggers the early-exit, while BM25 acts as a complementary signal without participating in the cache decision — because BM25 scores are unbounded and mixing scales would generate false positives that poison the memory. The result is a triage layer that is both semantically aware and lexically precise, built entirely on top of the Elastic MCP without any direct SDK calls.

What we learned

The difference between a chatbot and a real agent is not the LLM — it's the actions it executes before responding. Every VeritasAgent analysis triggers between 4 and 6 calls to real external services (Elastic, Bright Data, Vertex AI) before saying a single word.

What's next for Veritas Agent

  • Live view of all 8 pipeline steps in the frontend (real-time step tracking)
  • Batch analysis: verify multiple headlines in parallel
  • Alerts: continuous source monitoring with notifications when a verdict changes

Built With

  • adk
  • bright-data
  • elastic-mcp
  • elasticsearch
  • fast-api
  • gcp
  • gemini-2.5
  • google-adk
  • google-agent-garden
  • mcp
  • open-telemetry
  • python
  • streamlit
Share this project:

Updates