llm-structured-confidence
Extract path-aware confidence scores from LLM structured JSON outputs using token-level log-probabilities.
Installation • Supported JSON Formats • Quick Start • Path Syntax • Documentation • Supported Providers
Designed for structured JSON outputs from OpenAI, Gemini, and compatible providers. The library aligns token logprobs to exact JSON value spans, strips structural tokens, and computes confidence only from the tokens that belong to the value itself.
Installation
pip install llm-structured-confidence
For DataFrame helpers:
pip install "llm-structured-confidence[pandas]"
Supported JSON Formats
The library works with any structured JSON output. Here are the most common patterns and how to extract confidence from each.
Single scalar field
{"category": "health and wellness"}
entries = extract_logprobs(response, field_path="category")
# entries[0].path -> "category"
# entries[0].value -> "health and wellness"
Nested scalar field
{"classification": {"name": "Positive", "score": 0.95}}
entries = extract_logprobs(response, field_path="classification.name")
# entries[0].path -> "classification.name"
# entries[0].value -> "Positive"
Array of strings
{"categories": ["health and wellness", "sports", "technology"]}
entries = extract_logprobs(response, field_path="categories[]")
# entries[0].path -> "categories[0]", entries[0].value -> "health and wellness"
# entries[1].path -> "categories[1]", entries[1].value -> "sports"
# entries[2].path -> "categories[2]", entries[2].value -> "technology"
Array of objects (pick one field)
{"results": [{"id": 1, "category": "deposits"}, {"id": 2, "category": "shopping"}]}
entries = extract_logprobs(response, field_path="results[].category")
# entries[0].path -> "results[0].category", entries[0].value -> "deposits"
# entries[1].path -> "results[1].category", entries[1].value -> "shopping"
Top-level array of objects (Vertex AI only)
Vertex AI supports "type": "ARRAY" at the schema root, producing a bare JSON array.
OpenAI requires a top-level object, so these formats are Vertex-only.
[{"id": 1, "category": "deposits"}, {"id": 2, "category": "shopping"}]
entries = extract_logprobs(response, field_path="[].category")
# entries[0].path -> "[0].category", entries[0].value -> "deposits"
# entries[1].path -> "[1].category", entries[1].value -> "shopping"
Top-level array of strings (Vertex AI only)
The most compact multi-classification format — a flat list of category strings with no wrapper object.
The enum constraint in the schema is enforced by Vertex AI.
["bars and restaurants", "transportation", "digital services"]
entries = extract_logprobs(response, field_path="[]")
# entries[0].path -> "[0]", entries[0].value -> "bars and restaurants"
# entries[1].path -> "[1]", entries[1].value -> "transportation"
# entries[2].path -> "[2]", entries[2].value -> "digital services"
Deeply nested arrays
{"groups": [{"items": [{"label": "A"}, {"label": "B"}]}]}
entries = extract_logprobs(response, field_path="groups[].items[].label")
# entries[0].path -> "groups[0].items[0].label", entries[0].value -> "A"
# entries[1].path -> "groups[0].items[1].label", entries[1].value -> "B"
Provider compatibility
| JSON Format | OpenAI | Vertex AI | field_path |
|---|---|---|---|
{"category": "..."} |
Yes | Yes | category |
{"classification": {"name": "..."}} |
Yes | Yes | classification.name |
{"categories": ["a", "b"]} |
Yes | Yes | categories[] |
{"results": [{"id": 1, "category": "..."}]} |
Yes | Yes | results[].category |
["cat_a", "cat_b", "cat_c"] |
No | Yes | [] |
[{"id": 1, "category": "..."}] |
No | Yes | [].category |
{"groups": [{"items": [{"label": "..."}]}]} |
Yes | Yes | groups[].items[].label |
Note: OpenAI's
json_schemaresponse format requires"type": "object"at the root. To get array-like output on OpenAI, wrap it in an object (e.g.{"results": [...]}). Top-level arrays (both string and object variants) are exclusive to Vertex AI.
Quick Start
import litellm
from llm_structured_confidence import extract_logprobs
response = litellm.completion(
model="gpt-4.1-mini",
messages=[
{"role": "system", "content": "Classify this text."},
{"role": "user", "content": "Morning yoga and meditation session"},
],
response_format={
"type": "json_schema",
"json_schema": {
"name": "classification",
"strict": True,
"schema": {
"type": "object",
"properties": {
"category": {
"type": "string",
"enum": ["sports", "health and wellness", "technology"],
}
},
"required": ["category"],
"additionalProperties": False,
},
},
},
logprobs=True,
top_logprobs=5,
)
entries = extract_logprobs(response, field_path="category")
entry = entries[0]
print(entry.path) # category
print(entry.value) # health and wellness
print(entry.field_logprob.mean_nonzero_probability) # 0.8451
Schema auto-detection
If you pass response_schema=, the library auto-detects enum-valued paths recursively.
entries = extract_logprobs(response, response_schema=ClassificationModel)
That also enables TopAlternative.resolved_value, so token prefixes like "Pos" can resolve back to "Positive" when the match is unique.
Path Syntax
| Pattern | Meaning | Example output |
|---|---|---|
category |
Scalar field at root | {"category": "..."} |
classification.name |
Nested scalar field | {"classification": {"name": "..."}} |
categories[] |
Each element in an array | {"categories": ["a", "b"]} |
results[].category |
Field inside each array element | {"results": [{"category": "..."}]} |
[] |
Each element of a top-level string array | ["cat_a", "cat_b"] |
[].category |
Field inside each element of a top-level array | [{"category": "..."}] |
groups[].items[].label |
Deeply nested: array inside array | {"groups": [{"items": [{"label": "..."}]}]} |
Flat/DataFrame Helpers
from llm_structured_confidence import extract_confidence, add_confidence_columns
metrics = extract_confidence(response, field_path="category")
df = add_confidence_columns(
df,
response_column="response",
field_path="classifications[].name",
)
Helpers always return the first matching value and also expose its resolved path.
Documentation
- docs/USAGE.md: full public API and examples
- examples/examples.ipynb: notebook walkthrough
- AGENTS.md: compact reference for coding agents
Supported Providers
litellm.ModelResponseopenai.ChatCompletiongoogle.genai.GenerateContentResponse- raw OpenAI batch response dict with
choices - raw Vertex AI batch response dict with
candidates
Lower-level API
Internal modules remain available for custom workflows:
from llm_structured_confidence._parser import parse_json_spans, build_token_char_ranges, tokens_for_span
from llm_structured_confidence._converter import normalize_response
These are underscore-prefixed internals and may change in minor releases.
Metadata
Release files for llm-structured-confidence 0.4.5
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | |
|---|---|---|---|---|
| llm_structured_confidence-0.4.5.tar.gz | 34.0 kB | With provenance | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| llm_structured_confidence-0.4.5-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 61.8 kB
Release files / llm_structured_confidence-0.4.5.tar.gz
| Download URL | llm_structured_confidence-0.4.5.tar.gz |
|---|---|
| Size | 34.0 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
9810010722798d24cfe4a5056c0334cd1e18e0cbbd92f2d9398a083fead2f411
|
|
BLAKE2b-256 checksum How to use checksums |
cabd045655a7f3193c02fe005b6e00f095c955299277f67fe011e5bfe4bd7094
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/6.1.0 CPython/3.13.7
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Mar 13, 2026.
Transparency logRelease files / llm_structured_confidence-0.4.5-py3-none-any.whl
| Download URL | llm_structured_confidence-0.4.5-py3-none-any.whl |
|---|---|
| Size | 27.8 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
857df2b1d5f46b95a1a66e1ca0833687181ee6e9f6c872cb718b614d9c4fcbae
|
|
BLAKE2b-256 checksum How to use checksums |
24e2a2c63b3b445f52e45f69d8e63edd88744fc2f74cb5de87eb999983c4afbe
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/6.1.0 CPython/3.13.7
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Mar 13, 2026.
Transparency logSecurity for llm-structured-confidence 0.4.5
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
Full provenance
All 2 files in this release have been uploaded with provenance metadata.
Attestation for llm_structured_confidence-0.4.5.tar.gz
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Mar 13, 2026.
Transparency logA note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.