ランチチェーンデコレーターは、構文砂糖を提供するラングチェーンの上の層ですか?カスタムラングチェーンのプロンプトとチェーンを書くため
注:これは、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チャットモデルでのみサポートされています
あなたがする必要があるのは、@llm_functionデコレーターであなたの機能を注釈することだけです。
これにより、LLMの説明が解析されます(最初のコヒーレント段落は関数の説明と見なされます)
ASOパラメーターの説明(Google、numpy、spihnxの表記は今のところサポートされています)
デフォルトでは、DocString形式は自動的に解決されますが、DocStringの形式を設定すると、物事を少しスピードアップできます。 auto (デフォルト):フォーマットはDocStringから自動的に推測されますgoogle :DocStringはMarkdown(Google Docstring形式を参照)として解析されます( numpy :numpy:docstringはマークダウンとして解析されます(numpy docstring形式を参照) - sphinx :ドキュストリングはsphinx形式として描かれています(sphinx docstring formatを参照)
列挙を定義する最善の方法は、 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
""" 「列挙」のような「列挙」に注釈を付けるためのリテラルに代わる列。この「型」のような形式: ["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 )さらに、LLMプロンプトに
function_call引数を追加してGPTの動作を制御することもできます。
- 値を「なし」に設定すると、現時点では関数呼び出しが無効になりますが、それでもそれらを見ることができます(関数を呼び出す前に何らかの推論/計画に役立ちます)
- 値を「auto」に設定すると、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
"""
...スキーマがどのように構築されているかを確認したい場合は、decoratorによって関数に追加される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 )結果をMemory / Agent_ScratchPadに追加するために、 to_function_messageを使用して、LLMがツール /関数の結果として解釈する関数を生成できます
関数プロバイダーを使用すると、入力に基づいて関数のリストなど、より動的にLLM関数のセットを提供できます。また、このLLM実行の各関数に一意の名前を付けることができます。これは、2つの理由で役立つかもしれません。
関数スキーマ(および特にその説明)は、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" ))このクラスを使用すると、プロンプトの長さと予想される生成の長さに基づいてルールを使用してLLMSのシーケンスを定義できます...そして、しきい値が渡された後にのみ、より高価なモデルが自動的に使用されます。
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 ))ここでは、 llm_promptデコレーターを使用してプロンプトとして関数をマークし、効果的にLLMChainに変えています。実行する代わりに
Standard LLMChainは、inputs_variablesだけでプロンプトよりもはるかに多くのinitパラメーターを使用します...ここに、装飾器に隠されたこの実装の詳細があります。これがどのように機能するかです:
グローバル設定の使用:
# 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 「true」に設定することです
ここに示すように、グローバルな設定を定義することにより、このプログラムで制御することもできます
最後のオプションは、プロンプトで冗長モードをチューリングするだけで、各ケースごとにそれを制御することです。
@llm_prompt(verbose=True)
def your_prompt(param1):
...
PromptWatch IOは、Langchain実行で行われているすべてのことに関する詳細を追跡および追跡するためのプラットフォームです。エントリポイントコードをラッピングするだけで、統合の1行ドロップを可能にします
with PromptWatch():
run_your_code()
PromptWatchの詳細については、www.promptwatch.ioをご覧ください
フィードバック、貢献、PRを歓迎します