Secara inheren sulit untuk menghasilkan output dari LLMS dalam struktur yang konsisten. Typegpt menyederhanakan proses ini menjadi semudah mendefinisikan kelas dalam python.
Menggerakkan proyek kami sendiri, seperti spexia
pip install typegpt
Tentukan skema output prompt dan diinginkan Anda sebagai subclass di Python:
from typegpt import BaseLLMResponse , PromptTemplate
class ExamplePrompt ( PromptTemplate ):
def __init__ ( self , sentence : str ):
self . sentence = sentence
def system_prompt ( self ) -> str :
return "Given a sentence, extract sentence parts."
def user_prompt ( self ) -> str :
return self . sentence
class Output ( BaseLLMResponse ):
num_sentences : int
adjectives : list [ str ]
nouns : list [ str ]
verbs : list [ str ]
Jika Anda menggunakan OpenAI sebagai penyedia LLM Anda, cukup ganti nama kelas klien OpenAI dengan subclass TypeOpenAI
(untuk async menggunakan AsyncTypeOpenAI
, atau untuk menggunakan TypeAzureOpenAI
/ AsyncTypeAzureOpenAI
) untuk membuatnya aman. Anda masih dapat menggunakannya seperti yang akan Anda miliki sebelumnya, tetapi sekarang Anda juga dapat memanggil fungsi generate_output
untuk penyelesaian obrolan seperti ini untuk menghasilkan objek output:
from typegpt . openai import TypeOpenAI
prompt = ExamplePrompt ( "The young athlete demonstrated exceptional skill and agility on the field." )
client = TypeOpenAI ( api_key = "<your api key>" ) # subclass of `OpenAI`
output = client . chat . completions . generate_output ( model = "gpt-3.5-turbo" , prompt = prompt , max_output_tokens = 1000 )
Dan Anda mendapatkan hasil yang bagus seperti ini:
Output ( num_sentences = 1 , adjectives = [ 'young' , 'exceptional' ], nouns = [ 'athlete' , 'skill' , 'agility' , 'field' ], verbs = [ 'demonstrated' ])
Jenis output Anda dapat berisi string, integer, float, boolean, atau daftar ini. Dimungkinkan juga untuk menandai elemen sebagai opsional. Nilai default dapat disediakan juga.
class Output ( BaseLLMResponse ):
title : str = "My Recipe"
description : str | None
num_ingredients : int
ingredients : list [ int ]
estimated_time : float
is_oven_required : bool
Di sini, parser akan menguraikan description
jika LLM mengembalikannya, tetapi tidak akan memerlukannya. Itu None
secara default. Hal yang sama berlaku untuk title
, karena memiliki nilai default.
Anda juga dapat mendefinisikan lebih banyak pembatasan atau memberikan informasi lebih lanjut kepada LLM untuk beberapa elemen:
class Output ( BaseLLMResponse ):
title : str = LLMOutput ( instruction = "The title for the recipe." )
description : str | None = LLMOutput ( instruction = "An optional description for the recipe." )
num_ingredients : int
ingredients : list [ int ] = LLMArrayOutput ( expected_count = ( 1 , 5 ), instruction = lambda pos : f"The id of the { pos . ordinal } ingredient" ) # between 1 and 5 ingredients expected (and required at parse time)
estimated_time : float = LLMOutput ( instruction = "The estimated time to cook" )
is_oven_required : bool
Secara default, perpustakaan selalu mengharapkan hanya satu respons baris per elemen. Anda dapat mengganti ini dengan mengatur multiline=True
di LLMOutput
:
class Output ( BaseLLMResponse ):
description : str = LLMOutput ( instruction = "A description for the recipe." , multiline = True )
items : list [ str ] = LLMArrayOutput ( expected_count = 5 , instruction = lambda pos : f"The { pos . ordinal } item in the list" , multiline = True )
Anda dapat bersarang jenis respons. Perhatikan bahwa Anda perlu menggunakan BaseLLMArrayElement
untuk kelas yang ingin Anda bersarang di dalam daftar. Untuk menambahkan instruksi di dalam elemen BaseLLMArrayElement
, Anda harus menggunakan LLMArrayElementOutput
alih -alih LLMOutput
.
class Output ( BaseLLMResponse ):
class Item ( BaseLLMArrayElement ):
class Description ( BaseLLMResponse ):
short : str | None
long : str
title : str
description : Description
price : float = LLMArrayElementOutput ( instruction = lambda pos : f"The price of the { pos . ordinal } item" )
items : list [ Item ]
count : int
Anda mungkin memiliki prompt yang menggunakan sejumlah besar token karena kemungkinan dependensi yang besar. Untuk memastikan prompt Anda selalu cocok dalam batas token LLM, Anda dapat mengimplementasikan fungsi reduce_if_possible
di dalam kelas prompt Anda:
class SummaryPrompt ( PromptTemplate ):
def __init__ ( self , article : str ):
self . article = article
def system_prompt ( self ) -> str :
return "Summarize the given news article"
def user_prompt ( self ) -> str :
return f"ARTICLE: { self . article } "
def reduce_if_possible ( self ) -> bool :
if len ( self . article ) > 100 :
# remove last 100 characters at a time
self . article = self . article [: - 100 ]
return True
return False
class Output ( BaseLLMResponse ):
summary : str
Di dalam fungsi reduce_if_possible
, Anda harus mengurangi ukuran prompt Anda dalam langkah -langkah kecil dan mengembalikan True
jika berhasil dikurangi. Fungsinya dipanggil berulang kali sampai prompt cocok. Saat memanggil fungsi OpenAi generate_output
, ini secara otomatis memastikan prompt cocok untuk model yang diberikan. Selain itu, Anda dapat menentukan batas token input khusus dengan efek yang sama untuk menghemat biaya: client.chat.completions.generate_output(..., max_input_tokens=2000)
.
Dalam beberapa kasus, GPT mungkin masih mengembalikan output yang tidak mengikuti skema dengan benar. Ketika ini terjadi, klien OpenAI melemparkan LLMParseException
. Untuk mencoba kembali secara otomatis ketika output tidak memenuhi skema Anda, Anda dapat mengatur retry_on_parse_error
ke jumlah retries yang ingin Anda izinkan:
out = client . chat . completions . generate_output ( "gpt-3.5-turbo" , prompt = prompt , ..., retry_on_parse_error = 3 )
Sekarang, perpustakaan akan mencoba memanggil GPT tiga kali sebelum melakukan kesalahan. Namun, pastikan Anda hanya menggunakan ini saat suhunya tidak nol.
prompt = ExamplePrompt (...)
output = client . chat . completions . generate_output ( model = "gpt-4" , prompt = prompt , ...)
Karena sistem tipe Python yang terbatas, tipe output adalah tipe BaseLLMResponse
alih -alih subclass explicit ExamplePrompt.Output
. Untuk mencapai keamanan tipe penuh dalam kode Anda, cukup tambahkan parameter output_type=ExamplePrompt.Output
:
prompt = ExamplePrompt (...)
output = client . chat . completions . generate_output ( model = "gpt-4" , prompt = prompt , output_type = ExamplePrompt . Output , ...)
Parameter ini bukan hanya tipe dekorator. Ini juga dapat digunakan untuk menimpa tipe output aktual yang ingin diprediksi oleh GPT.
Berikan contoh kepada model untuk menjelaskan tugas yang sulit dijelaskan:
class ExamplePrompt ( PromptTemplate ):
class Output ( BaseLLMResponse ):
class Ingredient ( BaseLLMResponse ):
name : str
quantity : int
ingredients : list [ Ingredient ]
def system_prompt ( self ) -> str :
return "Given a recipe, extract the ingredients."
def few_shot_examples ( self ) -> list [ FewShotExample [ Output ]]:
return [
FewShotExample (
input = "Let's take two apples, three bananas, and four oranges." ,
output = self . Output ( ingredients = [
self . Output . Ingredient ( name = "apple" , quantity = 2 ),
self . Output . Ingredient ( name = "banana" , quantity = 3 ),
self . Output . Ingredient ( name = "orange" , quantity = 4 ),
])
),
FewShotExample (
input = "My recipe requires five eggs and two cups of flour." ,
output = self . Output ( ingredients = [
self . Output . Ingredient ( name = "egg" , quantity = 5 ),
self . Output . Ingredient ( name = "flour cups" , quantity = 2 ),
])
)
]
def user_prompt ( self ) -> str :
...
Pastikan untuk menggunakan AzureChatModel
sebagai model saat menghasilkan output, yang terdiri dari Deployment_id dan model dasar yang sesuai (ini digunakan untuk secara otomatis mengurangi petunjuk jika diperlukan).
from typegpt . openai import AzureChatModel , TypeAzureOpenAI
client = TypeAzureOpenAI (
azure_endpoint = "<your azure endpoint>" ,
api_key = "<your api key>" ,
api_version = "2023-05-15" ,
)
out = client . chat . completions . generate_output ( model = AzureChatModel ( deployment_id = "gpt-35-turbo" , base_model = "gpt-3.5-turbo" ), prompt = prompt , max_output_tokens = 1000 )
Setiap LLM yang memiliki gagasan tentang sistem dan petunjuk pengguna dapat menggunakan perpustakaan ini. Hasilkan Sistem dan Pesan Pengguna (termasuk prompt skema) seperti ini:
messages = prompt . generate_messages (
token_limit = max_prompt_length , token_counter = lambda messages : num_tokens_from_messages ( messages )
)
Di mana max_prompt_length
adalah jumlah maksimum token yang diizinkan untuk digunakan, dan num_tokens_from_messages
harus menjadi fungsi yang menghitung penggunaan token yang diprediksi untuk daftar pesan yang diberikan. Kembalikan 0
di sini jika Anda tidak ingin secara otomatis mengurangi ukuran prompt.
Gunakan pesan yang dihasilkan untuk menghubungi LLM Anda. Parse string penyelesaian yang Anda terima kembali ke kelas output yang diinginkan seperti ini:
out = ExamplePrompt . Output . parse_response ( completion )
Perpustakaan ini secara otomatis menghasilkan skema yang kompatibel dengan LLM dari kelas output yang Anda tentukan dan menambahkan instruksi ke akhir sistem prompt untuk mematuhi skema ini. Misalnya, untuk prompt abstrak berikut:
class DemoPrompt ( PromptTemplate ):
def system_prompt ( self ) -> str :
return "This is a system prompt"
def user_prompt ( self ) -> str :
return "This is a user prompt"
class Output ( BaseLLMResponse ):
title : str
description : str = LLMOutput ( "Custom instruction" )
mice : list [ str ]
Prompt sistem berikut akan dihasilkan:
This is a system prompt
Always return the answer in the following format:
"""
TITLE: <Put the title here>
DESCRIPTION: <Custom instruction>
MOUSE 1: <Put the first mouse here>
MOUSE 2: <Put the second mouse here>
...
"""
Perhatikan bagaimana "tikus" jamak secara otomatis dikonversi menjadi "mouse" tunggal untuk menghindari membingungkan model bahasa.