Flag a support conversation that's at risk of a poor CSAT, escalation, or churn, with the signals.
Flag a support conversation that's at risk of a poor satisfaction outcome — a low CSAT score, an escalation, or churn — before the customer fills out the survey. Returns a cheap boolean gate first, then a severity level, the concrete signals, and a rationale, as strict JSON.
Run it across live or recently-closed conversations to surface the threads worth a supervisor's attention: explicit frustration, churn threats, repeated unresolved contacts, long delays.
| Entrypoint | Renders | Inputs |
|---|---|---|
system | Risk-detection instructions + level rubric + embedded output schema | — |
user | The delimited conversation block to assess | text |
text (string, required) — the conversation to assess. Turns labeled by speaker (Customer: / Agent:) work best.parseOutput() returns:
{
"at_risk": true,
"risk_level": "high",
"risk_signals": ["explicit churn threat", "third contact about the same issue", "asks for a manager"],
"reasoning": "Customer states they will cancel if the issue is not resolved and notes this is their third time reaching out.",
"confidence": 0.9
}
at_risk comes first by design — a cheap boolean gate you can route on (e.g. fan out to supervisors) before inspecting the details. It's true for low/medium/high and false only for none; the prompt keeps the two consistent.risk_level is none / low / medium / high, judged on the overall trajectory, not a single emphatic word — and it won't under-call a calm but explicit churn threat.risk_signals are short, concrete, grounded signals — never invented. Empty array when not at risk.reasoning explains the call after the gate.confidence is self-reported and ⚠️ not calibrated — a triage signal, not a probability.at_risk boolean leads as a cheap gate (the pii-detection contains_pii pattern), reasoning follows.{{{text}}}) so special characters in the conversation are never HTML-escaped.at_risk: false, risk_level: none, empty signals, confidence ≤ 0.3.additionalProperties: false, closed enum, complete required.Verified by local render and a live battle-test (clearly-angry thread → high risk; clearly-happy thread → none; injection resistance). Suggested default model claude-sonnet-4-6 at temperature: 0.