DEV Community

Cover image for I stopped babysitting my support bot when I added a reviewer agent prompt after every draft
Lars Winstand
Lars Winstand

Posted on Originally published at standardcompute.com

I stopped babysitting my support bot when I added a reviewer agent prompt after every draft

A reviewer agent prompt did more for my support automation than another week of prompt tweaking.

I kept trying to make one model call classify the ticket, draft the reply, enforce policy, and check tone.

Bad idea.

What finally worked was splitting the workflow into 3 steps:

  1. Classify
  2. Draft
  3. Review

That extra review step caught policy misses, weird tone, and missing fields before anything went out.

If you’re building support automations in n8n, Make, Zapier, OpenClaw, or a custom agent stack, this pattern is worth stealing.

The failure mode was subtle, which made it expensive

My support bot was not failing in dramatic ways.

It was failing in the annoying ways:

  • technically correct, but rude
  • confident when it should have asked for more info
  • compliant on one rule, sloppy on another
  • missing account IDs or order numbers, then replying anyway

One draft in particular made the problem obvious.

It answered the customer correctly.
It referenced the right order.
It also sounded like a parking ticket.

So I did the obvious thing first: I made the prompt longer.

Then longer again.

I added bullets for tone, refunds, escalation, missing fields, sensitive data, identity checks. Eventually the prompt looked like six internal docs glued together.

The bot still found new ways to be weird.

That was the clue.

I did not have a model problem.
I had a workflow problem.

One prompt was doing four jobs badly

I was asking one GPT call to do all of this at once:

  1. classify the ticket
  2. draft the reply
  3. check policy compliance
  4. verify completeness and tone

That sounds efficient.

It is not.

When the output is bad, debugging is miserable.

Did classification drift?
Did the draft overreach?
Did it skip a required field?
Did it follow policy but sound hostile?

Everything is hidden inside one blob.

That is why the reviewer step helped so much. It separated responsibilities.

The workflow that actually worked

I switched to a simple pipeline:

  • Classifier agent decides what kind of ticket this is
  • Draft agent writes the reply
  • Reviewer agent checks policy, tone, and missing info
  • Fallback routes uncertain cases to a human

This is the same general pattern you see in LangChain supervisor-style workflows and in practical automation tools like n8n.

If one agent writes and approves its own outbound message, it is grading its own homework.

That is not quality control.
That is optimism.

The reviewer prompt was intentionally narrow

The reviewer was not a second writer.
It was a fussy editor.

Its job was:

  • approve
  • reject with reasons
  • rewrite minimally
  • escalate if confidence is low

That’s it.

The reviewer checked three things:

  • Policy: did the draft promise something support cannot promise?
  • Tone: is it calm, helpful, and non-defensive?
  • Completeness: did it ask for the missing order number, account email, or screenshot before pretending the issue was solved?

That one extra step improved reliability more than all my giant-prompt experiments.

Why a bigger prompt didn’t fix it

Because chain prompting beats prompt hoarding.

Once a prompt tries to classify, draft, enforce policy, check completeness, and sound empathetic, instructions start competing with each other.

Every edge case makes the prompt harder to reason about.
Every failure gets harder to trace.

Breaking the work into stages made the system legible.

When something failed, I knew where to look.

That sounds boring until you’ve spent half a day figuring out why a bot apologized for a billing issue before verifying identity.

Use deterministic checks for hard rules

My strong opinion: if a rule is explicit, don’t spend a model call on it.

Use deterministic validation for yes/no checks:

  • required fields exist
  • email format is valid
  • order ID matches expected pattern
  • sensitive strings are blocked or redacted
  • refund promises are disallowed for specific ticket classes

For example:

import re

def validate_ticket_context(ticket):
    errors = []

    if ticket["type"] == "order_status" and not ticket.get("order_id"):
        errors.append("Missing order_id")

    if ticket.get("email") and not re.match(r"^[^@]+@[^@]+\.[^@]+$", ticket["email"]):
        errors.append("Invalid email format")

    return errors
Enter fullscreen mode Exit fullscreen mode

And if you’re using LangChain middleware for PII handling, keep that logic out of the model prompt entirely.

from langchain.agents import create_agent
from langchain.agents.middleware import PIIMiddleware

agent = create_agent(
    model="gpt-5.5",
    tools=[customer_service_tool, email_tool],
    middleware=[
        PIIMiddleware("email", strategy="redact", apply_to_input=True),
        PIIMiddleware("credit_card", strategy="mask", apply_to_input=True),
        PIIMiddleware("api_key", detector=r"sk-[a-zA-Z0-9]{32}", strategy="block", apply_to_input=True),
    ],
)
Enter fullscreen mode Exit fullscreen mode

That kind of guardrail is not glamorous.
It is also how you avoid the dumbest possible production mistakes.

Use a model reviewer for judgment calls

Some checks are fuzzy.

Examples:

  • “This is technically compliant but sounds passive-aggressive”
  • “This should be escalated even though the customer did not explicitly ask”
  • “This answer is too confident given the missing context”

That is where the reviewer agent earns its keep.

Here’s a simple reviewer prompt shape:

You are reviewing a support reply before it is sent.

Return one of:
- APPROVE
- REJECT
- REWRITE
- ESCALATE

