Template - Support
PredicateSupport escalation
Whether a conversation should move from a frontline agent to a senior one.
A predicate decision that catches conversations going wrong, such as repeated contacts, rising frustration, and legal threats, before the customer asks for a manager.
The decision
Should this conversation be escalated to a senior agent?
Evidence checks (asked in the same request)
- Repeat contact: The customer has contacted us about this before.
- Negative sentiment: The customer expresses frustration or dissatisfaction.
- Legal or chargeback risk: The customer mentions a chargeback, bank dispute, or legal action.
Expected output: A probability from 0 to 1 that the conversation should be escalated, plus one probability per evidence check.
Input
The Decisions API reads one input. Combine these fields into it as labeled text so the model sees the facts the decision depends on.
| Field | Type | Required | Description |
|---|---|---|---|
conversation | string | Yes | The customer's latest message, ideally with the previous two or three turns. |
contact_count | number | No | How many times the customer has contacted you about this issue. |
Worked examples
Third contact, asking for a manager
This is the third time I'm asking. Nobody has replied in two weeks and this is unacceptable. I want to speak to a manager today.
A careful reviewer would say: Yes. Repeated contact, clear frustration, and an explicit request for a manager.
Run this exampleA thank-you after a fix
Thanks for the quick fix yesterday. Everything works now. Appreciate it!
A careful reviewer would say: No. The issue is resolved and the customer is satisfied.
Run this example
Expected answers are human judgments written for this template, not model output.
How it works
Customers who ask for a manager have usually been unhappy for a while. Escalating one contact earlier, before the demand, tends to cost less than recovering afterwards.
Include conversation history in the input when you can. A single message rarely shows that this is the third attempt unless the customer says so.
Human review and thresholds
Recommended review policy
Because escalation only hands the conversation to a senior agent, automating "Yes" carries little risk. Guard against the opposite failure by reviewing a sample of conversations that were not escalated and ended badly.
Choosing thresholds
Set the bar by your senior team's capacity. Start high, measure how many escalations were warranted, and lower it until the queue is as full as you want it.
- Starting automation threshold
- 80%
- Starting don’t-decide threshold
- 55%
Starting points for the playground, not recommendations. The right values depend on your costs and on how the model’s confidence tracks accuracy on your data. Calibrate them.
Limitations
- Without history, the model relies on the customer mentioning previous contacts.
- Some customers write forcefully about small problems. Sentiment alone over-escalates; the repeat-contact check is the more reliable signal.
- Escalation capacity is finite. If everything escalates, nothing has.
Use it in your code
The template definition is plain JSON: the question, the evidence checks, the input fields, and the starting policy. The SDK call below sends the same question and checks to the Decisions API from your server.
{
"$format": "thethinkloop.template/v1",
"slug": "support-escalation",
"title": "Support escalation",
"decides": "Whether a conversation should move from a frontline agent to a senior one.",
"question": {
"name": "decision",
"type": "predicate",
"instructions": "Should this conversation be escalated to a senior agent?"
},
"evidenceChecks": [
{
"name": "factor_1",
"label": "Repeat contact",
"type": "predicate",
"instructions": "The customer has contacted us about this before."
},
{
"name": "factor_2",
"label": "Negative sentiment",
"type": "predicate",
"instructions": "The customer expresses frustration or dissatisfaction."
},
{
"name": "factor_3",
"label": "Legal or chargeback risk",
"type": "predicate",
"instructions": "The customer mentions a chargeback, bank dispute, or legal action."
}
],
"inputs": [
{
"name": "conversation",
"type": "string",
"required": true,
"description": "The customer's latest message, ideally with the previous two or three turns."
},
{
"name": "contact_count",
"type": "number",
"required": false,
"description": "How many times the customer has contacted you about this issue."
}
],
"expectedOutput": "A probability from 0 to 1 that the conversation should be escalated, plus one probability per evidence check.",
"examples": [
{
"title": "Third contact, asking for a manager",
"input": "This is the third time I'm asking. Nobody has replied in two weeks and this is unacceptable. I want to speak to a manager today.",
"expected": "Yes"
},
{
"title": "A thank-you after a fix",
"input": "Thanks for the quick fix yesterday. Everything works now. Appreciate it!",
"expected": "No"
}
],
"startingPolicy": {
"automateAt": 0.8,
"abstainBelow": 0.55,
"note": "A starting point for exploration, not a recommendation. Calibrate against your own labeled examples."
}
}import OpenAI from "openai"; // openai >= 7.30.0
const client = new OpenAI(); // reads OPENAI_API_KEY on the server
const decision = await client.decisions.create({
model: "gpt-6-luna",
input: "This is the third time I'm asking. Nobody has replied in two weeks and this is unacceptable. I want to speak to a manager today.",
questions: [
{
type: "predicate",
name: "decision",
instructions: "Should this conversation be escalated to a senior agent?"
},
{
type: "predicate",
name: "factor_1",
instructions: "The customer has contacted us about this before."
},
{
type: "predicate",
name: "factor_2",
instructions: "The customer expresses frustration or dissatisfaction."
},
{
type: "predicate",
name: "factor_3",
instructions: "The customer mentions a chargeback, bank dispute, or legal action."
}
],
});
// Answers come back in question order. A question can also be refused.
const [main, ...checks] = decision.answers;
if (main.type === "refusal") throw new Error("The model declined to answer.");
if (main.type === "predicate") {
console.log(main.probability); // 0–1 estimate that the condition is true
}
Download it as support-escalation.json, or browse all developer resources.
Need this decision tuned to your policy?
Related
- Predicate template
Billing escalation
Whether a billing issue should leave the support queue and go to finance.
- Score template
Churn risk
How likely a customer is to leave, based on what they wrote.
- Score template
Ticket urgency
How urgently a support ticket needs a response, on a four-level rubric.
- Guide
AI decision routing
A routing decision is several smaller decisions plus a rule that combines them. How to design that rule, where people fit, and what to log.
- Guide
Human-in-the-loop AI
When should AI decide and when should it ask? Review patterns, what reviewers need to see, sizing the queue, and keeping oversight real.
- Guide
Confidence thresholds
Probability, confidence, accuracy, calibration, and correctness are different things. How to set a review policy from the cost of each kind of mistake.