xstructured
Validated Pydantic data and natural-language text from one LLM response.
xstructured wraps any LangChain v1 Runnable, chat model, or agent. The model answers in
its own words and places a JSON payload in an envelope; xstructured extracts it, validates
it with Pydantic v2, and returns both, even when the payload is wrapped in Markdown, buried
in prose, or still streaming in.
Highlights
- Validated, never guessed. Strict JSON decoding and Pydantic validation in JSON mode. Recovery only selects which part of a response to parse; it never rewrites JSON.
- Prose and data together.
result.contentfor people,result.structuredfor code. - Ordered streaming. Text deltas as they arrive, and the validated value the moment its envelope closes.
- A native Runnable.
invoke,batch,stream, async variants, tracing, retries, fallbacks, and composition behave as in any LangChain Runnable. - Bounded by design. Input, envelope, payload, and nesting limits; duplicate keys,
NaN, and overflowing numbers are rejected. - Optional, bounded repair. An opt-in repair Runnable gets a fixed number of attempts, and its output must pass the same schema.
- Fully typed. The value type is inferred from your schema.
Installation
pip install xstructured
Requires Python 3.12 or newer. The only runtime dependencies are langchain-core and
pydantic.
Quickstart
from langchain.chat_models import init_chat_model
from pydantic import BaseModel
from xstructured import with_xstructured_output
class Contact(BaseModel):
name: str
email: str
company: str | None = None
model = init_chat_model("openai:gpt-5-mini")
extractor = with_xstructured_output(model, Contact)
result = extractor.invoke(
"Please loop in Priya Shah (priya.shah@example.com) from Acme Corp."
)
print(result.structured) # Contact(name='Priya Shah', ...)
print(result.content) # The model's prose, with the envelope removed.
Stream prose and data in order:
from xstructured import StreamEventKind
message = "Add Priya Shah (priya.shah@example.com) to the review."
for event in extractor.stream(message):
if event.kind is StreamEventKind.TEXT_DELTA:
print(event.text, end="")
elif event.kind is StreamEventKind.STRUCTURED_END:
print("\nValidated:", event.structured)
Parse text from any source, without LangChain:
from xstructured import StructuredParser
reply = (
"Sure!\n"
"```json\n"
'{"name": "Priya Shah", "email": "priya.shah@example.com"}\n'
"```"
)
result = StructuredParser(Contact).parse(reply)
print(result.value, result.recovered) # Contact(...) True
Wrap chains, create_agent agents, Deep Agents, and LangGraph nodes too; see the
integration guides.
Benchmarks
An offline benchmark runs 11 model-style outputs through four parsers and checks each against an explicit expectation, counting a wrongly accepted truncated or ambiguous payload as a failure:
| Mechanism | Correct | Median latency |
|---|---|---|
json.loads + Pydantic |
45.45% | 3.5 µs |
LangChain JsonOutputParser + Pydantic |
45.45% | 284.0 µs |
LangChain PydanticOutputParser |
45.45% | 249.7 µs |
| xstructured | 100% | 21.0 µs |
Reproduce it with uv run python -m benchmarks; methodology and per-case results are in
the benchmark documentation.
Examples
Nine example scripts
cover single- and multi-agent extraction, Deep Agents, LangGraph routing, RAG citations,
incident analysis, streaming UIs, mixed payloads with repair, and named envelopes. Each
runs offline with a scripted model, or live against the Experiential Labs API when
EXPLABS_API_KEY is set.
Documentation
Full documentation is at xstructured.readthedocs.io: quickstart, user guide, architecture, security, and the API reference.
An Agent Skill teaches AI coding agents to use xstructured correctly:
npx skills add smuniharish/xstructured --skill xstructured
Contributing
Contributions are welcome. See CONTRIBUTING.md for the development workflow and SECURITY.md for reporting vulnerabilities.
License
Licensed under the Apache License 2.0.
Metadata
Release files for xstructured 0.1.1
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| xstructured-0.1.1.tar.gz | 35.9 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| xstructured-0.1.1-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 82.5 kB
Release files / xstructured-0.1.1.tar.gz
| Download URL | xstructured-0.1.1.tar.gz |
|---|---|
| Size | 35.9 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
d5dd84502b30b6b4fe03301de763b95be16c4bb6f5fc3552fa69184cee19493b
|
|
BLAKE2b-256 checksum How to use checksums |
d3d30d677fac324d60b69d502070dba6fc5be35c8997b9b15f59793802164aa9
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
uv/0.12.15 {"installer":{"name":"uv","version":"0.12.15","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":null,"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
|
Release files / xstructured-0.1.1-py3-none-any.whl
| Download URL | xstructured-0.1.1-py3-none-any.whl |
|---|---|
| Size | 46.5 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
c1ae8ea529cdc9d347881233ced34b27d91e3a3465c47fd4234338d923178264
|
|
BLAKE2b-256 checksum How to use checksums |
1aec813e7c46ba042efc7d79f5f0bd49554ea739155e92511026a1045d42c184
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
uv/0.12.15 {"installer":{"name":"uv","version":"0.12.15","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":null,"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
|