A useful creative brief needs to be specific enough to direct a creative team, grounded in actual performance data, and structured well enough for both human review and downstream app consumption.
Generating one from raw ad performance data is harder than it sounds.
A single LLM prompt that takes BigQuery data and outputs a brief produces generic output. The LLM does not have enough structured context to reason well about the creative situation.
The multi-phase design fixes this. By the time the final LLM runs, it is not working from raw data. It has interpreted signals, a synthesized scope, an analytical summary, and a pre-determined strategic mode.
The 6 phases
Phase A: Rule execution (parallel)
The pipeline starts with a set of performance rules running in parallel against BigQuery.
Each rule targets a specific signal:
creative fatigue ratios
CPM gaps across formats
pacing deviation by day segment
audience overlap indicesRules run as independent BigQuery queries via asyncio.gather(). Each returns a result object:
@dataclass
class RuleResult:
rule_id: str
triggered: bool
metric_value: float | None
evidence: dict
context: dictOnly triggered rules proceed. Non-triggered rules are recorded but discarded from the brief pipeline.
Phase B: Per-rule interpretation (LLM0)
Each triggered rule passes through a focused LLM call that interprets it in plain language.
The prompt is narrow. One rule at a time.
Rule: Creative frequency ratio by format
Triggered: Yes
Evidence: {format: "video", avg_frequency: 4.2, benchmark: 2.5, delta: +68%}
In 2-3 sentences, explain what this signal indicates for this creative group.
LLM0 does not make recommendations. It converts structured evidence into an interpreted signal description.
Phase C: Cross-rule synthesis (LLM1)
Phase C takes all LLM0 outputs and synthesizes them.
The synthesis LLM identifies which signals are related, which are compounding, and what the combined picture suggests about the creative strategy.
Interpreted signals:
1. Video frequency is 68% above benchmark - creative fatigue likely developing
2. CPM is rising 22% week-over-week for video formats
3. Conversion rate for video is declining despite stable spend
Synthesize these into a coherent scope for a creative brief.
The output is a structured BriefScope with sections for the primary problem, contributing signals, affected segments, and suggested focus areas.
Phase D: Candidate selection + analytical brief (LLM2a)
The BriefScope feeds into a candidate selection step.
The system looks at the advertiser's existing creative approach clusters and finds which ones are most relevant to the identified problems.
This is a mix of deterministic retrieval (BigQuery query for clusters matching affected segments) and a focused LLM call (LLM2a) that writes an analytical brief.
LLM2a output is an AnalyticalBrief. Factual, evidence-grounded. No creative direction yet.
Phase E: Brief mode (deterministic)
Before the final LLM runs, the system decides what kind of brief to generate.
Three modes:
variation → the current approach is working, make fresh executions
cross_pollinate → a different approach is outperforming, apply its signals here
creative_test → signals are unclear, run a structured testThis decision is not made by the LLM.
def compute_brief_mode(
current_approach_trend: Trend,
best_performing_approach: Approach | None,
signal_clarity: float,
fatigue_score: float,
) -> BriefMode:
if signal_clarity < 0.4:
return BriefMode.CREATIVE_TEST
if fatigue_score > 0.7:
if best_performing_approach and best_performing_approach.ctr > current_approach_trend.ctr * 1.15:
return BriefMode.CROSS_POLLINATE
return BriefMode.CREATIVE_TEST
if current_approach_trend.direction == "improving":
return BriefMode.VARIATION
if best_performing_approach and best_performing_approach.ctr > current_approach_trend.ctr * 1.25:
return BriefMode.CROSS_POLLINATE
return BriefMode.VARIATIONBrief mode is a strategic decision with a correct algorithmic answer given the inputs. Letting the LLM decide it introduces randomness into the most important structural choice in the output.
The LLM is told what mode it is working in. It does not choose.
Phase F: Final brief (LLM2b)
LLM2b receives the full package:
AnalyticalBrief from LLM2a
BriefMode (already computed)
Current approach cluster summary + discriminating tags
Reference approach (for cross_pollinate mode)
BriefScope from Phase C
Structured output schemaExample prompt for cross_pollinate mode:
Brief mode: CROSS_POLLINATE
Current approach (underperforming):
Performance: {current_approach.metrics}
Discriminating tags: {current_approach.tags}
Reference approach (outperforming):
Performance: {reference_approach.metrics}
What makes it distinctive: {reference_approach.tags}
Generate a creative brief that applies the winning approach's signals
to fresh executions for the current segment.
LLM2b returns a typed CreativeBrief object. App-consumable without further parsing.
What a completed brief looks like
Mode: cross_pollinate
Creative direction: 2-3 sentences
Format: video / static / carousel / DCO
Copy direction: headline angle + CTA style
Hypothesis: testable performance prediction
Evidence summary: the signals that triggered this brief
Analytical brief: structured summary for team referenceThe structured schema makes briefs filterable, comparable, and directly consumable by the app layer.
Scheduled vs on-demand
Scheduled. Runs nightly per advertiser after the data pipeline completes. Produces a briefing package for all triggered rules.
On-demand. Triggered by a performance alert. Produces a single brief for the specific rule that triggered it, with the same 6-phase pipeline.
On-demand briefs go through an idempotency check. If a brief was already generated for this rule x advertiser x period in the last N hours, the cached result is returned.
Stack
| Phase | What | How |
|---|---|---|
| A | Rule execution | BigQuery + asyncio.gather |
| B | Per-rule interpretation | Gemini (LLM0) + Langfuse prompts |
| C | Cross-rule synthesis | Gemini (LLM1) + structured schema |
| D | Candidate selection + analytical brief | BigQuery + Gemini (LLM2a) |
| E | Brief mode | Deterministic Python function |
| F | Final brief | Gemini (LLM2b) + structured schema |
Orchestration: Celery (scheduled + on-demand) Observability: Langfuse + OpenTelemetry
Related posts in this series:
- Clustering Ad Creatives into Approaches Using Embeddings
- When the Prompt Is Not the Problem
- How I Split a Marketing AI into 6 Parallel Agents
- Case study: Creative & Campaign Intelligence Data Platform
If you are building a similar AI pipeline for creative or marketing analytics and want to discuss the architecture, get in touch.