结构化输出
概述
对于许多应用,如聊天机器人,模型需要直接以自然语言回应用户。 然而,在某些场景中,我们需要模型以结构化格式输出。 例如,我们可能希望将模型输出存储在数据库中,并确保输出符合数据库模式。 这种需求催生了结构化输出的概念,即可以指示模型以特定的输出结构进行响应。
关键概念
(1) 模式定义: 输出结构表示为模式,可以通过多种方式定义。 (2) 返回结构化输出: 模型被赋予此模式,并被指示返回符合该模式的输出。
推荐用法
这段伪代码展示了使用结构化输出时推荐的工作流程。
LangChain 提供了一个方法,with_structured_output()
,它自动化了将模式绑定到模型并解析输出的过程。
这个辅助函数适用于所有支持结构化输出的模型提供商。
# Define schema
schema = {"foo": "bar"}
# Bind schema to model
model_with_structure = model.with_structured_output(schema)
# Invoke the model to produce structured output that matches the schema
structured_output = model_with_structure.invoke(user_input)
模式定义
核心概念是模型响应的输出结构需要以某种方式表示。 虽然您可以使用的对象类型取决于您正在使用的模型,但通常允许或推荐用于Python中结构化输出的常见对象类型。
结构化输出的最简单和最常见的格式是类似JSON的结构,在Python中可以表示为字典(dict)或列表(list)。 当工具需要原始、灵活且开销最小的结构化数据时,通常直接使用JSON对象(或Python中的字典)。
{
"answer": "The answer to the user's question",
"followup_question": "A followup question the user could ask"
}
作为第二个例子,Pydantic 特别适用于定义结构化输出模式,因为它提供了类型提示和验证。 以下是一个 Pydantic 模式的示例:
from pydantic import BaseModel, Field
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")
返回结构化输出
定义了模式后,我们需要一种方法来指示模型使用它。 虽然一种方法是在提示中包含此模式并礼貌地请求模型使用它,但这并不推荐。 有几种更强大的方法可以利用模型提供者API中的原生功能。
使用工具调用
许多模型提供商支持工具调用,这一概念在我们的工具调用指南中有更详细的讨论。
简而言之,工具调用涉及将工具绑定到模型,并在适当的时候,模型可以决定调用此工具并确保其响应符合工具的架构。
考虑到这一点,核心概念非常简单:只需将我们的架构作为工具绑定到模型!
以下是使用上面定义的ResponseFormatter
架构的示例:
from langchain_openai import ChatOpenAI
model = ChatOpenAI(model="gpt-4o", temperature=0)
# Bind responseformatter schema as a tool to the model
model_with_tools = model.bind_tools([ResponseFormatter])
# Invoke the model
ai_msg = model_with_tools.invoke("What is the powerhouse of the cell?")
工具调用的参数已经被提取为一个字典。
这个字典可以选择性地解析为一个Pydantic对象,匹配我们原始的ResponseFormatter
模式。
# Get the tool call arguments
ai_msg.tool_calls[0]["args"]
{'answer': "The powerhouse of the cell is the mitochondrion. Mitochondria are organelles that generate most of the cell's supply of adenosine triphosphate (ATP), which is used as a source of chemical energy.",
'followup_question': 'What is the function of ATP in the cell?'}
# Parse the dictionary into a pydantic object
pydantic_object = ResponseFormatter.model_validate(ai_msg.tool_calls[0]["args"])
JSON 模式
除了工具调用外,一些模型提供商支持一个名为JSON mode
的功能。
该功能支持将JSON模式定义作为输入,并强制模型生成符合要求的JSON输出。
您可以在此处找到支持JSON模式的模型提供商列表here。
以下是如何在OpenAI中使用JSON模式的示例:
from langchain_openai import ChatOpenAI
model = ChatOpenAI(model="gpt-4o", model_kwargs={ "response_format": { "type": "json_object" } })
ai_msg = model.invoke("Return a JSON object with key 'random_ints' and a value of 10 random ints in [0-99]")
ai_msg.content
'\n{\n "random_ints": [23, 47, 89, 15, 34, 76, 58, 3, 62, 91]\n}'
需要指出的一点是:模型仍然返回一个字符串,需要将其解析为JSON对象。
当然,如果您需要更高级的功能,可以简单地使用json
库或JSON输出解析器。
有关更多详细信息,请参阅此关于JSON输出解析器的操作指南。
import json
json_object = json.loads(ai_msg.content)
{'random_ints': [23, 47, 89, 15, 34, 76, 58, 3, 62, 91]}
结构化输出方法
使用上述方法生成结构化输出时存在一些挑战:
(1) 当使用工具调用时,需要将工具调用参数从字典解析回原始模式。
(2) 此外,模型需要被指示在我们想要强制执行结构化输出时始终使用工具,这是一个特定于提供者的设置。
(3) 当使用JSON模式时,输出需要解析为JSON对象。
考虑到这些挑战,LangChain 提供了一个辅助函数 (with_structured_output()
) 来简化流程。
这既将模式绑定到模型作为工具,又将输出解析为指定的输出模式。
# Bind the schema to the model
model_with_structure = model.with_structured_output(ResponseFormatter)
# Invoke the model
structured_output = model_with_structure.invoke("What is the powerhouse of the cell?")
# Get back the pydantic object
structured_output
ResponseFormatter(answer="The powerhouse of the cell is the mitochondrion. Mitochondria are organelles that generate most of the cell's supply of adenosine triphosphate (ATP), which is used as a source of chemical energy.", followup_question='What is the function of ATP in the cell?')
有关使用方法的更多详细信息,请参阅我们的操作指南。