Use Cases & Solutions

Draft Replies to Customer Reviews with AI: Brand Rules, Escalation Flags and Human Approval

6 steps 15 min read 8 views 0
On this page

Replying to reviews shows customers that someone listens, and future buyers read those replies too. Writing hundreds of thoughtful replies in several languages, however, takes hours every week. This guide uses a local language model to draft a reply to each review in the reviewer's language, following your brand notes and a strict set of rules. It flags the reviews that need a person, such as low ratings, safety problems, legal threats or suspected fraud, and writes everything into a sheet for approval. Nothing is posted automatically.

Follow each platform's rules for review replies: never offer refunds, gifts or discounts in exchange for changing or removing a review, never reveal customer data, and check whether the platform allows public replies at all. A person must approve every reply before it is posted.

Step 1: Prepare the Environment

Use the /opt/reviews environment with Ollama from analysing customer reviews with a local LLM. The same review CSV works here; the script needs the columns id and text, and uses rating when it is present.

Step 2: Write Your Brand Notes

The model uses these notes for tone, contact details and the facts it may mention. Keep them short and factual:

cat > /data/reviews/brand.txt <<'EOF2'
Business: ACME Home, sells bamboo office accessories online.
Tone: warm and simple, no slang, no emoji.
Support contact: the "Contact seller" button on the order page, or [email protected].
Facts you may mention: 12-month warranty on all stands.
Sign off as: The ACME Home team
EOF2

Step 3: Create the Reply Script

cat > /opt/reviews/replies.py <<'EOF2'
import csv, json, os, re, sys
import ollama

MODEL = os.environ.get("MODEL", "qwen2.5:7b")
BRAND = open(os.environ.get("BRAND_FILE", "brand.txt"), encoding="utf-8").read()
ESCALATE = re.compile(os.environ.get("ESCALATE",
    r"refund|chargeback|injur|burn|fire|smoke|allerg|lawyer|lawsuit|scam|fraud|fake|police|退款|投诉|受伤|起火|过敏|律师|骗"), re.I)
SCHEMA = {"type": "object", "properties": {
    "reply": {"type": "string"}, "needs_human": {"type": "boolean"}, "reason": {"type": "string"}},
    "required": ["reply", "needs_human", "reason"]}
SYSTEM = """You draft public replies to customer reviews for the business described in the brand notes.
Rules:
- Reply in the same language as the review, in 2 to 4 sentences.
- Thank the customer and respond to the specific point they made. Vary your wording.
- Never admit legal liability. Never promise refunds, replacements, discounts or compensation.
- Never ask the customer to change or remove their review, and never offer anything in return for a review.
- Never include order numbers, names or other personal data.
- For problems, apologise briefly and invite the customer to contact support as described in the brand notes.
- Set needs_human to true for safety issues, legal threats, suspected fraud, abuse, or if you are unsure,
  and give the reason. Otherwise leave reason empty.

Brand notes:
""" + BRAND

src, out = sys.argv[1], "replies.csv"
done = set()
if os.path.exists(out):
    with open(out, encoding="utf-8-sig") as f:
        done = {r["id"] for r in csv.DictReader(f)}
with open(src, encoding="utf-8-sig") as f:
    reviews = [r for r in csv.DictReader(f) if r.get("text", "").strip()]

new_file = not os.path.exists(out)
with open(out, "a", newline="", encoding="utf-8-sig") as f:
    w = csv.writer(f)
    if new_file:
        w.writerow(["id", "rating", "text", "draft_reply", "needs_human", "reason", "approved", "final_reply"])
    for r in reviews:
        if r["id"] in done:
            continue
        res = ollama.chat(model=MODEL, format=SCHEMA, options={"temperature": 0.5}, messages=[
            {"role": "system", "content": SYSTEM},
            {"role": "user", "content": f"Rating: {r.get('rating', '?')} of 5\nReview: {r['text'][:3000]}"}])
        d = json.loads(res.message.content)
        reasons = [d["reason"]] if d["needs_human"] and d["reason"] else []
        if r.get("rating", "").isdigit() and int(r["rating"]) <= 2:
            reasons.append("low rating")
        if ESCALATE.search(r["text"]):
            reasons.append("keyword: " + ESCALATE.search(r["text"]).group(0))
        w.writerow([r["id"], r.get("rating", ""), r["text"], d["reply"].strip(),
                    "yes" if reasons or d["needs_human"] else "no", "; ".join(reasons), "", ""])
        f.flush()
        print(r["id"], "NEEDS HUMAN" if reasons or d["needs_human"] else "draft ok", flush=True)
print("done: replies.csv")
EOF2

A review is marked for a person when the model asks for it, when the rating is 2 or lower, or when the text matches the ESCALATE keyword list. Finished reviews are saved immediately and skipped on the next run.

Step 4: Generate the Drafts

cd /data/reviews
/opt/reviews/bin/python /opt/reviews/replies.py reviews.csv

The result is replies.csv with the columns id, rating, text, draft_reply, needs_human, reason, approved and final_reply.

Step 5: Approve and Post

  1. Open replies.csv in Excel or Google Sheets and filter needs_human = yes first. Handle these yourself: contact the customer privately through the platform, solve the problem, then reply publicly.
  2. For the other rows, read the draft, copy it into final_reply with any changes, and set approved to yes.
  3. Post the approved replies through the seller centre, or through the platform's official API if it offers one.
  4. Keep the file as a record of what was answered and by whom.

Step 6: Tune It to Your Business

  • Extend ESCALATE with words in the languages your customers use, for example in Thai, Spanish or Japanese.
  • Add frequent facts to the brand notes, such as warranty terms or care instructions, so the drafts can answer common questions correctly.
  • Paste two or three replies you consider ideal into the brand notes as examples; the model will follow their style.
  • To alert the team immediately when a review needs a person, send the flagged rows to a Telegram group with a workflow tool, see building a Telegram bot with n8n.

FAQ

Can the replies be posted automatically?

Technically yes, through platform APIs, but we recommend human approval. A wrong public reply is hard to undo, and many platforms hold sellers responsible for every word.

The drafts all sound the same

The rules ask the model to vary its wording, and the temperature of 0.5 adds variety. Example replies with different structures in the brand notes help most.

Which reviews should we answer?

Prioritise negative and detailed reviews, where a good reply can change a buyer's mind. Short positive reviews need at most a brief thank-you. To understand what customers complain about overall, see finding what customers talk about with embeddings.

Still stuck after following these steps? Open a support ticket and the IMIDC 24/7 technical team will help. Include the server IP, the model you use and the error output so we can pinpoint the issue faster.

Was this answer helpful?

Related Tutorials