Skip to main content
Open In Colab在 GitHub 上打开

如何使用输出解析器将 LLM 响应解析为结构化格式

语言模型输出文本。但有时您希望获得更结构化的信息,而不仅仅是回复短信。虽然一些模型提供程序支持返回结构化输出的内置方法,但并非所有模型提供程序都支持。

输出解析器是帮助构建语言模型响应的类。输出解析器必须实现两种主要方法:

  • “Get format instructions(获取格式指令)”:返回一个字符串的方法,其中包含有关如何格式化语言模型输出的说明。
  • “Parse(解析)”:一种接收字符串(假设是来自语言模型的响应)并将其解析为某种结构的方法。

然后是一个可选的:

  • “Parse with prompt(使用提示解析)”:一种方法,它接收一个字符串(假设是来自语言模型的响应)和一个提示(假设是生成此类响应的提示)并将其解析为某种结构。提示符主要是在 OutputParser 想要以某种方式重试或修复输出的情况下提供的,并且需要来自提示符的信息才能这样做。

开始使用

下面我们介绍输出解析器的主要类型,PydanticOutputParser.

from langchain_core.output_parsers import PydanticOutputParser
from langchain_core.prompts import PromptTemplate
from langchain_openai import OpenAI
from pydantic import BaseModel, Field, model_validator

model = OpenAI(model_name="gpt-3.5-turbo-instruct", temperature=0.0)


# Define your desired data structure.
class Joke(BaseModel):
setup: str = Field(description="question to set up a joke")
punchline: str = Field(description="answer to resolve the joke")

# You can add custom validation logic easily with Pydantic.
@model_validator(mode="before")
@classmethod
def question_ends_with_question_mark(cls, values: dict) -> dict:
setup = values.get("setup")
if setup and setup[-1] != "?":
raise ValueError("Badly formed question!")
return values


# Set up a parser + inject instructions into the prompt template.
parser = PydanticOutputParser(pydantic_object=Joke)

prompt = PromptTemplate(
template="Answer the user query.\n{format_instructions}\n{query}\n",
input_variables=["query"],
partial_variables={"format_instructions": parser.get_format_instructions()},
)

# And a query intended to prompt a language model to populate the data structure.
prompt_and_model = prompt | model
output = prompt_and_model.invoke({"query": "Tell me a joke."})
parser.invoke(output)
Joke(setup='Why did the tomato turn red?', punchline='Because it saw the salad dressing!')

LCEL

输出解析器实现 Runnable 接口,这是 LangChain 表达式语言 (LCEL) 的基本构建块。这意味着他们支持invoke,ainvoke,stream,astream,batch,abatch,astream_log调用。

输出解析器接受字符串或BaseMessage作为 input,并且可以返回任意类型。

parser.invoke(output)
Joke(setup='Why did the tomato turn red?', punchline='Because it saw the salad dressing!')

除了手动调用解析器,我们也可以将其添加到我们的Runnable序列:

chain = prompt | model | parser
chain.invoke({"query": "Tell me a joke."})
Joke(setup='Why did the tomato turn red?', punchline='Because it saw the salad dressing!')

虽然所有解析器都支持流式接口,但只有某些解析器可以通过部分解析的对象进行流式传输,因为这在很大程度上取决于输出类型。无法构造部分对象的解析器将只产生完全解析的输出。

SimpleJsonOutputParser例如,可以通过 partial outputs 进行流式处理:

from langchain.output_parsers.json import SimpleJsonOutputParser

json_prompt = PromptTemplate.from_template(
"Return a JSON object with an `answer` key that answers the following question: {question}"
)
json_parser = SimpleJsonOutputParser()
json_chain = json_prompt | model | json_parser
list(json_chain.stream({"question": "Who invented the microscope?"}))
[{},
{'answer': ''},
{'answer': 'Ant'},
{'answer': 'Anton'},
{'answer': 'Antonie'},
{'answer': 'Antonie van'},
{'answer': 'Antonie van Lee'},
{'answer': 'Antonie van Leeu'},
{'answer': 'Antonie van Leeuwen'},
{'answer': 'Antonie van Leeuwenho'},
{'answer': 'Antonie van Leeuwenhoek'}]

同样,对于PydanticOutputParser:

list(chain.stream({"query": "Tell me a joke."}))
[Joke(setup='Why did the tomato turn red?', punchline=''),
Joke(setup='Why did the tomato turn red?', punchline='Because'),
Joke(setup='Why did the tomato turn red?', punchline='Because it'),
Joke(setup='Why did the tomato turn red?', punchline='Because it saw'),
Joke(setup='Why did the tomato turn red?', punchline='Because it saw the'),
Joke(setup='Why did the tomato turn red?', punchline='Because it saw the salad'),
Joke(setup='Why did the tomato turn red?', punchline='Because it saw the salad dressing'),
Joke(setup='Why did the tomato turn red?', punchline='Because it saw the salad dressing!')]