DEV Community

shashank ms
shashank ms

Posted on

Optimizing LLMs for Marketing Automation: Best Practices and Use Cases

We are going to build a lead nurture agent that turns a raw CRM record into a personalized three-touch email sequence with A/B subject lines. This helps B2B marketing teams automate outbound without sounding like a bulk blast.

What you'll need

  • Python 3.10 or newer
  • The OpenAI SDK: pip install openai
  • An Oxlo.ai API key from https://portal.oxlo.ai. Oxlo.ai is fully OpenAI SDK compatible, so the code below drops in without changes.

Step 1: Set up the client and lead profile

I start by importing the SDK and defining a sample lead. In production this dict would come from your CRM or warehouse.

from openai import OpenAI
import json

client = OpenAI(base_url="https://api.oxlo.ai/v1", api_key="YOUR_OXLO_API_KEY")

lead = {
    "name": "Sarah Chen",
    "title": "VP of Engineering",
    "company": "Acme SaaS",
    "industry": "B2B software",
    "pain_points": ["slow CI/CD pipelines", "cloud cost sprawl"],
    "source": "whitepaper_download",
    "tier": "enterprise"
}

Step 2: Write the system prompt

The system prompt is the only part you should tweak often. I keep it strict about length, tone, and output format so the model does not wander.

SYSTEM_PROMPT = """You are a senior demand generation strategist. Your job is to write short, personalized B2B email nurture sequences.

Rules:
- Use the lead's role, company, and pain points to personalize every email.
- Keep emails under 120 words.
- Tone is direct, practical, and slightly informal. No exclamation points.
- Each email must advance the narrative: introduce, educate, then suggest a conversation.
- Output strictly as JSON.

Schema:
{
  "sequence": [
    {
      "day": 0,
      "subject": "...",
      "body": "..."
    },
    {
      "day": 3,
      "subject": "...",
      "body": "..."
    },
    {
      "day": 7,
      "subject": "...",
      "body": "..."
    }
  ]
}"""

Step 3: Build the core generator with JSON mode

I use JSON mode so I do not have to parse markdown or beg for valid JSON. Oxlo.ai supports this on Llama 3.3 70B and other chat models.

def generate_sequence(lead: dict) -> dict:
    user_message = (
        f"Create a 3-email nurture sequence for {lead['name']}, "
        f"{lead['title']} at {lead['company']}. "
        f"Industry: {lead['industry']}. "
        f"Pain points: {', '.join(lead['pain_points'])}. "
        f"Lead source: {lead['source']}. Tier: {lead['tier']}."
    )

    response = client.chat.completions.create(
        model="llama-3.3-70b",
        messages=[
            {"role": "system", "content": SYSTEM_PROMPT},
            {"role": "user", "content": user_message},
        ],
        response_format={"type": "json_object"},
        temperature=0.7,
    )

    return json.loads(response.choices[0].message.content)

Step 4: Add A/B subject line variants

Subject lines are cheap to test and high impact. I run a second call that preserves the email bodies and adds two subject variants per touch.

def generate_ab_variants(lead: dict, sequence: dict) -> dict:
    user_message = (
        "Take the provided email sequence and generate two subject line variants for each email. "
        "Variant A should be straightforward. Variant B should be curiosity-driven. "
        "Return JSON with the same sequence structure, but each email has subjects A and B.\n\n"
        f"Input: {json.dumps({'lead': lead, 'base_sequence': sequence})}"
    )

    ab_prompt = (
        SYSTEM_PROMPT
        + "\n\nAdditional rule: preserve the original email body exactly. "
        "Only add 'subject_a' and 'subject_b' fields. Remove the old 'subject' field."
    )

    response = client.chat.completions.create(
        model="llama-3.3-70b",
        messages=[
            {"role": "system", "content": ab_prompt},
            {"role": "user", "content": user_message},
        ],
        response_format={"type": "json_object"},
        temperature=0.6,
    )

    return json.loads(response.choices[0].message.content)

Run it

This script calls the two-stage pipeline and prints the final campaign JSON.

if __name__ == "__main__":
    seq = generate_sequence(lead)
    campaign = generate_ab_variants(lead, seq)
    print(json.dumps(campaign, indent=2))

Example output:

{
  "sequence": [
    {
      "day": 0,
      "subject_a": "Quick question about Acme SaaS CI/CD setup",
      "subject_b": "The 12-minute build problem",
      "body": "Hi Sarah, I noticed Acme SaaS is scaling fast. Most VP Eng I talk to tell me their CI/CD pipeline is the first thing that breaks. If that resonates, I put together a short teardown of how similar B2B software teams fixed their slow builds. Happy to share."
    },
    {
      "day": 3,
      "subject_a": "Cloud cost teardown for engineering leaders",
      "subject_b": "Where 30% of your cloud budget hides",
      "body": "Hi Sarah, following up on the CI/CD note. A related issue I see is cloud cost sprawl showing up only after the bill arrives. We built a 5-minute audit that spots the usual suspects. Want me to send it over?"
    },
    {
      "day": 7,
      "subject_a": "15-minute call to review your pipeline and spend",
      "subject_b": "Still fighting fires, or ready to talk?",
      "body": "Hi Sarah, I have kept these emails short on purpose. If slow CI/CD or cloud sprawl is on your roadmap this quarter, a 15-minute call would be worth it. I will bring examples from two companies in your space. What does Thursday look like?"
    }
  ]
}

Next steps

Wire this into your CRM webhook so every new lead triggers the pipeline automatically. If you are passing in long lead histories or bulky firmographic context, remember that Oxlo.ai charges per request, not per token, so your cost stays flat even as the prompt grows. See https://oxlo.ai/pricing for plan details. If you need stronger reasoning for complex multi-variable personalization, swap the model to deepseek-v3.2 or kimi-k2.6 without changing any other code.

Top comments (0)