An intelligent, agentic AI application that automates the creation of marketing campaigns for Wealthsimple. It uses LangGraph to orchestrate a team of AI agents that plan, write, review, and publish marketing assets β grounded in Wealthsimple's real product knowledge base using RAG (Retrieval-Augmented Generation).
Built as a demonstration of AI-native marketing orchestration: replacing a 2-week, 5-person workflow with ~20 minutes and 3 human decisions.
- Strategic Planning: Automatically determines the best assets (emails, posts, blogs, press releases) for a campaign goal β with projected KPI benchmarks per asset type
- RAG-Powered Drafting: Writes content grounded in Wealthsimple product documentation, brand guidelines, and customer success stories
- Audience Variant Generator: Generates a primary draft and a complementary audience-segment variant for every asset
- Compliance Checker: Deterministic regex-based compliance gate (BLOCK / WARN / PASS) β checks for guaranteed-return language, missing disclaimers, competitor references, and unverified superlatives before human review
- Human-in-the-Loop (HITL): Three explicit human decision points β plan approval, draft review with per-draft feedback, and final publish authorization
- Brand Compliance Review: A dedicated reviewer agent validates all content against Wealthsimple brand voice guidelines
- Observability: Full Langfuse tracing β per-node spans, retrieval metrics, guardrail results, and human feedback scores
- MCP Integration: Optional Google Docs integration via Model Context Protocol, with automatic fallback to direct Google API
- Interactive UI: Built with Streamlit β 5-stage guided workflow with progress tracker and human decision audit trail
The system is built on a LangGraph StateGraph workflow and a ChromaDB RAG engine.
The following diagram shows the full agent workflow including the new Feedback Processor node for human-in-the-loop functionality:
The following diagram shows the full agent workflow including all 14 nodes and 4 HITL interrupt points.
graph TD
Router[Router\nIntent Classifier] -->|Factual/Analytical| Planner[Planner\nStrategist + KPI Estimator]
Router -->|ChitChat| Chitchat([Chitchat β END])
Router -->|ClarificationNeeded| Clarification([Clarification β END])
Planner -->|"βΈοΈ interrupt_after β Plan Approval"| Retriever
Retriever[Retriever\nChromaDB RAG] --> RetrievalGrader[Retrieval Grader\nRelevance Check]
RetrievalGrader -->|relevant| Writer[Writer\nDraft + Guardrails + Variant]
RetrievalGrader -->|irrelevant| QueryRewriter[Query Rewriter\nSemantic Optimiser]
QueryRewriter --> Retriever
Writer --> ComplianceChecker[Compliance Checker\nRegex β No LLM]
ComplianceChecker --> HallucinationGrader[Hallucination Grader\nGrounding Check]
HallucinationGrader -->|hallucinated| QueryRewriter
HallucinationGrader -->|grounded, more assets| Retriever
HallucinationGrader -->|"grounded, all done βΈοΈ interrupt_before"| FeedbackProcessor[Feedback Processor\nHITL Loop Handler]
FeedbackProcessor -->|needs revision| Retriever
FeedbackProcessor -->|all approved| Reviewer[Reviewer\nBrand Compliance β Function Calling]
Reviewer --> BrandReviewGate[Brand Review Gate\nHITL Pass-Through]
BrandReviewGate -->|"βΈοΈ interrupt_before β Compliance Review"| BrandDecision{User Decision}
BrandDecision -->|Accept| Publisher[Publisher\nGoogle Docs + Calendar]
BrandDecision -->|Revise| FeedbackProcessor
Publisher -->|"βΈοΈ interrupt_before β Publish Authorization"| End([END])
style Planner fill:#DDA0DD,color:#000
style Retriever fill:#ADD8E6,color:#000
style Writer fill:#FFE4B5,color:#000
style ComplianceChecker fill:#FFB3B3,color:#000
style FeedbackProcessor fill:#90EE90,color:#000
style BrandReviewGate fill:#FFFACD,color:#000
style Publisher fill:#B0C4DE,color:#000
style BrandDecision fill:#FFFACD,color:#000
Node Summary:
| Node | Role | LLM? | HITL? |
|---|---|---|---|
| Router | Classifies intent (Factual / Analytical / ChitChat / ClarificationNeeded) | β structured | β |
| Planner | Builds asset plan (3β5 items); calls CampaignPerformanceEstimatorTool for KPI benchmarks |
β structured | βΈοΈ interrupt_after |
| Retriever | ChromaDB similarity search (top-3 chunks) for the current asset | β | β |
| Retrieval Grader | Validates relevance of retrieved documents; triggers Query Rewriter on failure | β structured | β |
| Query Rewriter | Rewrites goal into a focused semantic query when retrieval fails or draft hallucinates | β | β |
| Writer | Generates primary draft (+ CompetitorCheck guardrail) + audience variant | β Γ2 | β |
| Compliance Checker | Deterministic regex scan: BLOCK / WARN / PASS β no LLM, fast and auditable | β | β |
| Hallucination Grader | Verifies draft is grounded in retrieved documents; computes confidence score | β structured | β |
| Feedback Processor | Removes drafts needing revision, re-triggers writing loop; logs to Langfuse | β | βΈοΈ interrupt_before |
| Reviewer | Brand compliance via LLM function calling + ContentQualityTool |
β function calling | β |
| Brand Review Gate | HITL pass-through β pauses for user to accept or request brand review revisions | β | βΈοΈ interrupt_before |
| Publisher | Creates Google Docs + schedules Calendar events per draft | β | βΈοΈ interrupt_before |
| Chitchat | Handles off-topic queries politely | β | β |
| Clarification | Prompts user to provide more detail for ambiguous goals | β | β |
| Workflow Nodes: |
- Router: Classifies user intent (marketing campaign vs chitchat)
- Planner: Determines which marketing assets to create
- Retriever: Fetches relevant context from knowledge base (RAG)
- Retrieval Grader: Validates relevance of retrieved documents
- Writer: Generates content using RAG-retrieved context
- Hallucination Grader: Ensures content is grounded in retrieved context
- Feedback Processor β NEW β: Handles human feedback and triggers regeneration
- Reviewer: Checks brand compliance against guidelines
- Publisher: Creates Google Docs and schedules calendar events
Agent Nodes:
- Router β Classifies intent (Factual / Analytical / ChitChat / ClarificationNeeded)
- Planner β Builds the asset plan + calls
CampaignPerformanceEstimatorToolfor KPI benchmarks - Retriever βΈοΈ β Fetches context from the Wealthsimple knowledge base
- Retrieval Grader β Validates document relevance; triggers Query Rewriter on failure
- Writer β Generates primary draft + audience variant; CompetitorCheck guardrail applied
- Compliance Checker β Deterministic regex scan: BLOCK / WARN / PASS; HIGH flags gate the UI Approve button
- Hallucination Grader β Verifies the draft is grounded in retrieved facts
- Feedback Processor βΈοΈ β Routes revised drafts back to Retriever or forwards approved drafts to Reviewer
- Reviewer β Brand voice and compliance review against Wealthsimple guidelines
- Publisher βΈοΈ β Creates Google Docs, schedules Calendar events
βΈοΈ = HITL interrupt point (interrupt_before=["retriever", "feedback_processor", "publisher"])
See rag_architecture.md for detailed RAG architecture and flow diagrams. See agents.md for detailed agent specifications.
βββ app.py # Streamlit frontend (5-stage HITL workflow)
βββ backend.py # FastAPI REST API alternative
βββ src/
β βββ agents.py # LangGraph StateGraph + all agent nodes
β βββ config.py # Model config, prompts, competitor list
β βββ rag.py # ChromaDB ingestion + retrieval
β βββ tools.py # LangChain tools (RAG, compliance, estimator)
β βββ google_utils.py # Google Docs + Calendar API helpers
β βββ mcp_client.py # MCP client for Google Docs integration
β βββ langfuse_integration.py # Langfuse observability client + handlers
βββ data/
β βββ brand_guidelines.txt # Wealthsimple brand voice + prohibited terms
β βββ product_catalog.txt # Wealthsimple Invest, Trade, Cash, Tax
β βββ customer_success_stories.txt# Anonymised user persona case studies
β βββ compliance_guidelines.txt # CIRO, OSC, CSA, FINTRAC, NI 31-103, CIPF
βββ chroma_db/ # Persisted ChromaDB vector store
βββ docs/
β βββ mcp_setup.md # MCP integration setup guide
β βββ LANGFUSE_SETUP.md # Langfuse observability setup guide
βββ rag_architecture.md # Detailed RAG + workflow architecture
βββ agents.md # Agent specifications
βββ requirements.txt
- Python 3.10+
- Google API Key (Gemini)
- Clone the repository
- Create a virtual environment and install dependencies:
python -m venv venv source venv/bin/activate # Windows: venv\Scripts\activate pip install -r requirements.txt
- Configure environment variables β copy
.env.exampleto.envand fill in:GOOGLE_API_KEY=your_key_here LANGFUSE_PUBLIC_KEY=optional LANGFUSE_SECRET_KEY=optional
- Start Streamlit:
streamlit run app.py
- Configure:
- Enter your Google API Key in the sidebar
- Click "Re-ingest Knowledge Base" to load Wealthsimple documents into the vector store
- Run a Campaign:
- Pick a quick-start template (Wealthsimple Invest / Trade / Cash / Tax Season) or use the Goal Builder
- Click "π Start Campaign"
- Stage 2 β Approve Plan: Review the strategic plan and KPI benchmark table
- Stage 3 β Review Drafts: Check compliance flags; view primary + variant tabs; acknowledge any HIGH flags
- Stage 3b β Feedback: Approve each draft or request targeted revisions
- Stage 4 β Authorize Publish: Final brand compliance review; export campaign brief or publish to Google Workspace
Three decisions are always kept human:
| Decision Point | Why it stays human |
|---|---|
| β Approve the strategic plan | Sets budget and resource direction |
| β Approve / revise each content draft | Editorial judgment; compliance accountability |
| β Authorize final publish to Google Workspace | Legal liability and reputational risk cannot be delegated to AI |
Compliance Gate: If a draft has HIGH-severity compliance flags (e.g., "guaranteed returns" language, missing financial disclaimer), the Approve button is disabled until you check an acknowledgement checkbox β creating an explicit, auditable record that a human reviewed the risk.
The Compliance Checker node runs deterministic regex checks (no LLM) on every draft:
| Severity | Behaviour | Example triggers |
|---|---|---|
| BLOCK (HIGH) | Approve button disabled until acknowledged | "guaranteed returns", "risk-free", missing disclaimer |
| WARN (MEDIUM) | Shown as warning; can publish with acknowledgement | Unsubstantiated %, missing CTA |
| PASS (LOW / none) | Green badge; no gate | Minor style notes |
Canadian regulatory coverage: CIRO, OSC, CSA, FINTRAC, NI 31-103, CIPF, CASL
When LANGFUSE_PUBLIC_KEY and LANGFUSE_SECRET_KEY are set:
- Every campaign run creates a trace with per-node spans
- Retrieval relevance scores and hallucination grades are tracked
- Human feedback decisions are logged as score events
- A live trace URL appears in the sidebar during a campaign run
See docs/LANGFUSE_SETUP.md for setup instructions.
The app supports Model Context Protocol (MCP) for Google Docs publishing. If not configured, it automatically falls back to direct Google API. See docs/mcp_setup.md for setup.
| Layer | Technology |
|---|---|
| LLM | Google Gemini 2.5 Flash |
| Embeddings | HuggingFace all-MiniLM-L6-v2 |
| Vector DB | ChromaDB (local persistence) |
| Orchestration | LangGraph StateGraph with HITL checkpointing |
| Framework | LangChain |
| Frontend | Streamlit |
| Observability | Langfuse |
| Publishing | Google Docs + Google Calendar API |
| Guardrails | Custom regex + Guardrails-AI |