{"slug": "decision-models-in-hugging-face", "title": "Decision Models in Hugging Face", "summary": "Hugging Face published a blog post introducing \"decision models,\" a model class that returns a probability distribution over predefined answer choices instead of generating text token by token, with the interface defined as \"State + Questions + Allowed Answers → Decisions + Probabilities.\" The post credits TypeSafe AI with introducing the concept as \"Jev\" and a \"System One model,\" and demonstrates a Transformers pipeline call to the model \"autotrust/GEV-26B-Decide\" that routed a duplicate-charge support ticket to \"billing\" with a confidence of 0.9974000453948975 and a billing probability of 0.9982666969299316. Hugging Face argues prompting an LLM for JSON risks invalid output, unexpected keys, or answers outside the allowed choices, and that constrained decoding helps but does not eliminate the problem.", "body_md": "# \n\t\tDecision Models in Hugging Face\n\t\n\n [Update on GitHub](https://github.com/huggingface/blog/blob/main/decision.md)\n\nLarge Language Models (LLMs) are exceptionally good at generating text. We use them to answer questions, write code, reason about problems, and so much more. *But not every problem requires generating text.*\n\nConsider a customer support system receiving the following message:\n\n\"I was charged twice for my subscription. I need a refund today.\"\n\nThe system needs to determine which team should handle the request, how urgent it is, and whether the customer is requesting a refund.\n\nWe could ask an LLM to return a JSON object containing these answers.\n\n```\nllama cli -hf ggml-org/gemma-4-e4b-it-GGUF:Q4_0\n\n> We have the following customer support ticket, \"I was charged twice for my subscription. I need a refund today.\", which team should handle the request, how urgent it is, and whether the customer is requesting a refund. Give the answers in JSON.\n\n[Start thinking]\n...\n[end thinking]\n``` json\n{\n  \"team_to_handle\": \"Billing\",\n  \"urgency\": \"High\",\n  \"request_refund\": true\n}\n```\n\nBut what if the model could directly evaluate the available options and return a probability distribution over them, *without generating any text*?\n\n``` python\nfrom transformers import pipeline\n\ndecide = pipeline(\"decision\", model=\"autotrust/GEV-26B-Decide\")\ndecision = decide(\n    {\n        \"state\": \"I was charged twice for my order and want a refund.\",\n        \"questions\": {\n            \"department\": {\n                \"type\": \"choice\",\n                \"instructions\": \"Which team should handle this?\",\n                \"criteria\": {\n                    \"billing\": \"Payments and refunds\",\n                    \"technical\": \"Bugs and technical issues\",\n                    \"sales\": \"Pricing and subscriptions\"\n                }\n            },\n        }\n    }\n)\n\n# {\n#   'department': {\n#       'type': 'choice',\n#       'choice': 'billing',\n#       'confidence': 0.9974000453948975,\n#       'probabilities': {\n#         'billing': 0.9982666969299316,\n#         'technical': 0.0010246571619063616,\n#         'sales': 0.0007087149424478412\n#       }\n#     }\n# }\n```\n\nThis is the key idea behind **decision models**.\n\n## \n\t\tWhat are decision models?\n\t\n\nA decision model takes some input context (state), evaluates a question with a set of predefined possible answers (primitives), and returns a structured decision along with probabilities. Instead of asking a model to generate an answer token by token, we ask it to assign probabilities to the answers that our application already understands.\n\n[TypeSafe AI introduced Jev](https://typesafe.ai/blog/introducing-system-one-models-and-jev), describing it as a [*System One model*](https://en.wikipedia.org/wiki/Thinking,_Fast_and_Slow). The name draws inspiration from the distinction between fast, intuitive thinking (System 1) and slower, deliberative thinking (System 2).\n\nThe community has converged to the term **decision model**, because it describes the model's computational role rather than invoking a particular theory of cognition. In the rest of the post we will refer to the models as \"decision models\" instead of \"system one models\". ([A poll on twitter deciding what we should be calling such models](https://x.com/ariG23498/status/2113220513158009022))\n\nFor a decision model, the fundamental interface is:\n\n```\nState + Questions + Allowed Answers → Decisions + Probabilities\n```\n\n## \n\t\tWhy not use LLMs for everything?\n\t\n\nWe could simply prompt an LLM to return a JSON object containing our decisions. In fact, this is how many applications already use language models for classification, routing, and other structured tasks.\n\nHowever, there are a few problems with this approach.\n\n- LLMs are not guaranteed to follow the requested schema: Even with explicit instructions, a model might produce invalid JSON, introduce unexpected keys, or return an answer outside the allowed choices.\n- Constrained decoding helps, but does not eliminate the computational overhead: Libraries such as [Outlines](https://github.com/dottxt-ai/outlines) and[XGrammar](https://github.com/mlc-ai/xgrammar) can enforce grammars or JSON schemas by restricting which tokens the model is allowed to generate at each step. This ensures the output follows the supported structural constraints, but introduces additional work.\n- Why generate an entire response: LLMs are designed for open-ended generation, but when our application only needs to choose between predefined answers, autoregressive decoding can be unnecessary work.\n\n## \n\t\tHow are decision models different from classification models?\n\t\n\nBefore understanding the interface of a decision model, it is useful to revisit two closely related approaches namely traditional classification and zero-shot classification.\n\n### \n\t\tTraditional classification\n\t\n\nSuppose we train a classifier that routes customer-support requests to three departments:\n\n- Billing\n- Technical support\n- Sales\n\nA conventional classification model learns a mapping from an input to a predefined set of labels. During training, the model learns to predict these labels from examples. A classification head typically produces one logit per class, and softmax turns those logits into a probability distribution.\n\nThe limitation here is that ***the output classes are baked into the model's classification head***.\n\nIf we introduce a fourth department, such as Legal, the existing classifier does not automatically acquire a corresponding output class. We may need to modify the head, collect training data, and **retrain** or adapt the model.\n\n### \n\t\tZero-shot classification\n\t\n\n[Zero-shot classification](https://huggingface.co/tasks/zero-shot-classification) addresses an important part of this limitation. Instead of requiring the classifier to be trained specifically on every output category, we supply the candidate labels at inference time.\n\nFor example:\n\n``` python\nfrom transformers import pipeline\n\nclassifier = pipeline(\n    \"zero-shot-classification\",\n    model=\"facebook/bart-large-mnli\",\n)\n\nclassifier(\n    \"My payment was deducted twice.\",\n    candidate_labels=[\"billing\", \"technical support\", \"sales\"],\n)\n\n# {'sequence': 'My payment was deducted twice.',\n#  'labels': ['billing', 'sales', 'technical support'],\n#  'scores': [0.8466812372207642, 0.0962134450674057, 0.05710534751415253]}\n```\n\nUnlike a conventional fixed-label classifier, the categories can change from one request to another. Let’s add another department, such as “Legal”, and see the model outputs.\n\n``` python\nfrom transformers import pipeline\n\nclassifier = pipeline(\n    \"zero-shot-classification\",\n    model=\"facebook/bart-large-mnli\",\n)\n\nclassifier(\n    \"My payment was deducted twice.\",\n    candidate_labels=[\"billing\", \"technical support\", \"sales\", \"legal\"],\n)\n\n# {'sequence': 'My payment was deducted twice.',\n#  'labels': ['billing', 'sales', 'technical support', 'legal'],\n#  'scores': [0.8185835480690002, 0.09302053600549698, 0.05521026626229286, 0.03318570926785469]}\n```\n\nOne common implementation uses a model trained for natural language inference (NLI). Each candidate label is converted into a hypothesis, and the model measures how strongly the input entails that hypothesis.\n\nThis already sounds quite similar to a decision model. And in many ways, it is.\n\n### \n\t\tWhere decision models differ\n\t\n\nDecision models extend this idea beyond simply assigning an input to a category. A decision model can accept several named questions about the same state, with different answer types. The types can be choosing between alternatives (choice), scoring an ordered scale (score), or estimating the probability that a statement is true (noul).\n\nMore importantly, its interface is designed around the **probability distribution over possible decisions**.\n\nConsider these three approaches:\n\n| Property | Classification | Zero-shot classification | Decision model | \n|---|---|---|---|\n| Probability over choices | Yes | Yes | Yes | \n| Labels defined at inference | No | Yes | Yes | \n| Multiple typed questions | No | No | Yes | \n| Ordered scoring and yes/no decisions | Task-specific | Possible with adaptation | Native primitives | \n\nThe advantage of decision models is not that they invented runtime-defined labels or probabilistic classification. It is that they organize these capabilities into a consistent interface, potentially backed by architectures and training procedures optimized specifically for decisions.\n\n## \n\t\tThe decision model interface\n\t\n\nA decision model request has the following two components:\n\n1. state\n2. questions\n\n### \n\t\tState\n\t\n\nThe state is the information the model should evaluate. It may be a string, a structured JSON object, or, other modalities for supported omni-modal models.\n\nFor example:\n\n```\n{\n  \"customer_message\": \"I was charged twice. Please refund me today.\",\n  \"subscription\": \"pro\",\n  \"previous_tickets\": 2\n}\n```\n\n### \n\t\tQuestions and their primitives\n\t\n\nQuestions describe what we want to know about the state. In the decision models interface, three fundamental primitives represent different forms of decisions:\n\n1. **Choice:** Select one of several possible answers.\n2. **Score:** Evaluate something on an ordered scale.\n3. **Noul:** Answer a yes/no question probabilistically.\n\nLet's go over them one by one.\n\n#### \n\t\tChoice: A probability distribution over options\n\t\n\nChoice is the most intuitive primitive and the closest to traditional classification.\n\nSuppose we ask:\n\nWhich department should handle this customer request?\n\nThe available options are Billing, Technical support, and Sales.\n\n``` python\nfrom transformers import pipeline\n\ndecide = pipeline(\"decision\", model=\"autotrust/GEV-26B-Decide\")\ndecision = decide(\n    {\n        \"state\": \"I was charged twice for my order and want a refund.\",\n        \"questions\": {\n            \"department\": {\n                \"type\": \"choice\",\n                \"instructions\": \"Which team should handle this?\",\n                \"criteria\": {\n                    \"billing\": \"Payments and refunds\",\n                    \"technical\": \"Bugs and technical issues\",\n                    \"sales\": \"Pricing and subscriptions\"\n                }\n            },\n        }\n    }\n)\n\n# {\n#   'department': {\n#     'type': 'choice',\n#     'choice': 'billing',\n#     'confidence': 0.9974000453948975,\n#     'probabilities': {\n#       'billing': 0.9982666969299316,\n#       'technical': 0.0010246571619063616,\n#       'sales': 0.0007087149424478412\n#     }\n#   }\n# }\n```\n\nThe model assigns a logit to each option. For logits ($z_1,\\ldots,z_K$), (with K classes) we can obtain the probabilities using softmax:\n\nHere, (K) is the number of choices.\n\nConsider this illustrative distribution:\n\n| Choice | Probability | \n|---|---|\n| Billing | 0.998 | \n| Technical support | 0.001 | \n| Sales | 0.001 | \n\nThe probabilities sum to one:\n\nThe model chooses the option with the largest probability:\n\nIn this case, the choice is Billing, with the probability of 0.998, but the remaining probabilities are useful too. They tell us how the model distributes its belief among the alternatives.\n\n#### \n\t\tScore: The expectation of an ordered distribution\n\t\n\nChoice works when there are several distinct alternatives. But what if we want to measure something on an ordered scale?\n\nConsider the question:\n\nHow urgent is this customer request?\n\nWe define three levels:\n\n- 0: Low urgency\n- 1: Medium urgency\n- 2: High urgency\n\n``` python\nfrom transformers import pipeline\n\ndecide = pipeline(\"decision\", model=\"autotrust/GEV-26B-Decide\")\ndecision = decide(\n    {\n        \"state\": \"I was charged twice for my order and want a refund.\",\n        \"questions\": {\n            \"urgency\": {\n                \"type\": \"score\",\n                \"instructions\": \"How urgent is the request?\",\n                \"criteria\": [\"low\", \"medium\", \"high\"]\n            },\n        }\n    }\n)\n\n# {\n#   'urgency': {\n#     'type': 'score',\n#     'score': 1.7053890228271484,\n#     'legend': {\n#       '0': 'low',\n#       '1': 'medium',\n#       '2': 'high'\n#     },\n#     'confidence': 0.5580834252759814,\n#     'probabilities': {\n#       '0': 0.014908230863511562,\n#       '1': 0.26479458808898926,\n#       '2': 0.7202972173690796\n#     }\n#   }\n# }\n```\n\nThe model again produces a probability distribution:\n\n| Level | Probability | \n|---|---|\n| 0 — Low | 0.10 | \n| 1 — Medium | 0.26 | \n| 2 — High | 0.72 | \n\nRather than returning only the most likely level, the Score primitive computes the **expected value of the level index**.\n\nFor a random variable (X) representing the level, the expectation is:\n\nFor our example:\n\nThe reported score is therefore `1.7`.\n\nThis does not mean that the model selected a fictional level halfway between medium and high. It means that the expectation of its probability distribution is 1.7.\n\n#### \n\t\tNoul: A Bernoulli decision\n\t\n\nThe third primitive is Noul, which represents a binary question.\n\nFor example:\n\nIs the customer requesting a refund?\n\n``` python\nfrom transformers import pipeline\n\ndecide = pipeline(\"decision\", model=\"autotrust/GEV-26B-Decide\")\ndecision = decide(\n    {\n        \"state\": \"I was charged twice for my order and want a refund.\",\n        \"questions\": {\n            \"refund\": {\n                \"type\": \"noul\",\n                \"instructions\": \"Is the customer requesting a refund?\"\n            }\n        }\n    }\n)\n\n# {\n#   'refund': {\n#     'type': 'noul',\n#     'noul': 0.9947046637535095\n#   }\n# }\n```\n\nRather than defining a list of choices, we ask the model to return the probability that the answer is true. We can understand this using the Bernoulli distribution (noul comes from Bernoulli).\n\nLet (Y) represent a binary outcome:\n\nwhere\n\nIf the model returns:\n\n```\n{\"type\": \"noul\", \"noul\": 0.92}\n```\n\nit assigns a probability of `0.92` to Yes and `0.08` to No.\n\nThe model is not randomly sampling a binary answer here. It returns the probability parameter itself, leaving the application to decide how to act on it.\n\n#### \n\t\tConfidence: How certain is the model?\n\t\n\nSo far, we have obtained probability distributions from the model. But the decision model interface also returns a field called `confidence` for Choice and Score.\n\nThe full distribution might contain several possible answers, and it is useful to summarize how concentrated the model's belief is. With `confidence` we achieve just that.\n\nFor a Choice with (K) options, the confidence is:\n\nwhere ($p_{\\max}$) is the largest predicted probability.\n\nThe intuition here is:\n\n- A uniform distribution has confidence 0. ($p_{\\max} = \\frac{1}{K}$). This means the model estimates that all choices are equally likely.\n- A distribution concentrated entirely on one option has confidence 1. ($p_{\\max} = 1$)\n- The larger the winning probability relative to a uniform distribution, the higher the confidence.\n\nIn our previous three-choice example, Billing had probability 0.80:\n\nNotice that the winning probability is 0.99, but the reported confidence is 0.98. The confidence normalizes the largest probability relative to the number of available options. In contrast, the ordered Score example only had a confidence of 0.558.\n\n## \n\t\tDecision models in the Hugging Face ecosystem\n\t\n\nDecision models are a young and fast-moving space. Each one makes decisions differently under the hood (heads that score the whole schema jointly, separate readouts on top of LLM backbones, edge-sized and multimodal variants, etc). This variety is healthy, but it comes at a cost. If every model exposes its own interface, every tool around it needs model-specific adaptations.\n\nOur goal at Hugging Face is to agree on a common **interface** without forcing a common **implementation**. A decision model should be free to work however it likes internally, as long as it accepts the same state and questions and returns the same typed decisions. Once that contract exists, the rest of the ecosystem can build on it once:\n\n- inference engines like llama.cpp can serve any decision model through the same API\n- the Hub can package and surface them consistently\n- and training tools can target shared primitives instead of individual architectures\n\nThe rest of this section walks through each of these pieces.\n\n### \n\t\t1. Serving with Transformers\n\t\n\nTransformers now supports the `DecisionPipeline`, `AutoModelForDecision`, and the `DecisionConfig` classes. These follow the same overall structure of the pipeline and model classes in `transformers` but are tailor made for decision models.\n\n``` python\nfrom transformers import pipeline\n\ndecide = pipeline(\"decision\", model=\"autotrust/GEV-26B-Decide\")\nprint(decide)\n\n# DecisionPipeline: {'model': 'JevForDecision', 'dtype': 'bfloat16', 'device': 'cuda', 'input_modalities': 'text'}\n```\n\nOne can also inspect the configuration and the model like so:\n\n``` python\nfrom transformers import AutoModelForDecision, DecisionConfig\n\nmodel_id = \"autotrust/GEV-26B-Decide\"\nconfig = DecisionConfig.from_pretrained(model_id)\nmodel = AutoModelForDecision.from_pretrained(model_id)\n```\n\n[Transformers also supports the `/v1/systemone` endpoint](https://huggingface.co/docs/transformers/main/en/serve-cli/serving#v1systemone).\n\nWe can start a local server using the serving dependencies:\n\n```\npip install \"transformers[serving]\"\ntransformers serve\n```\n\nUsing a compatible version of Transformers, we can then send a decision request:\n\n```\ncurl http://localhost:8000/v1/systemone \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\n    \"model\": \"autotrust/GEV-26B-Decide\",\n    \"state\": \"I was charged twice. Please refund me today.\",\n    \"questions\": {\n      \"department\": {\n        \"type\": \"choice\",\n        \"instructions\": \"Which team should handle this?\",\n        \"criteria\": {\n          \"billing\": \"Payments and refunds\",\n          \"technical\": \"Bugs and technical issues\",\n          \"sales\": \"Pricing and subscriptions\"\n        }\n      },\n      \"urgency\": {\n        \"type\": \"score\",\n        \"instructions\": \"How urgent is the request?\",\n        \"criteria\": [\"low\", \"medium\", \"high\"]\n      },\n      \"refund\": {\n        \"type\": \"noul\",\n        \"instructions\": \"Is the customer requesting a refund?\"\n      }\n    }\n  }'\n```\n\nThe response contains three named answers with the corresponding typed results and probabilities.\n\n```\n{\n  \"model\":\"autotrust/GEV-26B-Decide\",\n  \"answers\":{\n    \"department\":{\n      \"type\":\"choice\",\n      \"choice\":\"billing\",\n      \"confidence\":0.9974000453948975,\n      \"probabilities\":{\n        \"billing\":0.9982666969299316,\n        \"technical\":0.0010246571619063616,\n        \"sales\":0.0007087149424478412\n        }\n    },\n    \"urgency\":{\n      \"type\":\"score\",\n      \"score\":1.7525686174631119,\n      \"legend\":{\"0\":\"low\",\"1\":\"medium\",\"2\":\"high\"},\n      \"confidence\":0.6288529792800546,\n      \"probabilities\":{\n        \"0\":0.014000383205711842,\n        \"1\":0.2194305807352066,\n        \"2\":0.7665690183639526\n      }\n    },\n    \"refund\":{\n      \"type\":\"noul\",\n      \"noul\":0.9953224062919617\n    }\n  },\n  \"usage\":{\"input_tokens\":148,\"output_tokens\":0}\n}\n```\n\nAn interesting detail is that the above APIs works with compatible autoregressive language models too. Transformers constructs the decision prompts, evaluates the answer label logits in a batched forward pass, and applies softmax without generating response text. This means we can experiment with the decision interface **without** necessarily training a new model.\n\n### \n\t\t2. Serving with llama.cpp\n\t\n\n[llama.cpp also supports decision models](https://huggingface.co/blog/ggml-org/decision-models-in-llamacpp) using the same `/v1/systemone` API.\n\nFor example, we can launch a GGUF decision model from the Hub:\n\n```\nllama serve -hf ggml-org/Kev-4B-GGUF\n```\n\nThe default server runs on port 9931.\n\nWe can then send a request containing the same state and questions, using `http://localhost:9931/v1/systemone`. With the model selected by the server, we can omit the `model` field from the request.\n\nThe useful property is interface compatibility.\n\n```\ncurl http://localhost:9931/v1/systemone \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\n    \"model\": \"ggml-org/Kev-4B-GGUF\",\n    \"state\": \"I was charged twice. Please refund me today.\",\n    \"questions\": {\n      \"department\": {\n        \"type\": \"choice\",\n        \"instructions\": \"Which team should handle this?\",\n        \"criteria\": {\n          \"billing\": \"Payments and refunds\",\n          \"technical\": \"Bugs and technical issues\",\n          \"sales\": \"Pricing and subscriptions\"\n        }\n      },\n      \"urgency\": {\n        \"type\": \"score\",\n        \"instructions\": \"How urgent is the request?\",\n        \"criteria\": [\"low\", \"medium\", \"high\"]\n      },\n      \"refund\": {\n        \"type\": \"noul\",\n        \"instructions\": \"Is the customer requesting a refund?\"\n      }\n    }\n  }'\n```\n\n### \n\t\t3. Discovering models on the Hugging Face Hub\n\t\n\nHugging Face introduced a dedicated [`decision-model` tag](https://huggingface.co/models?other=decision-model&sort=trending) for discovering compatible models. This is useful because decision models do not have to share a single backbone or architecture.\n\nFor example, the ecosystem includes models based on encoder architectures such as ModernBERT, as well as models derived from larger generative language-model backbones.\n\n### \n\t\t4. Training decision models using Hugging Face tooling\n\t\n\nOnce we understand inference, the next question is whether we can adapt a decision model. Since decision models are integrated in transformers, we can fine-tune them with the `Trainer` API.\n\nBelow is a toy example that fine-tunes `JEV-9B` to route support requests. It is intentionally small, but it shows the parts that matter:\n\n- each example is a decision request (a `state` plus`questions` ) paired with the gold answer.\n- `model.decision_config.prepare_inputs` turns the request into model inputs, the same way it does at inference time.\n- the model returns one logit per option, so a `choice` question is trained with a plain cross-entropy loss over the options.\n\n``` python\nimport os; os.environ[\"CUDA_VISIBLE_DEVICES\"]=\"2\"\nimport torch\nimport torch.nn.functional as F\nfrom transformers import AutoTokenizer, AutoModelForDecision, Trainer, TrainingArguments\n\ncheckpoint = \"autotrust/JEV-9B\"\ntokenizer = AutoTokenizer.from_pretrained(checkpoint)\nmodel = AutoModelForDecision.from_pretrained(checkpoint)\n\nexamples = [\n    (\"I was charged twice. Please refund me.\", \"refund\"),\n    (\"My package has not arrived.\", \"shipping\"),\n    (\"The application crashes when I open it.\", \"technical\"),\n    (\"I want my money back.\", \"refund\"),\n    (\"Where is my delivery?\", \"shipping\"),\n    (\"I cannot log into my account.\", \"technical\"),\n]\n\noptions = {\n    \"refund\": \"Billing issues and refunds\",\n    \"shipping\": \"Orders and deliveries\",\n    \"technical\": \"Software and account issues\",\n}\n\ndef preprocess(text, label):\n    request = {\n        \"state\": text,\n        \"questions\": {\n            \"category\": {\n                \"type\": \"choice\",\n                \"instructions\": \"Classify the support request.\",\n                \"criteria\": options,\n            }\n        },\n    }\n    (inputs, questions), = model.decision_config.prepare_inputs(\n        request, tokenizer\n    )\n    inputs[\"marks\"] = inputs[\"marks\"].unsqueeze(0)\n    inputs[\"num_options\"] = torch.tensor([[len(questions[0].options)]])\n    inputs[\"question_type_ids\"] = torch.tensor([[1]])  # choice\n    inputs[\"labels\"] = torch.tensor(\n        [questions[0].options.index(label)]\n    )\n    return inputs\n\ndataset = [preprocess(text, label) for text, label in examples]\n\nclass DecisionTrainer(Trainer):\n    def compute_loss(self, model, inputs, return_outputs=False, **kwargs):\n        inputs = inputs.copy()\n        labels = inputs.pop(\"labels\")\n        logits = model(**inputs)\n\n        logits = logits.unsqueeze(0)  # [3] -> [1, 3]\n        loss = F.cross_entropy(logits.float(), labels)\n\n        return (loss, logits) if return_outputs else loss\n\ntrainer = DecisionTrainer(\n    model=model,\n    args=TrainingArguments(\n        output_dir=\"./decision-toy\",\n        max_steps=30,\n        per_device_train_batch_size=1,\n        learning_rate=1e-3,\n        logging_steps=5,\n        save_strategy=\"no\",\n        report_to=\"none\",\n        remove_unused_columns=False,\n    ),\n    train_dataset=dataset,\n    data_collator=lambda batch: batch[0],\n)\n\ntrainer.train()\n```\n\nFirst-class support for training decision models is also coming to TRL ([huggingface/trl#8040](https://github.com/huggingface/trl/pull/8040)), so we won't have to write this plumbing by hand. At the time of writing, the PR is still open.\n\nIf we want to go further and turn a generative LLM into a decision model, [Unsloth provides a recipe](https://unsloth.ai/docs/basics/train-your-own-decision-model-with-unsloth) that fine-tunes models such as Qwen with LoRA and a decision-scoring head.\n\n## \n\t\tFinal thoughts\n\t\n\nDecision models are interesting not because classification is new, but because they make **decisions and probabilities first-class outputs for software**.\n\nTraditional classifiers already produce probabilities, and zero-shot classifiers already allow runtime-defined categories. Decision models bring these ideas into a typed interface with multiple question primitives, non-generative scoring, and the possibility of specialized training for reliable, calibrated decisions.", "url": "https://wpnews.pro/news/decision-models-in-hugging-face", "canonical_source": "https://huggingface.co/blog/decision", "published_at": "2026-11-10 00:00:00+00:00", "updated_at": "2026-11-10 15:24:52.499429+00:00", "lang": "en", "topics": ["artificial-intelligence", "machine-learning", "large-language-models", "ai-tools", "ai-research"], "entities": ["Hugging Face", "Transformers", "TypeSafe AI", "Jev", "autotrust/GEV-26B-Decide", "ggml-org/gemma-4-e4b-it-GGUF"], "also_reported_by": [], "alternates": {"html": "https://wpnews.pro/news/decision-models-in-hugging-face", "markdown": "https://wpnews.pro/news/decision-models-in-hugging-face.md", "text": "https://wpnews.pro/news/decision-models-in-hugging-face.txt", "jsonld": "https://wpnews.pro/news/decision-models-in-hugging-face.jsonld"}}