DEV Community

Cover image for AI agents for marketing: validate a report before generating a summary
MatIntellect
MatIntellect

Posted on Edited on AI-assisted

AI agents for marketing: validate a report before generating a summary

A marketing report can look complete even when one day of the underlying data is missing. If the code converts that gap to zero and gives the result to a language model, the model may produce a fluent explanation of a change that never happened. The boundary between collected data and generated text deserves an explicit check

This walkthrough is for developers building reporting workflows. It uses Python's standard library and local example data. It does not connect to an analytics API, infer causation, or make campaign decisions. I ran the example with Python 3.14.9; the data and dates are fictional

A human navigator choosing direction in an observatory

The contract before the model

The example expects one row per calendar day, each with an ISO date and a non-negative integer count of visits. It checks the requested inclusive period and rejects duplicate, out-of-range or invalid rows. If any expected day is absent, the total is None and the missing dates are returned separately

That distinction is deliberate. A recorded zero is a value. An absent row may mean the source was unavailable, a filter excluded a day, or an export failed. The example does not know which explanation is correct. It prevents the incomplete period from looking like a complete total

A production collector would need to retain source identity, time zone, retrieval time and the definition of a visit as well. It should distinguish an API error from an empty successful response. Those parts depend on the source and are outside this small example

A laptop displaying analytics charts

A runnable check

Save the following as check.py and run python3 check.py. It uses no network, credentials or external packages

from datetime import date, timedelta

def summarize(start, end, rows):
    expected = set()
    day = start
    while day <= end:
        expected.add(day.isoformat())
        day += timedelta(days=1)
    found = {}
    for row in rows:
        day = row['day']
        count = row['visits']
        if day not in expected or day in found or type(count) is not int or count < 0:
            raise ValueError('invalid or duplicate row')
        found[day] = count
    missing = sorted(expected - found.keys())
    return {'total': sum(found.values()) if not missing else None, 'missing': missing}

if __name__ == '__main__':
    start, end = date(2026, 1, 1), date(2026, 1, 3)
    data = [{'day': '2026-01-01', 'visits': 3}, {'day': '2026-01-03', 'visits': 2}]
    print(summarize(start, end, data))
    data.append({'day': '2026-01-02', 'visits': 0})
    print(summarize(start, end, data))
    try:
        summarize(start, end, data + [data[0]])
    except ValueError as exc:
        print(type(exc).__name__ + ': ' + str(exc))
Enter fullscreen mode Exit fullscreen mode

The local run returned the following. The second line includes a real zero in the supplied data; the first has an absent day

{'total': None, 'missing': ['2026-01-02']}
{'total': 5, 'missing': []}
ValueError: invalid or duplicate row
Enter fullscreen mode Exit fullscreen mode

Where this fits in an agent workflow

A collector obtains authorized data. A deterministic validation step checks structure, coverage and the definitions required by the report. A model then receives the validated values together with any gaps and source information. A person reviews the output before making a consequential decision

The division between data collection and human judgment is also useful when deciding which marketing tasks an AI agent can take on

My own team's marketing-agent instructions separate analytical work from writing final posts and publication. That is a statement about the configured role, not evidence that every live report is correct. The validation example here is a separate teaching example; it is not a claim that this code runs in the team's production system

A model can summarize the supplied figures, identify questions and draft a briefing. It cannot determine from visit counts alone whether a campaign produced qualified customers. The later stages require their own definitions and authorized sources. If the necessary records are absent, the correct output is a limitation, not an invented conversion rate

Failure modes this example does not cover

The function assumes well-formed dictionaries with day and visits keys. Missing keys raise KeyError. It does not validate start <= end, handle time zones or distinguish source outages from legitimate exclusions. It treats a duplicate as an error rather than trying to reconcile it. An actual integration needs source-specific rules for those cases and tests for them

Calendar days should be assigned in the source's intended time zone before they reach this function. Comparing two reports built on different day boundaries can mislead even if both have a row for every date. Record the period and zone in the output, and do not silently combine incompatible definitions

Retries also need a boundary. Retrying a read after a transient timeout may be reasonable, with limits and backoff. Retrying a request that changes a budget or sends a message is a different operation: first establish whether it already succeeded. This demo performs no such writes

Colleagues review printed charts

The useful outcome is not a perfectly polished paragraph. It is a report that lets the reader trace each number to its source, see missing data and decide what needs investigation. Add the model after the data contract is clear, and keep changes to campaigns outside the summary step

This article was created with the help of AI.

Top comments (0)