A civic anti-corruption platform that audits Peruvian public contracts with an 11-agent AI pipeline — for ≈ 1 sol (US$0.30) and ≈ 3 minutes each.
Corruption in Peru is already public. Vigía makes it readable. Every tender, every contract, every debarred company is already open data on SEACE/OECE. The bottleneck was never the data — it was the cost of reading it. Vigía drops that cost to the price of a coffee.
🔗 Live demo: https://vigia-peru-frontend-36169102688.us-central1.run.app
📊 Observability (Arize Phoenix): project vigia-peru
Investigating a single suspicious state contract takes a journalist days: 80-page scanned
PDFs scattered across a dozen .gob.pe portals that don't talk to each other (SEACE, OECE, SUNAT,
INFOBRAS, ONPE, JNE…). There are thousands of new contracts every month. Oversight is a slow,
heroic act that doesn't scale.
Vigía Perú is a three-layer platform:
| Layer | What it does |
|---|---|
| 🟡 Machine | 11 AI agents read the bidding file, cross-check open data, and emit risk signals on suspicious contracts — each one linked to its official source. |
| 🔴 Citizen | Anyone reports a stalled or anomalous public work with a photo + geolocation. |
| ⬛ Convergence | When an automated alert and a citizen report point at the same work, the case turns "red": evidence ready for a journalist or prosecutor. |
Everything is plotted on an interactive map of Peru: 🟡 alert · 🔴 citizen report · ⬛ convergence.
Non-negotiable principle: we never accuse anyone. We say "risk signal", never "crime". No verifiable link to an official source → it is not published.
USER ──► FRONTEND (Next.js, Cloud Run) ──NDJSON stream──► ADK ORCHESTRATOR (Cloud Run)
▲ │ │ ADK Runner + Gemini 2.5
│ GET dossier │ ▼
│ ▼ ┌──────────────────────────────────┐
│ Read API (Hono/TS, Cloud Run) │ 11-AGENT PIPELINE │
│ + cache + gzip ◄── reads ─┐ └──────┬────────┬────────┬──────────┘
│ │ ▼ ▼ ▼
└──────────────────────────────────┤ Document AI Vertex SUNAT
│ (PDF OCR) AI Search (apis.net.pe)
Cloud SQL (PostgreSQL │ (RAG: 721
+ PostGIS): alerts, │ OECE opinions)
flags, network, pins ▼
OECE/SEACE (OCDS + PDFs)
via residential relay in Lima
A coordinator delegates to specialized sub-agents; each runs on Gemini 2.5:
orchestrator (coordinates) · compliance (hard rules) · document_parser (OCR + line items) ·
document_legal_analyst (OECE RAG) · market_analyst (price vs market) · web_research
(company profile) · person_network (partners/representatives) · political_financing (ONPE) ·
news_research (press) · citizen_reports (red pins) · report_writer (verdict) ·
evaluator (self-eval).
Beyond the web app, Vigía ships a remote Model Context Protocol
server (services/vigia-mcp, on Cloud Run) that exposes its risk signals and evidence as
read-only tools to any MCP-compatible LLM client. A journalist or prosecutor can ask, from their
own AI assistant, "show me the red alerts in Áncash" and get them back with their official
evidence attached — no scraping, no UI.
The server enforces the same non-negotiable rules: only public data (serving officials and state-contracting companies), risk signals never accusations, and read-only access (no tool ever writes to the database).
Vigía combines a local snapshot of Peru's public-procurement lifecycle with live external
sources. Full breakdown in docs/DATA.md.
The complete lifecycle of a Peruvian public contract, keyed end-to-end by codigoconvocatoria:
| Phase | Tables | Join key |
|---|---|---|
| Planning | plan_anual_contratacion (PAC) |
ruc_entidad + description |
| Call for bids | datos_de_la_convocatoria, miembros_comite, nulos, procesos_desiertos |
codigoconvocatoria |
| Bidding | listado_de_ofertantes, proveedores_y_consorcios |
codigoconvocatoria, ruc_postor |
| Award | datos_de_adjudicacion, contratacion_directa |
codigoconvocatoria, ruc_proveedor |
| Execution | contratos, ordenes_compra_y_servicio |
codigoconvocatoria, ruc_contratista |
| Post-control | arbitraje, PRONUNCIAMIENTOS |
codigoconvocatoria |
| Master data | entidades_contratantes, rnp_proveedores, sanciones, sican_certificados, opiniones_normativas |
RUC, DNI |
The 721 OECE normative opinions (opiniones_normativas) are indexed in Vertex AI Search
and power the legal-grounding RAG: every compliance finding cites the specific opinion it relies on.
| Source | Used for | Access |
|---|---|---|
| OECE — Contrataciones Abiertas | Contracts in OCDS format | REST API + downloads |
SUNAT (via apis.net.pe / decolecta) |
Company tax-ID (RUC) age & status | REST API |
| INFOBRAS (Comptroller) | Public-works progress | Web/downloads |
| MEF (Consulta Amigable / Datos Abiertos) | Budget (PIA, PIM, executed) | CSV/scrape |
| ONPE — Portal Claridad | Campaign contributions | Web |
| JNE | Officials' CVs | Web + PDFs |
The MVP implements C1 (RUC age vs winner) and C2 (single bidder at 100% of the reference value), plus hard compliance rules (sanctioned/debarred provider, direct award without valid grounds, addenda > 25% of original amount, etc.). Each red flag cites its legal basis (Law 32069 / Law 30225) and the relevant OECE opinion.
⚠️ The raw local dataset is not in this repo — it is ~739 MB and contains personal data (the RNP registry includes partners'/representatives' names and national IDs). Publishing it would violate our own ethics rule #2 ("we do not publish citizens' personal data"). We reference the official open-data sources instead. Seedocs/DATA.md.
| Service | Purpose |
|---|---|
| Vertex AI | Gemini 2.5 (Flash + Flash-Lite), global endpoint — the reasoning engine for all 11 agents |
| Agent Development Kit (ADK) | Multi-agent orchestration (coordinator + transfer_to_agent) |
| Vertex AI Search | Semantic RAG over 721 OECE normative opinions (legal grounding) |
| Document AI | OCR of bidding-file PDFs (per-use, imageless mode) |
| Cloud Run | Frontend, read API, orchestrator, and MCP server |
| Cloud Functions (gen2) | Orchestrator entrypoint (Cloud Run-backed) |
| Cloud SQL (PostgreSQL + PostGIS) | Procurement lifecycle, alerts, flags, corporate network, geospatial pins |
| Cloud Storage | Document & report staging |
| Secret Manager | All credentials (no plaintext keys in the codebase) |
| Cloud Build + Artifact Registry | Container builds & deploys |
| Cloud Logging / Monitoring | Pipeline observability |
| Firebase Authentication | Demo login |
| Model | Role |
|---|---|
| Gemini 2.5 Flash (Vertex AI, global) | Main agent reasoning and verdict writing |
| Gemini 2.5 Flash-Lite (Vertex AI, global) | Fast extraction / lightweight steps |
| Document AI (OCR processor) | Scanned-PDF text → fed to Gemini in a single call per document |
| Vertex AI Search | Embeddings + retrieval over the OECE legal corpus |
Why the Vertex global endpoint? New projects hit aggressive per-region throttling (429); the
global endpoint routes across regions and fixed exactly that, letting document-heavy tenders finish
without hitting the time wall.
Trust in an 11-agent system depends on being able to see and evaluate every decision.
- OpenInference instruments the ADK Runner (the full loop + every
transfer_to_agentbetween agents) and every Gemini call. Everything is exported over OTEL to Arize AX and Arize Phoenix (projectvigia-peru). - The result: a full span tree per OCID — tokens, cost, latency, and prompt/response for each step. If an agent hallucinates or drifts, it shows up in the trace.
- Inline self-eval: at the end of each analysis, 6 evaluators run (4 LLM-as-judge + 2 deterministic): flag support, evidence citation, price plausibility, object↔items coherence, non-accusatory tone, and pipeline completeness.
Arize turns an agentic black box into an auditable, evaluable system — a prerequisite for journalists and prosecutors to trust the signals.
| Metric | Value |
|---|---|
| Cost per full analysis | ≈ 1 sol (≈ US$0.30) |
| Latency per analysis | ≈ 3 minutes (depends on document weight) |
| Gemini calls per run | ≈ 12 |
| Tokens per run | ≈ 180K in + 80K out (≈ 245K total) |
| OCR | per-use (Document AI), only the actual pages of the file |
Cost/latency optimizations implemented:
- Document AI + one Gemini call per document (previously: page-by-page Vision).
- Per-URL parse cache — the same PDF is never OCR'd/parsed twice in a run.
- Semantic line-item dedup — the same item is never priced twice against the market.
- Read ≠ write — cached dossiers are served by a lightweight gzip API; the (expensive) orchestrator only runs new analyses.
- Persistence checkpoint before the verdict — a timeout never leaves an empty dossier.
| Layer | Technology |
|---|---|
| Frontend | Next.js 14 · React · TailwindCSS · Leaflet/OpenStreetMap |
| Read API | Hono (TypeScript) · cache · gzip |
| Orchestrator | Python · Google ADK · functions-framework |
| AI | Gemini 2.5 (Vertex AI global) · Document AI · Vertex AI Search |
| Data | Cloud SQL (PostgreSQL + PostGIS) · DuckDB (local analysis) |
| Observability | OpenInference · OpenTelemetry · Arize AX + Phoenix |
| Integration | Custom MCP server (Cloud Run) · residential relay (FastAPI) |
vigia-peru/
├── frontend/ # Web app (Next.js 14): map, dossiers, citizen reports
├── functions/agent-orchestrator-adk/ # 11-agent orchestrator (Python + ADK)
│ ├── agents/ # one subfolder per agent (prompt + config)
│ └── tools/ # OCDS, Document AI, market, legal RAG, persistence
├── api/ # Read API (Hono/TS) over Cloud SQL
├── downloader/ # Residential relay in Lima (FastAPI) — .gob.pe WAF bypass
├── services/vigia-mcp/ # Remote MCP server (exposes data as read-only tools)
├── docs/
│ ├── DATA.md # Data sources, tables, join keys (detailed)
│ └── img/ # Architecture & observability screenshots
├── ARQUITECTURA.md # GCP architecture + production roadmap (ES)
├── SOLUCION.md # How it works: end-to-end data flow (ES)
└── OBSERVABILITY.md # Observability setup detail — Arize/Phoenix (ES)
- We never accuse anyone — "risk signal" / "detected pattern", never "crime".
- We never publish citizens' personal data — only serving officials and companies that contract with the State (public by law).
- We do not replace the Comptroller / Prosecutor / journalism — we detect and prioritize.
- Citizen reports: two independent reports within ≤30 days to be "confirmed"; no photo → not published.
- No ads, no data monetization — open source, non-profit.
- Every flag links to official evidence (SEACE/OECE/MEF URL, contract code, OECE opinion number). No verifiable link → not published.
Each component ships a .env.example. In broad strokes:
# Frontend
cd frontend && npm install && cp .env.example .env.local && npm run dev
# Read API
cd api && npm install && cp .env.example .env && npm run dev
# Orchestrator (requires GCP / Vertex AI credentials)
cd functions/agent-orchestrator-adk && pip install -r requirements.txtCredentials (Cloud SQL, Vertex, Document AI, Arize/Phoenix) live in environment variables or Secret Manager — never in the repo.
Working MVP over a pilot region: full machine layer + citizen report form + interactive map.
Built for the Google Cloud Rapid Agent Hackathon (Arize observability track). Roadmap to
national coverage, report moderation, and Comptroller/Prosecutor hand-off in
ARQUITECTURA.md.
Released under the MIT License — see LICENSE. Open source, non-profit, no ads,
no data monetization.
Open source · non-profit · built for Peru. 🇵🇪



