[docs]classYamlOutputParser(BaseOutputParser[T]):"""Parse YAML output using a pydantic model."""pydantic_object:Type[T]"""The pydantic model to parse."""pattern:re.Pattern=re.compile(r"^```(?:ya?ml)?(?P<yaml>[^`]*)",re.MULTILINE|re.DOTALL)"""Regex pattern to match yaml code blocks within triple backticks with optional yaml or yml prefix."""
[docs]defparse(self,text:str)->T:try:# Greedy search for 1st yaml candidate.match=re.search(self.pattern,text.strip())yaml_str=""ifmatch:yaml_str=match.group("yaml")else:# If no backticks were present, try to parse the entire output as yaml.yaml_str=textjson_object=yaml.safe_load(yaml_str)returnself.pydantic_object.parse_obj(json_object)except(yaml.YAMLError,ValidationError)ase:name=self.pydantic_object.__name__msg=f"Failed to parse {name} from completion {text}. Got: {e}"raiseOutputParserException(msg,llm_output=text)frome
[docs]defget_format_instructions(self)->str:# Copy schema to avoid altering original Pydantic schema.schema={k:vfork,vinself.pydantic_object.schema().items()}# Remove extraneous fields.reduced_schema=schemaif"title"inreduced_schema:delreduced_schema["title"]if"type"inreduced_schema:delreduced_schema["type"]# Ensure yaml in context is well-formed with double quotes.schema_str=json.dumps(reduced_schema)returnYAML_FORMAT_INSTRUCTIONS.format(schema=schema_str)