AI_COMPLETE Structured Outputs¶
AI_COMPLETE Structured Outputs을 사용하면 완료 응답이 따라야 하는 JSON 스키마를 제공할 수 있습니다. 이렇게 하면 AI 데이터 파이프라인에서 후처리의 필요성이 줄어들고 결정론적 응답이 요구되는 시스템과 원활하게 통합할 수 있습니다. AI_COMPLETE 는 생성된 각 토큰을 JSON 스키마와 비교하여 응답이 제공된 스키마를 준수하는지 확인합니다.
AI_COMPLETE 에서 지원하는 모든 모델은 Structured Outputs을 지원하지만, 가장 강력한 모델은 일반적으로 더 높은 품질의 응답을 생성합니다.
AI_COMPLETE Structured Outputs 사용하기¶
정형 형식의 응답을 얻으려면 response_format
인자로 JSON 스키마 를 나타내는 오브젝트를 지정합니다. 제공된 JSON 스키마 오브젝트는 필수 필드를 포함하여 생성된 텍스트가 준수해야 하는 구조, 데이터 타입 및 제약 조건을 정의합니다. 간단한 작업의 경우 출력 형식에 대한 세부 사항을 지정하거나 모델에 “JSON 으로 응답”하도록 지침을 지정할 필요가 없습니다 보다 복잡한 작업의 경우 모델에 JSON 으로 응답하도록 요청하면 정확도를 높일 수 있습니다. JSON 준수 정확도 최적화하기 섹션을 참조하십시오.
ai_complete(
...
response_format => {
'type': 'json',
'schema': {
'type': 'object',
'properties': {
'property_name': {
'type': 'string'
},
...
},
'required': ['property_name', ...]
}
}
SQL 예제¶
다음 예에서는 response_format
인자를 사용하여 응답에 JSON 스키마를 지정하는 방법을 보여 줍니다.
SELECT AI_COMPLETE(
model => 'mistral-large2',
prompt => '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!',
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']}}}}
}
);
응답:
{
"sentiment_categories": [
{
"food_cost": "negative",
"food_quality": "positive",
"food_taste": "positive",
"wait_time": "neutral"
}
]
}
다음 예제에서는 response_format
인자를 사용하여 응답에 JSON 스키마를 지정하고 show_details
인자를 사용하여 추론 메타데이터를 반환하는 방법을 보여 줍니다.
SELECT AI_COMPLETE(
model => 'mistral-large2',
prompt => '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!',
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']}}}}
},
show_details => TRUE
);
응답:
{
"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 예제¶
참고
Structured Outputs은 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)
응답:
{"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}]}
Pydantic 예제¶
Pydantic은 Python용 데이터 유효성 검사 및 설정 관리 라이브러리입니다. 이 예에서는 Pydantic을 사용하여 응답 형식에 대한 스키마를 정의합니다. 코드는 다음 단계를 수행합니다.
Pydantic을 사용하여 스키마 정의하기
model_json_schema
메서드를 사용하여 Pydantic 모델을 JSON 스키마로 변환합니다JSON 스키마를
complete
함수에response_format
인자로 전달합니다
참고
이 예제는 이미 Snowflake에 연결되어 있는 Snowsight Python 워크시트에서 실행하기 위한 것입니다. 다른 환경에서 실행하려면 Python용 Snowflake Connector를 사용하여 Snowflake에 연결을 설정 해야 할 수 있습니다.
from pydantic import BaseModel, Field
import json
from snowflake.cortex import complete, CompleteOptions
from snowflake.snowpark.context import get_active_session
class Person(BaseModel):
age: int = Field(description="Person age")
name: str = Field(description="Person name")
people: list[Person] = Field(description="People list")
ppl = Person.model_json_schema()
'''
This is the ppl object, keep in mind there's a '$defs' key used
{'$defs': {'Person': {'properties': {'age': {'description': 'Person age', 'title': 'Age', 'type': 'integer'}, 'name': {'description': 'Person name', 'title': 'Name', 'type': 'string'}}, 'required': ['age', 'name'], 'title': 'Person', 'type': 'object'}}, 'properties': {'people': {'description': 'People list', 'items': {'$ref': '#/$defs/Person'}, 'title': 'People', 'type': 'array'}}, 'required': ['people'], 'title': 'People', 'type': 'object'}
'''
response_format_pydantic={
"type": "json",
"schema": ppl,
}
prompt=[{"role": "user", "content": "Please prepare me a data set of 5 ppl and their age"}]
options_pydantic = CompleteOptions( # random params
max_tokens=4096,
temperature=0.7,
top_p=1,
guardrails=False,
response_format=response_format_pydantic
)
model_name = "claude-3-5-sonnet"
session = get_active_session()
try:
result_pydantic = complete(
model=model_name,
prompt=prompt,
session=session,
stream=True,
options=options_pydantic,
)
except Exception as err:
result_pydantic = (chunk for chunk in err.response.text) # making sure it's generator, similar to the valid response
output_pydantic = "".join(result_pydantic)
print(output_pydantic)
응답:
{"people": [{"name":"John Smith","age":32},{"name":"Sarah Johnson","age":45},
{"name":"Mike Chen","age":28},{"name":"Emma Wilson","age":19},{"name":"Robert Brown","age":56}]}
REST API 예제¶
Snowflake Cortex LLM REST API 를 사용하여 원하는 LLM 으로 COMPLETE 를 호출할 수 있습니다. 다음은 Cortex LLM REST API 를 사용하여 스키마를 제공하는 예제입니다.
curl --location --request POST 'https://<account_identifier>.snowflakecomputing.com/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"
]
}
}
}
}'
응답:
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 Structured Outputs에서 최상의 정확도를 얻으려면 다음 지침을 따르십시오.
스키마에서 “필수” 필드를 사용 하여 필수 필드를 지정합니다. 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' ] }
응답:
{ "dataset_name": "name", "created_at": "date", "people": [ { "name": "Andrew", "isAdult": true } ] }
모델이 더 정확하게 식별할 수 있도록 추출할 필드에 대한 자세한 설명 을 제공하십시오. 예를 들어, 다음 스키마에는
people
:name
,age
, 및isAdult
의 각 필드에 대한 설명이 포함되어 있습니다.{ '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' } } } } } }
JSON 참조 사용하기¶
스키마 참조는 Cortex COMPLETE Structured Outputs을 사용할 때 실질적인 문제를 해결합니다. $ref
로 표시되는 참조를 사용하면 주소나 가격과 같은 공통 오브젝트를 한 번 정의한 다음 스키마 전체에서 참조할 수 있습니다. 이렇게 하면 유효성 검사 로직을 업데이트하거나 필드를 추가해야 할 때 여러 위치가 아닌 한 곳에서 변경할 수 있으므로 오류 발생 가능성을 줄일 수 있습니다.
참조를 사용하면 일관성 없는 구현으로 인한 버그가 줄어들고 코드 검토가 더 간단해집니다. 참조된 구성 요소는 데이터 모델링에서 엔터티 관계를 더 잘 표현하는 깔끔한 계층 구조를 생성합니다. 프로젝트가 점점 더 복잡해짐에 따라 이 모듈식 접근법은 스키마 무결성을 유지하면서 기술 부채를 관리하는 데 도움이 됩니다.
Pydantic과 같은 서드 파티 라이브러리는 Python에서 기본적으로 참조 메커니즘을 지원하므로 코드에서 스키마 사용을 간소화합니다.
다음 가이드라인은 JSON 스키마에서 참조를 사용하는 데 적용됩니다.
범위 제한:
$ref
메커니즘은 사용자의 스키마로만 제한되며 외부 스키마 참조(예: HTTP URLs)는 지원되지 않습니다.정의 배치: 오브젝트 정의는 스키마의 최상위 수준, 특히 정의 또는
$defs
키 아래에 배치해야 합니다.적용: JSON 스키마 사양에서는 정의에
$defs
키를 사용할 것을 권장하지만, Snowflake의 유효성 검사 메커니즘은 이 구조를 엄격하게 적용합니다. 다음은 유효한$defs
오브젝트의 예입니다.
{
'$defs': {
'person':{'type':'object','properties':{'name' : {'type' : 'string'},'age': {'type':'number'}}, 'required':['name','age']}},
'type': 'object',
'properties': {'title':{'type':'string'},'people':{'type':'array','items':{'$ref':'#/$defs/person'}}}
}
JSON 참조를 사용한 예제¶
이 SQL 예제는 JSON 스키마에서 참조를 사용하는 방법을 보여줍니다.
select ai_complete(
model => 'claude-3-5-sonnet',
prompt => 'Extract structured data from this customer interaction note: Customer Sarah Jones complained about the mobile app crashing during checkout. She tried to purchase 3 items: a red XL jacket ($89.99), blue running shoes ($129.50), and a fitness tracker ($199.00). The app crashed after she entered her shipping address at 123 Main St, Portland OR, 97201. She has been a premium member since January 2024.',
'response_format' => {
'type': 'json',
'schema': {
'type': 'object',
'$defs': {
'price': {
'type': 'object',
'properties': {
'amount': {'type': 'number'},
'currency': {'type': 'string'}
},
'required': ['amount']
},
'address': {
'type': 'object',
'properties': {
'street': {'type': 'string'},
'city': {'type': 'string'},
'state': {'type': 'string'},
'zip': {'type': 'string'},
'country': {'type': 'string'}
},
'required': ['street', 'city', 'state']
},
'product': {
'type': 'object',
'properties': {
'name': {'type': 'string'},
'category': {'type': 'string'},
'color': {'type': 'string'},
'size': {'type': 'string'},
'price': {'$ref': '#/$defs/price'}
},
'required': ['name', 'price']
}
},
'properties': {
'customer': {
'type': 'object',
'properties': {
'name': {'type': 'string'},
'membership': {
'type': 'object',
'properties': {
'type': {'type': 'string'},
'since': {'type': 'string'}
}
},
'shipping_address': {'$ref': '#/$defs/address'}
},
'required': ['name']
},
'issue': {
'type': 'object',
'properties': {
'type': {'type': 'string'},
'platform': {'type': 'string'},
'stage': {'type': 'string'},
'severity': {'type': 'string', 'enum': ['low', 'medium', 'high', 'critical']}
},
'required': ['type', 'platform']
},
'cart': {
'type': 'object',
'properties': {
'items': {
'type': 'array',
'items': {'$ref': '#/$defs/product'}
},
'total': {'$ref': '#/$defs/price'},
'item_count': {'type': 'integer'}
}
},
'recommended_actions': {
'type': 'array',
'items': {
'type': 'object',
'properties': {
'department': {'type': 'string'},
'action': {'type': 'string'},
'priority': {'type': 'string', 'enum': ['low', 'medium', 'high', 'urgent']}
}
}
}
},
'required': ['customer', 'issue','cart']
}
}
}
);
응답:
{
"created": 1747313083,
"model": "claude-3-5-sonnet",
"structured_output": [
{
"raw_message": {
"cart": {
"item_count": 3,
"items": [
{
"color": "red",
"name": "jacket",
"price": {
"amount": 89.99,
"currency": "USD"
},
"size": "XL"
},
{
"color": "blue",
"name": "running shoes",
"price": {
"amount": 129.5,
"currency": "USD"
}
},
{
"name": "fitness tracker",
"price": {
"amount": 199,
"currency": "USD"
}
}
],
"total": {
"amount": 418.49,
"currency": "USD"
}
},
"customer": {
"membership": {
"since": "2024-01",
"type": "premium"
},
"name": "Sarah Jones",
"shipping_address": {
"city": "Portland",
"state": "OR",
"street": "123 Main St",
"zip": "97201"
}
},
"issue": {
"platform": "mobile",
"severity": "high",
"stage": "checkout",
"type": "app_crash"
}
},
"type": "json"
}
],
"usage": {
"completion_tokens": 57,
"prompt_tokens": 945,
"total_tokens": 1002
}
}
JSON 준수 정확도 최적화하기¶
COMPLETE Structured Outputs은 일반적으로 프롬프트가 필요하지 않으며, 응답이 사용자가 지정한 스키마를 따라야 한다는 것을 이미 이해하고 있습니다. 그러나 작업 복잡성은 JSON 응답 형식을 따르는 LLMs 의 기능에 상당한 영향을 미칠 수 있습니다. 작업이 복잡할수록 프롬프트를 지정하여 결과의 정확도를 높일 수 있습니다.
복잡한 추론이 필요하지 않은 텍스트 분류, 엔터티 추출, 의역 및 요약 작업과 같은 단순 작업 은 일반적으로 추가 프롬프트가 필요하지 않습니다. 지능이 낮은 소규모 모델의 경우 Structured Outputs을 사용하는 것만으로도 모델이 제공한 스키마와 관련이 없는 모든 텍스트를 무시하므로 JSON 준수 정확도가 크게 향상됩니다.
중간 복잡도 작업 에는 분류 결정에 대한 근거를 제공하는 등 모델에 추가 추론을 요구하는 간단한 작업이 포함됩니다. 이러한 사용 사례의 경우 프롬프트에 “JSON 으로 응답”을 추가하여 성능을 최적화하는 것이 좋습니다.
복잡한 추론 작업 은 모델이 답변의 관련성, 전문성, 충실도를 기준으로 호출 품질을 평가하고 점수를 매기는 등 보다 개방적인 모호한 작업을 수행하도록 유도합니다. 이러한 사용 사례의 경우 Anthropic의
claude-3-5-sonnet
또는 Mistral AI 의mistral-large2
같은 가장 강력한 모델을 사용하고 프롬프트에 “JSON 으로 응답”과 생성하려는 스키마에 대한 세부 정보를 추가하는 것이 좋습니다.
가장 일관된 결과를 얻으려면 작업이나 모델에 관계없이 COMPLETE 를 호출할 때 temperature
옵션을 0으로 설정하십시오.
팁
모델에서 발생할 수 있는 오류를 처리하려면 COMPLETE 가 아닌 TRY_COMPLETE 를 사용하십시오.
비용 고려 사항¶
Cortex COMPLETE Structured Outputs은 처리된 토큰 수에 따라 컴퓨팅 비용이 발생하지만, 제공된 JSON 스키마와 비교하여 각 토큰을 검증하는 오버헤드에 대한 추가 컴퓨팅 비용은 발생하지 않습니다. 그러나 처리(및 청구)되는 토큰의 수는 스키마 복잡성에 따라 증가합니다. 일반적으로 제공된 스키마가 크고 복잡할수록 더 많은 입력 및 출력 토큰이 소비됩니다. 깊은 중첩이 있는 고도로 정형 응답(예: 계층적 데이터)은 단순한 스키마보다 더 많은 수의 토큰을 소비합니다.
제한 사항¶
스키마의 키에는 공백을 사용할 수 없습니다.
속성 이름에 사용할 수 있는 문자는 문자, 자릿수, 하이픈, 밑줄입니다. 이름은 최대 64자까지 입력할 수 있습니다.
$ref
또는$dynamicRef
를 사용하여 외부 스키마를 지정할 수 없습니다.
다음 제약 조건 키워드는 지원되지 않습니다. 지원되지 않는 제약 조건 키워드를 사용하면 오류가 발생합니다.
타입 |
키워드 |
---|---|
정수 |
|
숫자 |
|
문자열 |
|
배열 |
|
오브젝트 |
|
이러한 제한 사항은 향후 릴리스에서 해결될 수 있습니다.
오류 조건¶
상황 |
메시지 예시 |
HTTP 상태 코드 |
---|---|---|
요청 유효성 검사에 실패했습니다. 모델이 유효한 응답을 생성할 수 없으므로 쿼리가 취소되었습니다. 이는 잘못된 요청으로 인해 발생할 수 있습니다. |
|
400 |
입력 스키마 유효성 검사에 실패했습니다. 모델이 유효한 응답을 생성할 수 없으므로 쿼리가 취소되었습니다. 요청 페이로드에 필수가 누락되었거나 제약 조건과 같은 지원되지 않는 JSON 스키마 기능을 사용하거나 $ref 메커니즘을 부적절하게 사용(예: 스키마 외부에 도달하는 경우)하여 발생할 수 있습니다 |
|
400 |
모델 출력 유효성 검사에 실패했습니다. 모델이 스키마와 일치하는 응답을 생성할 수 없습니다. |
|
422 |