
奥本 AI 将所有的最新 AI 聚合到了一起,为您开启多模型 AI 绘画新时代!
扫码即刻关注公众号
引导大型语言模型的响应以创建结构化输出
7 个月前
指导大型语言模型生成结构化输出
在与大型语言模型(LLM)交互时,我们经常需要模型以结构化的方式输出信息,例如表格、列表或JSON格式。以下是一些指导原则和技巧,可以帮助我们引导模型生成所需的结构化输出。
-
明确指定输出格式:在提问时,明确指出你希望模型以何种格式输出信息。例如,如果你需要一个列表,可以在问题中直接要求:“请以列表的形式列出...”。
-
使用模板:提供一个模板或示例,让模型知道如何组织其回答。例如,如果你需要一个表格,可以先给出一个表格的头部和一两个示例行。
-
分步提问:如果问题复杂,可以将其分解成几个小问题,逐步引导模型生成最终的结构化输出。
-
使用关键词:在问题中使用关键词,如“表格”、“列表”、“JSON”等,以帮助模型理解你的意图。
-
限制输出长度:指定输出的最大长度或项目数量,以避免生成过多的信息。
-
请求验证:在模型生成输出后,请求模型验证其输出是否符合要求的格式。
-
迭代反馈:
学习如何构建语言模型的响应,以确保响应格式得到尊重,例如JSON。
在构建语言模型的响应时,确保遵循一定的格式是非常重要的,特别是当涉及到数据交换时。JSON(JavaScript Object Notation)是一种轻量级的数据交换格式,易于人阅读和编写,同时也易于机器解析和生成。以下是一些步骤和提示,帮助你确保语言模型的响应格式正确:
-
理解JSON格式:JSON是一种基于文本的格式,用于存储和传输数据对象。它由键值对组成,键和值之间用冒号(:)分隔,不同的键值对之间用逗号(,)分隔,整个对象用花括号({})包围。
-
定义响应结构:在构建响应之前,定义一个清晰的结构。例如,你可能需要一个包含用户查询、模型回答和时间戳的响应。
-
使用正确的数据类型:JSON支持多种数据类型,包括字符串(String)、数字(Number)、布尔值(Boolean)、数组(Array)和对象(Object)。确保你的响应中使用的数据类型与预期相符。
-
编码字符串:在JSON中,所有字符串必须用双引号(")包围。确保你的
照片由
您好!看起来您可能没有提供完整的句子或段落来翻译。如果您需要翻译某个特定的英文内容到中文,请提供完整的句子或段落,我会很高兴帮助您进行翻译。
这篇文章将教你如何使用Python中的验证库来构建像GPT-4或Llama 3这样的大型语言模型(LLM)的响应。 这是一个非常相关的话题,因为提取JSON格式的结构化信息,例如,对于数据挖掘任务来说至关重要,其中从非结构化格式(如自由文本)中提取精确信息。 此外,即使在最商业化的系统中,如GPT,由于大型语言模型(LLM)在生成输出令牌时的随机性质,结构化响应格式也不可靠。 我们将使用几个库,例如Pydantic和Instructor用于验证和模式建模,以及OpenAI和ollama用于大型语言模型(LLM)部分。所提出的内容将适用于闭源模型,如OpenAI的GPT或Anthropic,以及开源模型,如Llama 3。 通过阅读这篇文章,你将学到: * 它是什么以及如何定义一个数据模型 * 如何确保您的LLM通过验证规则尊重输出格式 * 如何使用 Instructor 和 Pydantic 库 享受阅读! 为什么我们需要结构化输出?
像GPT-4这样的大型语言模型即使不按照特定模式构建其响应,也能提供巨大的价值。然而,如果用户有此意愿,尤其是对于程序员和那些与数据打交道的人来说,遵循可能的响应模式是很重要的。
从GPT-3.5的某个特定版本开始,OpenAI在其completions API中添加了response_format
参数——这允许用户定义不同的键,例如json_object
,以引导模型生成更适合输入提示的响应。
这是一个例子:
```
from openai import OpenAI
client = OpenAI()
response = client.chat.completions.create( model="gpt-3.5-turbo-0125", response_format={ "type": "json_object" }, messages=[ {"role": "system", "content": "You are a helpful assistant designed to output JSON."}, {"role": "user", "content": "Who won the world series in 2020?"} ] ) print(response.choices[0].message.content)
"content": "{"winner": "Los Angeles Dodgers"}" ```
然而,这种逻辑并不总是有效。实际上,OpenAI在其文档中建议在提示中精确地写上“JSON”这个词,以指导GPT生成它。这是一个如此重要的提示,以至于当我们使用response_format={ "type": "json_object" }
时,我们被迫在提示中的某个地方写上它。
为什么大型语言模型(LLMs)难以产生一致的JSON输出?
JSON(JavaScript Object Notation)是一种轻量级的数据交换格式,它易于人阅读和编写,同时也易于机器解析和生成。然而,大型语言模型(LLMs)在生成JSON格式数据时可能会遇到一些困难,原因如下:
-
结构性要求:JSON需要严格的结构性,例如键值对的格式、数组的使用等。LLMs在生成文本时可能不会总是遵循这些结构性要求。
-
数据类型限制:JSON支持的数据类型有限,包括字符串、数字、布尔值、数组、对象和null。LLMs在生成数据时可能不会正确识别或转换这些数据类型。
-
语法错误:JSON对语法有严格的要求,例如使用双引号来定义字符串,使用逗号分隔对象的属性等。LLMs在生成文本时可能会忽略这些语法细节,导致生成的JSON无效。
-
嵌套结构:JSON允许复杂的嵌套结构,但LLMs可能在处理这些嵌套时遇到困难,特别是当嵌套层次较深或结构复杂时。
-
一致性问题:LLMs
这是因为大型语言模型(LLMs)本质上是机器,它们根据输入提示返回下一个更有可能跟随前一个的标记。实际上,除非模型在训练阶段被明确引导去识别和理解这些格式,否则很难在“自然”中遇到这种模式。 新型语言模型的JSON模式并不保证输出与特定模式匹配,只保证它是有效的并且没有错误地解析。 因此,能够验证这些输出中的内容并根据它们是否与我们的数据模型一致来抛出异常和错误仍然非常重要。 用例
我们将看到从向像GPT-4或Llama3这样的大型语言模型(LLM)提出一个简单问题开始,提取JSON信息的例子。 我们可以问任何问题,但我们将会问模型关于世界杯足球赛历史上的赢家的问题。 特别是我们想要提取 * 最终日期 * 比赛的东道国 * 获胜团队 * 得分最高者 我们将不担心验证数据的准确性,而只关心将LLM的文本响应适应我们现在要看到的方案。 在文章中,我们将研究这个例子,也许还会探索其他例子。 必需的依赖项
现在,让我们看看运行本教程需要安装的依赖项。 显然,假设我们已经拥有一个
active development environment
我们将要安装 Pydantic、Instructor、OpenAI 客户端和 ollama。 *
是社区中最著名的数据模型定义和验证库,因其易用性、效率和在数据科学中的相关性而受到广泛使用。 * 这个符号在Markdown中通常用来创建无序列表。在中文中,它没有特定的翻译,但可以表示为“星号”或“星形符号”。
实际上,它是一个专门用于与大型语言模型(LLMs)一起工作的Pydantic包装器,是允许您创建验证逻辑的库。 * 星号
: 用于查询GPT和其他OpenAI模型的著名客户端 *
非常便捷的界面,用于打开像llama3这样的开源大型语言模型。
在我们开发环境中,我们发出开始的命令
在我们开发环境中,我们发出开始的命令
pip install pydantic instructor openai ollama
由于我们也想测试开源模型,下一步是在系统范围内安装ollama。你可以通过阅读这篇专门的文章来了解如何安装和使用ollama。 [如何使用ollama和Python本地使用LLMs]
本文将指导您使用ollama,这是一个命令行工具,允许您下载、探索和使用大型语言模型。
https://pub.towardsai.net/how-to-use-llms-locally-with-ollama-and-python-215e978bb1e3)现在我们可以专注于开发了。 数据模型的定义
数据模型是数据库中用于组织和描述数据的框架。它定义了数据的结构、数据类型、数据之间的关系以及数据的约束条件。数据模型通常用于数据库设计,以确保数据的一致性、完整性和可访问性。
数据模型可以分为以下几种类型:
-
概念模型(Conceptual Model):用于描述现实世界中的实体及其关系,通常用于需求分析阶段。它不涉及具体的技术细节。
-
逻辑模型(Logical Model):基于概念模型,进一步定义了数据的逻辑结构,包括表、字段、数据类型和关系。逻辑模型是独立于数据库管理系统(DBMS)的。
-
物理模型(Physical Model):是逻辑模型的具体实现,它考虑了数据库管理系统的特定特性,如索引、存储和访问方法。
-
维度模型(Dimensional Model):主要用于数据仓库和多维数据分析,它将数据组织成事实表和维度表,以支持快速查询和复杂的数据分析。
-
对象模型(Object Model):基于面向对象的概念,用于描述系统中的对象及其属性和方法。
-
文档模型(Document Model):用于存储半结构化数据,
数据模型是一种用于组织数据的逻辑模式。它们在许多上下文中都有应用,从定义数据库中的表格到验证输入数据。 我已经在下面的帖子中介绍了一些使用Pydantic进行数据建模的数据科学和机器学习内容。👇 [使用Pydantic改进你的数据模型]
Pydantic 是一个 Python 库,它允许我们以高效的方式结构化和验证数据。
https://readmedium.com/improve-your-data-models-with-pydantic-f9f10ca66f26)让我们首先创建Pydantic数据模型: ``` from pydantic import BaseModel, Field from typing import List import datetime
class SoccerData(BaseModel): date_of_final: datetime.date = Field(..., description="Date of the final event") hosting_country: str = Field(..., description="The nation hosting the tournament") winner: str = Field(..., description="The soccer team that won the final cup") top_scorers: list = Field( ..., description="A list of the top 3 scorers of the tournament" )
class SoccerDataset(BaseModel): reports: List[SoccerData] = [] ```
在这个脚本中,我们从Pydnatic导入了BaseModel
和Field
类,并使用它们来创建一个数据模型。实际上,我们正在构建我们的最终结果必须具备的结构。
Pydantic 要求我们声明进入模型的数据类型。我们有 datetime.date
,例如,它强制 date
字段必须是日期而不是字符串。同时,top_scorers
字段必须是一个列表,否则 Pydantic 将返回验证错误。
最后,我们创建了一个数据模型,该模型收集了多个SoccerData
模型的实例。这被称为SoccerDataset
,将由Instructor用来验证多个报告的存在,而不仅仅是一个。
创建系统提示
非常简单,我们将用英语写出模型必须做的事情,通过提供示例来强调结果的意图和结构。 ``` system_prompt = """You are an expert sports journalist. You'll be asked to create a small report on who won the soccer world cups in specific years. You'll report the date of the tournament's final, the top 3 scorers of the entire tournament, the winning team, and the nation hosting the tournament. Return a JSON object with the following fields: date_of_final, hosting_country, winner, top_scorers.
If multiple years are inputted, separate the reports with a comma.
Here's an example [ { "date_of_final": "1966", "hosting_country": "England", "winner": "England", "top_scorers": ["Player A", "Player B", "Player C"] }, { "date_of_final": ... "hosting_country": ... "winner": ... "top_scorers": ... },
]
Here's the years you'll need to report on:
""" ```
这个提示将被用作系统提示,它将简单地允许我们通过逗号分隔来传递感兴趣的年份。 创建讲师代码
在这里,我们将创建JSON验证和结构化的主要逻辑,这要感谢讲师。它使用了一个类似于OpenAI通过API调用GPT提供的接口。
首先,我们将在名为 query_gpt
的函数中使用 OpenAI,这使我们能够参数化我们的提示:
```
from openai import OpenAI
import instructor
def query_gpt(prompt: str) -> list: client = instructor.from_openai(OpenAI(api_key="...")) resp = client.chat.completions.create( model="gpt-3.5-turbo", response_model=SoccerDataset, messages=[ {"role": "system", "content": system_prompt}, {"role": "user", "content": prompt}, ], ) return resp.model_dump_json(indent=4) ```
让我们记得将我们的OpenAI API密钥传递给新创建的客户端。我们将使用GPT-3.5-Turbo,并传递SoccerDataset
作为response_model
。当然,如果我们想使用本文撰写时最强大的模型,我们可以使用“gpt-4o”。
我们不使用
SoccerData
,而是使用SoccerDataset
。 如果我们使用前者,LLM将只会返回一个结果。 让我们把所有东西整合起来,启动软件,将年份“2010年,2014年和2018年”作为用户提示的内容输入,以便我们从中生成结构化报告。 ``` from openai import OpenAI import instructor
from typing import List from pydantic import BaseModel, Field import datetime
class SoccerData(BaseModel): date_of_final: datetime.date = Field(..., description="Date of the final event") hosting_country: str = Field(..., description="The nation hosting the tournament") winner: str = Field(..., description="The soccer team that won the final cup") top_scorers: list = Field( ..., description="A list of the top 3 scorers of the tournament" )
class SoccerDataset(BaseModel): reports: List[SoccerData] = []
system_prompt = """You are an expert sports journalist. You'll be asked to create a small report on who won the soccer world cups in specific years. You'll report the date of the tournament's final, the top 3 scorers of the entire tournament, the winning team, and the nation hosting the tournament. Return a JSON object with the following fields: date_of_final, hosting_country, winner, top_scorers.
If the query is invalid, return an empty report.
If multiple years are inputted, separate the reports with a comma.
Here's an example [ { "date_of_final": "1966", "hosting_country": "England", "winner": "England", "top_scorers": ["Player A", "Player B", "Player C"] }, { "date_of_final": ... "hosting_country": ... "winner": ... "top_scorers": ... },
]
Here's the years you'll need to report on:
"""
def query_gpt(prompt: str) -> list: client = instructor.from_openai(OpenAI()) resp = client.chat.completions.create( model="gpt-3.5-turbo", response_model=SoccerDataset, messages=[ {"role": "system", "content": system_prompt}, {"role": "user", "content": prompt}, ], ) return resp.model_dump_json(indent=4)
if name == "main": resp = query_llm("2010, 2014, 2018") print(resp) ```
这是结果:
{
"reports": [
{
"date_of_final": "2010-07-11",
"hosting_country": "South Africa",
"winner": "Spain",
"top_scorers": [
"Thomas Müller",
"David Villa",
"Wesley Sneijder"
]
},
{
"date_of_final": "2014-07-13",
"hosting_country": "Brazil",
"winner": "Germany",
"top_scorers": [
"James Rodríguez",
"Thomas Müller",
"Neymar"
]
},
{
"date_of_final": "2018-07-15",
"hosting_country": "Russia",
"winner": "France",
"top_scorers": [
"Harry Kane",
"Antoine Griezmann",
"Romelu Lukaku"
]
}
]
}
太棒了。GPT-3.5-Turbo完美地遵循了我们的提示,并且指导者验证了字段,创建了一个与数据模型一致的结构。实际上,输出不是一个字符串,正如像GPT这样的大型语言模型通常会返回的那样,而是一系列Python字典。 现在让我们尝试插入一个没有意义的内容。 ``` if name == "main": print(query_gpt("hi, how are you?"))
{ "reports": [] } ```
LLM 正确地返回了一个空报告,因为这是我们在系统提示中要求它处理无效查询的方式。 使用开源模板与讲师合作
我们已经看到了如何在Instructor中使用GPT来生成结构化的JSON输出。现在,让我们看看如何使用ollama来使用开源模板,比如llama3。
请记住,你需要通过ollama下载llama3才能使用它。 使用
ollama pull llama3
命令来下载它! 让我们创建一个名为query_llama
的新函数。def query_llama(prompt: str) -> list: client = instructor.from_openai( OpenAI( base_url="http://localhost:11434/v1", api_key="ollama", # valore richiesto, ma non influente ), mode=instructor.Mode.JSON, ) resp = client.chat.completions.create( model="llama3", messages=[ { "role": "system", "content": system_prompt }, { "role": "user", "content": prompt } ], response_model=SoccerDataset, ) return resp.model_dump_json(indent=4)
有一些与GPT代码不同的地方。让我们来看一下它们。
* ollama
是通过与 GPT 相同的接口调用的,但需要更改基础 URL 指针(base_url
)和 API 密钥,API 密钥是必需的,但对正确操作来说并不需要(不要问我为什么)
* 您需要通过模式参数来解释JSON模式
让我们运行新函数
让我们运行这个函数。
if __name__ == "__main__":
print(query_llama("2010, 2014, 2018"))
这里是结果:
{
"reports": [
{
"date_of_final": "2010-07-11",
"hosting_country": "South Africa",
"winner": "Spain",
"top_scorers": [
"Thomas Müller",
"Wolfram Toloi",
"Landon Donovan"
]
},
{
"date_of_final": "2014-07-13",
"hosting_country": "Brazil",
"winner": "Germany",
"top_scorers": [
"James Rodríguez",
"Miroslav Klose",
"Thomas Müller"
]
},
{
"date_of_final": "2018-07-15",
"hosting_country": "Russia",
"winner": "France",
"top_scorers": [
"Harry Kane",
"Kylian Mbappé",
"Antoine Griezmann"
]
}
]
}
我们有一个包含正确JSON的列表!所有这些都是在本地使用Llama 3完成的。 正如我之前提到的,验证是针对结构进行的,而不是内容。实际上,内容与GPT生成的内容不同。 让我们看看标记有何不同。也许通过迭代提示,明确指定我们想要接收的标记,就有可能得到正确的列表。 结论
我们已经看到了如何使用Pydantic、Instructor和ollama来将大型语言模型(LLM)的输出驱动到结构化格式,例如JSON。 请记住,在这个过程中模型实际上是被引导的,因此它不是确定性的。由于大型语言模型(LLMs)的非确定性本质,会有情况出现,JSON格式可能不会被遵守。
赋迪奥本AI
上海赋迪网络科技
电话:18116340052