Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
262 changes: 262 additions & 0 deletions .mintlify/skills/decision-model/SKILL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,262 @@
---
name: decision-model
description: Integrate Liquid AI's d1 decision model or review existing LLM calls for migration to bounded classification, routing, scoring, reranking, and yes/no decisions. Use when the output is a decision over defined outcomes rather than generated text.
metadata:
author: Liquid AI
version: "1.0"
documentation: https://docs.liquid.ai/lfm/models/decision-models
---

# Liquid AI Decision Model Skill

Use Liquid AI's d1 decision model when the output should be a structured decision rather than generated text. Good fits include classification, routing, binary gates, scoring, reranking, triage, moderation, guardrails, LLM-as-judge replacement, agent tool-call approval, and model routing or cascades.

Use an LLM instead when the task requires free-form text generation, creative writing, multi-turn conversation, complex multi-step reasoning, open-ended Q&A, summarization, or code generation.

## Setup

Get an API key from [console.liquid.ai](https://console.liquid.ai):

1. Register or sign in and join an organization.
2. Go to **Dashboard > API Keys**.
3. Create a key and store it server-side, outside client bundles and logs. Keys are prefixed with `liquid_`.

Set the key as an environment variable:

```bash
export LIQUID_API_KEY="liquid_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
```

Requests require a Liquid AI API key and HTTPS access to this decision endpoint:

```text
POST https://console.liquid.ai/decisions/v1/systemone
```

## Request Shape

A decision model call contains:

- `model`: the decision model to use, such as `d1:free`.
- `state`: the context to evaluate, supplied as plain text or a JSON object.
- `questions`: one or more typed questions, each with a name, a `type`, and `instructions`.

Choice questions include `criteria` as an object mapping option names to descriptions. Score questions include `criteria` as an ordered array of rubric descriptions. Noul questions have no criteria. Multiple independent questions can be evaluated in one call against the same state. Use the decision request schema below; this is not a chat-completions endpoint.

## Primitives

Every question uses one of three types:

| If the answer is... | Use | Return shape |
|---|---|---|
| Yes or no, where the probability itself is useful | `noul` | A probability between 0 and 1 |
| One option from an unordered set | `choice` | A selected option, probability distribution, and confidence |
| A rating along an ordered rubric | `score` | A continuous score, probability distribution, legend, and confidence |

Pick the primitive based on what your code does next. Use Choice when code branches on a category. Use Score when code compares against an ordered threshold. Use Noul when code gates on a boolean probability.

Noul and Score are different. A Noul value near `0.5` means uncertainty between yes and no; it does not measure degree or intensity. Use Score for degree, severity, skill level, urgency, or similar ordered concepts.

Score levels are zero-based: an array of four levels produces a continuous score from `0` to `3`, computed as the probability-weighted position on the rubric. Preserve this meaning when replacing a one-based or integer LLM rating; update downstream thresholds or explicitly map the scale.

## Review and Migration

When asked to audit a project, trace candidate model calls through their prompts, schemas or parsers, and downstream consumers. Look for enums, booleans, numeric ratings, routing branches, and loops that score retrieved passages. For each candidate, identify the call site, the current output contract, the proposed primitive and criteria, and any required changes to thresholds or fallback behavior. A recommendation request should produce recommendations; implement replacements when the user requests code changes.

- Classification or routing to one category: use Choice with the labels the caller expects and descriptions that distinguish the options.
- Yes/no checks: use Noul and convert its probability to an action using explicit thresholds. Do not cast a nonzero probability directly to a boolean.
- Ordered severity, priority, quality, or urgency ratings: use Score with clearly defined levels.
- Reranking: evaluate each query/passage pair with Noul for binary relevance or Score for graded relevance, then sort descending. A Choice selects one option; it does not return a ranked list.
- Multiple independent decisions over the same input: combine them into named questions in one request. Keep separate calls when later questions depend on earlier results.

Keep generation calls for prose, code, summaries, or open-ended answers. In a mixed pipeline, replace only the bounded decision stage. Preserve the application's expected labels and error handling, and compare representative inputs with the existing behavior before switching callers.

## Reading Decisions

Read each result from `answers[question_name]`: `.noul` for yes probability, `.choice` for the selected label, or `.score` for the continuous rating. Choice and Score also expose `.probabilities` and `.confidence`; Score includes `.legend` mapping positions to rubric descriptions.

Treat HTTP or SDK errors as failures, not decisions; preserve the project's bounded retry policy and fallback behavior.

Use probabilities and confidence to handle ambiguous cases through an application-appropriate fallback. Set thresholds using representative data and the cost of incorrect decisions; example thresholds in the docs are illustrative. A model's tool-call approval verdict is an input to the application's policy, not permission to bypass existing authorization checks.

## cURL Example

```bash
curl -s https://api.liquid.ai/decisions/v1/systemone \
-H "Authorization: Bearer $LIQUID_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "d1:free",
"state": "I was charged twice for my subscription last month. Please refund the duplicate charge today.",
"questions": {
"route": {
"type": "choice",
"instructions": "Which team should handle this request?",
"criteria": {
"billing": "Charges, payments, and refunds",
"technical": "Product bugs and outages",
"account": "Login and account settings"
}
},
"urgency": {
"type": "score",
"instructions": "How urgent is this request?",
"criteria": [
"Routine: no immediate impact",
"Time-sensitive: should handle today",
"Critical: immediate harm or system failure"
]
},
"wants_refund": {
"type": "noul",
"instructions": "Does the customer explicitly request a refund?"
}
}
}'
```

Example response:

```json
{
"model": "d1:free",
"answers": {
"route": {
"type": "choice",
"choice": "billing",
"probabilities": {
"billing": 0.9997,
"account": 0.0002,
"technical": 0.0001
},
"confidence": 0.9996
},
"urgency": {
"type": "score",
"score": 1.2,
"confidence": 0.85,
"probabilities": {
"0": 0.05,
"1": 0.70,
"2": 0.25
},
"legend": {
"0": "Routine: no immediate impact",
"1": "Time-sensitive: should handle today",
"2": "Critical: immediate harm or system failure"
}
},
"wants_refund": {
"type": "noul",
"noul": 0.99
}
},
"usage": {
"input_tokens": 84,
"output_tokens": 0
}
}
```

Decision models do not generate output tokens, so `usage.output_tokens` is `0`.

## Python Example

```bash
pip install typesafe-sdk
```

```python
import os
from typesafe_sdk import TypeSafeClient, Choice, Noul, Score

client = TypeSafeClient(
api_key=os.environ["LIQUID_API_KEY"],
base_url="https://api.liquid.ai",
)

result = client.system_one(
model="d1:free",
state="I was charged twice for my subscription last month.",
questions={
"route": Choice(
instructions="Which team should handle this request?",
criteria={
"billing": "Charges, payments, and refunds",
"technical": "Product bugs and outages",
"account": "Login and account settings",
},
),
"wants_refund": Noul(
instructions="Does the customer explicitly request a refund?",
),
"urgency": Score(
instructions="How urgent is this request?",
criteria=[
"Routine: no immediate impact",
"Time-sensitive: should handle today",
"Critical: immediate harm or system failure",
],
),
},
)

print(result.answers["route"].choice) # "billing"
print(result.answers["route"].confidence) # 0.99
print(result.answers["wants_refund"].noul) # 0.99
print(result.answers["urgency"].score) # 1.2
```

## TypeScript SDK

```bash
npm install @typesafe-ai/sdk
```

```typescript
import { TypeSafeClient } from "@typesafe-ai/sdk";

const client = new TypeSafeClient({
apiKey: process.env.LIQUID_API_KEY!,
baseURL: "https://api.liquid.ai",
});

const result = await client.systemOne({
model: "d1:free",
state: "I was charged twice for my subscription last month.",
questions: {
route: {
type: "choice",
instructions: "Which team should handle this request?",
criteria: {
billing: "Charges, payments, and refunds",
technical: "Product bugs and outages",
account: "Login and account settings",
},
},
wants_refund: {
type: "noul",
instructions: "Does the customer explicitly request a refund?",
},
urgency: {
type: "score",
instructions: "How urgent is this request?",
criteria: [
"Routine: no immediate impact",
"Time-sensitive: should handle today",
"Critical: immediate harm or system failure",
],
},
},
});

console.log(result.answers.route.choice); // "billing"
console.log(result.answers.route.confidence); // 0.99
console.log(result.answers.wants_refund.noul); // 0.99
console.log(result.answers.urgency.score); // 1.2
```

## References

- [Decision Models](https://docs.liquid.ai/lfm/models/decision-models): primitives, setup, API examples, and response fields
- [Decision Model Guide](https://docs.liquid.ai/guides/decision-model-guide): migration examples from LLM calls to d1
6 changes: 6 additions & 0 deletions guides/decision-model-guide.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,11 @@

If you use an LLM to classify text, route requests, score content, or make yes/no decisions, you are paying for text generation to get a structured answer. Decision models return typed decisions directly without generating tokens, parsing JSON, or validating schemas.

This guide shows when and how to migrate these calls from LLMs to the [d1 decision model](/lfm/models/decision-models).

Check warning on line 8 in guides/decision-model-guide.mdx

View check run for this annotation

Mintlify / Mintlify Validation (liquidai) - vale-spellcheck

guides/decision-model-guide.mdx#L8

Did you really mean 'LLMs'?

## When to Migrate

Migrate when the LLM's output is a **bounded decision**, meaning the set of possible answers is known before the call.

Check warning on line 12 in guides/decision-model-guide.mdx

View check run for this annotation

Mintlify / Mintlify Validation (liquidai) - vale-spellcheck

guides/decision-model-guide.mdx#L12

Did you really mean 'LLM's'?

| Task | LLM pattern | Primitive |
|---|---|---|
Expand All @@ -24,7 +24,7 @@

- **Text generation**: drafting emails, summaries, reports, code
- **Open-ended Q&A**: answering user questions in natural language
- **Multi-turn conversation**: chatbots and copilots

Check warning on line 27 in guides/decision-model-guide.mdx

View check run for this annotation

Mintlify / Mintlify Validation (liquidai) - vale-spellcheck

guides/decision-model-guide.mdx#L27

Did you really mean 'chatbots'?
- **Complex reasoning**: multi-step logic, math, planning

If the answer is one of N known options, use a decision model. If the answer is a new string the model must compose, use an LLM.
Expand All @@ -42,10 +42,16 @@

Install the relevant SDK and configure your client. The LLM examples use the OpenAI SDK, which works with any OpenAI-compatible endpoint. The decision model examples use the [TypeSafe SDK](https://pypi.org/project/typesafe-sdk/) to call the [d1 decision model](/lfm/models/decision-models) through the Liquid AI API. To get an API key, see [Decision Models: Setup](/lfm/models/decision-models#setup).

For larger migrations, you can hand your coding agent Liquid's decision-model skill before it audits the codebase:

```text
Load https://docs.liquid.ai/.well-known/skills/decision-model/skill.md, then inspect this project for generated-text calls that are really bounded decisions. Recommend d1 replacements for classification, routing, scoring, reranking, and yes/no gates.
```

<Tabs>
<Tab title="LLM">
```bash
pip install openai pydantic

Check warning on line 54 in guides/decision-model-guide.mdx

View check run for this annotation

Mintlify / Mintlify Validation (liquidai) - vale-spellcheck

guides/decision-model-guide.mdx#L54

Did you really mean 'openai'?

Check warning on line 54 in guides/decision-model-guide.mdx

View check run for this annotation

Mintlify / Mintlify Validation (liquidai) - vale-spellcheck

guides/decision-model-guide.mdx#L54

Did you really mean 'pydantic'?
```

```python
Expand Down Expand Up @@ -86,7 +92,7 @@
<Tabs>
<Tab title="LLM">
```python
from pydantic import BaseModel

Check warning on line 95 in guides/decision-model-guide.mdx

View check run for this annotation

Mintlify / Mintlify Validation (liquidai) - vale-spellcheck

guides/decision-model-guide.mdx#L95

Did you really mean 'pydantic'?
from typing import Literal

class Classification(BaseModel):
Expand All @@ -111,7 +117,7 @@
</Tab>
<Tab title="Decision Model">
```python
from typesafe_sdk import Choice

Check warning on line 120 in guides/decision-model-guide.mdx

View check run for this annotation

Mintlify / Mintlify Validation (liquidai) - vale-spellcheck

guides/decision-model-guide.mdx#L120

Did you really mean 'typesafe_sdk'?

inquiry = "I was charged twice for my subscription last month."

Expand Down Expand Up @@ -143,7 +149,7 @@
</Tabs>

**What changes:**
- Options are defined inline with descriptions. No Pydantic model or JSON schema needed.

Check warning on line 152 in guides/decision-model-guide.mdx

View check run for this annotation

Mintlify / Mintlify Validation (liquidai) - vale-spellcheck

guides/decision-model-guide.mdx#L152

Did you really mean 'Pydantic'?
- You get a probability distribution over all options alongside the top pick, plus a `confidence` value that summarizes how clear-cut the answer is.
- Zero output tokens generated. The model evaluates all options in a single call.
- Each option's description lives next to its label in `criteria` instead of in a separate prompt.
Expand All @@ -155,7 +161,7 @@
<Tabs>
<Tab title="LLM">
```python
from pydantic import BaseModel

Check warning on line 164 in guides/decision-model-guide.mdx

View check run for this annotation

Mintlify / Mintlify Validation (liquidai) - vale-spellcheck

guides/decision-model-guide.mdx#L164

Did you really mean 'pydantic'?
from typing import Literal

class Route(BaseModel):
Expand Down Expand Up @@ -183,7 +189,7 @@
</Tab>
<Tab title="Decision Model">
```python
from typesafe_sdk import Choice

Check warning on line 192 in guides/decision-model-guide.mdx

View check run for this annotation

Mintlify / Mintlify Validation (liquidai) - vale-spellcheck

guides/decision-model-guide.mdx#L192

Did you really mean 'typesafe_sdk'?

user_message = "What's the weather like today?"

Expand Down Expand Up @@ -225,7 +231,7 @@
<Tabs>
<Tab title="LLM">
```python
from pydantic import BaseModel

Check warning on line 234 in guides/decision-model-guide.mdx

View check run for this annotation

Mintlify / Mintlify Validation (liquidai) - vale-spellcheck

guides/decision-model-guide.mdx#L234

Did you really mean 'pydantic'?

class ModerationResult(BaseModel):
is_harmful: bool
Expand All @@ -249,7 +255,7 @@
</Tab>
<Tab title="Decision Model">
```python
from typesafe_sdk import Noul

Check warning on line 258 in guides/decision-model-guide.mdx

View check run for this annotation

Mintlify / Mintlify Validation (liquidai) - vale-spellcheck

guides/decision-model-guide.mdx#L258

Did you really mean 'typesafe_sdk'?

Check warning on line 258 in guides/decision-model-guide.mdx

View check run for this annotation

Mintlify / Mintlify Validation (liquidai) - vale-spellcheck

guides/decision-model-guide.mdx#L258

Did you really mean 'Noul'?

user_message = "You're an absolute idiot and I hope your company goes bankrupt."

Expand Down Expand Up @@ -287,7 +293,7 @@
<Tabs>
<Tab title="LLM">
```python
from pydantic import BaseModel, Field

Check warning on line 296 in guides/decision-model-guide.mdx

View check run for this annotation

Mintlify / Mintlify Validation (liquidai) - vale-spellcheck

guides/decision-model-guide.mdx#L296

Did you really mean 'pydantic'?
from typing import Literal

class UrgencyRating(BaseModel):
Expand Down Expand Up @@ -322,7 +328,7 @@
</Tab>
<Tab title="Decision Model">
```python
from typesafe_sdk import Score

Check warning on line 331 in guides/decision-model-guide.mdx

View check run for this annotation

Mintlify / Mintlify Validation (liquidai) - vale-spellcheck

guides/decision-model-guide.mdx#L331

Did you really mean 'typesafe_sdk'?

ticket_text = (
"Our production API is returning 500 errors on every request. "
Expand Down Expand Up @@ -360,14 +366,14 @@
- You get the full probability distribution across all levels, so you can detect ambiguous cases.
- No JSON parsing, no schema validation, no retries on malformed output.

### Reranking

Check warning on line 369 in guides/decision-model-guide.mdx

View check run for this annotation

Mintlify / Mintlify Validation (liquidai) - vale-spellcheck

guides/decision-model-guide.mdx#L369

Did you really mean 'Reranking'?

In retrieval-augmented generation (RAG) pipelines, a common pattern uses an LLM to score the relevance of each retrieved chunk before passing results to the generation step.

<Tabs>
<Tab title="LLM">
```python
from pydantic import BaseModel, Field

Check warning on line 376 in guides/decision-model-guide.mdx

View check run for this annotation

Mintlify / Mintlify Validation (liquidai) - vale-spellcheck

guides/decision-model-guide.mdx#L376

Did you really mean 'pydantic'?
from typing import Literal

class RelevanceScore(BaseModel):
Expand Down Expand Up @@ -406,7 +412,7 @@
</Tab>
<Tab title="Decision Model">
```python
from typesafe_sdk import Noul

Check warning on line 415 in guides/decision-model-guide.mdx

View check run for this annotation

Mintlify / Mintlify Validation (liquidai) - vale-spellcheck

guides/decision-model-guide.mdx#L415

Did you really mean 'typesafe_sdk'?

query = "How do I reset my API key?"
chunks = [
Expand Down Expand Up @@ -451,7 +457,7 @@
<Tabs>
<Tab title="LLM">
```python
from pydantic import BaseModel

Check warning on line 460 in guides/decision-model-guide.mdx

View check run for this annotation

Mintlify / Mintlify Validation (liquidai) - vale-spellcheck

guides/decision-model-guide.mdx#L460

Did you really mean 'pydantic'?
from typing import Literal

message = (
Expand Down Expand Up @@ -504,7 +510,7 @@
</Tab>
<Tab title="Decision Model">
```python
from typesafe_sdk import Choice, Noul, Score

Check warning on line 513 in guides/decision-model-guide.mdx

View check run for this annotation

Mintlify / Mintlify Validation (liquidai) - vale-spellcheck

guides/decision-model-guide.mdx#L513

Did you really mean 'typesafe_sdk'?

message = (
"The checkout page crashes with a white screen whenever I try to apply a promo code. "
Expand Down
6 changes: 6 additions & 0 deletions lfm/models/decision-models.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@

Every question you ask a decision model uses one of three types:

- **Noul**: A yes/no question that returns a probability between 0 and 1. Think of it as a boolean on a sliding scale. "Is this message spam?" might return `0.92`, meaning a 0.92 probability that the answer is yes.

Check warning on line 13 in lfm/models/decision-models.mdx

View check run for this annotation

Mintlify / Mintlify Validation (liquidai) - vale-spellcheck

lfm/models/decision-models.mdx#L13

Did you really mean 'Noul'?

- **Choice**: A pick-one-from-many question that returns a probability distribution over named options. "Which department should handle this?" might return `{"billing": 0.65, "technical": 0.30, "account": 0.05}`.

Expand All @@ -22,11 +22,11 @@
|---|---|---|
| Pick one from a set of unordered categories | **Choice** | Which department handles this ticket? |
| Rate something along an ordered scale with defined levels | **Score** | How severe is this bug? |
| Yes or no, where the probability itself is useful | **Noul** | Does this message contain personal data? |

Check warning on line 25 in lfm/models/decision-models.mdx

View check run for this annotation

Mintlify / Mintlify Validation (liquidai) - vale-spellcheck

lfm/models/decision-models.mdx#L25

Did you really mean 'Noul'?

**Noul vs Score**: A Noul at 0.5 means maximum uncertainty between yes and no. It says nothing about degree or intensity. If you want to measure degree (skill level, frustration, severity), use a Score with defined levels. If you need a yes/no gate, use a Noul.

Check warning on line 27 in lfm/models/decision-models.mdx

View check run for this annotation

Mintlify / Mintlify Validation (liquidai) - vale-spellcheck

lfm/models/decision-models.mdx#L27

Did you really mean 'Noul'?

Check warning on line 27 in lfm/models/decision-models.mdx

View check run for this annotation

Mintlify / Mintlify Validation (liquidai) - vale-spellcheck

lfm/models/decision-models.mdx#L27

Did you really mean 'Noul'?

Check warning on line 27 in lfm/models/decision-models.mdx

View check run for this annotation

Mintlify / Mintlify Validation (liquidai) - vale-spellcheck

lfm/models/decision-models.mdx#L27

Did you really mean 'Noul'?

**When the answer could fit more than one type**, think about what your code does next. If it branches on a category, use a Choice. If it compares against a threshold on a continuum, use a Score. If it gates on a boolean, use a Noul.

Check warning on line 29 in lfm/models/decision-models.mdx

View check run for this annotation

Mintlify / Mintlify Validation (liquidai) - vale-spellcheck

lfm/models/decision-models.mdx#L29

Did you really mean 'Noul'?

## Setup

Expand All @@ -40,6 +40,12 @@
export LIQUID_API_KEY="liquid_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
```

You can also use the following prompt to give your agent to enable it to use Liquid AI's decision models.

```text
Load https://docs.liquid.ai/.well-known/skills/decision-model/skill.md, then inspect this project for generated-text calls that are really bounded decisions. Recommend d1 replacements for classification, routing, scoring, reranking, and yes/no gates.
```

## Your First Call

A single API call contains three things:
Expand Down Expand Up @@ -73,7 +79,7 @@

```python
import os
from typesafe_sdk import TypeSafeClient, Noul

Check warning on line 82 in lfm/models/decision-models.mdx

View check run for this annotation

Mintlify / Mintlify Validation (liquidai) - vale-spellcheck

lfm/models/decision-models.mdx#L82

Did you really mean 'Noul'?

client = TypeSafeClient(
api_key=os.environ["LIQUID_API_KEY"],
Expand Down Expand Up @@ -256,7 +262,7 @@
</Tab>
<Tab title="Python">
```python
from typesafe_sdk import Choice

Check warning on line 265 in lfm/models/decision-models.mdx

View check run for this annotation

Mintlify / Mintlify Validation (liquidai) - vale-spellcheck

lfm/models/decision-models.mdx#L265

Did you really mean 'typesafe_sdk'?

result = client.system_one(
model="d1:free",
Expand Down Expand Up @@ -367,7 +373,7 @@
</Tab>
<Tab title="Python">
```python
from typesafe_sdk import Score

Check warning on line 376 in lfm/models/decision-models.mdx

View check run for this annotation

Mintlify / Mintlify Validation (liquidai) - vale-spellcheck

lfm/models/decision-models.mdx#L376

Did you really mean 'typesafe_sdk'?

result = client.system_one(
model="d1:free",
Expand Down Expand Up @@ -489,7 +495,7 @@
<Tab title="Python">
```python
import json
from typesafe_sdk import Choice, Noul, Score

Check warning on line 498 in lfm/models/decision-models.mdx

View check run for this annotation

Mintlify / Mintlify Validation (liquidai) - vale-spellcheck

lfm/models/decision-models.mdx#L498

Did you really mean 'typesafe_sdk'?

ticket = {
"message": "The checkout page crashes with a white screen whenever I try to apply a promo code. I've tried three different browsers. This is blocking a $4,200 order for our team and we need to place it before our procurement window closes on Friday.",
Expand Down
Loading