Multi-Agent Architecture for Automated Advertising Media Planning
spotify · Media & Entertainment · 2026 · source Agentic: yes · promotional bias: med · source-backed · extracted with prompt 0.5.6 (schema v2)
Generated from extraction.json — do not edit by hand. Every claim cites verbatim source evidence; stated means the quote directly asserts the claim, implied means it supports it indirectly.
Problem
Domain: Advertising media planning
Spotify needed to replace fragmented, channel-specific advertising workflow logic with a unified conversational media-planning system that could produce grounded plans quickly.
Constraints:
- Direct, self-serve, programmatic, Slack, Salesforce, and Ads Manager surfaces encoded similar decisions differently.
- The workflow depended on advertiser goals, inventory, budget, schedule, and business priorities, making deterministic state-machine logic brittle.
- User experience required responses in seconds rather than a 15-30 minute manual planning flow.
- The system needed structured outputs, real campaign-performance data, session state, observability, and guardrails.
Architecture
Spotify built Ads AI with Google ADK 0.2.0, Vertex AI Gemini 2.5 Pro, gRPC, Google Cloud session storage, PostgreSQL plus in-memory cache, and Spotify Apollo. A RouterAgent inspects user messages, conditionally invokes resolver agents for goals, audience, budget, and schedule, then passes resolved constraints to a MediaPlannerAgent that uses historical campaign data and heuristics to generate ad-set recommendations.
Diagram confidence: reconstructed (reconstructed from prose).
flowchart LR conversational-interface["Conversational Interface"] --> routeragent["RouterAgent"] routeragent --> goalresolveragent["GoalResolverAgent"] routeragent --> audienceresolveragent["AudienceResolverAgent"] routeragent --> budgetagent["BudgetAgent"] routeragent --> scheduleagent["ScheduleAgent"] routeragent --> session-store["Session Store"] goalresolveragent --> tool-layer["Tool Layer"] audienceresolveragent --> tool-layer tool-layer --> historical-performance-store["Historical Performance Store"] historical-performance-store --> mediaplanneragent["MediaPlannerAgent"] goalresolveragent --> mediaplanneragent audienceresolveragent --> mediaplanneragent budgetagent --> mediaplanneragent scheduleagent --> mediaplanneragent mediaplanneragent --> structured-output-parser["Structured Output Parser"]
Components
| Component | Role | Interacts with |
|---|---|---|
Conversational Interface |
Accepts natural-language media-planning requests from advertising users. | RouterAgent |
RouterAgent |
Triages messages and decides which specialized agents are needed. | GoalResolverAgent, AudienceResolverAgent, BudgetAgent, ScheduleAgent, Session Store |
GoalResolverAgent |
Maps user intent to campaign objectives and ad categories. | MediaPlannerAgent, Tool Layer |
AudienceResolverAgent |
Extracts targeting criteria from a predefined taxonomy. | MediaPlannerAgent, Tool Layer |
BudgetAgent |
Parses currency formats and converts budgets to internal units. | MediaPlannerAgent |
ScheduleAgent |
Parses date ranges and relative date expressions. | MediaPlannerAgent |
Tool Layer |
Exposes Google ADK FunctionTools for geo targets, ad categories, and performance retrieval. | Historical Performance Store |
Historical Performance Store |
PostgreSQL and in-memory cache storing campaign-performance data. | MediaPlannerAgent |
MediaPlannerAgent |
Optimizes recommendations with historical data, delivery heuristics, and budget rules. | Structured Output Parser |
Structured Output Parser |
Applies guardrails and parseable contracts before downstream use. | — |
Session Store |
Persists context across multi-turn planning sessions. | RouterAgent |
Data flow
An advertiser supplies one to three natural-language messages. The RouterAgent checks which information is present, conditional resolver agents fill in missing goal, audience, budget, and schedule fields, tool calls retrieve taxonomies and historical campaign performance, and the MediaPlannerAgent scores and returns budget-aware recommendations. Session storage preserves context across the conversation while structured outputs feed downstream ads systems.
Why this architecture
Spotify chose specialized parallel agents because media planning has separable but interdependent fields, and conditional execution avoids unnecessary LLM calls. Historical performance tools and structured outputs keep the planner grounded in real advertising data rather than free-form model recommendations.
Models used: Gemini 2.5 Pro
Scale
- The new interface reduced a 15-30 minute manual planning process to seconds.“transforms media planning from a manual 15-30 minute process requiring 20+ form fields into a conversational interface that generates optimized, data-driven media plans in 5-10 seconds”summary, stated
- Users could supply 1-3 natural language messages instead of 20+ form fields.“generates optimized, data-driven media plans in 5-10 seconds using 1-3 natural language messages.”summary, stated
- Recommendation count scaled with budget from one recommendation below 1000 euros to four or five above 15000 euros.“scaling the number of recommendations based on budget size (from 1 recommendation for budgets under €1,000 to 4-5 recommendations for budgets over €15,000).”summary, stated
- The planner drew on thousands of past campaigns.“the MediaPlannerAgent uses real performance data from thousands of past campaigns to inform its suggestions.”summary, stated
Alternatives considered (roads not taken)
Build another deterministic state-machine service
Rejected because: Advertising decisions were too combinatorial and context-dependent for a new hard-coded workflow.
Run every resolver for every user message
Rejected because: Router-driven conditional execution reduces unnecessary LLM calls when information is already present.
Let the model invent recommendations from prompt context
Rejected because: Spotify grounded recommendations in real historical performance data to avoid hallucinated plans.
Query historical data directly for every recommendation without caching
Rejected because: The team accepted higher memory usage to minimize latency through an in-memory cache.
Patterns
multi-agent-orchestration (architecture)
Spotify decomposed planning into router, resolver, and media-planning agents with parallel execution where dependencies allowed.
tool-use-orchestration (architecture)
Agents used Google ADK FunctionTool calls to retrieve geo targets, ad categories, and historical performance data.
structured-output-contract (reliability)
Prompts and parsing guardrails required consistent, parseable media-plan outputs.
latency-optimization (performance)
Conditional agent execution and in-memory cached historical performance data reduced latency.
eval-driven-development (quality)
Spotify added behavioral evaluation of agent decisions and tested specialized agents in isolation.
Tradeoffs
Use a multi-agent planner
Chose Specialized ADK agents for routing, resolving, and planning over A deterministic state-machine planning service.
Rationale: Agent specialization fit the combinatorial media-planning workflow better than hard-coded surface-specific logic.
Cache campaign-performance data in memory
Chose In-memory cache backed by PostgreSQL over Lower-memory direct lookup for every planning request.
Rationale: The team accepted memory cost to hit response-latency goals.
Invoke only needed agents
Chose RouterAgent conditional execution over Running the full agent suite for every message.
Rationale: Conditional execution reduced unnecessary LLM calls and kept the interaction efficient.
Gotchas (what bit them)
Consolidated backend services did not eliminate workflow-logic drift.
Root cause: Multiple buying channels and surfaces encoded similar advertising decisions in slightly different ways.
Resolution: Ads AI centralized the planning logic in a shared multi-agent service with common resolver and planner components.
LLM recommendations can hallucinate if not grounded in real advertising data.
Root cause: A planner that only reasons from prompt context could produce unsupported recommendations.
Resolution: The MediaPlannerAgent uses historical performance data and heuristics for cost, delivery, budget, and diversity.
Small prompt changes caused output-consistency problems.
Root cause: Structured LLM responses were sensitive to prompt wording.
Resolution: Spotify treated prompt engineering as software engineering with explicit output requirements, examples, and parser guardrails.
Evaluation
Spotify combined traditional tests with behavioral evaluation of what agents decided and why; the public writeup does not disclose detailed metrics beyond latency and workflow compression.
Metrics: 5-10 second planning response · 1-3 natural-language messages instead of 20+ form fields · 15-30 minute manual baseline
Outcomes
- Spotify compressed media planning from a multi-field manual workflow into a seconds-long conversational interaction.
- Ads AI unified planning decisions that had been duplicated across buying channels and surfaces.
- Recommendations were grounded in historical performance data and structured output guardrails.
The report cites thousands of historical campaigns and budget-conditioned recommendation ranges; it does not disclose live usage volumes.