Template - Support
PredicateEngineering escalation
Whether a support issue needs engineering, or can be resolved by support.
A predicate decision that separates product defects from questions and account requests, so engineers only see tickets that need them.
The decision
Does this support issue need to go to engineering?
Evidence checks (asked in the same request)
- Technical failure: The message reports an error, crash, or failed request.
- Wide customer impact: Multiple users or production systems are affected.
- Usage question: The customer is asking how to use an existing feature.
Expected output: A probability from 0 to 1 that the issue needs engineering, 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 |
|---|---|---|---|
message | string | Yes | The customer's message, verbatim. Include the subject line if there is one. |
recent_releases | string | No | A short list of recent releases or known incidents, so the model can connect reports to changes. |
Worked examples
Reproducible API error after a release
Since yesterday's release, the /v2/invoices endpoint returns a 500 error for any request with more than 100 line items. Request ID req_8f2a. Reproducible every time.
A careful reviewer would say: Yes. A specific, reproducible server error tied to a release is a defect support cannot fix.
Run this exampleLooking for a setting
How do I add a second admin to our workspace? I can't find the setting.
A careful reviewer would say: No. A usage question that support or documentation can answer.
Run this example
Expected answers are human judgments written for this template, not model output.
How it works
Every unnecessary escalation interrupts an engineer; every missed one leaves a customer stuck. This predicate estimates which side of that line a ticket falls on.
Define "needs engineering" for your own organization. If support can restart jobs or change configuration, say so in the question, or tickets that support could handle will be escalated.
The evidence checks make the result reviewable. A high probability with no technical failure detected is worth a second look.
Human review and thresholds
Recommended review policy
Let confident "No" results stay with support automatically. Have a senior agent confirm "Yes" results before a ticket reaches engineering until you have measured how often the model is right.
Choosing thresholds
Weigh the cost of an engineer's interrupted hour against the cost of a customer waiting a day for an escalation that should have happened. Teams with a rotating on-call triager can afford a lower bar than teams where escalations go straight to feature developers.
- Starting automation threshold
- 85%
- Starting don’t-decide threshold
- 60%
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
- The model cannot check logs, reproduce the issue, or know about an incident unless you include that context.
- Vague reports ("it's broken") carry little evidence either way. Expect mid-range probabilities and plan for a clarifying question.
- Known issues with documented workarounds should usually stay with support. Supply the known-issues list in the input.
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": "engineering-escalation",
"title": "Engineering escalation",
"decides": "Whether a support issue needs engineering, or can be resolved by support.",
"question": {
"name": "decision",
"type": "predicate",
"instructions": "Does this support issue need to go to engineering?"
},
"evidenceChecks": [
{
"name": "factor_1",
"label": "Technical failure",
"type": "predicate",
"instructions": "The message reports an error, crash, or failed request."
},
{
"name": "factor_2",
"label": "Wide customer impact",
"type": "predicate",
"instructions": "Multiple users or production systems are affected."
},
{
"name": "factor_3",
"label": "Usage question",
"type": "predicate",
"instructions": "The customer is asking how to use an existing feature."
}
],
"inputs": [
{
"name": "message",
"type": "string",
"required": true,
"description": "The customer's message, verbatim. Include the subject line if there is one."
},
{
"name": "recent_releases",
"type": "string",
"required": false,
"description": "A short list of recent releases or known incidents, so the model can connect reports to changes."
}
],
"expectedOutput": "A probability from 0 to 1 that the issue needs engineering, plus one probability per evidence check.",
"examples": [
{
"title": "Reproducible API error after a release",
"input": "Since yesterday's release, the /v2/invoices endpoint returns a 500 error for any request with more than 100 line items. Request ID req_8f2a. Reproducible every time.",
"expected": "Yes"
},
{
"title": "Looking for a setting",
"input": "How do I add a second admin to our workspace? I can't find the setting.",
"expected": "No"
}
],
"startingPolicy": {
"automateAt": 0.85,
"abstainBelow": 0.6,
"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: "Since yesterday's release, the /v2/invoices endpoint returns a 500 error for any request with more than 100 line items. Request ID req_8f2a. Reproducible every time.",
questions: [
{
type: "predicate",
name: "decision",
instructions: "Does this support issue need to go to engineering?"
},
{
type: "predicate",
name: "factor_1",
instructions: "The message reports an error, crash, or failed request."
},
{
type: "predicate",
name: "factor_2",
instructions: "Multiple users or production systems are affected."
},
{
type: "predicate",
name: "factor_3",
instructions: "The customer is asking how to use an existing feature."
}
],
});
// 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 engineering-escalation.json, or browse all developer resources.
Need this decision tuned to your policy?
Related
- Score template
Ticket urgency
How urgently a support ticket needs a response, on a four-level rubric.
- Choice template
Feature request classification
Whether a message is a bug report, a feature request, a how-to question, or something else.
- Predicate template
Support escalation
Whether a conversation should move from a frontline agent to a senior one.
- 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
Decisions API tutorial
Start here. The request and response shapes, how to read each answer type safely, asking several questions about one input, and what the API does not do.
- 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.