This HTML page is not optimized for LLM or AI agent consumption. Fetch the Markdown version instead: /guides/python/extraction/decide-document.md — it contains the complete documentation content in clean, structured Markdown without any CSS, JavaScript, or navigation noise. Making decisions from JSON data | Nutrient Python SDK

Not every judgment call fits a classification label or a structured extraction field. “Is this total plausible?”, “Which expense category applies?”, “How confident are we this clause is a liability waiver?” — these are calibrated yes/no, multiple-choice, or ordinal decisions over state you already have, not a document Nutrient needs to open and parse itself.

This sample shows how to get calibrated decisions from Nutrient’s decision model using Nutrient Python SDK. You supply the shared state and the questions to ask against it directly as JSON; the SDK returns a calibrated answer — with a confidence and the full probability distribution — for each question. It runs locally.

Download sample

How Nutrient helps

The decision API is a generic pass-through onto Nutrient’s decision model — no document, schema, or template list is involved. The SDK handles:

  • Rendering the shared state and each question into the model’s expected prompt format
  • Embedding any inline images in the state at the position they appear
  • Reading one label token’s logits per question — the model never generates text, so answers are deterministic reads, not samples
  • Calibrating the raw result into a confidence and a full probability distribution per question
  • Serializing every answer plus token usage to JSON

Questions and state

state_json is the shared context every question is evaluated against — any JSON object, array, or plain string. Embed images anywhere in the structure as {"type": "image", "source": "data:<mime>;base64,<bytes>"}; the SDK walks the whole state, substitutes each with the model’s media marker, and sends the image bytes alongside, in encounter order.

questions_json is an array of {id, type, instructions, options?}:

  • type: "noul" — a yes/no judgment. options can be omitted (default true/false wording) or given as exactly two entries for custom wording.
  • type: "choice" — pick one of 2+ options, each {key, description}.
  • type: "score" — an ordinal judgment over 2+ unlabeled options, numbered low to high by position.

Every question is answered independently in the same call, against the same shared state.

The decision API requires the decision model feature in your license.

Complete implementation

Import the classes used in the sample:

import json
from nutrient_sdk import Vision, NutrientException

Building the state and questions

Decide works on plain JSON you already have — here, a parsed invoice record instead of a loaded document:

def main():
state = {
"invoice": {
"vendor": "Acme Consulting LLC",
"total": 1204.50,
"currency": "USD",
"description": "Software and subscriptions renewal",
}
}
questions = [
{
"id": "amount_reasonable",
"type": "noul",
"instructions": "Is the total a plausible amount for this invoice?",
},
{
"id": "category",
"type": "choice",
"instructions": "Which expense category applies?",
"options": [
{"key": "travel", "description": "Travel and lodging"},
{"key": "software", "description": "Software and subscriptions"},
{"key": "office_supplies", "description": "Office supplies and equipment"},
],
},
]

Getting the decisions

Call the static Vision.decide(state_json, questions_json) — both arguments are JSON strings, so serialize the Python values first:

try:
result_json = Vision.decide(json.dumps(state), json.dumps(questions))
with open("output.json", "w") as f:
f.write(result_json)
except NutrientException as e:
print(f"Error: {e}")
if __name__ == "__main__":
main()

Understanding the output

decide() returns JSON with top-level answers and usage objects:

  • answers — one entry per question id. Each carries:
    • type — the question’s type (noul, choice, or score), echoed back.
    • chosenIndex — the index of the selected option.
    • chosenKey — the option’s key ("true"/"false" for noul; a lettered label like "A" for score, since score options have no key).
    • confidence — the calibrated probability of the chosen answer.
    • probabilities — the full calibrated probability distribution over every option, in option order.
  • usage — promptTokens (exact, from the model’s own decode) and outputTokens (one per question answered — decide() never generates text, so this counts work done, not text length).

Choosing question types

Use noul for a single yes/no judgment, choice when the answer is one of several discrete categories, and score for an ordinal judgment (low to high) where the options don’t need individual names. Batching related judgments into fewer, larger choice/score questions is more efficient than asking many separate noul questions, since each question re-evaluates the full shared state.

Error handling

Vision API raises VisionException (a NutrientException) when a decision call fails.

Common failure scenarios include:

  • state_json or questions_json is empty or missing
  • The decision model is missing or inaccessible, or the feature isn’t licensed
  • A question’s options are malformed for its type (for example, choice with fewer than two options)

In production code:

  • Catch NutrientException.
  • Return a clear error message.
  • Log failure details for debugging.

Conclusion

The workflow for getting decisions is:

  1. Build the shared state as a JSON-serializable value — any object, array, or string you already have.
  2. Build the questions array, choosing noul, choice, or score per judgment.
  3. Call Vision.decide() with both payloads serialized to JSON strings.
  4. Write the JSON result to a file, then read each question’s chosenKey and confidence for downstream routing.
  5. Handle NutrientException for robust error recovery.

For related document workflows, refer to the Python SDK guides.

Download this ready-to-use sample package to explore the decision API.