Last chance! 50% off DataCamp Premium
Sale ends in
Pada Agustus 2024, OpenAI mengumumkan fitur baru yang kuat di API mereka—Structured Outputs. Dengan fitur ini, sebagaimana namanya, Anda dapat memastikan LLM hanya akan menghasilkan respons dalam format yang Anda tentukan. Kapabilitas ini akan membuat pembangunan aplikasi yang memerlukan pemformatan data presisi menjadi jauh lebih mudah.
Dalam tutorial ini, Anda akan mempelajari cara memulai dengan OpenAI Structured Outputs, memahami sintaks barunya, dan mengeksplorasi penerapan utamanya.
Respons deterministik, atau dengan kata lain, respons dengan format yang konsisten, sangat penting untuk banyak tugas seperti entri data, pengambilan informasi, tanya jawab, alur kerja multi-langkah, dan seterusnya. Anda mungkin pernah mengalami bagaimana LLM dapat menghasilkan output dalam format yang sangat berbeda, meskipun prompt-nya sama.
Sebagai contoh, pertimbangkan fungsi sederhana classify_sentiment berikut yang ditenagai oleh GPT-4o:
# List of hotel reviews
reviews = [
"The room was clean and the staff was friendly.",
"The location was terrible and the service was slow.",
"The food was amazing but the room was too small.",
]
# Classify sentiment for each review and print the results
for review in reviews:
sentiment = classify_sentiment(review)
print(f"Review: {review}\nSentiment: {sentiment}\n")
Output:
Review: The room was clean and the staff was friendly.
Sentiment: Positive
Review: The location was terrible and the service was slow.
Sentiment: Negative
Review: The food was amazing but the room was too small.
Sentiment: The sentiment of the review is neutral.
Meskipun dua respons pertama menggunakan format satu kata yang sama, yang terakhir berupa satu kalimat penuh. Jika ada aplikasi hilir lain yang bergantung pada output kode di atas, aplikasi tersebut bisa gagal karena mengharapkan respons satu kata.
Kita bisa memperbaiki masalah ini dengan prompt engineering, tetapi ini adalah proses yang memakan waktu dan iteratif. Bahkan dengan prompt yang sempurna, kita tidak bisa 100% yakin respons akan mengikuti format kita pada permintaan berikutnya. Kecuali, tentu saja, kita menggunakan Structured Outputs:
def classify_sentiment_with_structured_outputs(review):
"""Sentiment classifier with Structured Outputs"""
...
# Classify sentiment for each review with Structured Outputs
for review in reviews:
sentiment = classify_sentiment_with_structured_outputs(review)
print(f"Review: {review}\nSentiment: {sentiment}\n")
Output:
Review: The room was clean and the staff was friendly.
Sentiment: {"sentiment":"positive"}
Review: The location was terrible and the service was slow.
Sentiment: {"sentiment":"negative"}
Review: The food was amazing but the room was too small.
Sentiment: {"sentiment":"neutral"}
Dengan fungsi baru classify_sentiment_with_structured_outputs, semua respons berada dalam format yang sama.
Kemampuan memaksa model bahasa menghasilkan format yang kaku ini sangat signifikan, menghemat banyak waktu Anda untuk prompt engineering atau ketergantungan pada alat open-source lainnya.
Pada bagian ini, kita akan menguraikan structured outputs menggunakan contoh fungsi penganalisis sentimen.
Sebelum memulai, pastikan Anda memiliki hal-hal berikut:
1. Instal paket Python OpenAI: Buka terminal Anda dan jalankan perintah berikut untuk memasang atau memperbarui paket Python OpenAI ke versi terbaru:
$ pip install -U openai
2. Atur kunci API Anda: Anda dapat mengatur kunci API sebagai variabel lingkungan atau langsung di kode Anda. Untuk mengaturnya sebagai variabel lingkungan, jalankan:
$ export OPENAI_API_KEY='your-api-key'
3. Verifikasi instalasi: Buat skrip Python sederhana untuk memverifikasi instalasi:
from openai import OpenAI
client = OpenAI()
response = client.chat.completions.create(
model="gpt-4o-mini",
messages=[
{"role": "system", "content": "You are a helpful assistant."},
{"role": "user", "content": "Say hello!"}
],
max_tokens=5
)
>>> print(response.choices[0].message.content.strip())
Hello! How can I
Jalankan skrip untuk memastikan semuanya sudah disiapkan dengan benar. Anda akan melihat respons model tercetak di terminal.
Selain paket OpenAI, Anda memerlukan pustaka Pydantic untuk mendefinisikan dan memvalidasi skema JSON bagi Structured Outputs. Pasang menggunakan pip:
$ pip install pydantic
Dengan langkah-langkah ini, lingkungan Anda kini siap menggunakan fitur Structured Outputs dari OpenAI.
Untuk menggunakan Structured Outputs, Anda perlu mendefinisikan struktur output yang diharapkan menggunakan model Pydantic. Pydantic adalah pustaka validasi data dan manajemen pengaturan untuk Python, yang memungkinkan Anda mendefinisikan model data menggunakan anotasi tipe Python. Model-model ini kemudian dapat digunakan untuk menegakkan struktur output yang dihasilkan oleh model OpenAI.
Berikut contoh model Pydantic untuk menentukan format bagi pengklasifikasi sentimen ulasan kita:
from pydantic import BaseModel
from typing import Literal
class SentimentResponse(BaseModel):
sentiment: Literal["positive", "negative", "neutral"]
Dalam contoh ini:
SentimentResponse adalah model Pydantic yang mendefinisikan struktur output yang diharapkan.sentiment, yang hanya dapat berisi salah satu dari tiga nilai literal: "positive", "negative", atau "neutral".Saat kita meneruskan model ini sebagai bagian dari permintaan API OpenAI, outputnya hanya akan berupa salah satu dari kata yang kita sediakan.
Mari lihat caranya.
Untuk menerapkan skema Pydantic kita dalam permintaan OpenAI, yang perlu kita lakukan hanyalah meneruskannya ke parameter response_format dari API chat completions. Secara garis besar, tampilannya seperti ini:
response = client.beta.chat.completions.parse(
model=MODEL,
messages=[...],
response_format=SentimentResponse
)
Perhatikan, alih-alih menggunakan client.chat.completions.create, kita menggunakan metode client.beta.chat.completions.parse. .parse() adalah metode baru di Chat Completions API yang ditulis khusus untuk Structured Outputs.
Sekarang, mari kita satukan semuanya dengan menulis ulang pengklasifikasi sentimen ulasan menggunakan Structured Outputs. Pertama, kita lakukan impor yang diperlukan, mendefinisikan model Pydantic, system prompt, dan templat prompt:
from openai import OpenAI
from pydantic import BaseModel
from typing import Literal
class SentimentResponse(BaseModel):
sentiment: Literal["positive", "negative", "neutral"]
client = OpenAI()
MODEL = "gpt-4o-mini"
SYSTEM_PROMPT = "You are a sentiment classifier assistant."
PROMPT_TEMPLATE = """
Classify the sentiment of the following hotel review as positive, negative, or neutral:\n\n{review}
"""
Lalu, kita tulis fungsi baru yang menggunakan metode helper .parse():
# Function to classify sentiment using OpenAI's chat completions API with structured outputs
def classify_sentiment_with_structured_outputs(review):
response = client.beta.chat.completions.parse(
model=MODEL,
messages=[
{"role": "system", "content": SYSTEM_PROMPT},
{"role": "user", "content": PROMPT_TEMPLATE.format(review=review)},
],
response_format=SentimentResponse
)
return response.choices[0].message
Baris penting dalam fungsi tersebut adalah response_format=SentimentResponse, yang benar-benar mengaktifkan Structured Outputs.
Mari kita uji pada salah satu ulasan:
# List of hotel reviews
reviews = [
"The room was clean and the staff was friendly.",
"The location was terrible and the service was slow.",
"The food was amazing but the room was too small.",
]
result = classify_sentiment_with_structured_outputs(reviews[0])
>>> print(result.content)
{"sentiment":"positive"}
Di sini, result adalah objek pesan:
>>> type(result)
openai.types.chat.parsed_chat_completion.ParsedChatCompletionMessage[SentimentResponse]
Selain atribut .content, yang mengambil respons, objek ini memiliki atribut .parsed yang mengembalikan informasi terurai sebagai sebuah kelas:
>>> result.parsed
SentimentResponse(sentiment='positive')
Seperti yang terlihat, kita mendapatkan instance dari kelas SentimentResponse. Artinya, kita dapat mengakses sentimen sebagai string alih-alih kamus menggunakan atribut .sentiment:
>>> result.parsed.sentiment
'positive'
Dalam beberapa kasus, Anda mungkin perlu mendefinisikan struktur output yang lebih kompleks yang melibatkan data bertingkat. Pydantic memungkinkan Anda untuk menumpuk model satu sama lain, sehingga Anda dapat membuat skema rumit yang mampu menangani berbagai kasus penggunaan. Ini sangat berguna saat menangani data hierarkis atau ketika Anda perlu menegakkan struktur tertentu untuk output yang kompleks.
Mari pertimbangkan contoh di mana kita perlu mengekstrak informasi pengguna secara rinci, termasuk nama, detail kontak, dan daftar alamat. Setiap alamat harus mencakup field untuk jalan, kota, negara bagian, dan kode pos. Ini memerlukan lebih dari satu model Pydantic untuk membangun skema yang benar.
Pertama, kita definisikan model Pydantic untuk alamat dan informasi pengguna:
from pydantic import BaseModel
from typing import List
# Define the Pydantic model for an address
class Address(BaseModel):
street: str
city: str
state: str
zip_code: str
# Define the Pydantic model for user information
class UserInfo(BaseModel):
name: str
email: str
phone: str
addresses: List[Address]
Dalam contoh ini:
Address adalah model Pydantic yang mendefinisikan struktur sebuah alamat.UserInfo adalah model Pydantic yang mencakup daftar objek Address, beserta field untuk nama, email, dan nomor telepon pengguna.Selanjutnya, kita gunakan model Pydantic bertingkat ini untuk menegakkan struktur output dalam panggilan OpenAI API:
SYSTEM_PROMPT = "You are a user information extraction assistant."
PROMPT_TEMPLATE = """ Extract the user information from the following text:\n\n{text}"""
# Function to extract user information using OpenAI's chat completions API with structured outputs
def extract_user_info(text):
response = client.beta.chat.completions.parse(
model=MODEL,
messages=[
{"role": "system", "content": SYSTEM_PROMPT},
{"role": "user", "content": PROMPT_TEMPLATE.format(text=text)},
],
response_format=UserInfo
)
return response.choices[0].message
# Example text containing user information
text = """John DoeEmail: john.doe@example.comPhone: 123-456-7890Addresses:- 123 Main St, Springfield, IL, 62701- 456 Elm St, Shelbyville, IL, 62702"""
# Extract user information and print the results
user_info = extract_user_info(text)
Teks contoh benar-benar sulit dibaca dan tidak memiliki spasi antar bagian informasi kunci. Mari kita lihat apakah model berhasil. Kita akan menggunakan pustaka json untuk mempercantik respons:
import json
data = json.loads(user_info.content)
pretty_response = json.dumps(data, indent=2)
print(pretty_response)
{
"name": "John Doe",
"email": "john.doe@example.com",
"phone": "123-456-7890",
"addresses": [
{
"street": "123 Main St",
"city": "Springfield",
"state": "IL",
"zip_code": "62701"
},
{
"street": "456 Elm St",
"city": "Shelbyville",
"state": "IL",
"zip_code": "62702"
}
]
}
Seperti terlihat, model berhasil menangkap informasi satu pengguna beserta dua alamat terpisahnya berdasarkan skema yang kita sediakan.
Singkatnya, dengan menyusun model Pydantic, Anda dapat mendefinisikan skema kompleks yang menangani data hierarkis dan menegakkan struktur khusus untuk output yang rumit.
Salah satu fitur yang luas digunakan pada model bahasa yang lebih baru adalah function calling (juga disebut tool calling). Kapabilitas ini memungkinkan Anda menghubungkan model bahasa ke fungsi yang didefinisikan pengguna, sehingga secara efektif memberi model akses ke dunia luar.
Beberapa contoh umum:
Kita tidak akan membahas detail cara kerja function calling di sini, namun Anda dapat membaca tutorial OpenAI Function Calling kami.
Yang penting untuk diketahui adalah dengan Structured Outputs, penggunaan function calling dengan model OpenAI menjadi jauh lebih mudah. Di masa lalu, fungsi yang Anda teruskan ke model OpenAI memerlukan penulisan skema JSON yang kompleks, merinci setiap parameter fungsi dengan petunjuk tipe. Berikut contohnya:
{
"type": "function",
"function": {
"name": "get_current_weather",
"description": "Get the current weather",
"parameters": {
"type": "object",
"properties": {
"location": {
"type": "string",
"description": "The city and state, e.g. San Francisco, CA",
},
"format": {
"type": "string",
"enum": ["celsius", "fahrenheit"],
"description": "The temperature unit to use. Infer this from the users location.",
},
},
"required": ["location", "format"],
},
}
}
Meskipun fungsi get_current_weather hanya memiliki dua parameter, skema JSON-nya menjadi sangat besar dan rawan kesalahan bila ditulis manual.
Hal ini diatasi dalam Structured Outputs dengan kembali menggunakan model Pydantic:
from pydantic import BaseModel from typing import Literal def get_weather(location: str, unit: str, condition: str): # Implementation details... pass class WeatherData(BaseModel): location: str unit: Literal["celsius", "fahrenheit"] condition: Literal["sunny", "cloudy", "rainy", "snowy"]Pertama, Anda menulis fungsinya dan logiknya. Lalu, Anda mendefinisikannya kembali dengan model Pydantic yang menentukan parameter input yang diharapkan.
Kemudian, untuk mengonversi model Pydantic ke skema JSON yang kompatibel, Anda memanggil
pydantic_function_tool:>>> import openai >>> openai.pydantic_function_tool(WeatherData) {'type': 'function', 'function': {'name': 'WeatherData', 'strict': True, 'parameters': {'properties': {'location': {'title': 'Location', 'type': 'string'}, 'unit': {'enum': ['celsius', 'fahrenheit'], 'title': 'Unit', 'type': 'string'}, 'condition': {'enum': ['sunny', 'cloudy', 'rainy', 'snowy'], 'title': 'Condition', 'type': 'string'}}, 'required': ['location', 'unit', 'condition'], 'title': 'WeatherData', 'type': 'object', 'additionalProperties': False}}}Berikut cara menggunakan tool ini sebagai bagian dari permintaan:
import openai client = OpenAI() tools = [openai.pydantic_function_tool(WeatherData)] messages = [ { "role": "system", "content": "You are a helpful customer support assistant. Use the supplied tools to assist the user.", }, { "role": "user", "content": "What is the weather in Tokyo?", } ] response = client.chat.completions.create( model=MODEL, messages=messages, tools=tools ) tool_call = response.choices[0].message.tool_calls[0] >>> tool_call ChatCompletionMessageToolCall(id='call_QnZZ0DmNN2cxw3bN433JQNIC', function=Function(arguments='{"location":"Tokyo","unit":"celsius","condition":"sunny"}', name='WeatherData'), type='function')Kita meneruskan model Pydantic dalam format JSON yang kompatibel ke parameter
toolsdari Chat Completions API. Lalu, bergantung pada kueri kita, model memutuskan apakah akan memanggil tool tersebut atau tidak.Karena kueri kita pada contoh di atas adalah “What is the weather in Tokyo?”, kita melihat sebuah panggilan pada
tool_callsdari objek pesan yang dikembalikan.Ingat, model tidak memanggil fungsi
get_weather, melainkan menghasilkan argumen untuknya berdasarkan skema Pydantic yang kita berikan:arguments = json.loads(tool_call.function.arguments) >>> arguments {'location': 'Tokyo', 'unit': 'celsius', 'condition': 'sunny'}Terserah kita untuk memanggil fungsi dengan argumen yang disediakan:
some_result = get_weather(**arguments)Jika Anda ingin model menghasilkan argumen untuk fungsi dan memanggilnya sekaligus, Anda memerlukan agen AI.
Kami memiliki tutorial LangChain Agents terpisah jika Anda tertarik.
Praktik Terbaik Saat Menggunakan OpenAI Structured Outputs
Saat menggunakan Structured Outputs, ada sejumlah praktik terbaik dan rekomendasi yang perlu diingat. Pada bagian ini, kami akan menguraikan beberapa di antaranya.
- Gunakan model Pydantic untuk mendefinisikan skema output, karena memberikan cara yang rapi dan aman tipe untuk mendefinisikan struktur output yang diharapkan.
- Jaga skema tetap sederhana dan spesifik untuk mendapatkan hasil yang paling akurat.
- Gunakan tipe data yang sesuai (
str,int,float,bool,List,Dict) untuk merepresentasikan data Anda secara akurat.- Gunakan tipe
Literaluntuk enum guna mendefinisikan nilai yang diizinkan secara spesifik untuk field.- Tangani penolakan model. Saat menggunakan metode baru
.parse(), objek pesan memiliki atribut baru.refusaluntuk menunjukkan penolakan:text = """John DoeEmail: john.doe@example.comPhone: 123-456-7890Addresses:- 123 Main St, Springfield, IL, 62701- 456 Elm St, Shelbyville, IL, 62702""" user_info = extract_user_info(text) if user_info.refusal: print(user_info.refusal) else: print(user_info.content)Output:
{"name":"John Doe","email":"john.doe@example.com","phone":"123-456-7890","addresses":[{"street":"123 Main St","city":"Springfield","state":"IL","zip_code":"62701"},{"street":"456 Elm St","city":"Shelbyville","state":"IL","zip_code":"62702"}]}6. Berikan deskripsi yang jelas dan ringkas untuk setiap field dalam model Pydantic Anda guna meningkatkan ketepatan output model:
from pydantic import BaseModel, Field class Person(BaseModel): name: str = Field(..., description="The person's full name") age: int = Field(..., description="The person's age in years") occupation: str = Field(..., description="The person's current job or profession")Praktik-praktik ini akan sangat membantu memaksimalkan pemanfaatan Structured Outputs dalam aplikasi Anda.
Penutup
Dalam tutorial ini, kita telah mempelajari cara memulai dengan fitur baru OpenAI API: Structured Outputs. Kita telah melihat bagaimana fitur ini memaksa model bahasa untuk menghasilkan output dalam format yang kita tentukan. Kita telah mempelajari cara menggunakannya bersama function calling dan mengeksplorasi beberapa praktik terbaik untuk memaksimalkan fitur ini.
Berikut beberapa sumber terkait untuk menambah pemahaman Anda:
Model Pydantic digunakan untuk mendefinisikan skema struktur output yang diinginkan, yang kemudian diteruskan ke OpenAI API untuk menegakkan format respons.
Ya, Structured Outputs dapat digunakan dengan function calling untuk menyederhanakan proses pendefinisian parameter fungsi dan output yang diharapkan.
Manfaatnya mencakup format respons yang konsisten, kebutuhan pasca-pemrosesan yang lebih sedikit, keandalan yang meningkat dalam aplikasi AI, dan integrasi yang lebih mudah dengan sistem yang ada.
Meskipun kuat, Structured Outputs dapat membatasi fleksibilitas respons AI dan memerlukan perancangan skema yang cermat untuk menyeimbangkan struktur dengan tingkat detail yang diinginkan pada output.
Saya adalah kreator konten data science dengan pengalaman lebih dari 2 tahun dan salah satu dengan jumlah pengikut terbesar di Medium. Saya suka menulis artikel mendalam tentang AI dan ML dengan sedikit gaya sarkastik—karena harus ada sesuatu untuk membuatnya tidak terlalu membosankan. Saya telah menghasilkan lebih dari 130 artikel dan satu kursus di DataCamp, dengan satu lagi sedang dalam proses. Konten saya telah dilihat oleh lebih dari 5 juta pasang mata, dan 20 ribu di antaranya menjadi pengikut di Medium dan LinkedIn.
Kursus OpenAI Teratas
{count, plural, one {Kursus} other {Kursus}}
{count, plural, one {Kursus} other {Kursus}}
{count, plural, one {Kursus} other {Kursus}}

{count, plural, one {blog} other {blogs}}
Javier Canales Luna
14 mnt
{count, plural, one {blog} other {blogs}}
David Woods
13 mnt
{count, plural, one {blog} other {blogs}}
Dario Radečić
15 mnt
{count, plural, one {blog} other {blogs}}
Hugo Bowne-Anderson
13 mnt