Cortex COMPLETE 结构化输出

COMPLETE 结构化输出允许您提供完成响应必须遵循的 JSON 架构。这减少了 AI 数据管道中对后处理的需求,并能无缝集成需要确定性响应的系统。COMPLETE 会根据你的 JSON 架构验证每个生成的词元,以确保响应符合所提供的架构。

COMPLETE 支持的每个模型支持结构化输出,但最强大的模型通常会产生更高质量的响应。

使用 COMPLETE 结构化输出

要获得采用结构化格式的响应,请指定 JSON 架构 (https://json-schema.org/) 作为 response_format 实参。提供的 JSON 架构对象定义了生成文本必须遵循的结构、数据类型和约束条件,包括必填字段。对于简单任务,您无需指定输出格式的任何细节,甚至无需指示模型“以 JSON 格式响应”。对于更复杂的任务,提示模型以 JSON 格式响应可以提高准确性;详见 优化 JSON 依从性准确性

该架构必须作为 options 实参内的子对象指定,如此处所示,而非字符串形式。这要求字符串使用单引号,而非 JSON 中使用的双引号,因为这是一个 SQL 对象。响应是一个 JSON 对象。

options: {
    ...
    response_format: {
        'type': 'json',
        'schema': {
            'type': 'object',
            'properties': {
                'property_name': {
                    'type': 'string'
                },
                ...
            },
            'required': ['property_name', ...]
        }
    }
Copy

SQL 示例

以下示例演示如何使用 response_format 实参来指定响应的 JSON 架构。

SELECT SNOWFLAKE.CORTEX.COMPLETE('mistral-large2', [
        {
        'role': 'user',
        'content': 'Return the customer sentiment for the following review: New kid on the block, this pizza joint! The pie arrived neither in a flash nor a snail\'s pace, but the taste? Divine! Like a symphony of Italian flavors, it was a party in my mouth. But alas, the party was a tad pricey for my humble abode\'s standards. A mixed bag, I\'d say!'
            }
    ],
    {
        'temperature': 0,
        'max_tokens': 1000,
        'response_format':{
            'type':'json',
            'schema':{'type' : 'object','properties' : {'sentiment_categories':{'type':'array','items':{'type':'object','properties':
            {'food_quality' : {'type' : 'string'},'food_taste': {'type':'string'}, 'wait_time': {'type':'string'}, 'food_cost': {'type':'string'}},'required':['food_quality','food_taste' ,'wait_time','food_cost']}}}}
            }
    }
);
Copy

响应:

{
    "created": 1738683744,
    "model": "mistral-large2",
    "structured_output": [
        {
        "raw_message": {
            "sentiment_categories": [
            {
                "food_cost": "negative",
                "food_quality": "positive",
                "food_taste": "positive",
                "wait_time": "neutral"
            }
            ]
        },
        "type": "json"
        }
    ],
    "usage": {
        "completion_tokens": 60,
        "prompt_tokens": 94,
        "total_tokens": 154
    }
}

Python 示例

备注

结构化输出功能在 snowflake-ml-python 版本 1.8.0 及更高版本中受支持。

以下示例演示如何使用 response_format 实参来指定响应的 JSON 架构。

from snowflake.cortex import complete, CompleteOptions

response_format = {
    "type": "json",
    "schema": {
        "type": "object",
        "properties": {
            "people": {
                "type": "array",
                "items": {
                    "type": "object",
                    "properties": {
                        "name": {"type": "string"},
                        "age": {"type": "number"},
                    },
                    "required": ["name", "age"],
                },
            }
        },
        "required": ["people"],
    },
}
prompt = [{
    "role": "user",
    "content": "Please prepare me a data set of 5 ppl and their age",
}]

options = CompleteOptions(
        max_tokens=4096,
        temperature=0.7,
        top_p=1,
        guardrails=False,
        response_format=response_format
    )


result = complete(
model="claude-3-5-sonnet",
prompt=prompt,
session={session_object}, # session created via connector
stream=True,
options=options,
)

output = "".join(result)
print(output)
Copy

响应:

{"people": [{"name":"John Smith","age":32},{"name":"Sarah Johnson","age":28},
{"name":"Michael Chen","age":45},{"name":"Emily Davis","age":19},{"name":"Robert Wilson","age":56}]}

REST API 示例

您可以使用 Snowflake Cortex LLM REST API 调用 COMPLETE 与您选择的 LLM。下面是使用 Cortex LLM REST API 提供架构的示例:

curl --location --request POST 'https://<account_identifier>.snowflakecomputing.cn/api/v2/cortex/inference:complete'
--header 'Authorization: Bearer <jwt>' \
--header 'Accept: application/json, text/event-stream' \
--header 'Content-Type: application/json' \
--data-raw '{
    "model": "claude-3-5-sonnet",
    "messages": [{
        "role": "user",
        "content": "Order a pizza for a hungry space traveler heading to the planet Zorgon. Make sure to include a special instruction to avoid any intergalactic allergens."
    }],
    "max_tokens": 1000,
    "response_format": {
            "type": "json",
            "schema":
            {
                "type": "object",
                "properties":
                {
                    "crust":
                    {
                        "type": "string",
                        "enum":
                        [
                            "thin",
                            "thick",
                            "gluten-free",
                            "Rigellian fungus-based"
                        ]
                    },
                    "toppings":
                    {
                        "type": "array",
                        "items":
                        {
                            "type": "string",
                            "enum":
                            [
                                "Gnorchian sausage",
                                "Andromedian mushrooms",
                                "Quasar cheese"
                            ]
                        }
                    },
                    "delivery_planet":
                    {
                        "type": "string"
                    },
                    "special_instructions":
                    {
                        "type": "string"
                    }
                },
                "required":
                [
                    "crust",
                    "toppings",
                    "delivery_planet"
                ]
            }
        }
    }
}'
Copy

