Dekorator Lanchchain adalah lapisan di atas langchain yang menyediakan gula sintaksis? untuk menuliskan petunjuk dan rantai kustom kustom
Catatan: Ini adalah addon tidak resmi ke perpustakaan Langchain. Itu tidak mencoba untuk bersaing, hanya untuk membuatnya lebih mudah. Banyak ide di sini benar -benar pendapat
Berikut adalah contoh sederhana dari kode yang ditulis dengan dekorator 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" )Prinsip dan Manfaat utama:
pythonicAwal yang cepat
Deklarasi yang cepat
Fungsi LLM (Fungsi OpenAI)
Streaming yang disederhanakan
Pilihan LLM Otomatis
Struktur yang lebih kompleks
Mengikat prompt ke suatu objek
Mendefinisikan pengaturan khusus
Debugging
Melewati memori, panggilan balik, berhenti dll.
Lainnya
pip install langchain_decoratorsIde bagus tentang cara memulai adalah meninjau contoh di sini:
Secara default prompt adalah seluruh fungsi dokumen, kecuali jika Anda menandai prompt Anda
Kami dapat menentukan bagian mana dari dokumen kami adalah definisi cepat, dengan menentukan blok kode dengan Tag bahasa
@ 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 Untuk model obrolan sangat berguna untuk mendefinisikan prompt sebagai satu set templat pesan ... inilah cara melakukannya:
@ 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))
"""
passPeran di sini adalah model peran asli (asisten, pengguna, sistem untuk chatgpt)
Sintaks untuk ini adalah sebagai berikut:
@ 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 )Saat ini hanya didukung untuk model obrolan openai terbaru
Yang perlu Anda lakukan adalah memberi anotasi fungsi Anda dengan dekorator @llm_function.
Ini akan menguraikan deskripsi untuk LLM (paragraf koheren pertama dianggap sebagai deskripsi fungsi)
dan deskripsi parameter ASO (Google, notasi Numpy dan Spihnx didukung untuk saat ini)
Secara default format docString diselesaikan secara otomatis, tetapi mengatur format docString dapat mempercepat sedikit. - auto (default): Format secara otomatis disimpulkan dari docString - google : DocString diuraikan sebagai penurunan harga (lihat format Google DocString) - numpy : DocString diuraikan sebagai penurunan harga (lihat format docstring numpy) - sphinx : Docstring) format sphinx (See Docstring) diparsikan sebagai format sphinx (See Docstring (See Docstring) diparsikan sebagai sphinx (See Docstring (See DocString (See DocString) dipars
Cara terbaik bagaimana mendefinisikan enum adalah melalui anotasi jenis menggunakan 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 alternatif untuk literal untuk membuat anotasi "enum" seperti argumen, Anda dapat menggunakan "naskah" ini seperti format: ["value_a" | "value_b"] ... jika akan diuraikan. Teks ini juga akan menjadi bagian dari deskripsi ... jika Anda tidak menginginkannya, Anda dapat menggunakan notasi ini sebagai notasi jenis. Contoh:
Args:
message_type (["email" | "sms"]): type of a message / channel how to send the message
Kemudian Anda meneruskan fungsi -fungsi ini sebagai argumen ke dan @llm_prompt (argumen harus dinamai functions
Inilah cara menggunakannya:
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 )Selain itu, Anda juga dapat menambahkan argumen
function_callke prompt LLM Anda untuk mengontrol perilaku GPT.
- Jika Anda menetapkan nilainya menjadi "tidak ada" - itu akan menonaktifkan panggilan fungsi untuk saat ini, tetapi masih dapat melihatnya (berguna untuk beberapa penalaran/perencanaan sebelum memanggil fungsi)
- Jika Anda menetapkan nilainya ke "Auto" - GPT akan memilih untuk menggunakan atau menggunakan fungsi
- Jika Anda menetapkan nilainya ke nama fungsi / atau fungsi itu sendiri (dekorator akan menangani menyelesaikan nama yang sama seperti yang digunakan dalam skema) itu akan memaksa GPT untuk menggunakan fungsi itu
Jika Anda menggunakan argumen fungsi, output akan selalu 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
"""
... Jika Anda ingin melihat bagaimana skema telah dibangun, Anda dapat menggunakan metode get_function_schema yang ditambahkan ke fungsi oleh dekorator:
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 ) Untuk menambahkan hasil ke memori / agen_scratchpad, Anda dapat menggunakan to_function_message untuk menghasilkan FunctionMessage yang akan ditafsirkan LLM sebagai hasil alat / fungsi
Penyedia fungsi memungkinkan Anda untuk menyediakan set fungsi LLM secara lebih dinamis, misalnya daftar fungsi - berdasarkan input. Ini juga memungkinkan Anda untuk memberikan nama unik untuk setiap fungsi untuk menjalankan LLM ini. Ini mungkin berguna karena dua alasan:
Skema fungsi (dan terutama deskripsi mereka) adalah alat penting untuk memandu LLM. Jika Anda mengaktifkan Deklarasi Fungsi Dinamis, Anda dapat menggunakan atribut prompt yang sama untuk prompt utama juga dalam skema 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 , ...])Ini hanya untuk ilustrasi, contoh yang dapat dieksekusi sepenuhnya tersedia di sini, dalam contoh kode
Jika kita ingin memanfaatkan streaming:
Dengan cara ini kita hanya menandai prompt mana yang harus dialirkan, tidak perlu mengotak -atik apa yang harus kita gunakan, melewati penangan streaming membuat dan mendistribusikan ke bagian tertentu dari rantai kita ... cukup nyalakan streaming/off pada tipe prompt/prompt tipe ...
Streaming akan terjadi hanya jika kita menyebutnya dalam konteks streaming ... di sana kita dapat mendefinisikan fungsi sederhana untuk menangani streaming
# 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 )Dalam kehidupan nyata mungkin ada situasi, di mana konteksnya akan tumbuh di atas jendela model dasar yang Anda gunakan (misalnya riwayat obrolan panjang) ... tetapi karena ini mungkin terjadi hanya beberapa kali, akan lebih bagus jika hanya dalam skenario ini model (biasanya lebih mahal) dengan jendela konteks yang lebih besar akan digunakan, dan sebaliknya kita akan menggunakan yang lebih murah.
Sekarang Anda bisa melakukannya dengan 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" ))Kelas ini memungkinkan Anda untuk mendefinisikan urutan LLMS dengan aturan berdasarkan panjang prompt, dan panjang generasi yang diharapkan ... dan hanya setelah ambang batas akan dilewati, model yang lebih mahal akan digunakan secara otomatis.
Anda dapat mendefinisikannya ke GlobalSettings:
langchain_decorators . GlobalSettings . define_settings (
llm_selector = my_llm_selector # pass the selector into global settings
)Catatan: Pada versi v0.0.10 Anda di sana, LLMSelector berada di pengaturan default yang telah ditentukan sebelumnya. Anda dapat menimpanya dengan menyediakan Anda sendiri, atau mengatur LLM default atau streaming default LLM
Atau ke tipe prompt tertentu:
from langchain_decorators import PromptTypes
class MyCustomPromptTypes ( PromptTypes ):
MY_TUBO_PROMPT = PromptTypeSettings ( llm_selector = my_llm_selector )Untuk Dict / Pydantic Anda perlu menentukan instruksi pemformatan ... Ini bisa membosankan, itu sebabnya Anda dapat membiarkan parser output menghasilkan instruksi berdasarkan model (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 )) Di sini kita hanya menandai fungsi sebagai prompt dengan dekorator llm_prompt , mengubahnya secara efektif menjadi llmchain. Bukannya menjalankannya
LLMChain standar membutuhkan lebih banyak parameter init daripada hanya inputs_variables dan prompt ... di sini adalah detail implementasi ini tersembunyi di dekorator. Begini cara kerjanya:
Menggunakan Pengaturan Global :
# 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
)Menggunakan tipe prompt yang telah ditentukan sebelumnya
#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 :
...Tentukan pengaturan langsung di dekorator
from langchain . llms import OpenAI
@ llm_prompt (
llm = OpenAI ( temperature = 0.7 ),
stop_tokens = [ " n Observation" ],
...
)
def creative_writer ( book_title : str ) -> str :
...Untuk melewati semua ini, cukup nyatakan dalam fungsi (atau gunakan kwargs untuk melewati apapun)
(Mereka tidak perlu dinyatakan, tetapi itu adalah praktik yang baik jika Anda akan menggunakannya)
@ 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" ) Ada beberapa opsi bagaimana mengontrol output yang masuk ke konsol. Cara termudah adalah dengan mendefinisikan variabel env: LANGCHAIN_DECORATORS_VERBOSE dan mengaturnya ke "true"
Anda juga dapat mengontrol ini secara terprogram dengan mendefinisikan pengaturan global Anda seperti yang ditunjukkan di sini
Opsi terakhir adalah mengontrolnya per setiap kasus, hanya dengan Turing pada mode verbose pada prompt:
@llm_prompt(verbose=True)
def your_prompt(param1):
...
PromptWatch IO adalah platform untuk melacak dan melacak detail tentang segala sesuatu yang terjadi dalam eksekusi Langchain. Ini memungkinkan penurunan satu baris dalam integrasi, hanya dengan membungkus kode titik masuk Anda
with PromptWatch():
run_your_code()
Pelajari lebih lanjut tentang PromptWatch di sini: www.promptwatch.io
Umpan balik, kontribusi dan PR disambut