YAMLOutputParser (yaml_parser.py)

On this page

class output_parser.yaml_parser.YAMLOutputParser(BaseOutputParser)

Overview

Extracts and parses YAML from raw LLM text, with optional Pydantic validation. Requires PyYAML — unlike the JSON/CSV/list parsers, this dependency is not optional at the class level: __init__ raises ImportError immediately if yaml isn't importable, even if you never call parse().

Depends on base_parser.py and PyYAML (required); optionally pydantic.

Constructor

Python
YAMLOutputParser(pydantic_model: Optional[Type] = None)

Raises:

  • ImportError("PyYAML is required for YAMLOutputParser. Install it with: pip install pyyaml") if yaml is not installed (checked via the module-level YAML_AVAILABLE flag set at import time).
  • Same pydantic_model validation as JSONOutputParser if a model is provided.

Public Methods

parse

Python
def parse(self, text: str) -> Any

Returns: parsed YAML content (dict, list, scalar, etc.), or a pydantic_model instance if configured.

Raises:

  • ParsingError("Cannot parse empty text", ...) for empty input.
  • ParsingError(f"Invalid YAML: {e}", ...) if yaml.safe_load() raises yaml.YAMLError.
  • ParsingError("YAML parsed to None/empty.", ...) if the result is None (e.g. input was just whitespace/comments after extraction).
  • ParsingError(f"Expected YAML mapping for Pydantic model, got {type}", ...) if a model is configured but the parsed data isn't a dict.
  • ParsingError(f"YAML does not match schema for {name}: {e}", ...) if Pydantic construction fails.
  • Also propagates any ParsingError raised inside _extract_yaml (see below) — these are not caught/wrapped again by parse(), they bubble up as-is.

Algorithm (_extract_yaml, multi-step cleaning pipeline):

  1. Empty input → raises ParsingError immediately.
  2. Best case: regex-search for a ```yaml / ```yml / bare ``` fence. If found and non-empty, returns the inner content directly — no further cleaning applied.
  3. No fence found: splits into lines and filters out noise: lines that are just ``` fences, lines that are literally "yaml"/"yml" on their own, and lines starting with common LLM chatter prefixes ("here is", "here's", "the following", "below is", "this is" — case-insensitive).
  4. If the cleaned text is empty after filtering, raises ParsingError("Text became empty after cleaning; no YAML content found.").
  5. Searches for the first line matching a YAML key pattern (^[\s\-]*[a-zA-Z0-9_\-]+\s*:\s*) and slices the text starting from that match — this trims any remaining leading prose that survived the line-filter step. If no key pattern is found, uses the full cleaned text as-is.
  6. Final sanity check: if the resulting text contains no : at all, raises ParsingError("Extracted text does not look like valid YAML (missing ':').").
  7. Any unexpected exception during this process is caught and re-raised as ParsingError(f"Unexpected error during YAML extraction: {e}", cause=e).

[!NOTE] Source contains embedded Arabic comments The _extract_yaml method's source contains a small number of inline Arabic-language comments (e.g. # تجاهل markdown — "ignore markdown", # تجاهل yaml لوحدها — "ignore yaml alone", # تجاهل جمل LLM — "ignore LLM sentences", # سيبه يعدي زي ما هو — "let it pass through as-is"). These are developer comments only and have no effect on behavior or the public API.

get_format_instructions

If pydantic_model is set, builds a ```yaml fenced example listing each schema property as field: <type> # required or # optional. Otherwise returns a generic YAML instruction with a hardcoded key: value / list example.

Complexity

_extract_yaml is O(n) in text length — one pass to split into lines, one filtering pass, one regex search for the key pattern. yaml.safe_load()'s complexity is governed by PyYAML itself (generally linear in document size for typical structures).

Thread Safety

Safe to share across threads for concurrent parse() calls — no mutable instance state beyond pydantic_model. yaml.safe_load itself is stateless per-call.

Side Effects

None beyond raising exceptions — no logging, no I/O, no global state mutation. Uses yaml.safe_load specifically (not yaml.load), which is intentionally restricted to prevent arbitrary Python object construction/code execution from untrusted YAML input.

Examples

Python · 9 lines
# Basic — fenced YAML
parser = YAMLOutputParser()
text = '''
```yaml
name: Alice
age: 30
skills:
  - Python
  - YAML

''' result = parser.parse(text)

text = "Here is the YAML:\nname: Bob\nrole: engineer" result = parser.parse(text)

from pydantic import BaseModel class Config(BaseModel): name: str age: int parser = YAMLOutputParser(pydantic_model=Config) config = parser.parse("name: Alice\nage: 30")

try: parser.parse("just some prose with no colon anywhere") except ParsingError as e: print(str(e))

from output_parser.yaml_parser import YAML_AVAILABLE if YAML_AVAILABLE: parser = YAMLOutputParser() else: parser = None # fall back to another format

code · 19 lines

## Best Practices

- Check `output_parser.yaml_parser.YAML_AVAILABLE` before constructing this class in environments where `pyyaml` may not be installed, to fail gracefully rather than catching `ImportError`.
- Always instruct the LLM to wrap YAML in a ` ```yaml ` fence via `get_format_instructions()` — the unfenced extraction path (steps 3–6 above) is a best-effort fallback, not a guarantee, and can fail on YAML that doesn't start with a clean `key:` line.

## Common Mistakes

- Assuming YAML support works out of the box — unlike `pydantic`, `PyYAML` failing to import raises immediately in `__init__`, not lazily. Wrap construction in a `try`/`except ImportError` if you need to support environments without it.
- Relying on the "LLM chatter" line filter to catch every possible preamble phrasing — it only matches a fixed, hardcoded set of prefixes (`"here is"`, `"here's"`, `"the following"`, `"below is"`, `"this is"`). Other preambles (e.g. `"Sure! The configuration is:"`) will not be filtered and could interfere with extraction if they land on a line containing a `:` before the actual YAML key pattern is found.

## Related APIs

- [`BaseOutputParser`, `ParsingError`](base_parser.md)
- [`OutputParser`](output_parser.md) — the orchestrator's internal `_parse_yaml` is a much simpler variant (fence-or-whole-text, no line-filtering pipeline).

## Version History

Not determinable from source.

Related pages