Strux is a Python framework for structured outputs model versioning
Project description
Strux: A Python framework for structured output model versioning
Strux is a Python framework designed to make comparing and validating model outputs across multiple experiments simple and straightforward. Its primary goal is to enable fast iteration during model development by making it extremely easy to:
- Compare an updated model’s outputs against a previously established baseline
- Track improvements and regressions at both the field and sample level
- Generate clear, automated reports to guide data scientists and engineers in calibrating or refining their models
The Problem
Testing AI models (especially those generating structured outputs) requires more than just raw accuracy checks. As models become increasingly complex (e.g., multi-step pipelines, large language model inference with structured outputs), practitioners need:
- Type-safe scrutiny of outputs against a schema.
- Fine-grained inspection of changes in performance or behavior, even at the field level (e.g., sentiment vs. rating).
- A way to confidently iterate and measure improvements without fear of accidentally introducing regressions.
Traditional testing frameworks don’t address these issues in a developer-friendly, integrated manner. They either require lots of custom scripts or rely on ad-hoc comparisons that can be error-prone and slow.
Why Strux?
-
Type-Safe with Pydantic: Strux is built on Pydantic for schema validation, ensuring your model’s outputs conform to the expected structures. This catches errors early and eliminates ambiguity in your data pipeline.
-
Simple Pipeline Abstractions: Model inference is packaged into “steps” that can be chained. Strux automatically validates outputs after each step according to configurable thresholds.
-
Comparison & Regression Testing: Quickly see if your new model version outperforms or regresses vs. the baseline. Each field can have its own strategy (e.g., exact match, allowable numeric deviation).
-
Rich Reporting: Strux can generate HTML reports that visually highlight improvements, regressions, or unchanged results. Summaries and per-sample breakdowns give you the context you need to iterate quickly.
-
Cookbook & Extensible: Built-in data sources (PostgreSQL, CSV, etc.) help bootstrap your pipeline. Community and team contributions can extend Strux to fit your own data retrieval or custom validation needs.
Getting Started
Below is a minimal example illustrating how to set up a Strux pipeline and perform a comparison against a baseline.
Install Strux
pip install strux
Step 1: Define Your Schemas
Use Pydantic models for both your input and output schemas:
from pydantic import BaseModel
from typing import Literal
class Review(BaseModel):
text: str
class ReviewAnalysis(BaseModel):
sentiment: Literal['positive', 'negative', 'neutral']
rating: float
Step 2: Implement an Inference Function
This function takes a single input record (Review) and returns structured outputs (ReviewAnalysis):
def analyze_review_v1(data: Review) -> ReviewAnalysis:
# Some simple logic or call a model endpoint
# Example: short, naive approach
text = data.text.lower()
if "love" in text:
sentiment = "positive"
rating = 5.0
elif "terrible" in text:
sentiment = "negative"
rating = 1.0
else:
sentiment = "neutral"
rating = 3.0
return ReviewAnalysis(sentiment=sentiment, rating=rating)
Step 3: Build and Run a Pipeline
Strux pipelines tie together data loading, inference steps, and validation rules:
from strux import CSVDataSource, RegressionConfig, Sequential, exact_match, absolute_deviation
# Load data from a CSV or other data source
data_source = CSVDataSource(
file_path="reviews.csv", # CSV file with a "text" column
schema=Review
)
# Configure validation rules for each field
config = RegressionConfig(
target_schema=ReviewAnalysis
)
config.configure_field(
"sentiment",
strategy=exact_match(), # Exact match strategy where the value must be exactly the same as the baseline
threshold=0.8 # 80% of the samples must match the baseline or annotation
)
config.configure_field(
"rating",
strategy=absolute_deviation(0.5), # Allowable value-based deviation of 0.5
threshold=0.9 # 90% of the samples must match the baseline or annotation
)
# Build the pipeline
pipeline = Sequential.from_steps(
data_source=data_source,
steps=[("analyze_review_v1", analyze_review_v1, ReviewAnalysis)],
config=config
)
# First run to create a baseline
results_v1 = pipeline.run()
results_v1.save_as_baseline("baselines/review_baseline.json")
# Compare against the baseline with a v2
def analyze_review_v2(data: Review) -> ReviewAnalysis:
# A new and improved approach!
# For demonstration, let’s just tweak thresholds slightly
text = data.text.lower()
if "love" in text or "amazing" in text:
sentiment = "positive"
rating = 5.0
elif "terrible" in text or "broke" in text:
sentiment = "negative"
rating = 1.0
else:
sentiment = "neutral"
rating = 3.0
return ReviewAnalysis(sentiment=sentiment, rating=rating)
pipeline_v2 = Sequential.from_steps(
data_source=data_source,
steps=[
("analyze_review_v2", analyze_review_v2, ReviewAnalysis)
],
config=config
)
# Run with baseline comparison
results_v2 = pipeline_v2.run(baseline_path="baselines/review_baseline.json")
print(results_v2.format_summary()) # Quick console summary
# Generate visual HTML report
results_v2.to_html("comparison_report.html")
You’ll see improvements, regressions, and unchanged samples clearly highlighted in both console output and the generated HTML file.
Documentation
For detailed documentation, see the docs/ directory:
Contributing
Contributions are welcome! Please read our Contributing Guidelines for details.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file strux-0.1.2.tar.gz.
File metadata
- Download URL: strux-0.1.2.tar.gz
- Upload date:
- Size: 5.5 MB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.0.1 CPython/3.10.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
bcaf622db965484fdf1ad2c83a38ca08e801fc44d59c28d44224d9b8568fe6f6
|
|
| MD5 |
0d94080e0fc29d226b59a25dbcebb2e5
|
|
| BLAKE2b-256 |
e66bab5ce79d46efaa6f90913fa4c9eced7599e93211098e84ab75f25d7d9de1
|
File details
Details for the file strux-0.1.2-py3-none-any.whl.
File metadata
- Download URL: strux-0.1.2-py3-none-any.whl
- Upload date:
- Size: 33.9 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.0.1 CPython/3.10.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
1c87fb486e454424f1ad2bac2cf55e3fcf26ef114dab75c08d48baf370a8c2b0
|
|
| MD5 |
decd491a1501a00800ef8011ec263e86
|
|
| BLAKE2b-256 |
4ed485837d8ba2d3160476c800bc188b24e7ecc843ed207841236f3e14021307
|