响应:

data: {"id":"4d62e41a-d2d7-4568-871a-48de1463ed2a","model":"claude-3-5-sonnet","choices":[{"delta":{"content":"{\"crust\":","content_list":[{"type":"text","text":"{\"crust\":"}]}}],"usage":{}}

data: {"id":"4d62e41a-d2d7-4568-871a-48de1463ed2a","model":"claude-3-5-sonnet","choices":[{"delta":{"content":" \"thin\"","content_list":[{"type":"text","text":" \"thin\""}]}}],"usage":{}}

data: {"id":"4d62e41a-d2d7-4568-871a-48de1463ed2a","model":"claude-3-5-sonnet","choices":[{"delta":{"content":", \"topping","content_list":[{"type":"text","text":", \"topping"}]}}],"usage":{}}

data: {"id":"4d62e41a-d2d7-4568-871a-48de1463ed2a","model":"claude-3-5-sonnet","choices":[{"delta":{"content":"s\": [\"Quasar","content_list":[{"type":"text","text":"s\": [\"Quasar"}]}}],"usage":{}}

创建一个 JSON 架构定义

为了获得 COMPLETE 结构化输出的最佳准确度,请遵循以下指导原则:

  • 使用架构中的“required”字段 来指定必填字段。如果无法提取必填字段,COMPLETE 会报错。

    在以下示例中,架构指示 COMPLETE 查找文档中提到的人员。people 字段被标记为必填项,以确保人员被识别。

    {
        'type': 'object',
        'properties': {
            'dataset_name': {
                'type': 'string'
            },
            'created_at': {
                'type': 'string'
            },
            'people': {
                'type': 'array',
                'items': {
                    'type': 'object',
                    'properties': {
                        'name': {
                            'type': 'string'
                        },
                        'age': {
                            'type': 'number'
                        },
                        'isAdult': {
                            'type': 'boolean'
                        }
                    }
                }
            }
        },
        'required': [
            'dataset_name',
            'created_at',
            'people'
        ]
    }
    
    Copy

    响应:

    {
        "dataset_name": "name",
        "created_at": "date",
        "people": [
            {
                "name": "Andrew",
                "isAdult": true
            }
        ]
    }
    
  • 提供要提取的字段的详细描述,以便模型能够更准确地识别它们。例如,以下架构包括每个 people 字段的描述:nameageisAdult

    {
        'type': 'object',
        'properties': {
            'dataset_name': {
                'type': 'string'
            },
            'created_at': {
                'type': 'string'
            },
            'people': {
                'type': 'array',
                'items': {
                    'type': 'object',
                    'properties': {
                        'name': {
                            'type': 'string',
                            'description': 'name should be between 9 to 10 characters'
                        },
                        'age': {
                            'type': 'number',
                            'description': 'Should be a value between 0 and 200'
                        },
                        'isAdult': {
                            'type': 'boolean',
                            'description': 'Persons is older than 18'
                        }
                    }
                }
            }
        }
    }
    
    Copy

