Structured output
https://python.langchain.com/docs/concepts/#structured-output
大型语言模型(LLMs)能够生成任意文本。这使模型能够对广泛的输入做出适当响应,但在某些使用场景下,将 LLM 的输出限制为特定格式或结构可能非常有用。这被称为结构化输出。
例如,如果输出要存储在关系型数据库中,那么如果模型生成的输出符合预定义的模式或格式,操作会更加方便。从非结构化文本中提取特定信息也是这种方法特别有用的一个例子。最常见的输出格式是 JSON,但其他格式如 YAML 也可能有用。接下来,我们将讨论几种在 LangChain 中从模型获取结构化输出的方法。
.with_structured_output()
为了方便起见,一些 LangChain 聊天模型支持 .with_structured_output() 方法。该方法只需要一个模式(schema)作为输入,并返回一个 dict 或 Pydantic 对象。通常,这个方法只在支持以下某些高级方法的模型上可用,并且会在后台使用其中的一个方法。它负责导入合适的输出解析器,并将模式格式化为适合模型的格式。
下面是一个示例:
from typing import Optional
from pydantic import BaseModel, Field
class Joke(BaseModel):
"""Joke to tell user."""
setup: str = Field(description="The setup of the joke")
punchline: str = Field(description="The punchline to the joke")
rating: Optional[int] = Field(description="How funny the joke is, from 1 to 10")
structured_llm = llm.with_structured_output(Joke)
structured_llm.invoke("Tell me a joke about cats")Joke(setup='Why was the cat sitting on the computer?',
punchline='To keep an eye on the mouse!', rating=None) 我们建议在处理结构化输出时以这种方法作为起点:
它在底层使用了其他与模型相关的特性,而无需导入输出解析器。对于支持工具调用的模型,无需特殊的提示。如果支持多种底层技术,你可以通过提供一个方法参数来切换所使用的技术。
你可能需要使用其他技术的情况包括:
- 你使用的聊天模型不支持工具调用。
- 你处理的是非常复杂的模式(schemas),且模型在生成符合要求的输出时遇到了困难。
欲了解更多信息,请查看此操作指南。
你还可以查看此表格,了解支持 with_structured_output() 的模型列表。
直接提示(Raw prompting)
让模型结构化输出的最直观方法就是礼貌地请求。除了你的查询外,你还可以提供指令,描述你希望的输出格式,然后使用输出解析器将模型的原始消息或字符串输出转换为更易于操作的格式。
直接提示的最大优势在于其灵活性:
- 直接提示不需要任何特殊的模型功能,只需具备足够的推理能力来理解所传递的模式。
- 你可以请求任何你想要的格式,不仅限于 JSON。如果你使用的模型在某类数据(如 XML 或 YAML)上进行了更多的训练,这将非常有用。
然而,这也有一些缺点:
- 大型语言模型 (LLM) 是非确定性的,因此让它们持续输出完全正确的格式以便于解析可能会出乎意料地困难,而且具体情况与模型相关。
- 各个模型会因为训练数据的不同而具有独特的特性,优化提示词可能相当困难。有些模型可能更擅长解释JSON Schema,另一些可能在 TypeScript 定义上表现更好,而还有一些则可能更偏好 XML。
虽然模型提供商提供的功能可以提高可靠性,但无论选择哪种方法,提示技术在调优结果时仍然至关重要。
JSON mode
一些模型,如Mistral、OpenAI、Together AI 和 Ollama,支持一种称为 JSON mode的功能,通常通过配置启用。
启用后,JSON mode会约束模型的输出始终为某种有效的JSON 格式。通常需要一些自定义提示,但相比完全自由的提示方式,这种模式的负担要轻得多,通常只需提示你必须始终返回JSON("you must always return JSON")。输出也通常更易于解析。
它也比工具调用更简单、更常用,并且在提示和调整结果方面比工具调用提供了更多的灵活性。
以下是一个示例:
from langchain_core.prompts import ChatPromptTemplate
from langchain_openai import ChatOpenAI
from langchain.output_parsers.json import SimpleJsonOutputParser
model = ChatOpenAI(
model="gpt-4o",
model_kwargs={ "response_format": { "type": "json_object" } },
)
prompt = ChatPromptTemplate.from_template(
"Answer the user's question to the best of your ability."
'You must always output a JSON object with an "answer" key and a "followup_question" key.'
"{question}"
)
chain = prompt | model | SimpleJsonOutputParser()
chain.invoke({ "question": "What is the powerhouse of the cell?" })API Reference: ChatPromptTemplate | ChatOpenAI | SimpleJsonOutputParser
{'answer': 'The powerhouse of the cell is the mitochondrion. It is responsible for producing energy in the form of ATP through cellular respiration.',
'followup_question': 'Would you like to know more about how mitochondria produce energy?'}有关支持JSON mode的模型提供商的完整列表,请参见此表格。
工具调用(Tool calling)
对于支持工具调用的模型,使用工具调用可以非常方便地生成结构化输出。这消除了围绕如何最佳提示模式(schemas)的猜测,转而使用模型内置功能。
它的工作原理是首先通过 .bind_tools() 方法,将所需的schema直接或通过LangChain tool绑定到聊天模型。模型随后会生成一个包含 tool_calls 字段的 AIMessage,其中包含与所需匹配的参数。
在LangChain中,有几种可接受的格式可以用于将工具绑定到模型。以下是一个示例:
from pydantic import BaseModel, Field
from langchain_openai import ChatOpenAI
class ResponseFormatter(BaseModel):
"""Always use this tool to structure your response to the user."""
answer: str = Field(description="The answer to the user's question")
followup_question: str = Field(description="A followup question the user could ask")
model = ChatOpenAI(
model="gpt-4o",
temperature=0,
)
model_with_tools = model.bind_tools([ResponseFormatter])
ai_msg = model_with_tools.invoke("What is the powerhouse of the cell?")
ai_msg.tool_calls[0]["args"]API Reference: ChatOpenAI
{'answer': "The powerhouse of the cell is the mitochondrion. It generates most of the cell's supply of adenosine triphosphate (ATP), which is used as a source of chemical energy.",
'followup_question': 'How do mitochondria generate ATP?'}工具调用是一种让模型生成结构化输出的普遍一致方法,并且是模型支持的情况下用于 .with_structured_output() 方法的默认技术。
以下操作指南是使用函数/工具调用生成结构化输出的实用资源:
有关支持工具调用的模型提供商的完整列表,请参阅此表格。