xstructured
xstructured is a schema-guided structured output layer for
LangChain v1
Runnables and agents. It wraps any chat model, create_agent agent, or
custom Runnable so that its natural-language output is turned into a
validated Pydantic v2 object, with
conservative recovery from markdown fences and surrounding prose, an
optional delimited envelope protocol for reliable extraction alongside
free-form text, and ordered streaming of text and structured deltas.
It is not a replacement for create_agent's built-in output_schema and
does not call an LLM provider itself: it composes with whatever Runnable
you already have, focuses on making structured extraction robust to
imperfect model output, and stays out of the way otherwise.
Installation
pip install xstructured
The Python import namespace is:
from xstructured import with_xstructured_output, XStructuredResult
Running the examples against a real LLM provider additionally requires the
examples dependency group (LangChain, an OpenAI chat model, and optionally
Deep Agents):
uv sync --group examples
Quickstart
from langchain.agents import create_agent
from langchain_core.messages import HumanMessage
from langchain_core.runnables import RunnableLambda
from pydantic import BaseModel
from xstructured import with_xstructured_output
class ContactInfo(BaseModel):
name: str
email: str
agent = create_agent(model="openai:gpt-4o-mini", tools=[])
def run_agent(messages):
# create_agent's compiled graph takes/returns a {"messages": [...]} state,
# so it is adapted to the plain-message Runnable contract xstructured expects.
state = agent.invoke({"messages": list(messages)})
return state["messages"][-1]
extractor = with_xstructured_output(RunnableLambda(run_agent), ContactInfo)
result = extractor.invoke(
[HumanMessage(content="Reach Priya Shah at priya.shah@example.com.")]
)
print(result.structured) # ContactInfo(name='Priya Shah', email='priya.shah@example.com')
print(result.content) # the agent's natural-language reply, envelope stripped
print(result.raw) # the original AIMessage
See Why xstructured? for ten practical use cases and guidance on when LangChain or LangGraph native features are the better choice.
with_xstructured_output composes with .invoke, .ainvoke, .batch,
.abatch, .stream, and .astream, following native Runnable semantics
throughout. Streaming yields ordered TEXT_DELTA, STRUCTURED_START,
STRUCTURED_DELTA, STRUCTURED_END, and RESULT events so a UI can render
prose and structured data as they arrive.
Lower-level building blocks are also public, for callers who want schema
instructions, parsing, or fingerprinting without the Runnable wrapper:
from xstructured import StructuredParser, fingerprint_schema, schema_instructions
instructions = schema_instructions(ContactInfo, envelope="xstructured")
result = StructuredParser(ContactInfo).parse(model_output_text)
digest = fingerprint_schema(ContactInfo)
Offline benchmark
Compare plain JSON plus Pydantic, LangChain's JSON and Pydantic output
parsers, and xstructured against the same local fixture corpus:
uv run python -m benchmarks --help
uv run python -m benchmarks
The benchmark performs no network calls and needs no API key. Its correctness
criteria, corpus, and timing methodology are documented in
docs/benchmarks.md.
Resource limits and strict JSON
ParserConfig bounds all untrusted response handling. Its defaults limit
whole inputs, envelopes, and JSON payloads to 1,000,000 characters and JSON
container nesting to 100 levels. The same configuration is used by
StructuredParser and streaming wrappers.
from xstructured import ParserConfig, StructuredParser
parser = StructuredParser(
ContactInfo,
config=ParserConfig(
max_input_chars=100_000,
max_envelope_chars=50_000,
max_payload_chars=40_000,
max_nesting_depth=32,
),
)
JSON decoding rejects duplicate object keys and non-standard NaN,
Infinity, and -Infinity constants. Envelopes that are incomplete or
exceed their configured bounds fail explicitly rather than continuing to
accumulate streamed content.
Examples
Runnable, environment-gated example scripts live in examples/:
examples/single_agent_extraction.py— onecreate_agentagent wrapped withwith_xstructured_output.examples/multi_agent_pipeline.py— an extractor agent feeding a reviewer agent, each schema-validated.examples/deep_agent_optional.py— the same pattern applied to adeepagentsdeep agent, skipped automatically whendeepagentsis not installed.
Each script checks for EXPLABS_API_KEY and prints an explanation and exits
instead of failing when it is not set,
so they are safe to run in any environment. See
examples/README.md for details.
Documentation
Full documentation, including user guides, architecture, security, benchmarks,
and API reference, is
published at https://xstructured.readthedocs.io and built from
docs/ with MkDocs Material.
Development
uv sync
uv run ruff check .
uv run ruff format --check .
uv run flake8 .
uv run pyrefly check
uv run pytest -m "not live"
Documentation diagrams are Mermaid sources rendered to PNG with a pinned
Mermaid CLI (see scripts/render-diagrams.mjs):
# Install this tooling globally; the Python package has no Node runtime dependency.
npm install --global @mermaid-js/mermaid-cli@11.17.0
node scripts/render-diagrams.mjs
node scripts/render-diagrams.mjs --check
node_modules/ is not required in the repository. The renderer uses a local
CLI when present and otherwise resolves the pinned global Mermaid CLI.
See CONTRIBUTING.md for the full workflow.
The project requires Python 3.12 or newer and is licensed under Apache-2.0.
Release files for xstructured 0.1.0
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.0.tar.gz | 24.0 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| xstructured-0.1.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 57.6 kB
Release files / xstructured-0.1.0.tar.gz
| Download URL | xstructured-0.1.0.tar.gz |
|---|---|
| Size | 24.0 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
e1e60345543124a630f2df478165c18481d77f93a7573d57b310abbb0068f125
|
|
BLAKE2b-256 checksum How to use checksums |
3f0189c5e8c64dcc9d54af34a63e091818660ec6ac8d17c3663afab515a4cfc5
|
| 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.0-py3-none-any.whl
| Download URL | xstructured-0.1.0-py3-none-any.whl |
|---|---|
| Size | 33.7 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
a239375eb6ae3e2cf7bbcd3cd7d9557d944c63aa9632e42e8a5133e5d3a03b22
|
|
BLAKE2b-256 checksum How to use checksums |
a6ed699517a2ad75019c541da15d8a7fbda70f8ba09a08f2e38c5d37d8f94259
|
| 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}
|