diff --git a/docs.json b/docs.json
index 1e18a3b..2c3a5b8 100644
--- a/docs.json
+++ b/docs.json
@@ -1,7 +1,7 @@
{
"$schema": "https://mintlify.com/docs.json",
"banner": {
- "content": "๐ New: d1 โ our first decision model is now available! [Learn more โ](/lfm/models/decision-models)",
+ "content": "๐ New: Open d1 โ run decision models locally with d1-3B and d1-omni-600M! [Learn more โ](/lfm/models/decision-models)",
"dismissible": true
},
"theme": "mint",
diff --git a/lfm/models/complete-library.mdx b/lfm/models/complete-library.mdx
index 4dfca1f..eb11931 100644
--- a/lfm/models/complete-library.mdx
+++ b/lfm/models/complete-library.mdx
@@ -121,6 +121,8 @@ Quantization reduces model size and speeds up inference with minimal quality los
| [LFM2-2.6B-Transcript](/lfm/models/lfm2-2.6b-transcript) | LFM2 | [โ](https://huggingface.co/LiquidAI/LFM2-2.6B-Transcript) | [โ](https://huggingface.co/LiquidAI/LFM2-2.6B-Transcript-GGUF) | โ | [โ](https://huggingface.co/onnx-community/LFM2-2.6B-Transcript-ONNX) | Yes (TRL) |
| **Decision Models** | | | | | | |
-| [d1](/lfm/models/decision-models) | d1 | API | โ | โ | โ | No |
+| [d1-3B](/lfm/models/d1-3b) | d1 (Latest release) | [โ](https://huggingface.co/LiquidAI/d1-3B) | [โ](https://huggingface.co/LiquidAI/d1-3B-GGUF) | โ | โ | No |
+| [d1-omni-600M](/lfm/models/d1-omni-600m) | d1 (Latest release) | [โ](https://huggingface.co/LiquidAI/d1-omni-600M) | [โ](https://huggingface.co/LiquidAI/d1-omni-600M-GGUF) | โ | โ | No |
+| [d1](/lfm/models/d1) | d1 | API | โ | โ | โ | No |
Looking for an older model? Deprecated models and their recommended replacements are listed on the [Deprecations](/lfm/help/deprecations) page.
diff --git a/lfm/models/d1-3b.mdx b/lfm/models/d1-3b.mdx
new file mode 100644
index 0000000..86aa75c
--- /dev/null
+++ b/lfm/models/d1-3b.mdx
@@ -0,0 +1,132 @@
+---
+title: "d1-3B"
+description: "3B parameter multimodal decision model for text and images, built on LFM2.5-VL-3B"
+---
+
+โ Back to Decision Models
+
+d1-3B is a 3.1B parameter decision model built on [LFM2.5-VL-3B](/lfm/models/lfm25-vl-3b). It evaluates text, JSON, images, or a mix and returns calibrated Noul, Choice, and Score answers in one forward pass with zero output tokens.
+
+
"
+ }
+ ]
+}
+```
+
+### Multi-Image Input
+
+All questions in a request receive all images. The order of the images matters. Refer to images by position in the state or question instructions.
+
+
+
+ ```bash
+ REF_BASE64=$(base64 < image1.jpg | tr -d '\r\n')
+ INSPECT_BASE64=$(base64 < image2.jpg | tr -d '\r\n')
+
+ curl -s https://api.liquid.ai/decisions/v1/systemone \
+ -H "Authorization: Bearer $LIQUID_API_KEY" \
+ -H "Content-Type: application/json" \
+ --data-binary @- <
+
+ ```python
+ import base64
+ import os
+ from pathlib import Path
+
+ import requests
+
+ image1 = base64.b64encode(Path("image1.jpg").read_bytes()).decode("ascii")
+ image2 = base64.b64encode(Path("image2.jpg").read_bytes()).decode("ascii")
+
+ response = requests.post(
+ "https://api.liquid.ai/decisions/v1/systemone",
+ headers={"Authorization": f"Bearer {os.environ['LIQUID_API_KEY']}"},
+ json={
+ "model": "d1",
+ "state": "The first image shows a reference circuit board with no defects. The second image shows the board being inspected.",
+ "images": [
+ f"data:image/jpeg;base64,{image1}",
+ f"data:image/jpeg;base64,{image2}",
+ ],
+ "questions": {
+ "defect": {
+ "type": "noul",
+ "instructions": "Does the board in the second image have a visible defect compared with the reference board in the first image?",
+ }
+ },
+ },
+ )
+ ```
+
+
+ ```typescript
+ import { readFileSync } from "node:fs";
+
+ const image1 = readFileSync("image1.jpg").toString("base64");
+ const image2 = readFileSync("image2.jpg").toString("base64");
+
+ const response = await fetch("https://api.liquid.ai/decisions/v1/systemone", {
+ method: "POST",
+ headers: {
+ Authorization: `Bearer ${process.env.LIQUID_API_KEY!}`,
+ "Content-Type": "application/json",
+ },
+ body: JSON.stringify({
+ model: "d1",
+ state: "The first image shows a reference circuit board with no defects. The second image shows the board being inspected.",
+ images: [
+ `data:image/jpeg;base64,${image1}`,
+ `data:image/jpeg;base64,${image2}`,
+ ],
+ questions: {
+ defect: {
+ type: "noul",
+ instructions: "Does the board in the second image have a visible defect compared with the reference board in the first image?",
+ },
+ },
+ }),
+ });
+
+ ```
+
+
+
+**Response** (`answers` field):
+
+```json
+{
+ "defect": {
+ "type": "noul",
+ "noul": 0.92
+ }
+}
+```
+
+### Image Requirements
+
+| Requirement | Limit |
+|---|---|
+| Formats | JPEG (`image/jpeg`), PNG (`image/png`), WebP (`image/webp`), GIF (`image/gif`) |
+| Images per request | Up to 8 |
+| Request size | Keep the entire JSON body under 4.5 MB, including Base64 image data, state, and questions |
+| Total image patches | Up to 10,000 patches of 32 ร 32 pixels across all images in a request |
+| Aspect ratio | The longer side of each image can be at most 100 times the shorter side |
+
+Base64 encoding increases the request size compared with the original files. Resize or compress images before encoding them if the request is too large, and use the media type that matches each file.
+
+
+If a request returns ``The model `d1:free` does not accept images.``, use `d1`. If the same error names `d1`, image input is not available for that model on the endpoint you called.
+
+
+### Image Token Usage
+
+Each image is billed at 1.5 input tokens per 32 ร 32 pixel patch, rounded up per image:
+
+```text
+patches = ceil(width / 32) ร ceil(height / 32)
+image_tokens = ceil(patches ร 1.5)
+```
+
+For example, a 1024 ร 1024 image covers 1,024 patches and contributes 1,536 input tokens per question. Two questions about that image contribute 3,072 image tokens, plus the text tokens for each question.
+
+Every question is charged for its text and all the images again. These tokens are included in `usage.input_tokens` and charged at the model's input token rate. Image tokens also count toward each question's input token limit. `usage.output_tokens` remains `0`.
diff --git a/lfm/models/decision-models.mdx b/lfm/models/decision-models.mdx
index 6c0fc27..0516001 100644
--- a/lfm/models/decision-models.mdx
+++ b/lfm/models/decision-models.mdx
@@ -6,942 +6,90 @@ icon: "scale-balanced"
Decision models are a new class of AI model purpose-built for structured decisions. Instead of generating text token by token, a decision model evaluates a situation and returns calibrated probabilities across a fixed set of outcomes in a single call with zero generated tokens.
-Liquid's decision model evaluates text, images, or both. Use the same Noul, Choice, and Score questions to classify an image, inspect a part for defects, or make a decision from a screenshot.
+
+
-## Primitives
-
-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.
-
-- **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}`.
-
-- **Score**: A rate-on-a-scale question that returns a probability-weighted position on an ordered rubric. "How urgent is this?" with three levels might return a score of `1.85` (between "Medium" and "High"), with a probability distribution over each level.
-
-Pick the type that matches the shape of the answer your code needs.
-
-| If the answer is... | Use | Example |
-|---|---|---|
-| 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? |
-
-**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.
-
-**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.
-
-## Setup
-
-1. Go to [console.liquid.ai](https://console.liquid.ai). If you don't have an account yet, register and join an organization.
-2. Navigate to **Dashboard > API Keys**.
-3. Create a new key and copy it. Keys are prefixed with `liquid_`.
-
-Set the key as an environment variable:
-
-```bash
-export LIQUID_API_KEY="liquid_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
-```
-
-Install the SDK and create a client:
-
-
-
- For text-only inputs:
-
- ```bash
- pip install typesafe-sdk
- ```
-
- ```python
- import os
- from typesafe_sdk import TypeSafeClient
-
- client = TypeSafeClient(
- api_key=os.environ["LIQUID_API_KEY"],
- base_url="https://api.liquid.ai",
- )
- ```
-
- For [image inputs](#image-inputs), the SDK does not support images yet, so the image examples use [`requests`](https://pypi.org/project/requests/):
-
- ```bash
- pip install requests
- ```
-
-
- For text-only inputs:
-
- ```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",
- });
- ```
-
- For [image inputs](#image-inputs), the SDK does not support images yet, so the image examples use `fetch` instead.
-
-
-
-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 the following fields:
-
-1. **Model**: which decision model to use.
-2. **State**: the context the model should evaluate. This can be plain text (a customer message, an email, a log entry) or a JSON object with structured fields.
-3. **Questions**: one or more typed questions, each with a name, a type, and instructions. Choice and Score questions also take criteria that define the options or levels. You can ask multiple questions in the same call, and the model evaluates them all at once.
-4. **Images** (optional): images to evaluate alongside the state. Pass them in the top-level `images` array. See [Image Inputs](#image-inputs) for the request format and examples.
-
-
-
- ```bash
- curl -s https://api.liquid.ai/decisions/v1/systemone \
- -H "Authorization: Bearer $LIQUID_API_KEY" \
- -H "Content-Type: application/json" \
- -d '{
- "model": "d1",
- "state": "I have been waiting over three weeks for my order and nobody has responded to my emails. This is completely unacceptable.",
- "questions": {
- "is_complaint": {
- "type": "noul",
- "instructions": "Is this message a complaint from the customer?"
- }
- }
- }'
- ```
-
-
- ```python
- from typesafe_sdk import Noul
-
- result = client.system_one(
- model="d1",
- state="I have been waiting over three weeks for my order and nobody has responded to my emails. This is completely unacceptable.",
- questions={
- "is_complaint": Noul(
- instructions="Is this message a complaint from the customer?",
- ),
- },
- )
- print(result.answers["is_complaint"].noul) # 0.999
- ```
-
-
- ```typescript
- const result = await client.systemOne({
- model: "d1",
- state: "I have been waiting over three weeks for my order and nobody has responded to my emails. This is completely unacceptable.",
- questions: {
- is_complaint: {
- type: "noul",
- instructions: "Is this message a complaint from the customer?",
- },
- },
- });
- console.log(result.answers.is_complaint.noul); // 0.999
- ```
-
-
-
-**Response:**
-
-```json
-{
- "model": "d1",
- "answers": {
- "is_complaint": {
- "type": "noul",
- "noul": 0.999
- }
- },
- "usage": {
- "input_tokens": 84,
- "output_tokens": 0
- }
-}
-```
-
-**Reading the response:**
-
-- **`answers.is_complaint.noul`**: The probability that the answer is "yes." Here, `0.999` means a 0.999 probability that this is a complaint.
-- **`usage.output_tokens`**: Always `0`. Decision models do not generate tokens.
-- **`usage.input_tokens`**: The total input tokens across all questions, including image tokens when images are provided. Each question is charged for its text and all supplied images.
-
-The response contains one answer per question, keyed by the question name. A Noul answer is a single probability. Choice and Score answers also include a full probability distribution and a `confidence` value.
-
-## Usage Examples
-
-### Noul
-
-A Noul question returns a single probability between 0 and 1. Your code receives a float that you can threshold to make a binary decision, use as a weight, or pass directly to downstream logic. Values near 0 or 1 express a clear answer; values near 0.5 express genuine uncertainty.
-
-
-
- ```bash
- curl -s https://api.liquid.ai/decisions/v1/systemone \
- -H "Authorization: Bearer $LIQUID_API_KEY" \
- -H "Content-Type: application/json" \
- -d '{
- "model": "d1",
- "state": "You'\''re an absolute idiot and I hope your company goes bankrupt. I'\''m going to find out where you work.",
- "questions": {
- "is_harmful": {
- "type": "noul",
- "instructions": "Does this user message contain harmful, threatening, or abusive content?"
- }
- }
- }'
- ```
-
-
- ```python
- from typesafe_sdk import Noul
-
- result = client.system_one(
- model="d1",
- state="You're an absolute idiot and I hope your company goes bankrupt. I'm going to find out where you work.",
- questions={
- "is_harmful": Noul(
- instructions="Does this user message contain harmful, threatening, or abusive content?",
- ),
- },
- )
- ```
-
-
- ```typescript
- const result = await client.systemOne({
- model: "d1",
- state: "You're an absolute idiot and I hope your company goes bankrupt. I'm going to find out where you work.",
- questions: {
- is_harmful: {
- type: "noul",
- instructions: "Does this user message contain harmful, threatening, or abusive content?",
- },
- },
- });
- ```
-
-
-
-**Response** (`answers` field):
-
-```json
-{
- "is_harmful": {
- "type": "noul",
- "noul": 0.99
- }
-}
-```
-
-**Using the result:**
-
-```python
-p = result.answers["is_harmful"].noul
-
-if p > 0.8:
- action = "block"
-elif p < 0.2:
- action = "allow"
-else:
- action = "human_review"
-```
-
-### Choice
-
-A Choice question returns the selected option, a probability distribution over all options, and a `confidence` value. `confidence` summarizes how clear-cut the answer is: high when one option clearly wins, lower when the probability is spread across several options. The distribution tells you not just the top pick but how much probability mass sits on the runner-up, which is useful for flagging ambiguous cases or routing to a fallback.
-
-
-
- ```bash
- curl -s https://api.liquid.ai/decisions/v1/systemone \
- -H "Authorization: Bearer $LIQUID_API_KEY" \
- -H "Content-Type: application/json" \
- -d '{
- "model": "d1",
- "state": "Hi, I was charged twice for my subscription last month. The amounts are $29.99 on March 3rd and again on March 5th. Can you refund the duplicate charge?",
- "questions": {
- "intent": {
- "type": "choice",
- "instructions": "What is the primary topic of this customer inquiry?",
- "criteria": {
- "billing": "Questions about charges, invoices, refunds, or payment methods",
- "technical": "Bug reports, feature requests, or how-to questions about the product",
- "shipping": "Order status, delivery tracking, or shipping address changes",
- "returns": "Return requests, exchanges, or product condition issues",
- "account": "Login issues, profile updates, or subscription management"
- }
- }
- }
- }'
- ```
-
-
- ```python
- from typesafe_sdk import Choice
-
- result = client.system_one(
- model="d1",
- state="Hi, I was charged twice for my subscription last month. The amounts are $29.99 on March 3rd and again on March 5th. Can you refund the duplicate charge?",
- questions={
- "intent": Choice(
- instructions="What is the primary topic of this customer inquiry?",
- criteria={
- "billing": "Questions about charges, invoices, refunds, or payment methods",
- "technical": "Bug reports, feature requests, or how-to questions about the product",
- "shipping": "Order status, delivery tracking, or shipping address changes",
- "returns": "Return requests, exchanges, or product condition issues",
- "account": "Login issues, profile updates, or subscription management",
- },
- ),
- },
- )
- ```
-
-
- ```typescript
- const result = await client.systemOne({
- model: "d1",
- state: "Hi, I was charged twice for my subscription last month. The amounts are $29.99 on March 3rd and again on March 5th. Can you refund the duplicate charge?",
- questions: {
- intent: {
- type: "choice",
- instructions: "What is the primary topic of this customer inquiry?",
- criteria: {
- billing: "Questions about charges, invoices, refunds, or payment methods",
- technical: "Bug reports, feature requests, or how-to questions about the product",
- shipping: "Order status, delivery tracking, or shipping address changes",
- returns: "Return requests, exchanges, or product condition issues",
- account: "Login issues, profile updates, or subscription management",
- },
- },
- },
- });
- ```
-
-
-
-**Response** (`answers` field):
-
-```json
-{
- "intent": {
- "type": "choice",
- "choice": "billing",
- "probabilities": {
- "billing": 0.9997,
- "account": 0.0002,
- "returns": 0.00005,
- "shipping": 0.00003,
- "technical": 0.00002
- },
- "confidence": 0.9996
- }
-}
-```
-
-**Using the result:**
-
-```python
-intent = result.answers["intent"].choice
-confidence = result.answers["intent"].confidence
-
-queue_map = {
- "billing": "billing-team",
- "technical": "engineering-support",
- "shipping": "logistics",
- "returns": "returns-desk",
- "account": "account-management",
-}
+
+ Intent detection, ticket routing, content moderation, and triage.
+
-target_queue = queue_map[intent]
-print(f"Route to: {target_queue} (confidence: {confidence:.2f})")
-# Route to: billing-team (confidence: 1.00)
-```
+
+ Urgency scoring, quality assessment, LLM-as-judge replacement.
+
-### Score
+
+ Safety checks, guardrails, extraction validation, yes/no decisions.
+
-A Score question returns a continuous value across an ordered rubric you define, plus the probability distribution over each level. The value is the probability-weighted position on the scale: if you define four levels (0 through 3), a score of `2.9995` means the model places nearly all weight on the top level.
+
+ Visual inspection, image classification, voice-command routing.
+
-
-
- ```bash
- curl -s https://api.liquid.ai/decisions/v1/systemone \
- -H "Authorization: Bearer $LIQUID_API_KEY" \
- -H "Content-Type: application/json" \
- -d '{
- "model": "d1",
- "state": "Our production API is returning 500 errors on every request. All customers are affected. Revenue impact is approximately $12,000 per hour. Started 15 minutes ago.",
- "questions": {
- "urgency": {
- "type": "score",
- "instructions": "How urgent is this support request?",
- "criteria": [
- "Can wait: no immediate business impact, can be addressed in normal queue",
- "Should handle today: minor inconvenience or non-blocking issue",
- "Time-sensitive: noticeable customer impact, needs attention within hours",
- "Blocking revenue: critical system failure affecting customers or revenue"
- ]
- }
- }
- }'
- ```
-
-
- ```python
- from typesafe_sdk import Score
+
+
- result = client.system_one(
- model="d1",
- state="Our production API is returning 500 errors on every request. All customers are affected. Revenue impact is approximately $12,000 per hour. Started 15 minutes ago.",
- questions={
- "urgency": Score(
- instructions="How urgent is this support request?",
- criteria=[
- "Can wait: no immediate business impact, can be addressed in normal queue",
- "Should handle today: minor inconvenience or non-blocking issue",
- "Time-sensitive: noticeable customer impact, needs attention within hours",
- "Blocking revenue: critical system failure affecting customers or revenue",
- ],
- ),
- },
- )
- ```
-
-
- ```typescript
- const result = await client.systemOne({
- model: "d1",
- state: "Our production API is returning 500 errors on every request. All customers are affected. Revenue impact is approximately $12,000 per hour. Started 15 minutes ago.",
- questions: {
- urgency: {
- type: "score",
- instructions: "How urgent is this support request?",
- criteria: [
- "Can wait: no immediate business impact, can be addressed in normal queue",
- "Should handle today: minor inconvenience or non-blocking issue",
- "Time-sensitive: noticeable customer impact, needs attention within hours",
- "Blocking revenue: critical system failure affecting customers or revenue",
- ],
- },
- },
- });
- ```
-
-
+d1 Models Latest release
-**Response** (`answers` field):
+
-```json
-{
- "urgency": {
- "type": "score",
- "score": 2.9995,
- "confidence": 0.9995,
- "probabilities": {
- "0": 0.00001,
- "1": 0.00002,
- "2": 0.0004,
- "3": 0.9996
- },
- "legend": {
- "0": "Can wait: no immediate business impact, can be addressed in normal queue",
- "1": "Should handle today: minor inconvenience or non-blocking issue",
- "2": "Time-sensitive: noticeable customer impact, needs attention within hours",
- "3": "Blocking revenue: critical system failure affecting customers or revenue"
- }
- }
-}
-```
+
+ 3.1B ยท Recommended
-**Using the result:**
+ Multimodal decision model (text + images) built on LFM2.5-VL-3B.
+
-```python
-score = result.answers["urgency"].score
+
+ 587M ยท Smallest
-if score >= 2.5:
- print("ACTION: Page on-call engineer immediately")
-elif score >= 1.5:
- print("ACTION: Escalate to senior support")
-else:
- print("ACTION: Add to standard queue")
-```
+ Multimodal decision model (text + images or audio) built on LFM2.5-Encoder-350M.
+
-### Combining All Three Primitives
+
+ Hosted ยท API
-You can ask multiple questions of different types in the same call. The model evaluates all of them at once against the same state, so you get a complete decision in one round trip. This is useful when a single piece of input needs to be classified, routed, and prioritized together.
+ Hosted decision model with Python and TypeScript SDKs via the Liquid API.
+
-
-
- ```bash
- curl -s https://api.liquid.ai/decisions/v1/systemone \
- -H "Authorization: Bearer $LIQUID_API_KEY" \
- -H "Content-Type: application/json" \
- -d '{
- "model": "d1",
- "state": "{\"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.\", \"account\": {\"plan\": \"enterprise\", \"arr\": 52000, \"customer_since\": \"2022-03-15\"}}",
- "questions": {
- "is_bug": {
- "type": "noul",
- "instructions": "Is the customer reporting a software bug (as opposed to a usage question, feature request, or account issue)?"
- },
- "team": {
- "type": "choice",
- "instructions": "Which team should handle this ticket?",
- "criteria": {
- "billing": "Billing, invoicing, charges, and payment method issues",
- "engineering": "Software bugs, crashes, and technical malfunctions",
- "frontend": "UI/UX issues, display problems, and browser-specific bugs",
- "account": "Account setup, permissions, plan changes, and access issues"
- }
- },
- "urgency": {
- "type": "score",
- "instructions": "How urgent is this ticket? Consider business impact, time sensitivity, and customer tier.",
- "criteria": [
- "Low: no immediate impact, standard queue",
- "Medium: some business impact, handle within 24 hours",
- "High: significant business impact or time-sensitive, handle within 4 hours"
- ]
- }
- }
- }'
- ```
-
-
- ```python
- import json
- from typesafe_sdk import Choice, Noul, Score
+
- 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.",
- "account": {
- "plan": "enterprise",
- "arr": 52000,
- "customer_since": "2022-03-15",
- },
- }
-
- result = client.system_one(
- model="d1",
- state=json.dumps(ticket),
- questions={
- "is_bug": Noul(
- instructions="Is the customer reporting a software bug (as opposed to a usage question, feature request, or account issue)?",
- ),
- "team": Choice(
- instructions="Which team should handle this ticket?",
- criteria={
- "billing": "Billing, invoicing, charges, and payment method issues",
- "engineering": "Software bugs, crashes, and technical malfunctions",
- "frontend": "UI/UX issues, display problems, and browser-specific bugs",
- "account": "Account setup, permissions, plan changes, and access issues",
- },
- ),
- "urgency": Score(
- instructions="How urgent is this ticket? Consider business impact, time sensitivity, and customer tier.",
- criteria=[
- "Low: no immediate impact, standard queue",
- "Medium: some business impact, handle within 24 hours",
- "High: significant business impact or time-sensitive, handle within 4 hours",
- ],
- ),
- },
- )
- ```
-
-
- ```typescript
- const 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.",
- account: {
- plan: "enterprise",
- arr: 52000,
- customer_since: "2022-03-15",
- },
- };
-
- const result = await client.systemOne({
- model: "d1",
- state: JSON.stringify(ticket),
- questions: {
- is_bug: {
- type: "noul",
- instructions: "Is the customer reporting a software bug (as opposed to a usage question, feature request, or account issue)?",
- },
- team: {
- type: "choice",
- instructions: "Which team should handle this ticket?",
- criteria: {
- billing: "Billing, invoicing, charges, and payment method issues",
- engineering: "Software bugs, crashes, and technical malfunctions",
- frontend: "UI/UX issues, display problems, and browser-specific bugs",
- account: "Account setup, permissions, plan changes, and access issues",
- },
- },
- urgency: {
- type: "score",
- instructions: "How urgent is this ticket? Consider business impact, time sensitivity, and customer tier.",
- criteria: [
- "Low: no immediate impact, standard queue",
- "Medium: some business impact, handle within 24 hours",
- "High: significant business impact or time-sensitive, handle within 4 hours",
- ],
- },
- },
- });
- ```
-
-
-
-**Response** (`answers` field):
-
-```json
-{
- "is_bug": {
- "type": "noul",
- "noul": 0.9998
- },
- "team": {
- "type": "choice",
- "choice": "engineering",
- "probabilities": {
- "engineering": 0.80,
- "frontend": 0.18,
- "billing": 0.02,
- "account": 0.0005
- },
- "confidence": 0.74
- },
- "urgency": {
- "type": "score",
- "score": 1.996,
- "confidence": 0.995,
- "probabilities": {
- "0": 0.0002,
- "1": 0.004,
- "2": 0.996
- },
- "legend": {
- "0": "Low: no immediate impact, standard queue",
- "1": "Medium: some business impact, handle within 24 hours",
- "2": "High: significant business impact or time-sensitive, handle within 4 hours"
- }
- }
-}
-```
-
-**Using the result:**
-
-```python
-answers = result.answers
-
-is_bug = answers["is_bug"].noul > 0.7
-team = answers["team"].choice
-team_confidence = answers["team"].confidence
-urgency = answers["urgency"].score
-
-if is_bug and urgency > 1.5:
- print(f"ESCALATE to {team} on-call (SLA: 4h)")
-elif urgency > 1.0:
- print(f"PRIORITIZE in {team} queue (SLA: 24h)")
-else:
- print(f"QUEUE in {team} standard backlog")
-
-if team_confidence < 0.5:
- probs = answers["team"].probabilities
- runner_up = sorted(probs.items(), key=lambda x: x[1], reverse=True)[1]
- print(f"NOTE: Routing uncertain. Runner-up: {runner_up[0]} ({runner_up[1]:.0%})")
-
-# ESCALATE to engineering on-call (SLA: 4h)
-# The NOTE line only prints when team confidence is below 0.5.
-```
-
-## Image Inputs
-
-Send images to the decision model through the same `/decisions/v1/systemone` endpoint used for text decisions. Add an `images` array alongside `model`, `state`, and `questions`. The question types and response format stay the same.
-
-
-Vision is available through the Liquid API with the paid `d1` model. `d1:free` is text-only.
-
-
-Each image can be a Base64 data URL or an object with `content_type` and `base64` fields. Remote image URLs are not accepted. If an image is hosted online, download it and encode its contents before sending the request.
-
-### Single Image Input
-
-Pass a single image as a Base64 data URL in the `images` array. The model evaluates it alongside the text state.
-
-
-
- ```bash
- IMAGE_BASE64=$(base64 < image.jpg | tr -d '\r\n')
-
- curl -s https://api.liquid.ai/decisions/v1/systemone \
- -H "Authorization: Bearer $LIQUID_API_KEY" \
- -H "Content-Type: application/json" \
- --data-binary @- <
-
- ```python
- import base64
- import os
- from pathlib import Path
-
- import requests
-
- image = base64.b64encode(Path("image.jpg").read_bytes()).decode("ascii")
-
- response = requests.post(
- "https://api.liquid.ai/decisions/v1/systemone",
- headers={"Authorization": f"Bearer {os.environ['LIQUID_API_KEY']}"},
- json={
- "model": "d1",
- "state": "Camera image of a circuit board on the production line.",
- "images": [f"data:image/jpeg;base64,{image}"],
- "questions": {
- "defect": {
- "type": "noul",
- "instructions": "Does this circuit board have a visible defect?",
- }
- },
- },
- )
- ```
-
-
- ```typescript
- import { readFileSync } from "node:fs";
-
- const image = readFileSync("image.jpg").toString("base64");
-
- const response = await fetch("https://api.liquid.ai/decisions/v1/systemone", {
- method: "POST",
- headers: {
- Authorization: `Bearer ${process.env.LIQUID_API_KEY!}`,
- "Content-Type": "application/json",
- },
- body: JSON.stringify({
- model: "d1",
- state: "Camera image of a circuit board on the production line.",
- images: [`data:image/jpeg;base64,${image}`],
- questions: {
- defect: {
- type: "noul",
- instructions: "Does this circuit board have a visible defect?",
- },
- },
- }),
- });
-
- ```
-
-
-
-**Response** (`answers` field):
-
-```json
-{
- "defect": {
- "type": "noul",
- "noul": 0.85
- }
-}
-```
-
-**Using the result:**
-
-```python
-p = result["answers"]["defect"]["noul"]
-
-if p > 0.8:
- action = "reject"
-elif p < 0.2:
- action = "pass"
-else:
- action = "manual_review"
-```
-
-The object form is equivalent to a data URL and accepts `content_type` and `base64` fields without the `data:` prefix:
-
-```json
-{
- "images": [
- {
- "content_type": "image/jpeg",
- "base64": ""
- }
- ]
-}
-```
-
-### Multi-Image Input
-
-All questions in a request receive all images. The order of the images matters. Refer to images by position in the state or question instructions.
-
-
-
- ```bash
- REF_BASE64=$(base64 < image1.jpg | tr -d '\r\n')
- INSPECT_BASE64=$(base64 < image2.jpg | tr -d '\r\n')
-
- curl -s https://api.liquid.ai/decisions/v1/systemone \
- -H "Authorization: Bearer $LIQUID_API_KEY" \
- -H "Content-Type: application/json" \
- --data-binary @- <
-
- ```python
- import base64
- import os
- from pathlib import Path
-
- import requests
-
- image1 = base64.b64encode(Path("image1.jpg").read_bytes()).decode("ascii")
- image2 = base64.b64encode(Path("image2.jpg").read_bytes()).decode("ascii")
-
- response = requests.post(
- "https://api.liquid.ai/decisions/v1/systemone",
- headers={"Authorization": f"Bearer {os.environ['LIQUID_API_KEY']}"},
- json={
- "model": "d1",
- "state": "The first image shows a reference circuit board with no defects. The second image shows the board being inspected.",
- "images": [
- f"data:image/jpeg;base64,{image1}",
- f"data:image/jpeg;base64,{image2}",
- ],
- "questions": {
- "defect": {
- "type": "noul",
- "instructions": "Does the board in the second image have a visible defect compared with the reference board in the first image?",
- }
- },
- },
- )
- ```
-
-
- ```typescript
- import { readFileSync } from "node:fs";
-
- const image1 = readFileSync("image1.jpg").toString("base64");
- const image2 = readFileSync("image2.jpg").toString("base64");
-
- const response = await fetch("https://api.liquid.ai/decisions/v1/systemone", {
- method: "POST",
- headers: {
- Authorization: `Bearer ${process.env.LIQUID_API_KEY!}`,
- "Content-Type": "application/json",
- },
- body: JSON.stringify({
- model: "d1",
- state: "The first image shows a reference circuit board with no defects. The second image shows the board being inspected.",
- images: [
- `data:image/jpeg;base64,${image1}`,
- `data:image/jpeg;base64,${image2}`,
- ],
- questions: {
- defect: {
- type: "noul",
- instructions: "Does the board in the second image have a visible defect compared with the reference board in the first image?",
- },
- },
- }),
- });
-
- ```
-
-
-
-**Response** (`answers` field):
-
-```json
-{
- "defect": {
- "type": "noul",
- "noul": 0.92
- }
-}
-```
-
-### Image Requirements
-
-| Requirement | Limit |
-|---|---|
-| Formats | JPEG (`image/jpeg`), PNG (`image/png`), WebP (`image/webp`), GIF (`image/gif`) |
-| Images per request | Up to 8 |
-| Request size | Keep the entire JSON body under 4.5 MB, including Base64 image data, state, and questions |
-| Total image patches | Up to 10,000 patches of 32 ร 32 pixels across all images in a request |
-| Aspect ratio | The longer side of each image can be at most 100 times the shorter side |
-
-Base64 encoding increases the request size compared with the original files. Resize or compress images before encoding them if the request is too large, and use the media type that matches each file.
-
-
-If a request returns ``The model `d1:free` does not accept images.``, use `d1`. If the same error names `d1`, image input is not available for that model on the endpoint you called.
-
-
-### Image Token Usage
-
-Each image is billed at 1.5 input tokens per 32 ร 32 pixel patch, rounded up per image:
+## Primitives
-```text
-patches = ceil(width / 32) ร ceil(height / 32)
-image_tokens = ceil(patches ร 1.5)
-```
+Every question you ask a decision model uses one of three types:
-For example, a 1024 ร 1024 image covers 1,024 patches and contributes 1,536 input tokens per question. Two questions about that image contribute 3,072 image tokens, plus the text tokens for each question.
+| If the answer is... | Use | Example |
+|---|---|---|
+| 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? |
-Every question is charged for its text and all the images again. These tokens are included in `usage.input_tokens` and charged at the model's input token rate. Image tokens also count toward each question's input token limit. `usage.output_tokens` remains `0`.
+- **Noul**: A yes/no question that returns a probability between 0 and 1. "Is this message spam?" might return `0.92`.
+- **Choice**: A pick-one-from-many question that returns a probability distribution over named options.
+- **Score**: A rate-on-a-scale question that returns a probability-weighted position on an ordered rubric.
## When to Use Decision Models
Decision models are a good fit when the answer is a structured decision: classification, categorization, routing (tickets, emails, requests), scoring, triage, content moderation, guardrails and safety checks, LLM-as-judge replacement, agent tool-call approval, and model routing or cascades.
-With image input, the same primitives support visual inspection, image classification, and decisions based on screenshots.
+With image input, the same primitives support visual inspection, image classification, and decisions based on screenshots. With audio (d1-omni-600M), they support voice-command routing and spoken-intent detection.
Use a language model instead for free-form text generation, creative writing, multi-turn conversation, complex multi-step reasoning, open-ended Q&A, summarization, and code generation.
To move existing LLM calls to a decision model, see the [Decision Model Guide](/guides/decision-model-guide).
-## Next Steps
+## Examples
+
+
+
+
+ Pixel-art racing game using d1 Choice for lane selection.
+
+ **Platform:** Desktop
+
+
+
-- [Decision Model Guide](/guides/decision-model-guide) for migrating LLM classification, routing, and scoring calls to d1
-- [Model Library](/lfm/models/complete-library) for all available Liquid AI models
+
+ - [Liquid Console](https://console.liquid.ai)
+ - [OpenRouter API](https://openrouter.ai/liquid)
+ - [Vercel AI Gateway](https://vercel.com/ai-gateway/models/d1)
+
diff --git a/link-snapshot.yaml b/link-snapshot.yaml
index 80bb432..6a9f34c 100644
--- a/link-snapshot.yaml
+++ b/link-snapshot.yaml
@@ -153,6 +153,9 @@ active:
- /lfm/key-concepts/vision-capabilities
- /lfm/models/audio-models
- /lfm/models/complete-library
+ - /lfm/models/d1
+ - /lfm/models/d1-3b
+ - /lfm/models/d1-omni-600m
- /lfm/models/decision-models
- /lfm/models/lfm2-1.2b
- /lfm/models/lfm2-1.2b-extract