guarded-llm
Strict JSON output from any LLM, with retry + schema validation + multi-provider routing in one call.
Pre-release: not yet on PyPI; install from source.
What it does
LLMs hallucinate JSON. guarded-llm wraps a single call into a 4-layer
defense:
- Strip markdown fences and locate the JSON envelope in chatty output.
- State-machine fix common drift: trailing commas, single quotes,
NaN/Infinity, comments, unescaped interior quotes, BOM. - Parse with
json.loads. - Validate against a schema (JSON Schema via
LLMSchema, or any class exposing a.validate(d) -> (ok, err, instance)classmethod).
If any layer fails, the call is retried with the previous error injected back
into the prompt as a hint. After max_retries, it returns a structured
GuardrailResult with parsed, errors, attempts, and cost_usd.
Install
# From source (pre-release)
pip install git+https://github.com/dada8899/structural-isomorphism#subdirectory=packages/guarded-llm
# Once published
pip install guarded-llm
Optional extras for vendor SDKs (you don't need them — built-in adapters use
plain HTTP via requests):
pip install guarded-llm[anthropic] # if you want the official anthropic SDK
pip install guarded-llm[openai] # if you want the official openai SDK
pip install guarded-llm[dev] # pytest, ruff, mypy
Quickstart
from guarded_llm import guardrailed_llm_call, LLMSchema
schema = LLMSchema({
"type": "object",
"properties": {
"verdict": {"type": "string", "enum": ["KEEP", "REJECT", "SPLIT", "MERGE"]},
"confidence": {"type": "number", "minimum": 0, "maximum": 1},
},
"required": ["verdict", "confidence"],
})
result = guardrailed_llm_call(
provider="deepseek",
model="deepseek-v4-flash",
messages=[{"role": "user", "content": "Is gravity a self-organized criticality system?"}],
schema=schema,
max_retries=3,
budget_cap_usd=0.05,
)
if result.ok:
print(result.parsed) # {"verdict": "REJECT", "confidence": 0.9}
print(result.cost_usd) # 0.0012
print(result.attempts) # 1
else:
print("All retries failed:", result.errors)
Set DEEPSEEK_API_KEY in your env (or pass api_key= via **kwargs).
Features
- Multi-provider out of the box — DeepSeek, Anthropic Claude, OpenAI, Kimi (Moonshot). All built-in adapters use plain HTTP — no vendor SDK required.
- Pluggable — subclass
BaseProvider+ callregister_provider("name", cls)to add anything else (OpenRouter, Together, Google Gemini, local Ollama, …). - Schema validation — bring your own JSON Schema via
LLMSchema(...), or use the legacy dataclass schemas (Layer3CriticVerdict,Layer4Prediction,B3EnsembleReview) shipped from the structural-isomorphism V4 pipeline. - Automatic retry with error feedback — each retry's prompt includes the prior validation error so the model can self-correct.
- Budget cap — pass
budget_cap_usd=and aBudgetExceededErrorfires before you torch your wallet on a runaway loop. - Structured result —
GuardrailResultexposesparsed,errors,attempts,cost_usd, andraw_outputsfor debugging. - Drop-in compat — supports the legacy
guardrailed_llm_call(prompt_fn, llm_caller, schema_cls, max_retries)signature for existing callers.
How it compares
| Feature | guarded-llm | instructor | outlines | guidance |
|---|---|---|---|---|
| Multi-provider | ✅ 4 built-in | ✅ many | partial (HF-first) | partial |
| Works on closed-model APIs | ✅ | ✅ | mostly local | partial |
| JSON Schema input | ✅ | via Pydantic | ✅ | ✅ |
| State-machine fixer for drift | ✅ | retry only | grammar-constrained | grammar-constrained |
| No SDK lock-in (HTTP only) | ✅ | requires vendor SDK | ✅ | ✅ |
| Cost tracking | ✅ | ❌ | ❌ | ❌ |
| Budget cap | ✅ | ❌ | ❌ | ❌ |
| Footprint | tiny (3 deps) | medium | large (torch optional) | medium |
guarded-llm's niche: closed-model APIs where you can't grammar-constrain
the decoder, but you still want strict JSON without writing five layers of
defensive parsing. If you're using local HF models, prefer outlines'
grammar-level approach; if you're already deep in Pydantic, instructor is
elegant.
Provider environment variables
| Provider | API key env | Base URL env (optional) |
|---|---|---|
deepseek |
DEEPSEEK_API_KEY |
DEEPSEEK_BASE_URL |
anthropic |
ANTHROPIC_API_KEY |
ANTHROPIC_BASE_URL |
openai |
OPENAI_API_KEY |
OPENAI_BASE_URL |
kimi |
KIMI_API_KEY or MOONSHOT_API_KEY |
KIMI_BASE_URL |
You can also pass api_key=, base_url= directly in the call.
License
MIT — see LICENSE.
Contributing
This package lives inside the structural-isomorphism
monorepo at packages/guarded-llm/. PRs welcome — see the
repo issues page.
Metadata
Release files for guarded-llm 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 | |
|---|---|---|---|
| guarded_llm-0.1.0.tar.gz | 24.0 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| guarded_llm-0.1.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 46.6 kB
Release files / guarded_llm-0.1.0.tar.gz
| Download URL | guarded_llm-0.1.0.tar.gz |
|---|---|
| Size | 24.0 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
faef638f99eb80275e487dea7032c64579168d2ab067621062e35fe72708883d
|
|
BLAKE2b-256 checksum How to use checksums |
7d077307fe294b991075b829a465afd504b80df18a7dc0653d11debef5dcd4c5
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.14.3
|
Release files / guarded_llm-0.1.0-py3-none-any.whl
| Download URL | guarded_llm-0.1.0-py3-none-any.whl |
|---|---|
| Size | 22.6 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
d3e3de8a486346448bff327fc85d99766c6be51ccac066055398cf4c017eb62f
|
|
BLAKE2b-256 checksum How to use checksums |
867cc14d8d9f02d6a2ca97c2521b63dc4d9d0321885c5a7dbab43b373ec7ed04
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.14.3
|