Schema#
大型语言模型非常擅长以 JSON 或其他格式生成结构化输出。LLM 的 **Schema** 功能允许您定义希望从模型接收的 JSON 数据的确切结构。
此功能受 OpenAI、Anthropic、Google Gemini 的模型支持,并且可以通过插件为其他模型实现。
本页描述了通过 llm
命令行工具使用的 Schema。Schema 也可以通过 Python API 使用。
Schema 教程#
在本教程中,我们将使用 Schema 来分析一些新闻报道。
但首先,让我们虚构一些狗狗!
从狗狗开始#
LLM 非常擅长创建测试数据。让我们使用 LLM 的简洁 Schema 语法为狗狗定义一个简单的 Schema。我们将通过 llm --schema
将其传递给 LLM,并提示它“虚构一只很酷的狗狗”。
llm --schema 'name, age int, one_sentence_bio' 'invent a cool dog'
我得到了 Ziggy
{
"name": "Ziggy",
"age": 4,
"one_sentence_bio": "Ziggy is a hyper-intelligent, bioluminescent dog who loves to perform tricks in the dark and guides his owner home using his glowing fur."
}
响应与我的 Schema 匹配,包含 name
和 one_sentence_bio
字符串列,以及 age
的整数。
我们这里使用的是默认的 LLM 模型 - gpt-4o-mini
。添加 -m model
来使用其他模型 - 例如使用 -m o3-mini
让 O3 mini 虚构一些狗狗。
要查看支持 Schema 的可用模型列表,请运行此命令
llm models --schemas
想要更多狗狗?您可以使用 --schema-multi
传入相同的 Schema,并一次性请求多个。
llm --schema-multi 'name, age int, one_sentence_bio' 'invent 3 really cool dogs'
这是我得到的结果
{
"items": [
{
"name": "Echo",
"age": 3,
"one_sentence_bio": "Echo is a sleek, silvery-blue Siberian Husky with mesmerizing blue eyes and a talent for mimicking sounds, making him a natural entertainer."
},
{
"name": "Nova",
"age": 2,
"one_sentence_bio": "Nova is a vibrant, spotted Dalmatian with an adventurous spirit and a knack for agility courses, always ready to leap into action."
},
{
"name": "Pixel",
"age": 4,
"one_sentence_bio": "Pixel is a playful, tech-savvy Poodle with a rainbow-colored coat, known for her ability to interact with smart devices and her love for puzzle toys."
}
]
}
这就是基本思想:我们可以传入一个 Schema,LLM 会将其传递给底层模型,然后(通常)会返回符合该 Schema 的 JSON。
当您开始将其应用于大量文本,从非结构化内容中提取结构化细节时,这项功能会变得更加有用。
从新闻文章中提取人物信息#
我们将提取在不同新闻报道中提到的人物细节,然后使用这些信息编译一个数据库。
我们先来编译一个 Schema。对于提到的每个人,我们希望提取以下细节:
他们的姓名
他们工作的组织
他们的角色
我们从报道中了解到的关于他们的信息
我们还会记录文章标题和发布日期,以便日后使用更方便。
这次使用 LLM 的自定义简洁 Schema 语言,用换行符分隔各个字段(在狗狗示例中我们使用了逗号)。
name: the person's name
organization: who they represent
role: their job title or role
learned: what we learned about them from this story
article_headline: the headline of the story
article_date: the publication date in YYYY-MM-DD
如您所见,这个 Schema 定义非常简单——每一行都有我们想要捕获的属性名称,然后是一个可选的冒号:后面跟着描述,这个描述同时作为给模型的指示。
完整语法在下方描述——您还可以包含数字等类型的类型信息。
让我们对一篇新闻文章运行此操作。
访问 美联社新闻 (AP News) 并获取一篇文章的 URL。我使用的是这篇:
https://apnews.com/article/trump-federal-employees-firings-a85d1aaf1088e050d39dcf7e3664bb9f
该页面上有相当多的 HTML,甚至可能足以超出 GPT-4o mini 的 128,000 令牌输入限制。我们将使用另一个名为 strip-tags 的工具来减少它。如果您安装了 uv,可以使用 uvx strip-tags
调用它,否则您需要先安装它。
uv tool install strip-tags
# Or "pip install" or "pipx install"
现在我们可以运行此命令从该文章中提取人物信息
curl 'https://apnews.com/article/trump-federal-employees-firings-a85d1aaf1088e050d39dcf7e3664bb9f' | \
uvx strip-tags | \
llm --schema-multi "
name: the person's name
organization: who they represent
role: their job title or role
learned: what we learned about them from this story
article_headline: the headline of the story
article_date: the publication date in YYYY-MM-DD
" --system 'extract people mentioned in this article'
我得到的输出以这种方式开始:
{
"items": [
{
"name": "William Alsup",
"organization": "U.S. District Court",
"role": "Judge",
"learned": "He ruled that the mass firings of probationary employees were likely unlawful and criticized the authority exercised by the Office of Personnel Management.",
"article_headline": "Judge finds mass firings of federal probationary workers were likely unlawful",
"article_date": "2025-02-26"
},
{
"name": "Everett Kelley",
"organization": "American Federation of Government Employees",
"role": "National President",
"learned": "He hailed the court's decision as a victory for employees who were illegally fired.",
"article_headline": "Judge finds mass firings of federal probationary workers were likely unlawful",
"article_date": "2025-02-26"
}
这些数据已记录到 LLM 的SQLite 数据库中。我们可以使用 llm logs 命令再次检索数据,如下所示:
llm logs -c --data
-c
标志表示“使用最近的对话”,--data
标志仅输出响应中捕获的 JSON 数据。
我们打算将相同的 Schema 用于其他事物。我们使用的 Schema 会自动记录到数据库中——我们可以使用 llm schemas
查看它们。
llm schemas
这是输出:
- id: 3b7702e71da3dd791d9e17b76c88730e
summary: |
{items: [{name, organization, role, learned, article_headline, article_date}]}
usage: |
1 time, most recently 2025-02-28T04:50:02.032081+00:00
要查看完整的 Schema,请使用 --full
运行该命令。
llm schemas --full
输出如下:
- id: 3b7702e71da3dd791d9e17b76c88730e
schema: |
{
"type": "object",
"properties": {
"items": {
"type": "array",
"items": {
"type": "object",
"properties": {
"name": {
"type": "string",
"description": "the person's name"
},
...
该 3b7702e71da3dd791d9e17b76c88730e
ID 可以用于再次运行相同的 Schema。现在让我们在不同的 URL 上尝试一下。
curl 'https://apnews.com/article/bezos-katy-perry-blue-origin-launch-4a074e534baa664abfa6538159c12987' | \
uvx strip-tags | \
llm --schema 3b7702e71da3dd791d9e17b76c88730e \
--system 'extract people mentioned in this article'
这里我们使用 --schema
,因为我们的 Schema ID 已经对应于一个项目数组。
结果以这种方式开始:
{
"items": [
{
"name": "Katy Perry",
"organization": "Blue Origin",
"role": "Singer",
"learned": "Katy Perry will join the all-female celebrity crew for a spaceflight organized by Blue Origin.",
"article_headline": "Katy Perry and Gayle King will join Jeff Bezos’ fiancee Lauren Sanchez on Blue Origin spaceflight",
"article_date": "2023-10-15"
},
还有一个技巧:让我们将 Schema 和系统提示的组合变成一个模板。
llm --schema 3b7702e71da3dd791d9e17b76c88730e \
--system 'extract people mentioned in this article' \
--save people
这将创建一个名为“people”的新模板。我们可以使用以下命令确认模板已正确创建:
llm templates show people
它将输出模板的 YAML 版本,看起来像这样:
name: people
schema_object:
properties:
items:
items:
properties:
article_date:
description: the publication date in YYYY-MM-DD
type: string
article_headline:
description: the headline of the story
type: string
learned:
description: what we learned about them from this story
type: string
name:
description: the person's name
type: string
organization:
description: who they represent
type: string
role:
description: their job title or role
type: string
required:
- name
- organization
- role
- learned
- article_headline
- article_date
type: object
type: array
required:
- items
type: object
system: extract people mentioned in this article
现在我们可以针对另一个新的 URL 运行我们的人物信息提取器了。我们来使用卫报 (The Guardian) 的一篇文章:
curl https://www.theguardian.com/commentisfree/2025/feb/27/billy-mcfarland-new-fyre-festival-fantasist | \
strip-tags | llm -t people
将 Schema 存储在模板中意味着我们可以直接使用 llm -t people
来运行提示。这是我得到的结果:
{
"items": [
{
"name": "Billy McFarland",
"organization": "Fyre Festival",
"role": "Organiser",
"learned": "Billy McFarland is known for organizing the infamous Fyre Festival and was sentenced to six years in prison for wire fraud related to it. He is attempting to revive the festival with Fyre 2.",
"article_headline": "Welcome back Billy McFarland and a new Fyre festival. Shows you can’t keep a good fantasist down",
"article_date": "2025-02-27"
}
]
}
根据模型不同,Schema 提取也可能适用于图片和 PDF 文件。
我截取了 洋葱新闻 (The Onion) 的这篇报道 的一部分,并保存到以下 URL:
https://static.simonwillison.net/static/2025/onion-zuck.jpg
我们可以使用 -a
选项将其作为附件传递。这次我们使用 GPT-4o。
llm -t people -a https://static.simonwillison.net/static/2025/onion-zuck.jpg -m gpt-4o
它给了我这个结果:
{
"items": [
{
"name": "Mark Zuckerberg",
"organization": "Facebook",
"role": "CEO",
"learned": "He addressed criticism by suggesting anyone with similar values and thirst for power could make the same mistakes.",
"article_headline": "Mark Zuckerberg Insists Anyone With Same Skewed Values And Unrelenting Thirst For Power Could Have Made Same Mistakes",
"article_date": "2018-06-14"
}
]
}
现在我们已经从多个不同来源提取了人物信息,接下来将它们加载到数据库中。
llm logs 命令有几个功能用于处理记录的 JSON 对象。由于我们一直使用 people
模板将每个页面上的多个对象记录到 "items"
数组中,我们可以使用以下命令访问它们:
llm logs --schema t:people --data-key items
我们可以使用 3b7702e71da3dd791d9e17b76c88730e
Schema ID,甚至原始的 Schema 字符串来代替 t:people
,详见指定 Schema。
此命令会为使用指定 Schema 捕获的每个项目输出以换行符分隔的 JSON。
{"name": "Katy Perry", "organization": "Blue Origin", "role": "Singer", "learned": "She is one of the passengers on the upcoming spaceflight with Blue Origin."}
{"name": "Gayle King", "organization": "Blue Origin", "role": "TV Journalist", "learned": "She is participating in the upcoming Blue Origin spaceflight."}
{"name": "Lauren Sanchez", "organization": "Blue Origin", "role": "Helicopter Pilot and former TV Journalist", "learned": "She selected the crew for the Blue Origin spaceflight."}
{"name": "Aisha Bowe", "organization": "Engineering firm", "role": "Former NASA Rocket Scientist", "learned": "She is part of the crew for the spaceflight."}
{"name": "Amanda Nguyen", "organization": "Research Scientist", "role": "Activist and Scientist", "learned": "She is included in the crew for the upcoming Blue Origin flight."}
{"name": "Kerianne Flynn", "organization": "Movie Producer", "role": "Producer", "learned": "She will also be a passenger on the upcoming spaceflight."}
{"name": "Billy McFarland", "organization": "Fyre Festival", "role": "Organiser", "learned": "He was sentenced to six years in prison for wire fraud in 2018 and has launched a new festival called Fyre 2.", "article_headline": "Welcome back Billy McFarland and a new Fyre festival. Shows you can\u2019t keep a good fantasist down", "article_date": "2025-02-27"}
{"name": "Mark Zuckerberg", "organization": "Facebook", "role": "CEO", "learned": "He attempted to dismiss criticism by suggesting that anyone with similar values and thirst for power could have made the same mistakes.", "article_headline": "Mark Zuckerberg Insists Anyone With Same Skewed Values And Unrelenting Thirst For Power Could Have Made Same Mistakes", "article_date": "2018-06-14"}
如果我们添加 --data-array
,我们将得到一个有效的 JSON 对象数组,而不是以换行符分隔的 JSON。
llm logs --schema t:people --data-key items --data-array
输出开始:
[{"name": "Katy Perry", "organization": "Blue Origin", "role": "Singer", "learned": "She is one of the passengers on the upcoming spaceflight with Blue Origin."},
{"name": "Gayle King", "organization": "Blue Origin", "role": "TV Journalist", "learned": "She is participating in the upcoming Blue Origin spaceflight."},
我们可以使用 sqlite-utils 将其加载到 SQLite 数据库中,特别是 sqlite-utils insert 命令。
uv tool install sqlite-utils
# or pip install or pipx install
现在我们可以将 JSON 通过管道传输到该工具中,创建一个包含 people
表的数据库。
llm logs --schema t:people --data-key items --data-array | \
sqlite-utils insert data.db people -
要查看包含 name、organization 和 role 列的表格,请使用 sqlite-utils rows:
sqlite-utils rows data.db people -t -c name -c organization -c role
它会产生:
name organization role
--------------- ------------------ -----------------------------------------
Katy Perry Blue Origin Singer
Gayle King Blue Origin TV Journalist
Lauren Sanchez Blue Origin Helicopter Pilot and former TV Journalist
Aisha Bowe Engineering firm Former NASA Rocket Scientist
Amanda Nguyen Research Scientist Activist and Scientist
Kerianne Flynn Movie Producer Producer
Billy McFarland Fyre Festival Organiser
Mark Zuckerberg Facebook CEO
我们还可以使用 Datasette 在 Web 界面中浏览数据库。
uvx datasette data.db
# Or install datasette first:
uv tool install datasette # or pip install or pipx install
datasette data.db
访问 http://127.0.0.1:8001/data/people
开始导航数据。
使用 JSON Schema#
上述示例都使用了简洁 Schema 语法。LLM 会将此格式转换为 JSON Schema,如果您愿意,也可以直接使用 JSON Schema。
JSON Schema 涵盖以下内容:
字段的数据类型(字符串、数字、数组、对象等)
必需字段与可选字段
嵌套数据结构
值的约束(最小值/最大值、模式等)
这些字段的描述——它们可以用来指导语言模型
不同的模型可能支持整体 JSON Schema 语言的不同子集。您应该通过实验来确定您正在使用的模型支持哪些功能。
LLM 建议 Schema 的顶层是一个对象而不是数组,以提高跨多个模型的兼容性。如果您想返回一个数组,我建议使用 {"items": [对象数组]}
。
上面狗狗的 Schema,name, age int, one_sentence_bio
,作为完整的 JSON Schema 看起来像这样:
{
"type": "object",
"properties": {
"name": {
"type": "string"
},
"age": {
"type": "integer"
},
"one_sentence_bio": {
"type": "string"
}
},
"required": [
"name",
"age",
"one_sentence_bio"
]
}
这个 JSON 可以直接传递给 --schema
选项,或者保存到文件中并作为文件名传递。
llm --schema '{
"type": "object",
"properties": {
"name": {
"type": "string"
},
"age": {
"type": "integer"
},
"one_sentence_bio": {
"type": "string"
}
},
"required": [
"name",
"age",
"one_sentence_bio"
]
}' 'a surprising dog'
输出示例
{
"name": "Baxter",
"age": 3,
"one_sentence_bio": "Baxter is a rescue dog who learned to skateboard and now performs tricks at local parks, astonishing everyone with his skill!"
}
指定 Schema 的方法#
LLM 接受用于运行提示和探索记录响应的 Schema 定义,使用 --schema
选项。
此选项可以采用多种形式:
提供 JSON Schema 的字符串:
--schema '{"type": "object", ...}'
一个简明 Schema 定义:
--schema 'name,age int'
磁盘上包含 JSON Schema 的文件的名称或路径:
--schema dogs.schema.json
先前记录的 Schema 的十六进制 ID:
--schema 520f7aabb121afd14d0c6c237b39ba2d
- 这些 ID 可以使用llm schemas
命令找到。已保存到模板中的 Schema:
--schema t:name-of-template
简洁 LLM Schema 语法#
手动构建 JSON Schema 可能很耗时。LLM 还支持一种简洁的替代语法来指定 Schema。
包含两个字符串属性 name
和 bio
的简单对象 Schema 如下所示:
name, bio
您可以通过在属性名称后添加类型指示符来包含类型信息,类型指示符与属性名称之间用空格分隔。
name, bio, age int
支持的类型包括整数的 int
、浮点数的 float
、字符串的 str
(默认值)以及布尔值 true/false 的 bool
。
要包含字段描述作为对模型的提示,请在冒号后添加描述:
name: the person's name, age int: their age, bio: a short bio
如果您的 Schema 变长了,可以从逗号分隔切换到换行符分隔,这也可以让您在描述中使用逗号。
name: the person's name
age int: their age
bio: a short bio, no more than three sentences
您可以使用 llm schemas dsl
命令来试验语法,该命令将输入转换为 JSON Schema。
llm schemas dsl 'name, age int'
输出:
{
"type": "object",
"properties": {
"name": {
"type": "string"
},
"age": {
"type": "integer"
}
},
"required": [
"name",
"age"
]
}
Python 实用函数 llm.schema_dsl(schema)
可以用于在Python API 中使用 Schema 时,将此语法转换为等效的 JSON Schema 字典。
浏览使用 Schema 创建的记录的 JSON 对象#
默认情况下,所有使用 Schema 生成的 JSON 都会记录到一个 SQLite 数据库中。您可以使用 llm logs
命令的特殊选项,以有用的格式仅提取这些 JSON 对象。
llm logs --schema X
过滤选项可以用来过滤出仅使用指定 Schema 创建的响应。您可以传递完整的 Schema JSON、磁盘上 Schema 的路径或 Schema ID。
--data
选项会输出该 Schema 收集的 JSON 数据,格式为以换行符分隔的 JSON。
如果您想要一个 JSON 对象数组(带起始和结束方括号),则可以使用 --data-array
。
让我们虚构一些狗狗
llm --schema-multi 'name, ten_word_bio' 'invent 3 cool dogs'
llm --schema-multi 'name, ten_word_bio' 'invent 2 cool dogs'
记录了这些很酷的狗狗后,您可以这样只查看那些提示返回的数据:
llm logs --schema-multi 'name, ten_word_bio' --data
这里我们需要使用 --schema-multi
,因为我们在首次创建这些记录时使用了它。--schema
选项也受支持,也可以传递文件名、JSON Schema 或 Schema ID。
输出:
{"items": [{"name": "Robo", "ten_word_bio": "A cybernetic dog with laser eyes and super intelligence."}, {"name": "Flamepaw", "ten_word_bio": "Fire-resistant dog with a talent for agility and tricks."}]}
{"items": [{"name": "Bolt", "ten_word_bio": "Lightning-fast border collie, loves frisbee and outdoor adventures."}, {"name": "Luna", "ten_word_bio": "Mystical husky with mesmerizing blue eyes, enjoys snow and play."}, {"name": "Ziggy", "ten_word_bio": "Quirky pug who loves belly rubs and quirky outfits."}]}
请注意,狗狗们嵌套在 "items"
键中。要从该键访问项目列表,请使用 --data-key items
。
llm logs --schema-multi 'name, ten_word_bio' --data-key items
输出:
{"name": "Bolt", "ten_word_bio": "Lightning-fast border collie, loves frisbee and outdoor adventures."}
{"name": "Luna", "ten_word_bio": "Mystical husky with mesmerizing blue eyes, enjoys snow and play."}
{"name": "Ziggy", "ten_word_bio": "Quirky pug who loves belly rubs and quirky outfits."}
{"name": "Robo", "ten_word_bio": "A cybernetic dog with laser eyes and super intelligence."}
{"name": "Flamepaw", "ten_word_bio": "Fire-resistant dog with a talent for agility and tricks."}
最后,要输出 JSON 数组而不是以换行符分隔的 JSON,请使用 --data-array
。
llm logs --schema-multi 'name, ten_word_bio' --data-key items --data-array
输出:
[{"name": "Bolt", "ten_word_bio": "Lightning-fast border collie, loves frisbee and outdoor adventures."},
{"name": "Luna", "ten_word_bio": "Mystical husky with mesmerizing blue eyes, enjoys snow and play."},
{"name": "Ziggy", "ten_word_bio": "Quirky pug who loves belly rubs and quirky outfits."},
{"name": "Robo", "ten_word_bio": "A cybernetic dog with laser eyes and super intelligence."},
{"name": "Flamepaw", "ten_word_bio": "Fire-resistant dog with a talent for agility and tricks."}]
添加 --data-ids
以在返回的每个对象中包含 "response_id"
和 "conversation_id"
字段,这些字段反映了它们所属的响应和对话的数据库 ID。这对于跟踪每个单独行的来源很有用。
llm logs --schema-multi 'name, ten_word_bio' --data-key items --data-ids
输出:
{"name": "Nebula", "ten_word_bio": "A cosmic puppy with starry fur, loves adventures in space.", "response_id": "01jn4dawj8sq0c6t3emf4k5ryx", "conversation_id": "01jn4dawj8sq0c6t3emf4k5ryx"}
{"name": "Echo", "ten_word_bio": "A clever hound with extraordinary hearing, master of hide-and-seek.", "response_id": "01jn4dawj8sq0c6t3emf4k5ryx", "conversation_id": "01jn4dawj8sq0c6t3emf4k5ryx"}
{"name": "Biscuit", "ten_word_bio": "An adorable chef dog, bakes treats that everyone loves.", "response_id": "01jn4dawj8sq0c6t3emf4k5ryx", "conversation_id": "01jn4dawj8sq0c6t3emf4k5ryx"}
{"name": "Cosmo", "ten_word_bio": "Galactic explorer, loves adventures and chasing shooting stars.", "response_id": "01jn4daycb3svj0x7kvp7zrp4q", "conversation_id": "01jn4daycb3svj0x7kvp7zrp4q"}
{"name": "Pixel", "ten_word_bio": "Tech-savvy pup, builds gadgets and loves virtual playtime.", "response_id": "01jn4daycb3svj0x7kvp7zrp4q", "conversation_id": "01jn4daycb3svj0x7kvp7zrp4q"}
如果某一行已经有名为 "conversation_id"
或 "response_id"
的属性,则会在 ID 键后添加额外的下划线,直到它不再与现有键冲突。
--id-gt $ID
和 --id-gte $ID
选项对于忽略某个点之前记录的 Schema 数据很有用,详见过滤特定 ID 之后的数据。