TL;DR

  • → LLM summarises your data; AgentGen formats it as a styled, downloadable PDF
  • → Works as a tool in LangChain, OpenAI, AutoGen, or any HTTP-capable framework
  • → 2 tokens per page (~$0.03). No monthly fee — buy once, use whenever

AI Agent PDF Report Generation

The classic AI agent limitation: it can analyse your data beautifully, but all you get back is a wall of text. AgentGen fixes that. Your agent summarises the data, AgentGen renders it as a branded, structured PDF — delivered as a CDN link in the same conversation turn.

The two-stage architecture

1

LLM stage

Claude or GPT-4o reads raw metrics, writes an executive summary, and identifies highlights and concerns.

2

Render stage

A Python template maps the structured output to styled HTML. AgentGen converts it to a PDF via headless Chrome.

Step 1 — LLM analysis

import json
from langchain_anthropic import ChatAnthropic

llm = ChatAnthropic(model="claude-opus-4-6", temperature=0.2)

def analyse_metrics(raw_metrics: list[dict]) -> dict:
    """Ask Claude to interpret the numbers and return structured analysis."""
    response = llm.invoke(
        f"""Analyse these metrics and return JSON with:
- "summary": 2-3 sentence executive overview (use specific numbers)
- "highlights": list of 2-3 positive trends
- "concerns": list of 1-2 areas needing attention

Metrics: {json.dumps(raw_metrics, indent=2)}

Return only valid JSON."""
    )
    return json.loads(response.content)

Step 2 — Build the report HTML

def build_report_html(title: str, week: str, metrics: list, analysis: dict) -> str:
    def card(m):
        color = "#16a34a" if m["change_pct"] >= 0 else "#dc2626"
        arrow = "↑" if m["change_pct"] >= 0 else "↓"
        return f"""
          <div style="background:white;border:1px solid #e5e7eb;border-radius:10px;
                      padding:20px;flex:1;min-width:140px">
            <p style="margin:0 0 6px;font-size:11px;color:#9ca3af;text-transform:uppercase">{m['label']}</p>
            <p style="margin:0 0 4px;font-size:26px;font-weight:800">{m['value']}</p>
            <p style="margin:0;font-size:13px;font-weight:600;color:{color}">
              {arrow} {abs(m['change_pct']):.1f}% vs last week
            </p>
          </div>"""

    cards = "".join(card(m) for m in metrics)
    highlights = "".join(f"<li style='color:#166534;margin-bottom:4px'>{h}</li>"
                         for h in analysis["highlights"])
    concerns = "".join(f"<li style='color:#991b1b;margin-bottom:4px'>{c}</li>"
                       for c in analysis["concerns"])

    return f"""<!DOCTYPE html>
    <html><head><meta charset="UTF-8"></head>
    <body style="margin:0;padding:36px;background:#f9fafb;
                 font-family:'Helvetica Neue',Arial,sans-serif">
      <div style="background:linear-gradient(135deg,#1e1b4b,#3730a3);border-radius:12px;
                  padding:28px 32px;color:white;margin-bottom:24px">
        <h1 style="margin:0 0 4px;font-size:22px;font-weight:800">{title}</h1>
        <p style="margin:0;opacity:.7;font-size:13px">Week ending {week}</p>
      </div>
      <div style="background:white;border:1px solid #e5e7eb;border-radius:10px;
                  padding:20px;margin-bottom:20px">
        <p style="margin:0 0 8px;font-size:11px;color:#9ca3af;text-transform:uppercase">
          Executive Summary</p>
        <p style="margin:0;line-height:1.7;color:#374151">{analysis['summary']}</p>
      </div>
      <div style="display:flex;gap:12px;flex-wrap:wrap;margin-bottom:20px">{cards}</div>
      <div style="display:flex;gap:12px">
        <div style="flex:1;background:#f0fdf4;border:1px solid #bbf7d0;border-radius:10px;padding:16px">
          <p style="margin:0 0 8px;color:#15803d;font-size:11px;text-transform:uppercase;font-weight:600">
            Highlights</p>
          <ul style="margin:0;padding-left:18px">{highlights}</ul>
        </div>
        <div style="flex:1;background:#fef2f2;border:1px solid #fecaca;border-radius:10px;padding:16px">
          <p style="margin:0 0 8px;color:#dc2626;font-size:11px;text-transform:uppercase;font-weight:600">
            Watch</p>
          <ul style="margin:0;padding-left:18px">{concerns}</ul>
        </div>
      </div>
    </body></html>"""

Step 3 — Render to PDF and return the link

import os, requests

def generate_report(title: str, week: str, raw_metrics: list[dict]) -> str:
    analysis = analyse_metrics(raw_metrics)
    html = build_report_html(title, week, raw_metrics, analysis)

    r = requests.post(
        "https://www.agent-gen.com/api/v1/generate/pdf",
        headers={"X-API-Key": os.environ["AGENTGEN_API_KEY"], "Content-Type": "application/json"},
        json={"html": html, "format": "A4",
              "margin": {"top": "10mm", "bottom": "10mm", "left": "10mm", "right": "10mm"}},
        timeout=30,
    )
    r.raise_for_status()
    return r.json()["url"]

# Example
url = generate_report(
    title="AgentGen — Weekly Report",
    week="March 2, 2026",
    raw_metrics=[
        {"label": "Active Users", "value": "12,847", "change_pct": 8.3},
        {"label": "Revenue",      "value": "$48,200", "change_pct": 12.1},
        {"label": "Churn",        "value": "2.1%",    "change_pct": -0.4},
    ],
)
print(url)  # https://cdn.agent-gen.com/output/abc123.pdf

Automate with a cron job

Run this pipeline every Monday morning with GitHub Actions, Railway, or Vercel Cron. Fetch last week's data, call generate_report(), and Slack the PDF link to your team — all without touching a design tool.

A two-page report costs 4 tokens (~$0.06). For a 10-person team that's under $4/year in generation costs.

Ready to automate your reports?

50 free tokens on signup — enough for 12 full reports before you spend anything.