6.3 KiB
Web-API ↔ didi-brain integration
Web-api folosește didi-brain ca layer de cache cu 2 fețe:
- Cache read (ambele tiers — free și premium) — înainte să cheme SearXNG sau paid providers, web-api întreabă brain. Dacă brain are evidence relevante cached, le servește direct; clientul primește răspuns în ~1-2s în loc de 10-30s.
- Cache write (doar tier premium, quality-gated) — după o cerere premium care a trecut pragurile de calitate, web-api pompează evidence în brain fire-and-forget. Brain face extraction async. Viitoarele cereri pe claim-uri similare vor hit-ui cache-ul.
Ideea de bază: free users primesc quality-ul plătit de premium users, dar doar premium plătește pentru popularea cache-ului.
Flow-ul per request
POST /v1/gather { claim, tier }
│
▼
┌─────────────────────────────────────────┐
│ 1. Cache READ (brain /v1/gather) │
│ (ambele tiers, dacă brain configured│
│ și brain_cache_read_enabled=true) │
└────────┬────────────────────────────────┘
│
├─ brain HIT cu quality OK
│ → returnează direct răspunsul (skip orchestrator)
│
└─ brain MISS sau quality slab
│
▼
┌────────────────────────────────┐
│ 2. Orchestrator normal │
│ free → SearXNG + Qwen │
│ premium → Paid + OpenRouter│
└────────┬───────────────────────┘
│
▼
┌────────────────────────────────┐
│ 3. Cache WRITE (doar premium) │
│ dacă quality_ok_for_cache │
│ fire-and-forget ingest │
│ (nu blochează response) │
└────────────────────────────────┘
│
▼
Return to client
Componente
src/web/brain/client.py — BrainClient
Client HTTP minimal pentru brain:
gather(claim, max_evidence, run_nli, ...)— cache read, returnează JSON sau None pe eroareingest(payload)— cache write, fire-and-forget via sink de obicei
Timeout-uri separate (gather e rapid, ingest poate fi mai lent).
src/web/brain/sink.py — BrainIngestSink
Queue bounded (1000 items max) processat de un single worker task. Overflow → drop oldest. Eșecuri → log DEBUG, swallowed. Zero impact pe latența web-api.
src/web/brain/quality.py — Quality gates
quality_ok_for_cache(response)— decide dacă un gather result e worth-caching (3+ evidence, cel puțin 1 sursă credibilă dacă sunt scored, toate stages OK, execution > 2s)brain_hit_acceptable(brain_raw)— decide dacă un brain HIT e suficient de bun (HIT = da; PARTIAL = da doar dacă 3+ items cu relevance ≥ 0.7)
src/web/brain/adapter.py — Schema conversion
brain_response_to_web(brain_raw, request_id)— convertește response-ul brain înGatherResponseweb (datetime → ISO string, provenance dict,brain_metaflatten în provenance per evidence item)web_response_to_ingest_payload(response, claim)— converteșteGatherResponseînIngestRequestpentru brain (ISO dates, safe defaults pentru field-urile required brain-side: title/retrieved_at/score defaults)
Configurare
În deploy/.env:
WEB_BRAIN_URL=http://didibrain-api:8090
# Feature toggles (default true dacă brain_url setat)
WEB_BRAIN_CACHE_READ_ENABLED=true
WEB_BRAIN_INGEST_ENABLED=true
# Quality thresholds pentru ingest
WEB_BRAIN_INGEST_MIN_EVIDENCE=3
WEB_BRAIN_INGEST_MIN_CREDIBILITY=0.7
WEB_BRAIN_INGEST_MIN_EXECUTION_MS=2000
# Acceptance thresholds pentru PARTIAL cache hit
WEB_BRAIN_HIT_MIN_EVIDENCE=3
WEB_BRAIN_HIT_MIN_RELEVANCE=0.7
# Timeouts
WEB_BRAIN_GATHER_TIMEOUT=8.0
WEB_BRAIN_INGEST_TIMEOUT=15.0
Toate sunt optional. Dacă WEB_BRAIN_URL e gol, integrarea e dezactivată
complet (fallback la orchestrator normal pentru tot).
Networking Docker
Web-api trăiește pe rețeaua deploy_default (cu dashboard, video, audio,
searxng). Brain trăiește pe rețeaua proprie didibrain.
Web-api e atașat la ambele rețele în deploy/docker-compose.yml:
networks:
deploy_default:
external: true
didibrain:
external: true
services:
web-api:
networks:
- deploy_default
- didibrain
Asta îi permite să rezolve didibrain-api prin DNS-ul Docker.
Fail-open
Brain down ≠ web-api down. Toate apelurile spre brain sunt wrapped cu try/except generos:
- Gather cache read eșuează → continuă la orchestrator normal
- Ingest eșuează → log și drop event (queue-ul va reumple)
Clientul nu vede niciodată o eroare datorită brain.
Cum monitorizezi HIT rate
Log-urile web-api emit Brain cache HIT [tier=X, N items]: <claim> pe fiecare
hit. Pentru producție, integrarea cu dashboard face count-uri în tabela
request_history (câmp raw_response.stages conține retrieval/rerank când
e din brain vs search/fetch când e direct).
Query exemplu (post-deploy):
-- HIT rate per tier pe ultimele 24h
SELECT
tier,
COUNT(*) FILTER (
WHERE raw_response::jsonb -> 'stages' @> '[{"stage":"retrieval"}]'
) AS brain_hits,
COUNT(*) AS total_gathers,
ROUND(100.0 * COUNT(*) FILTER (
WHERE raw_response::jsonb -> 'stages' @> '[{"stage":"retrieval"}]'
) / NULLIF(COUNT(*), 0), 1) AS hit_rate_pct
FROM request_history
WHERE endpoint = '/v1/gather'
AND created_at > now() - interval '24 hours'
GROUP BY tier;
Ce NU face integrarea
- Nu scrie la brain pe tier
free(doar citește) — tip premium gold standard - Nu face fallback la premium când brain MISS pe free (menține tier isolation)
- Nu retry — un singur request la brain, orice eșec → fallback silent
Pentru detaliile contractului verification_cache (backend ↔ brain),
vezi modules/didi_brain/CONTRACT_VERIFICATION_CACHE.md.