优化 JSON 依从性准确性

COMPLETE 结构化输出通常不需要提示;它已经明白它的响应应该符合您指定的架构。然而,任务复杂度会显著影响 LLMs 遵循 JSON 响应格式的能力。任务越复杂,指定提示就越能提高结果的准确性。

  • 简单任务,例如文本分类、实体提取、释义和摘要任务,这些任务不需要复杂的推理,通常不需要额外的提示。对于智能程度较低的小型模型,仅使用结构化输出功能就能显著提高 JSON 的格式遵循准确度,因为它会忽略模型生成的、与提供架构无关的任何文本。

  • 中等复杂度任务 包括任何要求模型进行额外推理的简单任务,例如为分类决策提供理由。对于这些用例,我们建议添加“以 JSON 响应”来优化性能。

  • 复杂推理任务​ ​会要求模型执行更具开放性和模糊性的任务,例如根据回答的相关性、专业性和忠实度来评估和评分通话质量。对于这些用例,我们建议使用最强大的模型,例如 Anthropic 的 claude-3-5-sonnet 或 Mistral AI 的 mistral-large2,并添加“以 JSON 响应”,以及有关您想要在提示中生成的架构的详细信息。

为了获得最一致的结果,请在调用 COMPLETE 时将 temperature 选项设置为 0,无论任务或模型如何。

小技巧

要处理模型可能引发的错误,请使用 TRY_COMPLETE 而不是 COMPLETE。

成本注意事项

Cortex COMPLETE 结构化输出功能根据处理的词元数量计算成本,但不会因对照 JSON 架构验证每个词元而产生额外计算成本。然而,处理(和计费)的词元数量会随着架构复杂性的增加而增加。一般来说,提供的架构越大越复杂,消耗的输入和输出词元就越多。深度嵌套的高度结构化响应(例如分层数据)比简单架构消耗更多词元。

限制

  • 您不能在架构的键中使用空格。

  • 属性名称允许使用的字符包括:字母、数字、连字符和下划线。名称的最大长度为 64 个字符。

  • 您不能使用 $ref 或者 $dynamicRef 引用外部架构。

不支持以下约束关键字。使用不受支持的约束关键字会导致错误。

类型

关键字

整数

multipleOf

数字

multipleOfminimummaximumexclusiveMinimumexclusiveMaximum

字符串

minLengthmaxLengthformat

数组

uniqueItemscontainsminContainsmaxContainsminItemsmaxItems

对象

patternPropertiesminPropertiesmaxPropertiespropertyNames

这些限制可能会在未来的版本中得到解决。

错误条件

情况

示例消息

模型输出验证失败。模型无法生成与架构匹配的响应。这可能是由于文档中未出现必填字段所致。

解组模型输出时发生错误。模型返回无法解析的无效 JSON。%!(EXTRA string=JSON 输入意外终止)"

附加属性“dataset_name”不遵循架构。错误消息指定了未通过验证的属性。

{"$ref":"值与参考架构不匹配"}},{"errors":{"properties":"属性“type”与架构不匹配"}}, {"evaluationPath":"/properties/type","errors":{"enum":"值应与枚举指定的值之一匹配"}}]"

不允许有额外的约束。错误消息指定了哪个属性未通过验证。

[{"evaluationPath":"/properties/properties","errors":{"additionalProperties":"其他属性“company”与架构不匹配"}},{"evaluationPath":"/additionalProperties/company","errors": {"$ref"值与参考架构不匹配"}},{"errors":{"additionalProperties":"其他属性“maxLength”与架构不匹配"}},{"evaluationPath":"/additionalProperties/maxLength","errors":{"schema":"由于架构设置为“false”,因此不允许任何值"}}]"

语言: 中文