Decorators Lanchchain เป็นชั้นบนของ Langchain ที่ให้น้ำตาลวากยสัมพันธ์หรือไม่? สำหรับการเขียนพรอมต์และโซ่ Langchain ที่กำหนดเอง
หมายเหตุ: นี่เป็นส่วนเสริมที่ไม่เป็นทางการไปยังห้องสมุด Langchain มันไม่ได้พยายามที่จะแข่งขันเพียงเพื่อให้การใช้งานง่ายขึ้น ความคิดมากมายที่นี่มีความเห็นโดยสิ้นเชิง
นี่คือตัวอย่างง่ายๆของรหัสที่เขียนด้วย นักตกแต่ง Langchain
@ llm_prompt
def write_me_short_post ( topic : str , platform : str = "twitter" , audience : str = "developers" ) -> str :
"""
Write me a short header for my post about {topic} for {platform} platform.
It should be for {audience} audience.
(Max 15 words)
"""
return
# run it naturaly
write_me_short_post ( topic = "starwars" )
# or
write_me_short_post ( topic = "starwars" , platform = "redit" )หลักการและผลประโยชน์หลัก:
pythonic เพิ่มเติมเริ่มต้นอย่างรวดเร็ว
การประกาศแจ้ง
ฟังก์ชั่น LLM (ฟังก์ชั่น OpenAI)
สตรีมมิ่งง่ายๆ
การเลือก LLM อัตโนมัติ
โครงสร้างที่ซับซ้อนมากขึ้น
ผูกพรอมต์กับวัตถุ
กำหนดการตั้งค่าที่กำหนดเอง
การดีบัก
ผ่านหน่วยความจำการโทรกลับหยุด ฯลฯ
อื่น
pip install langchain_decoratorsความคิดที่ดีเกี่ยวกับวิธีการเริ่มต้นคือการตรวจสอบตัวอย่างที่นี่:
โดยค่าเริ่มต้นพรอมต์เป็นเอกสารฟังก์ชันทั้งหมดเว้นแต่คุณจะทำเครื่องหมายพรอมต์ของคุณ
เราสามารถระบุได้ว่าส่วนใดของเอกสารของเราคือคำจำกัดความที่รวดเร็วโดยการระบุบล็อกรหัสด้วย แท็กภาษา
@ llm_prompt
def write_me_short_post ( topic : str , platform : str = "twitter" , audience : str = "developers" ):
"""
Here is a good way to write a prompt as part of a function docstring, with additional documentation for devs.
It needs to be a code block, marked as a `<prompt>` language
```<prompt>
Write me a short header for my post about {topic} for {platform} platform.
It should be for {audience} audience.
(Max 15 words)
```
Now only the code block above will be used as a prompt, and the rest of the docstring will be used as a description for developers.
(It also has a nice benefit that IDE (like VS code) will display the prompt properly (not trying to parse it as markdown, and thus not showing new lines properly))
"""
return สำหรับโมเดลแชทมีประโยชน์มากในการกำหนดพรอมต์เป็นชุดของเทมเพลตข้อความ ... นี่คือวิธีการทำ:
@ llm_prompt
def simulate_conversation ( human_input : str , agent_role : str = "a pirate" ):
"""
## System message
- note the `:system` sufix inside the <prompt:_role_> tag
```<prompt:system>
You are a {agent_role} hacker. You must act like one.
You reply always in code, using python or javascript code block...
for example:
... do not reply with anything else.. just with code - respecting your role.
```
# human message
(we are using the real role that are enforced by the LLM - GPT supports system, assistant, user)
``` <prompt:user>
Helo, who are you
```
a reply:
``` <prompt:assistant>
``` python <<- escaping inner code block with that should be part of the prompt
def hello():
print("Argh... hello you pesky pirate")
```
```
we can also add some history using placeholder
```<prompt:placeholder>
{history}
```
```<prompt:user>
{human_input}
```
Now only the code block above will be used as a prompt, and the rest of the docstring will be used as a description for developers.
(It also has a nice benefit that IDE (like VS code) will display the prompt properly (not trying to parse it as markdown, and thus not showing new lines properly))
"""
passบทบาทที่นี่คือบทบาทดั้งเดิมของโมเดล (ผู้ช่วยผู้ใช้ระบบสำหรับ chatgpt)
ไวยากรณ์สำหรับสิ่งนี้มีดังนี้:
@ llm_prompt
def prompt_with_optional_partials ():
"""
this text will be rendered always, but
{? anything inside this block will be rendered only if all the {value}s parameters are not empty (None | "") ?}
you can also place it in between the words
this too will be rendered{? , but
this block will be rendered only if {this_value} and {this_value}
are not empty?} !
""" # this code example is complete and should run as it is
from langchain_decorators import llm_prompt
@ llm_prompt
def write_name_suggestions ( company_business : str , count : int ) -> list :
""" Write me {count} good name suggestions for company that {company_business}
"""
pass
write_name_suggestions ( company_business = "sells cookies" , count = 5 )ปัจจุบันรองรับเฉพาะสำหรับโมเดล OpenAI Chat ล่าสุด
สิ่งที่คุณต้องทำคือใส่หมายเหตุฟังก์ชั่นของคุณด้วย @llm_function Decorator
สิ่งนี้จะแยกวิเคราะห์คำอธิบายสำหรับ LLM (ย่อหน้าแรกที่เชื่อมโยงกันถือเป็นคำอธิบายฟังก์ชั่น)
และคำอธิบายพารามิเตอร์ ASO (Google, NumPy และ SPIHNX Notations ได้รับการสนับสนุนในตอนนี้)
โดยค่าเริ่มต้นรูปแบบ docString จะได้รับการแก้ไขโดยอัตโนมัติ แต่การตั้งค่ารูปแบบของเอกสารสามารถเร่งความเร็วได้เล็กน้อย - auto (ค่าเริ่มต้น): รูปแบบถูกอนุมานโดยอัตโนมัติจาก docString - google : docString ถูกแยกวิเคราะห์เป็น markdown (ดูรูปแบบ Google docString) - numpy : docString ถูกแยกวิเคราะห์เป็น markdown (ดูรูปแบบเอกสาร numpy) - sphinx : เอกสารถูกแยกวิเคราะห์
วิธีที่ดีที่สุดในการกำหนด enum คือผ่านคำอธิบายประกอบประเภทโดยใช้ Literal :
@ llm_function
def do_magic ( spell : str , strength : Literal [ "light" , "medium" , "strong" ]):
"""
Do some kind of magic
Args:
spell (str): spall text
strength (str): the strength of the spell
""" enum ทางเลือกสำหรับตัวอักษร เพื่อใส่คำอธิบายประกอบ "enum" เช่นอาร์กิวเมนต์คุณสามารถใช้ "typescript" เช่นรูปแบบ: ["value_a" | "value_b"] ... ถ้าจะแยกวิเคราะห์ออก ข้อความนี้จะเป็นส่วนหนึ่งของคำอธิบายด้วย ... หากคุณไม่ต้องการคุณสามารถใช้สัญลักษณ์นี้เป็นสัญลักษณ์ประเภท ตัวอย่าง:
Args:
message_type (["email" | "sms"]): type of a message / channel how to send the message
จากนั้นคุณจะส่งฟังก์ชั่นเหล่านี้เป็นอาร์กิวเมนต์และ @llm_prompt (อาร์กิวเมนต์จะต้องมีชื่อว่า functions
นี่คือวิธีการใช้งาน:
from langchain . agents import load_tools
from langchian_decorators import llm_function , llm_prompt , GlobalSettings
@ llm_function
def send_message ( message : str , addressee : str = None , message_type : Literal [ "email" , "whatsapp" ] = "email" ):
""" Use this if user asks to send some message
Args:
message (str): message text to send
addressee (str): email of the addressee... in format [email protected]
message_type (str, optional): style of message by platform
"""
if message_type == "email" :
send_email ( addressee , message )
elif message_type == "whatsapp" :
send_whatsapp ( addressee , message )
# load some other tools from langchain
list_of_other_tools = load_tools (
tool_names = [...],
llm = GlobalSettings . get_current_settings (). default_llm )
@ llm_prompt
def do_what_user_asks_for ( user_input : str , functions : List [ Union [ Callable , BaseTool ]]):
"""
```<prompt:system>
Your role is to be a helpful asistant.
```
```<prompt:user>
{user_input}
```
"""
user_input = "Yo, send an email to John Smith that I will be late for the meeting"
result = do_what_user_asks_for (
user_input = user_input ,
functions = [ send_message , * list_of_other_tools ]
)
if result . is_function_call :
result . execute ()
else :
print ( result . output_text )นอกจากนี้คุณยังสามารถเพิ่มอาร์กิวเมนต์
function_callลงในพรอมต์ LLM ของคุณเพื่อควบคุมพฤติกรรม GPT
- หากคุณตั้งค่าเป็น "ไม่มี" - มันจะปิดการใช้งานฟังก์ชั่นการเรียกใช้ในขณะนี้ แต่ก็ยังสามารถดูได้
- หากคุณตั้งค่าเป็น "อัตโนมัติ" - GPT จะเลือกใช้หรือใช้ฟังก์ชั่น
- หากคุณตั้งค่าเป็นชื่อของฟังก์ชั่น / หรือฟังก์ชั่นมันเอง (นักตกแต่งจะจัดการการแก้ไขชื่อเดียวกับที่ใช้ในสคีมา) มันจะบังคับให้ GPT ใช้ฟังก์ชันนั้น
หากคุณใช้อาร์กิวเมนต์ฟังก์ชั่นเอาต์พุตจะเป็น OutputWithFunctionCall เสมอ
class OutputWithFunctionCall ( BaseModel ):
output_text : str
output : T
function_name : str = None
function_arguments : Union [ Dict [ str , Any ], str , None ]
function : Callable = None
function_async : Callable = None
@ property
def is_function_call ( self ):
...
@ property
def support_async ( self ):
...
@ property
def support_sync ( self ):
...
async def execute_async ( self ):
"""Executes the function asynchronously."""
...
def execute ( self ):
""" Executes the function synchronously.
If the function is async, it will be executed in a event loop.
"""
...
def to_function_message ( self , result = None ):
"""
Converts the result to a FunctionMessage...
you can override the result collected via execute with your own
"""
... หากคุณต้องการดูว่าสคีมาได้รับการสร้างอย่างไรคุณสามารถใช้วิธี get_function_schema ที่เพิ่มเข้ากับฟังก์ชั่นโดยมัณฑนากร:
from langchain_decorators import get_function_schema
@ llm_function
def my_func ( arg1 : str ):
...
f_schema = get_function_schema ( my_func . get_function_schema )
print ( f_schema ) ในการเพิ่มผลลัพธ์ลงในหน่วยความจำ / agent_scratchpad คุณสามารถใช้ to_function_message เพื่อสร้าง functionMessage ที่ LLM จะตีความเป็นผลลัพธ์เครื่องมือ / ฟังก์ชั่น
ฟังก์ชั่นผู้ให้บริการช่วยให้คุณสามารถจัดเตรียมชุดของฟังก์ชั่น LLM ได้มากขึ้นเช่นรายการฟังก์ชั่น - ขึ้นอยู่กับอินพุต นอกจากนี้ยังช่วยให้คุณสามารถให้ชื่อเฉพาะกับแต่ละฟังก์ชั่นสำหรับการทำงาน LLM นี้ สิ่งนี้อาจมีประโยชน์ด้วยเหตุผลสองประการ:
ฟังก์ชั่น schemas (และโดยเฉพาะอย่างยิ่งคำอธิบายของพวกเขา) เป็นเครื่องมือสำคัญในการให้คำแนะนำ LLM หากคุณเปิดใช้งานการประกาศฟังก์ชั่นแบบไดนามิกคุณสามารถ (อีกครั้ง) ใช้แอตทริบิวต์พร้อมท์เดียวกันสำหรับพรอมต์หลักในรูปแบบ LLM_FUNCTION:
@ llm_function ( dynamic_schema = True )
def db_search ( query_input : str ):
"""
This function is useful to search in our database.
{?Here are some examples of data available:
{closest_examples}?}
"""
@ llm_prompt
def run_agent ( query_input : str , closest_examples : str , functions ):
"""
Help user. Use a function when appropriate
"""
closest_examples = get_closest_examples ()
run_agent ( query_input , closest_examples , functions = [ db_search , ...])นี่เป็นเพียงภาพประกอบตัวอย่างที่ใช้งานได้อย่างสมบูรณ์มีอยู่ที่นี่ในตัวอย่างรหัส
หากเราต้องการใช้ประโยชน์จากการสตรีม:
วิธีนี้เราเพียงทำเครื่องหมายว่าควรสตรีมแบบใดโดยไม่จำเป็นต้องใช้คนจรจัดกับสิ่งที่เราควรใช้ LLM ผ่านการสร้างและแจกจ่ายตัวจัดการสตรีมมิ่งไปยังส่วนหนึ่งของห่วงโซ่ของเรา ... เพียงแค่เปิด/ปิดการสตรีมมิ่งตามประเภทพรอมต์/พรอมต์ ...
การสตรีมจะเกิดขึ้นเฉพาะในกรณีที่เราเรียกมันในบริบทการสตรีม ... ที่นั่นเราสามารถกำหนดฟังก์ชั่นง่าย ๆ เพื่อจัดการสตรีม
# this code example is complete and should run as it is
from langchain_decorators import StreamingContext , llm_prompt
# this will mark the prompt for streaming (useful if we want stream just some prompts in our app... but don't want to pass distribute the callback handlers)
# note that only async functions can be streamed (will get an error if it's not)
@ llm_prompt ( capture_stream = True )
async def write_me_short_post ( topic : str , platform : str = "twitter" , audience : str = "developers" ):
"""
Write me a short header for my post about {topic} for {platform} platform.
It should be for {audience} audience.
(Max 15 words)
"""
pass
# just an arbitrary function to demonstrate the streaming... wil be some websockets code in the real world
tokens = []
def capture_stream_func ( new_token : str ):
tokens . append ( new_token )
# if we want to capture the stream, we need to wrap the execution into StreamingContext...
# this will allow us to capture the stream even if the prompt call is hidden inside higher level method
# only the prompts marked with capture_stream will be captured here
with StreamingContext ( stream_to_stdout = True , callback = capture_stream_func ):
result = await run_prompt ()
print ( "Stream finished ... we can distinguish tokens thanks to alternating colors" )
print ( " n We've captured" , len ( tokens ), "tokens? n " )
print ( "Here is the result:" )
print ( result )ในชีวิตจริงอาจมีสถานการณ์ที่บริบทจะเติบโตเหนือหน้าต่างของโมเดลพื้นฐานที่คุณใช้ (เช่นประวัติการแชทที่ยาวนาน) ... แต่เนื่องจากสิ่งนี้อาจเกิดขึ้นได้เพียงบางครั้งมันจะดีมากถ้าในสถานการณ์นี้ (โดยปกติจะมีราคาแพงกว่า)
ตอนนี้คุณสามารถทำได้ด้วย LLMSelector
from langchain_decorators import LlmSelector
my_llm_selector = LlmSelector (
generation_min_tokens = 0 , # how much token at min. I for generation I want to have as a buffer
prompt_to_generation_ratio = 1 / 3 # what percentage of the prompt length should be used for generation buffer
)
. with_llm_rule ( ChatGooglePalm (), max_tokens = 512 ) # ... if you want to use LLM whose window is not defined in langchain_decorators.common.MODEL_LIMITS (only OpenAI and Anthropic are there)
. with_llm ( ChatOpenAI ( model = "gpt-3.5-turbo" )) # these models are known, therefore we can just pass them and the max window will be resolved
. with_llm ( ChatOpenAI ( model = "gpt-3.5-turbo-16k-0613" ))
. with_llm ( ChatOpenAI ( model = "claude-v1.3-100k" ))คลาสนี้ช่วยให้คุณสามารถกำหนดลำดับของ LLM ด้วยกฎตามความยาวของพรอมต์และความยาวการสร้างที่คาดหวัง ... และหลังจากเกณฑ์จะถูกส่งผ่านแล้วโมเดลที่มีราคาแพงกว่าจะถูกใช้โดยอัตโนมัติ
คุณสามารถกำหนดให้เป็น globalsettings:
langchain_decorators . GlobalSettings . define_settings (
llm_selector = my_llm_selector # pass the selector into global settings
)หมายเหตุ: เป็นเวอร์ชัน v0.0.10 คุณมี LLMSelector อยู่ในการตั้งค่าเริ่มต้นที่กำหนดไว้ล่วงหน้า คุณสามารถแทนที่ด้วยการให้คุณเป็นเจ้าของหรือตั้งค่า LLM เริ่มต้นหรือการสตรีมเริ่มต้น LLM
หรือเป็นประเภทพรอมต์เฉพาะ:
from langchain_decorators import PromptTypes
class MyCustomPromptTypes ( PromptTypes ):
MY_TUBO_PROMPT = PromptTypeSettings ( llm_selector = my_llm_selector )สำหรับ dict / pydantic คุณต้องระบุคำแนะนำในการจัดรูปแบบ ... ซึ่งอาจน่าเบื่อนั่นคือเหตุผลที่คุณสามารถปล่อยให้ตัวแยกวิเคราะห์เอาต์พุตสร้างคำแนะนำตามโมเดล (Pydantic)
from langchain_decorators import llm_prompt
from pydantic import BaseModel , Field
class TheOutputStructureWeExpect ( BaseModel ):
name : str = Field ( description = "The name of the company" )
headline : str = Field ( description = "The description of the company (for landing page)" )
employees : list [ str ] = Field ( description = "5-8 fake employee names with their positions" )
@ llm_prompt ()
def fake_company_generator ( company_business : str ) -> TheOutputStructureWeExpect :
""" Generate a fake company that {company_business}
{FORMAT_INSTRUCTIONS}
"""
return
company = fake_company_generator ( company_business = "sells cookies" )
# print the result nicely formatted
print ( "Company name: " , company . name )
print ( "company headline: " , company . headline )
print ( "company employees: " , company . employees ) from pydantic import BaseModel
from langchain_decorators import llm_prompt
class AssistantPersonality ( BaseModel ):
assistant_name : str
assistant_role : str
field : str
@ property
def a_property ( self ):
return "whatever"
def hello_world ( self , function_kwarg : str = None ):
"""
We can reference any {field} or {a_property} inside our prompt... and combine it with {function_kwarg} in the method
"""
@ llm_prompt
def introduce_your_self ( self ) -> str :
"""
``` <prompt:system>
You are an assistant named {assistant_name}.
Your role is to act as {assistant_role}
```
```<prompt:user>
Introduce your self (in less than 20 words)
```
"""
personality = AssistantPersonality ( assistant_name = "John" , assistant_role = "a pirate" )
print ( personality . introduce_your_self ( personality )) ที่นี่เราเพิ่งทำเครื่องหมายฟังก์ชั่นเป็นพรอมต์ด้วย Dornator llm_prompt โดยเปลี่ยนเป็น LLMChain ได้อย่างมีประสิทธิภาพ แทนที่จะเรียกใช้
LLMCHAIN มาตรฐานใช้พารามิเตอร์ INT มากกว่าเพียงแค่ inputs_variables และพรอมต์ ... นี่คือรายละเอียดการใช้งานที่ซ่อนอยู่ในมัณฑนากร นี่คือวิธีการทำงาน:
การใช้ การตั้งค่าทั่วโลก :
# define global settings for all prompty (if not set - chatGPT is the current default)
from langchain_decorators import GlobalSettings
GlobalSettings . define_settings (
default_llm = ChatOpenAI ( temperature = 0.0 ), this is default ... can change it here globally
default_streaming_llm = ChatOpenAI ( temperature = 0.0 , streaming = True ), this is default ... can change it here for all ... will be used for streaming
)ใช้ ประเภทพรอมต์ ที่กำหนดไว้ล่วงหน้า
#You can change the default prompt types
from langchain_decorators import PromptTypes , PromptTypeSettings
PromptTypes . AGENT_REASONING . llm = ChatOpenAI ()
# Or you can just define your own ones:
class MyCustomPromptTypes ( PromptTypes ):
GPT4 = PromptTypeSettings ( llm = ChatOpenAI ( model = "gpt-4" ))
@ llm_prompt ( prompt_type = MyCustomPromptTypes . GPT4 )
def write_a_complicated_code ( app_idea : str ) -> str :
...กำหนดการตั้งค่า โดยตรงในมัณฑนากร
from langchain . llms import OpenAI
@ llm_prompt (
llm = OpenAI ( temperature = 0.7 ),
stop_tokens = [ " n Observation" ],
...
)
def creative_writer ( book_title : str ) -> str :
...หากต้องการผ่านสิ่งเหล่านี้เพียงแค่ประกาศพวกเขาในฟังก์ชั่น (หรือใช้ kwargs เพื่อผ่านอะไรก็ได้)
(พวกเขาไม่จำเป็นต้องประกาศ แต่มันก็เป็นวิธีปฏิบัติที่ดีถ้าคุณจะใช้พวกเขา)
@ llm_prompt ()
async def write_me_short_post ( topic : str , platform : str = "twitter" , memory : SimpleMemory = None ):
"""
{history_key}
Write me a short header for my post about {topic} for {platform} platform.
It should be for {audience} audience.
(Max 15 words)
"""
pass
await write_me_short_post ( topic = "old movies" ) มีหลายตัวเลือกวิธีการควบคุมเอาต์พุตลงชื่อเข้าใช้คอนโซล วิธีที่ง่ายที่สุดคือการกำหนดตัวแปร Env: LANGCHAIN_DECORATORS_VERBOSE และตั้งค่าเป็น "จริง"
นอกจากนี้คุณยังสามารถควบคุมสิ่งนี้ได้โดยการกำหนดการตั้งค่าทั่วโลกของคุณดังที่แสดงไว้ที่นี่
ตัวเลือกสุดท้ายคือการควบคุมต่อแต่ละกรณีเพียงแค่ทัวริงในโหมด verbose ตามพรอมต์:
@llm_prompt(verbose=True)
def your_prompt(param1):
...
Promptwatch IO เป็นแพลตฟอร์มในการติดตามและติดตามรายละเอียดเกี่ยวกับทุกสิ่งที่เกิดขึ้นในการประหารชีวิต Langchain ช่วยให้การรวมบรรทัดเดียวลดลงเพียงแค่ห่อรหัสจุดเข้าของคุณใน
with PromptWatch():
run_your_code()
เรียนรู้เพิ่มเติมเกี่ยวกับ Promptwatch ที่นี่: www.promptwatch.io
ยินดีรับการตอบรับผลงานและการประชาสัมพันธ์