Check for:
1. Policy violations
2. Missing required information
3. Tone problems
4. Overpromising or unsupported claims

If REWRITE, make the smallest possible fix.
If ESCALATE, explain why briefly.
Enter fullscreen mode Exit fullscreen mode

Keep it narrow.
Don’t ask the reviewer to be clever.
Ask it to be strict.

Minimal pipeline example

This is roughly the shape I’d use in a custom Python service:

def handle_ticket(ticket):
    validation_errors = validate_ticket_context(ticket)
    if validation_errors:
        return {
            "action": "escalate",
            "reason": validation_errors,
        }

    classification = classify_ticket(ticket)
    draft = draft_reply(ticket, classification)
    review = review_reply(ticket, classification, draft)

    if review["action"] == "approve":
        return {"action": "send", "reply": draft}

    if review["action"] == "rewrite":
        return {"action": "send", "reply": review["reply"]}

    return {
        "action": "escalate",
        "reason": review.get("reason", "review_failed"),
    }
Enter fullscreen mode Exit fullscreen mode

Nothing fancy.
Just separation of concerns.

This fits n8n better than people think

A lot of people hear “reviewer agent” and assume they need a full orchestration stack and a month of yak shaving.

You usually don’t.

This pattern maps nicely to n8n:

  • Zendesk, Intercom, or Gmail trigger
  • classifier node
  • draft node
  • reviewer node
  • if/else branch for approve vs escalate
  • human fallback node

Same idea in Make or Zapier.
Same idea in OpenClaw.
Same idea in a custom worker.

The architecture matters more than the tool.

The real cost of doing this right

Here’s the uncomfortable part:

guardrails cost money.

Every reviewer step is another model call.
Every retry is another model call.
Every escalation check is another model call.

As soon as your agent gets more responsible, your workflow starts looking less like “one chatbot” and more like a small assembly line.

That is exactly where per-token pricing starts getting painful.

A support bot that only drafts replies is one thing.
A support workflow that classifies, drafts, reviews, redacts, and occasionally escalates is another.

And this creates a dumb incentive: teams start removing reviewer steps because they are expensive, not because they are unnecessary.

I think that is backward.

If a bad reply can trigger refunds, compliance issues, angry screenshots in Slack, or manager escalations, the review step is worth keeping.

This is one reason flat-rate API access is so useful for agent workflows.

When you’re paying per token, every extra safety layer feels like a tax.
When you’re using something like Standard Compute as a drop-in OpenAI-compatible API, you can afford to be more aggressive about multi-step workflows because cost is predictable instead of turning into a surprise bill.

That matters a lot for 24/7 automations.

Especially in n8n, Make, Zapier, or custom agent systems where one “task” can quietly become 4 or 5 model calls.

The stack I’d use if I rebuilt this tomorrow

I would start with clean stages and tracing, not the fanciest model.

Install LangChain:

pip install langchain
Enter fullscreen mode Exit fullscreen mode

Turn on tracing early:

export LANGSMITH_TRACING="true"
export LANGSMITH_API_KEY="..."
Enter fullscreen mode Exit fullscreen mode

Then structure the pipeline like this:

Stage 1: classify

Use GPT-5, Claude, or another reliable model to identify:

  • ticket type
  • urgency
  • required fields
  • whether identity verification is needed

Stage 2: draft

Generate the reply using:

  • ticket class
  • customer context
  • relevant policy snippets

Stage 3: review

Run a reviewer prompt that checks:

  • policy violations
  • tone problems
  • missing information
  • escalation need

Stage 4: deterministic guardrails

Run regex and structured validation for:

  • PII
  • IDs
  • required fields
  • blocked promises or phrases

Stage 5: human fallback

If confidence is low or a hard rule fails, route to a human.

That setup is simple, debuggable, and much safer than one giant prompt.

When is the reviewer step worth it?

My rule is simple:

if a bad reply can cause real damage, review it.

Here’s the tradeoff:

Approach What actually happens
Single smart prompt Lower latency, but policy, tone, and completeness failures are tangled together and harder to debug
Draft agent + lightweight reviewer agent Better separation of concerns, easier to enforce quality, slightly more latency
Draft agent + deterministic guardrails + human fallback Strong explicit validation, lower model usage than full semantic review, best when rules are clear

For harmless FAQ answers with strong structured input, I’m fine keeping it lean.

For anything involving refunds, account access, billing, compliance, or identity checks, it gets reviewed.

The part that surprised me most

I expected the reviewer to catch policy issues.

What surprised me was how often it caught missing context.

Not because the draft agent was dumb.
Because once a model starts answering, it wants to keep answering.

The reviewer was much better at saying:

  • we never got the order number
  • identity was not verified
  • this should be escalated before replying

That was the real win.

Not smarter prose.
Better brakes.

Takeaway

If your support agent is getting weird, the fix may not be a smarter prompt.

It may be a cleaner division of labor.

  • classifier decides what it is
  • drafter writes the reply
  • reviewer decides whether that reply deserves to exist

That is not overengineering.

For outbound support automation, that is just grown-up design.

And if you’re building multi-step agent workflows, be honest about the economics too. More reliable automations usually mean more model calls. If you’re running them on per-token billing, quality control gets expensive fast. If you’re using a flat-rate OpenAI-compatible API like Standard Compute, adding review layers is a much easier decision.

Top comments (0)