Define the trait basis

A SteerConfigInput (used by the SDK today) describes the trait basis grid that drives sampling. Treat it as the source of truth for personas and intents. Keep all trait intensities between 0 and 2.
from collinear.schemas.steer import SteerConfigInput

trait_basis: SteerConfigInput = {
    "ages": ["13-17", "18-24", "25-34", "35-44", "45-54", "55-64", "65+"],
    "genders": ["male", "female", "other"],
    "occupations": ["Unemployed", "Employed", "Student", "Retired", "Not in Labor Force"],
    "intents": [
        "search_flights",
        "make_booking",
        "modify_booking",
        "cancel_booking_request_refund",
        "online_checkin",
        "seat_selection_or_upgrade",
        "boarding_pass_retrieval",
        "check_flight_status",
        "track_baggage",
        "rebook_due_to_disruption",
        "manage_frequent_flyer_account",
        "redeem_or_earn_miles",
        "request_lounge_access",
    ],
    "traits": {
        "impatience": [0, 1, 2],
        "confusion": [0, 1, 2],
        "skeptical": [0, 1, 2],
    },
    "locations": ["USA", "Canada", "UK", "Australia", "other"],
    "languages": ["English", "Spanish", "French", "other"],
    "tasks": ["airline support"],
}
The SDK enforces the canonical age buckets and occupation taxonomy above. If a combination pairs "Retired" with an age bucket below "35-44", that persona is skipped rather than sent downstream.

Controlling Sample Volume

Client.simulate exposes levers for scale and pacing:
  • k: number of trait basis combinations to draw; omit it to use all combinations.
  • num_exchanges: user/assistant pairs per conversation. Each exchange adds one user line and one assistant line.
  • batch_delay: seconds to sleep between samples to avoid rate limits.
  • mix_traits: set True to mix two traits per persona (requires at least two traits defined by the Trait Basis API).
  • steer_temperature and steer_max_tokens: forwarded to the Trait Basis service when generating user turns.
simulations = client.simulate(
    steer_config=trait_basis,
    k=5,
    num_exchanges=4,
    batch_delay=0.5,
    mix_traits=True,
    steer_temperature=0.6,
    steer_max_tokens=200,
)
Each SimulationResult contains the conversation prefix (conv_prefix), the assistant’s final response (response), and the resolved trait basis attributes (steer in the SDK today).

Custom Prompts and Tone

The assistant system prompt can be ovverridden as follows:
runner = client.simulation_runner
runner.ASSISTANT_PROMPT_TEMPLATE = "You are a concierge..."
If you leave templates unset, the runner falls back to the SDK defaults defined in SimulationRunner.ASSISTANT_PROMPT_TEMPLATE.

Logging and Progress

  • Set progress=False on simulate to disable the tqdm progress bar (useful in headless environments).

Saving Outputs

Convert results into JSONL for downstream tooling:
from pathlib import Path
import json

out_path = Path("data/simulations.jsonl")
out_path.parent.mkdir(exist_ok=True)

with out_path.open("w", encoding="utf-8") as f:
    for sim in simulations:
        f.write(json.dumps(
            {
                "persona": sim.steer.model_dump() if sim.steer else None,
                "conversation": sim.conv_prefix,
                "assistant_response": sim.response,
            },
            ensure_ascii=False,
        ) + "\n")
Pair this with the recipes in the dedicated page to plug simulations into evaluation pipelines.