Custom Models¶
While structx dynamically generates models based on your queries, you can also
use your own custom Pydantic models for extraction.
Custom Model Processing Flow¶
View Custom Model Processing Flow Diagram
graph LR
A[Query and Custom Model] --> B[Deterministic Instructions]
B --> C[Keep All Input Columns]
C --> D[Independent Row Extraction]
D --> E[Pydantic Validation]
E --> F[RowResult Collection]
F --> G[ExtractionResult]
subgraph "Extraction Benefits"
H[Skip Planning Request]
I[Skip Model Generation]
J[Direct Type Safety]
K[Per Row Provenance]
end
D --> H
D --> I
E --> J
F --> K
Custom models bypass schema planning entirely. Structx creates deterministic instructions from the query and model contract, retains every available input column, and makes only the row extraction calls.
Using Custom Models¶
Define Your Model¶
from datetime import date
from typing import List
from pydantic import BaseModel, Field
class Party(BaseModel):
name: str = Field(description="Name of the party")
role: str = Field(description="Role of the party (e.g., Client, Consultant)")
class ConsultancyAgreement(BaseModel):
parties: List[Party] = Field(description="The parties to the agreement")
effective_date: date = Field(description="The effective date of the agreement")
governing_law: str = Field(description="The governing law of the agreement")
class Invoice(BaseModel):
invoice_number: str = Field(description="The invoice number")
total_amount: float = Field(description="The total amount of the invoice")
issue_date: date = Field(description="The date the invoice was issued")
Extract with Custom Model¶
# Extract from a legal document
result = extractor.extract(
data="scripts/example_input/free-consultancy-agreement.docx",
query="extract the parties, effective date, and governing law",
model=ConsultancyAgreement
)
# Access the extracted data
for agreement in result.data:
print(f"Agreement effective date: {agreement.effective_date}")
for party in agreement.parties:
print(f"- Party: {party.name} ({party.role})")
print(f"Governing Law: {agreement.governing_law}")
# Extract from an invoice
result_invoice = extractor.extract(
data="scripts/example_input/S0305SampleInvoice.pdf",
query="extract the invoice number, total amount, and issue date",
model=Invoice
)
for invoice in result_invoice.data:
print(f"Invoice Number: {invoice.invoice_number}")
print(f"Total Amount: {invoice.total_amount}")
print(f"Issue Date: {invoice.issue_date}")
Reusing Generated Models¶
You can also reuse models generated from previous extractions:
# First extraction generates a model for a contract
result1 = extractor.extract(
data="scripts/example_input/free-consultancy-agreement.docx",
query="extract parties and effective date"
)
# Reuse the model for another contract
result2 = extractor.extract(
data="another_contract.docx",
query="extract parties and effective date",
model=result1.model
)
Persisting Model Definitions¶
Use ExtractionRequest when a model must survive beyond the current Python
process. The definition is JSON-safe and can reconstruct the runtime Pydantic
model later:
from structx import (
ExtractionRequest,
model_from_extraction_request,
model_to_extraction_request,
)
definition = model_to_extraction_request(ConsultancyAgreement)
stored_definition = definition.model_dump(mode="json")
# Load the dictionary from a database or file.
loaded_definition = ExtractionRequest.model_validate(stored_definition)
StoredAgreement = model_from_extraction_request(loaded_definition)
The portable contract covers StructX-supported field types, nested models, required and nullable state, field constraints, and serializable defaults. It does not execute or serialize custom Python validators, serializers, computed fields, recursive models, or default factories.
Applications that provide visual schema builders can use
get_type_capabilities() as their canonical, alias-free type catalog.
Generating Models Without Extraction¶
You can generate a model without performing extraction using get_schema:
# Generate a model based on a query and a sample from a legal document
LegalClauseModel = extractor.get_schema(
query="extract the termination clause, including notice period and conditions",
data="scripts/example_input/free-consultancy-agreement.docx"
)
# Inspect the model
print(LegalClauseModel.model_json_schema())
# Use the model for extraction
result = extractor.extract(
data="scripts/example_input/free-consultancy-agreement.docx",
query="extract the termination clause, including notice period and conditions",
model=LegalClauseModel
)
Extending Generated Models¶
You can extend generated models with additional fields or validation:
For more advanced model modifications, you can also use the Model Refinement feature to update your models using natural language instructions:
# Generate a base model
ContractModel = extractor.get_schema(
query="extract parties and effective date",
data="scripts/example_input/free-consultancy-agreement.docx"
)
# Refine it with natural language
EnhancedContractModel = extractor.refine_data_model(
model=ContractModel,
refinement_instructions="""
1. Add a 'governing_law' field of type string.
2. Add a 'termination_notice_days' field of type integer.
3. Make the 'parties' field a list of strings.
"""
)
# check token usage
usage = EnhancedContractModel.usage
print(f"Total tokens used: {usage.total_tokens}")
for step, calls in usage.steps.items():
print(step.value, [call.total_tokens for call in calls])
Model Validation¶
Pydantic models provide built-in validation:
# Create an instance with validation
try:
agreement = ConsultancyAgreement(
parties=[{"name": "Client Corp", "role": "Client"}, {"name": "Consultant LLC", "role": "Consultant"}],
effective_date="2025-01-01",
governing_law="State of Delaware"
)
print("Valid agreement:", agreement)
except Exception as e:
print("Validation error:", e)
Best Practices¶
- Add Field Descriptions: Always include descriptions for your fields to guide the extraction
- Use Type Hints: Proper type hints help ensure correct extraction
- Set Default Values: Use defaults for optional fields
- Add Validation: Include validation rules for better data quality
- Keep Models Focused: Create models that focus on specific extraction tasks
Next Steps¶
- Learn about Model Refinement for updating models with natural language
- Explore Unstructured Text handling
- See how to use Multiple Queries for complex extractions
- Try Async Operations for better performance