Architecture
The AI Ingredient Scanner uses a sophisticated multi-agent architecture powered by LangGraph. Specialized agents handle research, analysis, and validation while maintaining quality through automated retry loops.
System Overview
āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā
ā FRONTEND LAYER ā
ā āāāāāāāāāāāāāāāāāāāāāāā āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā ā
ā ā Streamlit Web UI ā ā React Native Mobile (Expo) ā ā
ā ā :8501 ā ā Camera ⢠OCR ⢠Firebase Auth ā ā
ā āāāāāāāāāāāā¬āāāāāāāāāāā āāāāāāāāāāāāāāāāāāāā¬āāāāāāāāāāāāāāāāāāā ā
āāāāāāāāāāāāāāā¼āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā¼āāāāāāāāāāāāāāāāāāāāā
ā ā
ā¼ ā¼
āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā
ā BACKEND LAYER ā
ā āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā ā
ā ā FastAPI REST API (:8000) ā ā
ā ā POST /ocr ⢠POST /analyze ā ā
ā āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā¬āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā ā
ā ā ā
ā āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā¼āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā ā
ā ā LangGraph Workflow Engine ā ā
ā ā āāāāāāāāāāāāāā āāāāāāāāāāāāāā āāāāāāāāāāāāāā āāāāāāāāāāāāāā ā ā
ā ā ā Supervisor ā ā ā Research ā ā ā Analysis ā ā ā Critic ā ā ā
ā ā ā Agent ā ā Agent ā ā Agent ā ā Agent ā ā ā
ā ā āāāāāāāāāāāāāā āāāāāāā¬āāāāāāā āāāāāāāāāāāāāā āāāāāāā¬āāāāāāā ā ā
ā ā ā ā ā ā
ā ā ā¼ ā¼ ā ā
ā ā āāāāāāāāāāāāāāāāāāāā āāāāāāāāāāāāāāāāāāāā ā ā
ā ā ā Parallel Lookup ā ā 5-Gate Validate ā ā ā
ā ā ā (3 workers) ā ā APPROVED/REJECT ā ā ā
ā ā āāāāāāāāāāāāāāāāāāāā āāāāāāāāāāāāāāāāāāāā ā ā
ā āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā ā
āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā¬āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā
ā
āāāāāāāāāāāāāāāāāāāāāā¼āāāāāāāāāāāāāāāāāāāāā
ā¼ ā¼ ā¼
āāāāāāāāāāāāāāāāāāāā āāāāāāāāāāāāāāāāāāāā āāāāāāāāāāāāāāāāāāāā
ā Qdrant Cloud ā ā Redis Cloud ā ā LangSmith ā
ā Vector Search ā ā Session Cache ā ā Observability ā
āāāāāāāāāāāāāāāāāāāā āāāāāāāāāāāāāāāāāāāā āāāāāāāāāāāāāāāāāāāā
ā
ā¼
āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā
ā AI SERVICES ā
ā āāāāāāāāāāāāāāāāāāāāāāā āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā ā
ā ā Gemini 2.0 Flash ā ā Google Search Grounding ā ā
ā ā Analysis + OCR ā ā Real-time web fallback ā ā
ā āāāāāāāāāāāāāāāāāāāāāāā āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā ā
āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāMulti-Agent Workflow
The workflow orchestrates four specialized agents in sequence, with the Supervisor managing routing and retry logic.
Agent Responsibilities
šÆSupervisor Agent
Workflow orchestrator that determines which agent processes next based on current state.
- Routes to Research if ingredient data is missing
- Routes to Analysis if report needs generation
- Routes to Critic for quality validation
- Handles retry logic (max 2 attempts)
š¬Research Agent
Fetches ingredient safety data from multiple sources with parallel processing.
- Parallel Processing: Handles 3+ ingredients concurrently
- Dual-Source Strategy: Qdrant first, Google Search fallback
- Confidence Threshold: 0.7 minimum for Qdrant results
- Auto-Learning: Saves search results back to Qdrant
šAnalysis Agent
Generates personalized safety reports using Gemini 2.0 Flash.
- Personalization: Considers allergies, skin type, expertise level
- Output: Verdict, summary, warnings, recommendations, ingredient table
- Modes: Beginner (simple) vs Expert (technical) explanations
ā
Critic Agent
Validates report quality using a 5-gate validation system.
| Gate | Check | Criteria |
|---|---|---|
| 1. Completeness | All ingredients addressed | 8/9 ingredients = PASS |
| 2. Format | Markdown structure | Valid table exists |
| 3. Allergen Match | User allergies flagged | Matching highlighted |
| 4. Consistency | Ratings match concerns | Ratings 1-10 valid |
| 5. Tone | Appropriate for expertise | Readable, informative |
Validation Outcomes
APPROVED
All gates pass ā deliver report
REJECTED
Critical failures ā retry (max 2)
ESCALATED
Max retries ā deliver with warning
State Management
The workflow uses a typed state dictionary to maintain context across agents:
class WorkflowState(TypedDict):
session_id: str
product_name: str
raw_ingredients: list[str]
user_profile: UserProfile
ingredient_data: list[IngredientData]
analysis_report: AnalysisReport | None
critic_feedback: CriticFeedback | None
retry_count: int
routing_history: list[str]
stage_timings: StageTiming
error: str | NoneResearch Data Schema
Each ingredient lookup returns structured safety data:
| Field | Type | Description |
|---|---|---|
| safety_rating | int (1-10) | Safety score (10 = safest) |
| concerns | string | Known safety issues |
| recommendation | enum | SAFE / CAUTION / AVOID |
| allergy_risk_flag | enum | HIGH / LOW |
| origin | string | Natural / Synthetic |
| regulatory_status | string | US FDA and EU status |
Technology Stack
Core AI
| Technology | Purpose | Details |
|---|---|---|
| Google Gemini 2.0 Flash | LLM | Analysis, validation, translation, OCR |
| LangGraph | Orchestration | Multi-agent workflow management |
| LangSmith | Tracing | LLM call logging and debugging |
Backend
| Technology | Purpose | Details |
|---|---|---|
| Python 3.11+ | Language | Type hints, async support |
| FastAPI | REST API | Mobile app integration |
| Streamlit | Web UI | Interactive dashboard |
| Pydantic | Validation | Request/response schemas |
Data Layer
| Technology | Purpose | Details |
|---|---|---|
| Qdrant Cloud | Vector DB | Semantic ingredient search |
| Redis Cloud | Caching | Session persistence (24h TTL) |
| Google Embeddings | Vectors | gemini-embedding-001 model |
Mobile
| Technology | Purpose | Details |
|---|---|---|
| React Native | Framework | Cross-platform mobile |
| Expo | Toolchain | Development and builds |
| TypeScript | Language | Type-safe mobile code |
| Firebase Auth | Authentication | Google Sign-In |
| Firestore | Database | User profiles & settings |
Performance Characteristics
3-5s
Research Time
5-8s
Analysis Time
2-3s
Critic Time
10-15s
Total (First Run)
Caching Strategy
- Qdrant: Ingredient data persisted permanently
- Redis: Session state cached for 24 hours
- LRU Cache: In-memory settings caching
Parallel Processing
# Research agent processes 3 ingredients per worker
BATCH_SIZE = 3
with ThreadPoolExecutor(max_workers=num_workers) as executor:
futures = {
executor.submit(_research_batch, idx, batch): idx
for idx, batch in enumerate(batches)
}Deployment Options
| Environment | Stack |
|---|---|
| Local Development | Streamlit + uvicorn |
| Production API | Railway |
| Production Web | Cloudflare Pages |
| Mobile Testing | Expo Go |
| Production Mobile | EAS Build |