Architecture
On this page
Two independent layers
The package contains two things that can be used separately:
- Single-format parser toolkit (
base_parser.py+json_parser.py,yaml_parser.py,csv_parser.py,list_parser.py,structured_parser.py,pydantic_parser.py) — each parser implements theBaseOutputParserabstract interface (parse(),get_format_instructions()) independently. They share no runtime state with the orchestrator;pydantic_parser.pyandjson_parser.pyare the only two that depend on each other (PydanticOutputParserwraps aJSONOutputParserinternally). - The orchestrator (
parser.py'sOutputParser), which composesFormatDetector,OutputFixer,OutputValidator, andRetryHandlerinto one pipeline. It does not import or reuse the single-format parser classes — it has its own internal module-level parse functions (_parse_json,_parse_yaml,_parse_csv,_parse_markdown_table,_parse_list,_parse_xml,_parse_tool_call,_parse_key_value,_parse_plain_text) mapped byOutputFormatin the_FORMAT_PARSERSdict.
The orchestrator pipeline
OutputParser.parse() runs _run_pipeline(), which executes stages in a fixed order, short-circuiting as soon as a stage succeeds:
Data flow of types
Initialization flow of OutputParser
OutputParser.__init__ builds its sub-components eagerly (not lazily):
- Stores
schema,fields,mode,expected_format,llm_fn,max_retries,enable_safety,enable_cache,original_promptas instance attributes. - Creates a
FormatDetector()(stateless, no config). - Calls
self._build_validator()→ constructs anOutputValidator(fields=self.fields, pydantic_model=self.schema, enable_safety=self.enable_safety). - Calls
self._build_fixer()→ constructs anOutputFixer(required_fields=[required field names], field_defaults={name: default}, llm_fn=self.llm_fn). - Constructs a
RetryHandleronly if bothllm_fnis truthy andmax_retries > 0; otherwiseself._retry = Noneand the retry stage of the pipeline is skipped entirely. - Initializes
self._cache = {}(a plain in-process dict, keyed by MD5 hash of the input text via_cache_key).
Caching model
Caching is per-OutputParser-instance, in-memory, and keyed by hashlib.md5(text). It only stores results where result.ok is True (i.e. result.data is not None). There is no TTL, size cap, or eviction policy — cache entries live until clear_cache() is called or the instance is garbage collected. This means:
- Long-running processes that pass many unique texts through the same
OutputParserinstance will grow the cache unboundedly. - Caching is not shared across threads/processes beyond normal Python object-sharing semantics — it is a plain
dict, so concurrent writes from multiple threads are not synchronized (see Concepts → Thread safety).
Extension points
- Custom schema/fields: pass a Pydantic
schemaclass or a list ofFieldSchematoOutputParser. - Custom business rules: build your own
OutputValidator(rules=[ValidationRule(...), ...])and either use it standalone, or subclass/monkeypatchOutputParser._build_validator(no built-in constructor argument exists onOutputParserfor injecting customValidationRules directly — this is a determinable limitation of the current implementation). - Custom LLM backend: any
Callable[[str], str]works asllm_fn— it's used both byOutputFixer(LLM_REFORMATstrategy) andRetryHandler. - Composable single-format parsers:
ChainedParser([ParserA(), ParserB()])tries each in order;AutoFixingParser(parser, fixer=callable)retries a single parser with a fixer callback between attempts.