มันเป็นเรื่องยากที่จะผลิตผลลัพธ์จาก LLM ในโครงสร้างที่สอดคล้องกัน TypeGpt ทำให้กระบวนการนี้ง่ายขึ้นเหมือนการกำหนดคลาสใน Python
การเพิ่มพลังโครงการของเราเองเช่น Spexia
pip install typegpt
กำหนดสคีมาที่พร้อมท์และต้องการของคุณเป็นคลาสย่อยใน 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 ]
หากคุณใช้ OpenAI เป็นผู้ให้บริการ LLM ของคุณเพียงแทนที่ชื่อคลาสไคลเอนต์ OpenAI ด้วย subclass TypeOpenAI
(สำหรับ async ใช้ AsyncTypeOpenAI
หรือสำหรับการใช้ Azure TypeAzureOpenAI
/ AsyncTypeAzureOpenAI
) เพื่อให้ปลอดภัย คุณยังสามารถใช้มันได้ตามที่คุณเคยมีมาก่อน แต่ตอนนี้คุณสามารถเรียกฟังก์ชัน generate_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 )
และคุณจะได้รับผลลัพธ์ที่ดีเช่นนี้:
Output ( num_sentences = 1 , adjectives = [ 'young' , 'exceptional' ], nouns = [ 'athlete' , 'skill' , 'agility' , 'field' ], verbs = [ 'demonstrated' ])
ประเภทเอาต์พุตของคุณสามารถมีสตริงจำนวนเต็มลอยบูลีนหรือรายการเหล่านี้ นอกจากนี้ยังเป็นไปได้ที่จะทำเครื่องหมายองค์ประกอบเป็นตัวเลือก สามารถให้ค่าเริ่มต้นได้เช่นกัน
class Output ( BaseLLMResponse ):
title : str = "My Recipe"
description : str | None
num_ingredients : int
ingredients : list [ int ]
estimated_time : float
is_oven_required : bool
ที่นี่ตัวแยกวิเคราะห์จะแยกวิเคราะห์ description
หาก LLM ส่งคืน แต่จะไม่ต้องการ None
โดยค่าเริ่มต้น ถือเป็น title
เดียวกันเนื่องจากมีค่าเริ่มต้น
คุณยังสามารถกำหนดข้อ จำกัด เพิ่มเติมหรือให้ข้อมูลเพิ่มเติม LLM สำหรับองค์ประกอบบางอย่าง:
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
โดยค่าเริ่มต้นไลบรารีคาดว่าจะมีการตอบกลับบรรทัดเดียวต่อองค์ประกอบเสมอ คุณสามารถแทนที่สิ่งนี้ได้โดยการตั้งค่า multiline=True
ใน 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 )
คุณสามารถทำรังประเภทการตอบสนอง โปรดทราบว่าคุณต้องใช้ BaseLLMArrayElement
สำหรับชั้นเรียนที่คุณต้องการทำรังในรายการ ในการเพิ่มคำแนะนำภายในองค์ประกอบของ BaseLLMArrayElement
คุณต้องใช้ LLMArrayElementOutput
แทน 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
คุณอาจมีพรอมต์ที่ใช้โทเค็นจำนวนมากที่คาดเดาไม่ได้เนื่องจากการพึ่งพาขนาดใหญ่ เพื่อให้แน่ใจว่าพรอมต์ของคุณจะพอดีกับขีด จำกัด โทเค็นของ LLM เสมอคุณสามารถใช้ฟังก์ชั่น reduce_if_possible
ภายในคลาสพรอมต์ของคุณ:
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
ภายในฟังก์ชั่น reduce_if_possible
คุณควรลดขนาดของพรอมต์ของคุณในขั้นตอนเล็ก ๆ และกลับมา True
หากลดลงสำเร็จ ฟังก์ชั่นนี้เรียกซ้ำ ๆ จนกว่าพรอมต์จะพอดี เมื่อเรียกใช้ฟังก์ชัน OpenAI generate_output
สิ่งนี้จะช่วยให้มั่นใจได้ว่าพรอมต์จะเหมาะสำหรับรุ่นที่กำหนด นอกจากนี้คุณสามารถระบุขีด จำกัด โทเค็นอินพุตที่กำหนดเองด้วยเอฟเฟกต์เดียวกันเพื่อประหยัดค่าใช้จ่าย: client.chat.completions.generate_output(..., max_input_tokens=2000)
ในบางกรณี GPT อาจยังคงส่งคืนผลลัพธ์ที่ไม่เป็นไปตามสคีมาอย่างถูกต้อง เมื่อสิ่งนี้เกิดขึ้นไคลเอนต์ OpenAI จะส่ง LLMParseException
หากต้องการลองใหม่โดยอัตโนมัติเมื่อเอาต์พุตไม่ตรงกับสคีมาของคุณคุณสามารถตั้งค่า retry_on_parse_error
เป็นจำนวนการลองใหม่ที่คุณต้องการอนุญาต:
out = client . chat . completions . generate_output ( "gpt-3.5-turbo" , prompt = prompt , ..., retry_on_parse_error = 3 )
ตอนนี้ห้องสมุดจะพยายามโทรหา GPT สามครั้งก่อนที่จะพบข้อผิดพลาด อย่างไรก็ตามตรวจสอบให้แน่ใจว่าคุณใช้สิ่งนี้เมื่ออุณหภูมิไม่เป็นศูนย์
prompt = ExamplePrompt (...)
output = client . chat . completions . generate_output ( model = "gpt-4" , prompt = prompt , ...)
เนื่องจากระบบประเภทที่ จำกัด ของ Python ประเภทเอาต์พุตเป็นประเภท BaseLLMResponse
แทนที่จะเป็น subclass ExamplePrompt.Output
ที่ชัดเจน เพื่อให้ได้ความปลอดภัยแบบเต็มรูปแบบในรหัสของคุณเพียงเพิ่มพารามิเตอร์ output_type=ExamplePrompt.Output
:
prompt = ExamplePrompt (...)
output = client . chat . completions . generate_output ( model = "gpt-4" , prompt = prompt , output_type = ExamplePrompt . Output , ...)
พารามิเตอร์นี้ไม่ได้เป็นเพียงนักตกแต่งประเภท นอกจากนี้ยังสามารถใช้เพื่อเขียนทับประเภทเอาต์พุตจริงที่ GPT พยายามทำนาย
ยกตัวอย่างให้กับแบบจำลองเพื่ออธิบายงานที่ยากที่จะอธิบาย:
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 :
...
ตรวจสอบให้แน่ใจว่าใช้ AzureChatModel
เป็นแบบจำลองเมื่อสร้างเอาต์พุตซึ่งประกอบด้วยการปรับใช้ _id และโมเดลพื้นฐานที่สอดคล้องกัน (ใช้สำหรับลดพรอมต์โดยอัตโนมัติหากจำเป็น)
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 )
LLM ใด ๆ ที่มีแนวคิดเกี่ยวกับระบบและการแจ้งเตือนของผู้ใช้สามารถใช้ไลบรารีนี้ได้ สร้างระบบและข้อความผู้ใช้ (รวมถึงพรอมต์สคีมา) เช่นนี้:
messages = prompt . generate_messages (
token_limit = max_prompt_length , token_counter = lambda messages : num_tokens_from_messages ( messages )
)
โดยที่ max_prompt_length
เป็นจำนวนสูงสุดของโทเค็นที่พรอมต์ได้รับอนุญาตให้ใช้และ num_tokens_from_messages
จะต้องเป็นฟังก์ชันที่นับการใช้โทเค็นที่คาดการณ์ไว้สำหรับรายการข้อความที่กำหนด ส่งคืน 0
ที่นี่หากคุณไม่ต้องการลดขนาดของพรอมต์โดยอัตโนมัติ
ใช้ข้อความที่สร้างขึ้นเพื่อเรียก LLM ของคุณ แยกวิเคราะห์สตริงความสำเร็จที่คุณได้รับกลับเข้าสู่คลาสเอาต์พุตที่ต้องการเช่นนี้:
out = ExamplePrompt . Output . parse_response ( completion )
ไลบรารีนี้จะสร้างสคีมาที่เข้ากันได้กับ LLM โดยอัตโนมัติจากคลาสเอาต์พุตที่กำหนดไว้ของคุณและเพิ่มคำแนะนำไปยังจุดสิ้นสุดของพรอมต์ระบบเพื่อให้เป็นไปตามสคีมานี้ ตัวอย่างเช่นสำหรับพรอมต์นามธรรมต่อไปนี้:
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 ]
จะมีการสร้างพรอมต์ระบบต่อไปนี้:
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>
...
"""
สังเกตว่าพหูพจน์ "หนู" จะถูกแปลงเป็น "เมาส์" แบบเอกพจน์โดยอัตโนมัติเพื่อหลีกเลี่ยงความสับสนในรูปแบบภาษา