Concepts
On this page
Output formats (OutputFormat)
Defined in schema.py. Represents the detected or expected shape of an LLM output:
Parse modes (ParseMode)
Format detection scoring
FormatDetector (in format_detector.py) does not try parsers one at a time and catch exceptions — it runs independent regex/structural scorers for every format and assigns each a confidence score in [0.0, 1.0]:
_score_json— 0.99 ifjson.loads()succeeds directly; 0.65 if the text merely starts/ends with{}/[]; 0.45 for an embedded{"key":pattern._score_yaml— scores on count ofkey: valuelines (≥3 lines → +0.5) and list items (≥2 → +0.25), with a 0.3 penalty if the text starts with{/[(to avoid misclassifying JSON as YAML, since both use colons)._score_csv— checks each of, ; \t |as a candidate delimiter, requires ≥75% row-to-row consistency in delimiter count across the first 4 data rows._score_markdown_table— 0.92 if a proper| header |+|---|separator row is found; 0.5 for merely pipe-delimited lines._score_numbered_list/_score_bulleted_list— 0.85/0.82 for ≥3 matched items, 0.4/0.38 for 1–2._score_key_value— 0.60 if ≥2key: valuematches and no YAML list markers present (to avoid double-counting with YAML)._score_xml— 0.88 for ≥2 paired tags, 0.35 for a bare self-closing/opening tag._score_tool_call— 0.82 with anAction:/Tool:/Function:line plus an argument block, 0.55 without; 0.90 for OpenAI-style"name": ..., "arguments"JSON._score_plain_text— always returns a baseline score (max(0.1, 0.55 - 0.1 * structure_signal_count)) so there is always at least one fallback candidate.
A code fence with an explicit language tag (```json, ```yaml, ```csv, ```xml) short-circuits with high confidence (0.90–0.95) via _detect_from_code_fence, and is combined with — not simply replacing — the structural scores.
detect() returns just the top candidate; rank() returns all candidates above _MIN_CONFIDENCE = 0.15, deduplicated by format and sorted descending; detect_with_confidence() returns (format, confidence) for the top candidate.
Fix strategies (FixStrategy)
Applied in order by OutputFixer.fix() (see api/fixer.md for full detail):
REGEX_REPAIR— strips markdown fences, fixes trailing commas, converts single→double quotes, quotes bare keys; if still invalid, tries extracting the first complete JSON block, then progressively truncating from the right to find a valid JSON prefix.FIELD_INJECTION— if the text is valid-enough JSON to parse into a dict, injectsNone/default values for anyrequired_fieldsthat are missing.FALLBACK_PARSE— extractskey: valuepairs from plain text via regex and re-serializes as JSON.LLM_REFORMAT— (only ifllm_fnis set) sends the malformed text to the LLM with an explicit "reformat this as X" prompt.
If none succeed, fix() returns the original text unchanged with FixStrategy.NONE.
Retry strategies (RetryStrategy)
Applied in order by RetryHandler.run() (see api/retry_handler.md):
STRICT_FORMAT— re-sends the original question plus the previous error, a preview of the bad response, and the parser's format instructions.JSON_STRICT— demands JSON-only output and includes a generated schema example (from the Pydantic model if available, else fromrequired_fields).SIMPLIFIED— asks a stripped-down version of the question, requesting just{"answer": "...", "confidence": ...}.GRACEFUL_FAIL— terminal state; no further LLM call is made, andRetryResult.success = Falseis returned.
Each attempt sleeps backoff_seconds * attempt_idx before calling llm_fn (linear backoff, default 0.5s per step).
Validation layers
OutputValidator.validate() (see api/validator.md) runs up to four layers, all independent and all additive to the results list:
- Field completeness/typing — only runs if
fieldswere provided anddatais adict. Checks required fields present, then soft type-coerces mismatches toWARNINGwhere possible (e.g."3"for anintfield), elseFAILED. Also emitsWARNINGfor any unexpected extra keys not declared infields. - Business rules — arbitrary
ValidationRulepredicates you supply. - Safety checks — regex scans for hallucination-admission phrases (
WARNING), sensitive data leakage patterns like credit-card-shaped numbers, SSNs, emails,password=/api_key=strings, and Bearer tokens (FAILED), and prompt-injection markers like "ignore previous instructions" (FAILED). Only runs ifenable_safety=True(default). - Pydantic structural validation — only runs if a
pydantic_modelwas supplied anddatais adict; re-validates by instantiating the model.
Thread safety
None of the classes in this package (OutputParser, FormatDetector, OutputValidator, OutputFixer, RetryHandler, or any BaseOutputParser subclass) implement explicit locking. Specifically:
OutputParser._cacheis a plaindict— concurrentparse()calls from multiple threads on the same instance with overlapping text can race on cache writes (a lost update is possible, not a crash, since dict assignment is atomic in CPython, but you should not rely on the cache being consistent under concurrent write-heavy load).- All other components hold only configuration state set at
__init__time and are read-only duringparse()/detect()/validate()/fix()/run(), making them safe to share across threads as long as you don't mutate their config after construction. - Async:
BaseOutputParser.async_parse()(inbase_parser.py) runs the synchronousparse()in a thread-pool executor viaasyncio.get_event_loop().run_in_executor(None, self.parse, text). This makes it safe to call from an async context, but does not makeparse()itself non-blocking — it just moves the blocking call off the event loop thread. TheOutputParserorchestrator (parser.py) does not define an async entry point at all; onlyBaseOutputParsersubclasses (the single-format toolkit) getasync_parse()for free.