llm-json-repair
Repara JSON roto devuelto por LLMs y devuélvelo como dict válido. Sin dependencias (solo stdlib).
Problema que resuelve: los modelos (GPT, Claude, Llama, etc.) suelen devolver JSON con comas sueltas, comillas sin cerrar, bloques ```json incompletos, texto explicativo alrededor, literales Python (True/None), comentarios o corchetes sin cerrar. Esta librería lo repara automáticamente.
v0.2: motor FSM
Nuevo núcleo sintáctico en v0.2.0 (ver CHANGELOG.md y docs/ARCHITECTURE.md):
- Tokenizer char-by-char sin regex en el núcleo: recorre la entrada carácter a carácter, respetando strings y escapes.
- Autoclose de truncados: cierra strings, objetos y arrays incompletos (
{"a": [1, 2→{"a": [1, 2]}). repair_stream/parse_stream/StreamingRepairer: reparación incremental para tokens en streaming.repair_and_validatecon Pydantic (opcional): repara y valida contra unBaseModel.- Benchmarks con 500 casos: comparativa vs
json-repairydirtyjson(verdocs/BENCHMARKS.md).
Benchmark (resumen)
| Librería | Casos | Reparados | Tasa |
|---|---|---|---|
llm-output-repair (v0.2.0) |
500 | 500 | 100.0% (0.04 ms/caso) |
json-repair |
500 | 500 | 100.0% (0.06 ms/caso) |
dirtyjson |
500 | 219 | 43.8% |
Detalle completo y metodología en
docs/BENCHMARKS.md.
Compatibilidad API v0.1:
repair_json(text) -> str,loads(text) -> AnyyRepairErrormantienen la misma firma y semántica que en v0.1.0. Lo nuevo (streaming,validation) es solo aditivo, no rompe código existente.
Ejemplo rápido
from llm_json_repair import loads
broken = '''Here is your JSON:
```json
{"name": "Ana", "tags": ['ia', 'python',], "active": True,}
'''
print(loads(broken))
# {'name': 'Ana', 'tags': ['ia', 'python'], 'active': True}
Instalación
pip install llm-output-repair
PyPI:
llm-output-repair· import:llm_json_repair(el nombre PyPI estaba ocupado).
Requiere Python >= 3.9. Sin dependencias de terceros.
Desde fuente:
git clone https://github.com/sergioo7r/llm-json-repair
pip install -e .
Uso
from llm_json_repair import repair_json, loads, RepairError
# 1. Reparar a string JSON válido
fixed_str = repair_json('{"a": 1,}')
# '{"a": 1}'
# 2. Reparar + parsear a objeto Python
data = loads('{"a": 1,}')
# {'a': 1}
# 3. Manejo de errores
try:
data = loads("esto no es json")
except RepairError as e:
print("irreparable:", e)
repair_json(text) -> str: devuelve string JSON válido. LanzaTypeErrorsi la entrada no esstr,RepairErrorsi no hay objeto/array reparable.loads(text) -> Any: repara y parsea conjson.loads. Misma semántica de errores.RepairError(ValueError): indica entrada irreparable (vacía, sin{/[, o inválida tras el pipeline).
Tabla de reparaciones
| Caso | Input | Output |
|---|---|---|
| Coma final | {"a": 1,} |
{"a": 1} |
| Comillas simples | {'a': 'x'} |
{"a": "x"} |
| Claves sin comillas | {name: "x"} |
{"name": "x"} |
| Literales Python | {"a": True, "b": None} |
{"a": true, "b": null} |
| Comentarios | {"a": 1 /* c */, "b": 2} |
{"a": 1, "b": 2} |
| Markdown cerrado | ```json\n{"a": 1}\n``` |
{"a": 1} |
| Markdown sin cerrar | ```json\n{"a": 1} |
{"a": 1} |
| Texto alrededor | Here is your JSON: {"a": 1} done |
{"a": 1} |
| Llave sin cerrar | {"a": 1 |
{"a": 1} |
| Lista sin cerrar | {"a": [1, 2 |
{"a": [1, 2]} |
| String sin cerrar | {"a": "hello} |
{"a": "hello"} |
Placeholder ... |
[1, 2, ...] |
[1, 2] |
| Salto literal en string | {"a": "x<LF>y"} |
{"a": "x\ny"} |
| Combinado | ```json\n{name: 'Bot', tags: ["ia",],}\n |
{"name": "Bot", "tags": ["ia"]} |
Ver detalle por etapa en docs/PIPELINE.md y referencia completa en docs/API.md.
Integración con OpenAI
examples/openai_integration_test.py genera respuestas con la API de OpenAI y mide la tasa de reparación por modelo. Sirve como evidencia para solicitudes de créditos y como test de regresión.
export OPENAI_API_KEY=sk-... # Windows: set OPENAI_API_KEY=sk-...
pip install openai
python examples/openai_integration_test.py --model gpt-4o-mini --n 50
# Reparadas: 48/50 (96.0%)
Quickstart sin claves:
python examples/quickstart.py
Ver docs/OPENAI_PROGRAM.md para justificación, coste estimado y evidencias.
Desarrollo
pip install -e ".[test]" # o: pip install pytest
pytest -q
Estructura:
src/llm_json_repair/repair.py # pipeline de 9 etapas (stdlib only)
tests/test_repair.py # suite unitaria
examples/quickstart.py # demo sin API keys
examples/openai_integration_test.py # test suite masivo con OpenAI
docs/ # documentación extendida
Convenciones y guía de contribución en CONTRIBUTING.md. Historial de cambios en CHANGELOG.md.
Roadmap
- v0.2: streaming (reparación incremental), CLI (
llm-json-repair fix), validación opcional con pydantic. - v0.3: benchmarks multilingües y matriz de modelos ampliada, corpus de fallos reales.
- v1.0: API estable, garantía de no-regresión, política de versionado semántico.
Detalle en ROADMAP.md.
Licencia
MIT. Ver LICENSE.
FAQ
1. ¿Sustituye a json.loads?
No. Úsalo como fallback: intenta json.loads primero y loads de esta librería solo si falla. Así evitas transformaciones innecesarias en JSON válido.
2. ¿Puede corromper JSON válido?
El pipeline conserva el input válido intacto (test test_valid_passthrough). Las transformaciones solo actúan fuera de strings con comillas dobles.
3. ¿Qué hace si la entrada es irreparable?
Lanza RepairError (subclase de ValueError). Captúrala y aplica tu política: reintentar al modelo, pedir formato estricto o registrar el fallo.
4. ¿Funciona sin internet ni API keys?
Sí. Es 100 % local y sin dependencias. Solo examples/openai_integration_test.py requiere OPENAI_API_KEY.
5. ¿Soporta JSONL, YAML o streaming? No en v0.1.0. Solo un objeto/array JSON por llamada. Streaming, CLI y validación pydantic están en el roadmap v0.2.
Metadata
Release files for llm-output-repair 0.2.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 | Provenance | |
|---|---|---|---|---|
| llm_output_repair-0.2.0.tar.gz | 12.5 kB | Without provenance | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| llm_output_repair-0.2.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 17.8 kB
Release files / llm_output_repair-0.2.0.tar.gz
| Download URL | llm_output_repair-0.2.0.tar.gz |
|---|---|
| Size | 12.5 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
f718849acef3cb8a7178620a51b28acf1460230f769bca47c6bafde9f9f0d615
|
|
BLAKE2b-256 checksum How to use checksums |
98a5781e42846116a26f0910559b79e5980aa5b1e41d24cfc086151e39c9f693
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.14.5
|
Release files / llm_output_repair-0.2.0-py3-none-any.whl
| Download URL | llm_output_repair-0.2.0-py3-none-any.whl |
|---|---|
| Size | 5.3 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
bc2526017503c42e623f4332fddeefa93acf94b84d43d9c608a0b1b111c6c95f
|
|
BLAKE2b-256 checksum How to use checksums |
a5338cf394e91497946db44b45ff31c5474c9b1263474896bb41ed1ff3ee41d4
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.14.5
|
Security for llm-output-repair 0.2.0
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
No provenance found
None of the files in this release were uploaded with provenance metadata.
A note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.