pcd-rlcd
Parallel constrained decoding for structured extraction and classification on Apple Silicon.
pcd-rlcd extracts the core inference engine from the original Parallel Constrained Decoding project and makes it available as a small, reusable Python package.
It evaluates multiple schema fields in parallel instead of generating a complete JSON document token by token. This is useful for classification, decision routing, structured extraction, and other workloads where fields have bounded candidate values.
Features
- Parallel evaluation of multiple structured fields
- Enum and boolean schema fields
- Constrained candidate selection
- Programmatic JSON assembly
- Field-level confidence scores
- Top-choice probability telemetry
- MLX backend for Apple Silicon
- Torch backend support
- Configurable language model through
MODEL_ID - Typed Python package
- Benchmark utilities
Requirements
- Python 3.10+
- Apple Silicon Mac for the MLX backend
- macOS 14 or later recommended
- A model supported by the selected inference backend
The package defaults to:
mlx-community//Qwen2.5-1.5B-Instruct
The example configuration uses:
mlx-community/Qwen2.5-0.5B-Instruct-4bit
You can select a different model with the MODEL_ID environment variable.
Installation
Using uv:
uv add pcd-rlcd
Using pip:
pip install pcd-rlcd
To install directly from the repository:
git clone <repository-url>
cd <repository-directory>
uv sync
Quickstart
from pcd_rlcd.schema import StructuredSchema
from pcd_rlcd.engine import run_parallel_generation
schema_definition = {
"fraud_risk": {
"type": "enum",
"choices": ["LOW", "ELEVATED", "SUSPICIOUS", "CRITICAL"],
"description": "Risk assessment tier for incoming transaction",
},
"block_account": {
"type": "boolean",
"description": "Whether immediate account restriction is required",
},
"recommended_action": {
"type": "enum",
"choices": [
"ALLOW",
"STEP_UP_2FA",
"TEMPORARY_HOLD",
"TERMINATE_SESSION",
],
"description": "Immediate mitigation action",
},
}
def main():
schema = StructuredSchema(schema_definition)
context = """
User ID: usr_9921
Location: Lagos, Nigeria (usual: Seattle, USA)
Device: Unknown Linux Chromium browser
Action: Wire transfer $49,500 to offshore escrow
Prior velocity: 0 transfers in 90 days
"""
result = run_parallel_generation(context, schema)
print(f"Elapsed time: {result['elapsed_ms']} ms")
print(f"Sequential passes: {result['sequential_forward_passes']}")
print(f"Parsed JSON: {result['parsed_json']}")
if __name__ == "__main__":
main()
Example output:
Elapsed time: 146.88 ms
Sequential passes: 1
Parsed JSON: {
'fraud_risk': {'value': 'SUSPICIOUS', 'prob': 0.8131},
'block_account': {'value': True, 'prob': 0.6637},
'recommended_action': {
'value': 'TEMPORARY_HOLD',
'prob': 0.6054
}
}
Model Configuration
Set MODEL_ID before running your application:
export MODEL_ID=mlx-community/Qwen2.5-0.5B-Instruct-4bit
For example:
MODEL_ID=mlx-community/Qwen2.5-0.5B-Instruct-4bit python example.py
If MODEL_ID is not set, the engine uses:
mlx-community/Qwen2.5-1.5B-Instruct
The selected model must be compatible with the active inference backend.
Defining Schemas
Schemas are created with StructuredSchema. Each field includes:
type: eitherenumorbooleandescription: semantic guidance for the modelchoices: allowed values for enum fields
Enum fields
{
"priority": {
"type": "enum",
"choices": ["LOW", "MEDIUM", "HIGH", "CRITICAL"],
"description": "Urgency of the incident",
}
}
Boolean fields
{
"requires_review": {
"type": "boolean",
"description": "Whether the result requires manual review",
}
}
Combined schema
from pcd_rlcd.schema import StructuredSchema
schema = StructuredSchema(
{
"priority": {
"type": "enum",
"choices": ["LOW", "MEDIUM", "HIGH", "CRITICAL"],
"description": "Urgency of the incident",
},
"requires_review": {
"type": "boolean",
"description": "Whether manual review is required",
},
"department": {
"type": "enum",
"choices": [
"BILLING",
"INFRASTRUCTURE",
"SECURITY",
"PRODUCT_SUPPORT",
],
"description": "Department responsible for handling the issue",
},
}
)
Result Format
run_parallel_generation returns a dictionary containing the structured result and execution telemetry.
{
"mode": "parallel_constrained_calibrated",
"elapsed_ms": 146.88,
"prefill_ms": 100.42,
"suffix_eval_ms": 42.17,
"sequential_forward_passes": 1,
"is_valid_json": True,
"schema_match": True,
"parsed_json": {
"priority": {
"value": "HIGH",
"prob": 0.91,
},
"requires_review": {
"value": True,
"prob": 0.84,
},
"department": {
"value": "SECURITY",
"prob": 0.96,
},
},
"field_telemetry": {
"priority": {
"value": "HIGH",
"confidence": 0.91,
"cardinality": 4,
"top_choices": [
{
"choice": "HIGH",
"probability": 0.91,
},
{
"choice": "CRITICAL",
"probability": 0.06,
},
],
}
},
}
The exact timing fields depend on the selected backend, model, hardware, and input.
How It Works
Traditional structured generation produces JSON autoregressively:
"context" -> "{" -> "\"field\"" -> ":" -> "\"value\"" -> ...
Each generated token requires another model evaluation. As the output grows, the number of sequential evaluations also grows.
Parallel constrained decoding uses a different strategy:
- The input context and schema descriptions are prefetched once.
- The resulting key-value cache is shared across schema fields.
- Each field is evaluated against only its valid candidate values.
- Candidate probabilities are normalized within each field.
- The selected values are assembled programmatically.
- The final structure is guaranteed to match the requested schema.
This approach is especially useful when fields contain bounded values such as enums, labels, routing decisions, or booleans.
Package Structure
.
├── pyproject.toml
├── README.md
├── requirements.txt
├── uv.lock
└── src
└── pcd_rlcd
├── __init__.py
├── benchmark.py
├── engine.py
├── engine_mlx.py
├── engine_torch.py
├── prompt_builder.py
├── py.typed
└── schema.py
Main modules
schema.py— schema definitions and field metadataengine.py— public engine interfaceengine_mlx.py— MLX-based inference implementationengine_torch.py— PyTorch-based inference implementationprompt_builder.py— prompt construction utilitiesbenchmark.py— benchmark and comparison utilities
Running Benchmarks
The package includes benchmark utilities for comparing parallel constrained decoding with autoregressive generation.
Run the benchmark module with:
python -m pcd_rlcd.benchmark
Benchmark results depend on:
- Model size and quantization
- Apple Silicon generation
- Available memory
- Input length
- Number of fields
- Number of candidate choices
- Backend configuration
Use benchmark results as hardware- and model-specific measurements rather than universal performance guarantees.
Choosing Candidate Values
Enum fields work best when:
- The candidate set is known in advance
- Each choice is semantically distinct
- Values are reasonably short
- The model can infer the correct choice from the context
For example:
{
"severity": {
"type": "enum",
"choices": ["INFO", "WARNING", "ERROR", "CRITICAL"],
"description": "Operational severity of the event",
}
}
For open-ended text generation, use a conventional autoregressive generation approach instead.
Limitations
- The engine is designed for bounded structured decisions, not arbitrary JSON generation.
- Results are model predictions and should be validated against application-specific requirements.
- Confidence values represent model probabilities over the candidate set; they are not guaranteed to be calibrated for every domain.
- Performance varies significantly between models, devices, and backends.
- MLX execution requires compatible Apple Silicon hardware.
- The available schema field types are currently limited to the types supported by the package implementation.
Relationship to the Original Project
This package extracts and refactors the reusable core of the original Parallel Constrained Decoding implementation into an independently installable Python package.
The original project demonstrated parallel constrained decoding for Apple Silicon using MLX. pcd-rlcd focuses on making the core schema and inference functionality easier to install and use from other Python applications.
License
Apache License 2.0.
Release files for pcd-rlcd 0.1.4
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| pcd_rlcd-0.1.4.tar.gz | 14.5 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| pcd_rlcd-0.1.4-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 33.4 kB
Release files / pcd_rlcd-0.1.4.tar.gz
| Download URL | pcd_rlcd-0.1.4.tar.gz |
|---|---|
| Size | 14.5 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
f31f4d11525408690906245d430004cd6b820319a6681d5003df6e2f35a7d246
|
|
BLAKE2b-256 checksum How to use checksums |
84feea06c960882635171622ce176ea438cfeda5ad7cc7d212e68343a727a7d6
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
uv/0.11.24 {"installer":{"name":"uv","version":"0.11.24","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
|
Release files / pcd_rlcd-0.1.4-py3-none-any.whl
| Download URL | pcd_rlcd-0.1.4-py3-none-any.whl |
|---|---|
| Size | 18.9 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
449889096db3926622f9ebc7696774ec513f80b8b6c55b2b22c5e46c80a73691
|
|
BLAKE2b-256 checksum How to use checksums |
312eab596f706f45d52980f14402191bc92bba57fd3c118edd0f297f9bd98fc5
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
uv/0.11.24 {"installer":{"name":"uv","version":"0.11.24","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
|