Text decisions
Routing, checks and ratings over text and structured data.
The answers on this page show the shape of a response; the numbers are not from a real run.
Route a support ticket
One choice for the team, and noul questions for the flags you act on. Everything in one request.
{
"state": {
"channel": "email",
"plan": "Team, annual",
"message": "Hey, the export button on the reports page threw an error twice today. Not asking for a refund, I just want it fixed since we rely on this for our weekly report."
},
"questions": {
"team": {
"type": "choice",
"instructions": "Which team should handle this ticket?",
"criteria": {
"billing": "Payments, invoices, refunds, subscriptions.",
"technical": "Bugs, errors, outages, integration problems.",
"sales": "Pricing questions, upgrades, new purchases.",
"other": "Anything that fits none of the above."
}
},
"wants_refund": { "type": "noul", "instructions": "Is the customer asking for a refund?" },
"urgency": {
"type": "score",
"instructions": "How urgent is this for the customer?",
"criteria": [
"No time pressure.",
"Wants it soon, but work is not blocked.",
"Work is blocked or a deadline is at risk."
]
}
}
}team = answers["team"]
if team["confidence"] < 0.6:
queue = "triage" # not sure: a person looks at it
else:
queue = team["choice"]
priority = "high" if answers["urgency"]["score"] >= 1.5 else "normal"Check text against a rule
A noul with criteria states the rule on both sides. This is the pattern for moderation, policy checks and
guards on the output of another model.
{
"state": {
"policy": "Agents must not promise a delivery date. They may say when the order was shipped and link to tracking.",
"draft_reply": "Thanks for your patience! Your order shipped on Monday and will definitely arrive by Friday."
},
"questions": {
"violates_policy": {
"type": "noul",
"instructions": "Does `draft_reply` break `policy`?",
"criteria": {
"true": "The reply states or promises a date or day by which the order will arrive.",
"false": "The reply gives no arrival date; it may mention the shipping date or tracking."
}
}
}
}if answers["violates_policy"]["noul"] > 0.5:
send_back_for_rewrite(draft_reply)Because the check takes about a hundred milliseconds, it can run on every reply before it is sent.
Rate on a scale
score returns a number on your own scale, with the distribution behind it.
{
"state": {
"service": "checkout-api",
"alert": "p99 latency above 2 s for 12 minutes",
"error_rate": "0.4%",
"region": "eu-west-1",
"recent_deploy": "38 minutes ago"
},
"questions": {
"severity": {
"type": "score",
"instructions": "How severe is this alert?",
"criteria": [
"Informational. Nothing for anyone to do.",
"Minor. Look at it during working hours.",
"Serious. Customers notice; act today.",
"Critical. Page the on-call engineer now."
]
}
}
}severity = answers["severity"]
if severity["probabilities"]["3"] > 0.5:
page_on_call()
elif severity["score"] >= 1.5:
open_ticket()Thresholding on the probability of the top level, rather than on the average, pages only when the model puts most of its weight on "Critical".
Tag with several labels
For labels that are not exclusive, ask one noul per label in the same request.
{
"state": "Loved the new dashboard, but the mobile app logs me out every hour and support took three days to reply.",
"questions": {
"mentions_ui": { "type": "noul", "instructions": "Does the review talk about the interface or design?" },
"mentions_bug": { "type": "noul", "instructions": "Does the review report a bug or malfunction?" },
"mentions_support": { "type": "noul", "instructions": "Does the review talk about customer support?" },
"mentions_price": { "type": "noul", "instructions": "Does the review talk about price or billing?" }
}
}tags = [name for name, a in answers.items() if a["noul"] >= 0.5]Label a list of items
Use the batch endpoint: one call, one concurrent slot, the answers in order.
import os
import requests
QUESTIONS = {
"intent": {
"type": "choice",
"instructions": "What does the user want?",
"criteria": {
"cancel": "To cancel a subscription or an order.",
"status": "To know the status of an order or a request.",
"complaint": "To complain about a product or a service.",
"other": "Anything else.",
},
}
}
def label(messages):
response = requests.post(
"https://api.openinstinct.dev/v1/systemone/batch",
headers={"Authorization": f"Bearer {os.environ['OPENINSTINCT_API_KEY']}"},
json={"requests": [{"state": m, "questions": QUESTIONS} for m in messages]},
timeout=300,
)
response.raise_for_status()
return [
None if "error" in r else (r["answers"]["intent"]["choice"], r["answers"]["intent"]["confidence"])
for r in response.json()["responses"]
]A batch holds up to 256 requests; split longer lists.