On July 30, Simile raised more than $200M at a $2B valuation — five months after a $100M Series A — to sell synthetic users: LLM-driven simulations of real customers you can survey before you build (TechCrunch). The category is now funded, which means the question for a solo founder isn't whether simulated users are real — it's whether you can build a rough one yourself.

You can. Here's a panel you can stand up this afternoon. Read the caveats first, because the wrong version of this tool is worse than useless — it's a confident mirror for your own bias.

What it's for (front-load this)#

A synthetic-user panel is a pre-filter, not a focus group. Use it to:

Do not use it to pick a winner, predict a conversion rate, or estimate willingness to pay. Personas don't spend money, and their "yes" is free. We argued the boundary in where synthetic users belong in your loop; this is how to build the part that stays inside it.

1. Generate diverse personas grounded in your real segment#

The panel is only as good as the disagreement in it. A persona needs a concrete constraint — a budget, a job, a past scar — or it collapses into a generic agreeable customer.

import os, json
from openai import OpenAI

client = OpenAI(api_key=os.environ["OPENAI_API_KEY"])

SEGMENT = "bootstrapped solo founders evaluating a $20-50/mo dev tool"

def make_personas(segment, n=8):
    resp = client.chat.completions.create(
        model="gpt-5.6-terra",
        messages=[{"role": "user", "content": f"""
Generate {n} DISTINCT customer personas in segment: {segment}.
Maximize diversity of budget sensitivity, technical depth, and skepticism.
Each must include one concrete constraint or past bad experience that shapes buying.
Return JSON list of objects: name, role, budget, skepticism (1-5), constraint.
"""}],
        response_format={"type": "json_object"},
    )
    return json.loads(resp.choices[0].message.content)["personas"]

Seed the constraints from real quotes if you have any — support tickets, sales-call notes, a subreddit thread. A persona whose objection is lifted from a real customer is far more useful than one the model invented.

2. Run each persona past the artifact — with a required objection#

The trick that beats sycophancy: don't ask "would you buy this?" Force a structured verdict where the objection field is mandatory. "I'd sign up" is not a complete answer.

def run_panel(personas, artifact):
    verdicts = []
    for p in personas:
        resp = client.chat.completions.create(
            model="gpt-5.6-terra",
            messages=[
                {"role": "system", "content":
                 f"You are {p['name']}, {p['role']}. Budget: {p['budget']}. "
                 f"Skepticism {p['skepticism']}/5. You care most about: {p['constraint']}. "
                 f"Stay in character. Be honest, not polite."},
                {"role": "user", "content":
                 f"Here is a product page:\n\n{artifact}\n\n"
                 "Respond as JSON: rating (1-10), would_try (bool), "
                 "strongest_objection (required, one sentence), "
                 "what_confused_me (string or null)."},
            ],
            response_format={"type": "json_object"},
        )
        verdicts.append({"persona": p["name"], **json.loads(resp.choices[0].message.content)})
    return verdicts

3. Aggregate the objections, not the votes#

The mean rating is the least useful number the panel produces. Read the reasons. Cluster the strongest_objection fields and the what_confused_me fields; the option that generates the most distinct, legible objections is the one to worry about, even if its average score is fine.

def report(verdicts):
    for v in sorted(verdicts, key=lambda v: v["rating"]):
        print(f'{v["rating"]}/10  {v["persona"]:16}  {v["strongest_objection"]}')
    confused = [v for v in verdicts if v.get("what_confused_me")]
    print(f'\n{len(confused)}/{len(verdicts)} hit a comprehension problem:')
    for v in confused:
        print(f'  - {v["what_confused_me"]}')

A panel where 6 of 8 personas flag the same confusion about your pricing has told you something real and free. A panel-wide 8/10 with no objections has told you your prompt is broken.

4. Calibrate — the step that separates a tool from a mirror#

This is non-negotiable. Before you trust the panel on a live question, replay a decision you already know the answer to. Take a page that actually converted and one that flopped, strip any labels, and run the panel blind.

An uncalibrated panel doesn't measure your customers. It measures your assumptions about them, laundered through a model. The QA version of this same trap — trusting a simulator you never validated — is exactly the failure we walked through in testing an agent with simulated users.

5. The three failure modes to watch#

When to reach for the funded version#

Simile raised nine figures because the last 80% of fidelity — making a simulated human actually behave like a real one — is genuinely hard, and a roughly $80B market-research industry is the prize for closing that gap. Your afternoon panel buys the cheap 20%: a fast, private pre-filter that kills bad options and drafts a better real study. Run it before every real test, trust it for none of them, and when a decision is expensive enough that the missing fidelity would pay for itself, that's when you rent the real thing.