schematize
Automated extraction-schema generation using a multi-agent LangGraph pipeline.
schematize turns a natural language research question into a typed, validated extraction schema, ready to drive structured information extraction from document collections.
Instead of hand-crafting a JSON schema, you describe what you want to extract. The pipeline asks clarifying questions, drafts a schema, refines it against quality criteria, tests it against real documents from your corpus, and opens a chat so you can make final adjustments.
See it in action first: browse the worked examples — three real, unedited pipeline runs, each run through five different LLMs.
Why schematize?
Hand-crafting an extraction schema means guessing at fields, missing edge cases, and only finding out when extraction quality is poor. Asking an LLM for a schema once is better, but you still get an untested first draft with no critique loop and no contact with your real data.
schematize closes that loop: clarify → draft → criteria-based refinement → data-grounded refinement against retrieved documents → interactive chat. The result is a Pydantic model you can plug straight into extraction.
Key features
- Five-stage pipeline: clarification, query generation, criteria-based refinement, data-grounded refinement, and interactive chat.
- Model-agnostic. Any LangChain
BaseChatModelworks, and the built-in setup speaks the OpenAI-compatible API — official OpenAI, LiteLLM, vLLM, Ollama, and many others — see Configuration. - Data connectors are pluggable — implement one async method, or use the bundled HuggingFace and Weaviate adapters.
- Typed output. Schemas are Pydantic models, so they plug directly into an extractor.
- An expert-question coverage evaluator is included, so you can score how well a schema answers the questions your domain experts actually care about.
Quick look
Any object with an async __call__(query, max_docs) is a valid retriever, so you can get a first
schema without standing up a vector store:
from langchain_openai import ChatOpenAI
from schematize import SchemaGenerator, load_prompts
class MyRetriever:
async def __call__(self, query: str, max_docs: int = 100) -> list:
return [{"text": "The court awarded 15,000 PLN for breach of personal rights..."}]
llm = ChatOpenAI(model="gpt-4o")
generator = SchemaGenerator(
llm=llm,
retriever=MyRetriever(),
**load_prompts(language="en", system_type="law"),
)
state = generator.stream_graph_updates(
"Study personal-rights violations and assess their severity."
)
print(state["current_schema"])
For real corpora, swap in the bundled HuggingFace or Weaviate adapter.
What you get
A generated schema is a typed spec — field names, types, descriptions, and enums:
{
"fields": [
{"name": "violation_type", "type_": "enum", "enum_name": "ViolationType",
"enum_values": ["privacy", "reputation", "image", "bodily_integrity"],
"description": "Category of personal right that was violated."},
{"name": "severity", "type_": "integer",
"description": "Severity of the violation on a 0–5 scale."},
{"name": "compensation_awarded", "type_": "boolean",
"description": "Whether monetary compensation was granted."},
]
}
Convert it to a Pydantic model and use it for extraction:
from schematize import SchemaFields, DynamicModelFactory
model_cls = DynamicModelFactory()(SchemaFields(**state["current_schema"]))