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
كل ما عليك فعله هو التعليق على وظيفتك باستخدام DecoratorLM_Function.
سيؤدي ذلك إلى تحليل وصف LLM (تعتبر الفقرة الأولى المتماسكة وصف الوظيفة)
وأوصاف معلمة ASO (Google و Numpy و Spihnx تدوينات مدعومة الآن)
بشكل افتراضي ، يتم حل تنسيق DocString تلقائيًا ، ولكن يمكن أن يؤدي تعيين تنسيق Docstring إلى تسريع الأمور قليلاً. - auto (افتراضي): يتم استنتاج التنسيق تلقائيًا من docstring - google : يتم تحليل docstring على أنه تخفيض (انظر تنسيق google docstring) - numpy : يتم تحليل docstring على أنه تخفيض (انظر شكل docstring sphinx )
أفضل طريقة لتحديد التعداد هي من خلال التعليق التوضيحي النوع باستخدام 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
""" التعداد البديل للحرفي لتوضيح "التعداد" مثل الوسيطة ، يمكنك استخدام هذا "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.
- إذا قمت بتعيين القيمة على "لا شيء" - فستقوم بتعطيل دعوة الوظيفة للحظة ، ولكن لا يزال بإمكانها رؤيتها (مفيدة لبعض الأسباب/التخطيط قبل الاتصال بالوظيفة)
- إذا قمت بتعيين القيمة على "Auto" - فسيختار 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 لإنشاء وظيفة تفسرها LLM كنتيجة للأداة / وظيفة
يمكّنك مزود الوظائف من توفير مجموعة من وظائف LLM بشكل أكثر ديناميكية ، على سبيل المثال قائمة الوظائف - بناءً على الإدخال. كما أنه يتيح لك إعطاء اسم فريد لكل وظيفة لتشغيل LLM هذا. قد يكون هذا مفيدًا لسببين:
تعتبر مخططات الوظائف (وخاصة أوصافها) أدوات مهمة لتوجيه 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 الافتراضي أو Dreaming 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 )) نحن هنا فقط نضع علامة على وظيفة كمطالبة مع Decorator llm_prompt ، ونحولها بشكل فعال إلى llmchain. بدلا من تشغيله
يأخذ LLMCHAIN القياسي معلمة init أكثر بكثير من مجرد 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 وتعيينه على "صحيح"
يمكنك أيضًا التحكم في هذا البرمجي من خلال تحديد إعداداتك العالمية كما هو موضح هنا
الخيار الأخير هو التحكم فيه في كل حالة ، وذلك ببساطة عن طريق تورينج على وضع المطالبة على المطالبة:
@llm_prompt(verbose=True)
def your_prompt(param1):
...
PromplWatch IO هو منصة لتتبع وتتبع التفاصيل حول كل ما يجري في عمليات الإعدام Langchain. يسمح بانخفاض سطر واحد في التكامل ، فقط عن طريق لف رمز نقطة الدخول في
with PromptWatch():
run_your_code()
تعرف على المزيد حول برنامج korderwatch هنا: www.promptwatch.io
يتم الترحيب بالتعليقات والمساهمات والعلاقات العامة