الفكرة الأساسية لوكيل سلسلة اللغات هي استخدام LLM كعقل يفكر تلقائيًا، يتخذ قرارات، وينفذ إجراءات مختلفة لإنجاز المهام المستهدفة في النهاية.
نصيحة: من وجهة نظر التطوير، يعني هذا أننا نطور مجموعة متنوعة من الواجهات البرمجية المسبقة ومن ثم نعطي الوكيل مهمة، مما يسمح لـ LLM بتحليل أي واجهة برمجية لاستكمال المهمة.
لفهم المشكلة التي تهدف وكيل سلسلة اللغات لحلها، دعنا نأخذ مثالاً.
على سبيل المثال:
إذا أردنا أن نبحث ما إذا كان "Docker يمكن استخدامه كحل لنشر الإنتاج"، فإننا سنقوم أولاً بالبحث عن "مقدمة لـ Docker" على محرك البحث Baidu، تصفح نتائج البحث، ثم البحث بشكل أعمق عن "مزايا وعيوب نشر Docker" وتصفح النتائج، وهكذا، حتى نصل إلى استنتاج.
يهدف وكيل سلسلة اللغات إلى محاكاة هذه العملية. يمكنني تحزيم سلسلة من الأدوات (على سبيل المثال: بحث Baidu، أدوات استخراج محتوى عناوين URL)، ثم إعطاء الوكيل مهمة مستهدفة "هل يمكن استخدام Docker كحل لنشر الإنتاج؟" ثم سيقوم الوكيل ببناء دعوات لاستدعاء LLM. ومن أجل تحقيق هذه المهمة، الخطوة التالية هي تنفيذ أي عمل (أي الاستدعاء إلى أي أداة). ستقوم الذكاء الاصطناعي بإعادة الأداة المطلوبة المطلوبة للتنفيذ، ثم يمرر النتائج للذكاء الاصطناعي ويطلب الخطوة التالية في تنفيذ أي أداة. وتكرار هذه العملية سيكتمل المهمة المذكورة سابقًا.
نصيحة: منذ إصدار نموذج GPT، هذه قدرة متفجرة، تسمح لـ LLM بالعمل كعقل، والتفكير بنشاط، ومن ثم استدعاء مختلف الواجهات التي قمنا بتطويرها. هذا يعزز قدرات LLM بشكل كبير. حالياً، هذه الميزة تزال في مرحلة التجربة وسوف تستدعي LLM بشكل متكرر، لذا فإنها تستهلك عددًا كبيرًا من الرموز. يمكن أن يكلف إكمال مهمة عشرات الآلاف من الرموز في دقائق. إذا كنت ترغب في توفير المال، فمن الموصى به أولاً السماح لـ LLM بأداء المهام المنطقية البسيطة.
المفاهيم الأساسية
دعونا الآن نقدم المكونات والمفاهيم المتعلقة.
الوكيل
يمكن فهم الوكيل على أنه مساعدنا، يتصرف نيابة عنا في اتخاذ القرارات. في التنفيذ الأساسي لوكيل سلسلة اللغات، يتم ذلك من خلال LLM الذي يحدد الإجراء القادم (أو الاستدعاء البرمجي). يصف وضع الرد عملية اتخاذ القرار للذكاء الاصطناعي. يمكن لأولئك الذين يهتمون الاستكشاف الأعمق لهذا الموضوع.
توفر سلسلة اللغات عدة أنواع من الوكيل لسيناريوهات مختلفة.
الأدوات
أعتقد أن الأدوات يُفهم عنها بشكل أفضل كواجهات برمجية، معبأة مسبقاً بمجموعة من الواجهات البرمجية التي تهدف إلى توسيع قدرات LLM. يحدد LLM أي واجهة برمجية محددة يجب استدعاؤها لاستكمال مهمة.
مجموعات الأدوات
تُوفر مجموعات الأدوات عادة لـ LLM ليستفيد ليستفيد ليس فقط من أداة أو اثنتين، وإنما من مجموعة من الأدوات ليمنح LLM المزيد من الخيارات عند استكمال المهام.
مُقْتَنِصُ الوكيل
تكون المكسية مسؤولة عن تنفيذ الأداة (الواجهة البرمجية) التي اختارها LLM. يكون الشيفرة الزائفة لهذا المُحْرّك هكذا:
next_action = agent.get_action(...)
while next_action != AgentFinish:
observation = run(next_action)
next_action = agent.get_action(..., next_action, observation)
return next_action
على الرغم من أن عملية التنفيذ ليست معقدة، إلا أن المقتنص يتعامل مع العديد من المشاكل التفصيلية، وتشمل بشكل رئيسي:
- التعامل مع الحالة التي يختار فيها الوكيل أداة غير موجودة
- التعامل مع حالات الأخطاء في الأداة
- التعامل مع الحالات التي ينتج فيها الوكيل إخراجا لا يمكن حله كاستدعاء لأداة
- قضايا الإصلاح.
البدء السريع
يقدم هذا القسم استخدام LangChain's Agent الأساسي.
1. تحميل LLM
أولاً، دعنا نحمل نموذج اللغة (LLM) الذي سنستخدمه للتحكم في الوكيل.
from langchain_openai import ChatOpenAI
llm = ChatOpenAI(model="gpt-3.5-turbo", temperature=0)
2. تحديد الأدوات
بعد ذلك، نحدد بعض الأدوات التي سيستدعيها الوكيل. سنكتب دالة بسيطة جدًا بلغة Python لحساب طول الكلمة المدخلة.
from langchain.agents import tool
@tool
def get_word_length(word: str) -> int:
"""يُرجع طول الكلمة."""
return len(word)
get_word_length.invoke("abc")
ملاحظة: يعتبر تعليق الدالة مهمًا جدًا. يخبرون LLM ماهية المشكلة التي يمكنها حلها عن طريق استدعائها. يقول تعليق الدالة
get_word_length
لـ LLM أنه يمكنه حساب طول كلمة.
3
تحديد مجموعة من الأدوات
tools = [get_word_length]
3. إنشاء موجه
الآن دعنا ننشئ موجه. لأن استدعاء وظيفة OpenAI تم تحسينه للاستخدام في الأدوات، فإننا بالكاد نحتاج إلى أي تعليمات حول التفكير أو تنسيق الإخراج. لدينا فقط متغيران مدخليان: input
و agent_scratchpad
. input
يمثل سؤال المستخدم الدخل، و agent_scratchpad
هو عنصر نائل لتعليمات استدعاء الوكيل، الذي سيتم إدراجه في قالب الموجه عند تشغيل أمر استدعاء الأداة.
from langchain_core.prompts import ChatPromptTemplate,MessagesPlaceholder
prompt = ChatPromptTemplate.from_messages(
[
(
"system",
"أنت مساعد قوي لكن لا تفهم الوضع الحالي.",
),
("user", "{input}"),
MessagesPlaceholder(variable_name="agent_scratchpad"),
]
)
4. ربط الأدوات بـ LLM
كيف يعرف الوكيل أي الأدوات التي يمكنه استخدامها؟
هذا يعتمد على ميزة استدعاء الأداة في OpenAI (تدعم العديد من النماذج ميزات مماثلة). نحتاج فقط إلى أن نخبر النموذج بتنسيق الاستدعاء المحدد للأداة.
llm_with_tools = llm.bind_tools(tools)
5. إنشاء وكيل
الآن بعد أن دمجنا المحتوى السابق، يمكننا المضي قدمًا في إنشاء البرنامج الوكيل. سوف نقوم بدخول الدالتين الأخيرتين للأدوات العملية: واحدة لتهيئة الخطوات الوسيطة (إجراءات الوكيل، مخرجات الأدوات) إلى رسائل دخل يمكن إرسالها إلى النموذج، وآخر لتحويل رسائل الخرج إلى إجراءات وكيل نائل/نهاية وكيل نائل.
from langchain.agents.format_scratchpad.openai_tools import format_to_openai_tool_messages
from langchain.agents.output_parsers.openai_tools import OpenAIToolsAgentOutputParser
agent = (
{
"input": lambda x: x["input"],
"agent_scratchpad": lambda x: format_to_openai_tool_messages(x["intermediate_steps"]),
}
| prompt
| llm_with_tools
| OpenAIToolsAgentOutputParser()
)
تحديد مشغل الوكيل
from langchain.agents import AgentExecutor
agent_executor = AgentExecutor(agent=agent, tools=tools, verbose=True)
دعونا نوضح عمل برنامج الوكيل من خلال مثال:
list(agent_executor.stream({"input": "كم عدد الحروف في كلمة 'أدوات'؟"}))
مثال على سجل خرج الوكيل
> تدخل سلسلة تنفيذ جديدة للوكيل...
استدعاء: يتم تشغيل `get_word_length` بالمعامل `{'word': 'educa'}`
هناك 5 حروف في كلمة "educa".
> استكمال سلسلة التنفيذ.
من خلال هذا المثال، قمنا بتوضيح العملية الكاملة لبرنامج الوكيل.
إضافة وظيفة الذاكرة إلى الوكيل
إذا أردنا أن يتذكر الوكيل المحادثات السابقة، فإن ذلك بسيط في الواقع: نحتاج فقط إلى إدراج المحتوى الذي يعود به الذكاء الاصطناعي إلى الموجه وتقديمه إلى الذكاء الاصطناعي معًا.
تعديل قالب الموجه
أدناه نقوم بتعديل قالب الموجه لتضمين قالب لتاريخ المحادثة.
from langchain.prompts import MessagesPlaceholder
MEMORY_KEY = "chat_history"
prompt = ChatPromptTemplate.from_messages(
[
(
"system",
"أنت مساعد رائع، ولكن لا تجيد حساب طول الكلمات.",
),
MessagesPlaceholder(variable_name=MEMORY_KEY),
("user", "{input}"),
MessagesPlaceholder(variable_name="agent_scratchpad"),
]
)
تعديل تعريف عملية الوكيل
قم بتعديل تعريف عملية الوكيل لتوفير بيانات تاريخ المحادثة لقالب الموجه، كما هو موضح في الكود التالي، بإضافة معالج لمعلمة chat_history
.
agent = (
{
"input": lambda x: x["input"],
"agent_scratchpad": lambda x: format_to_openai_tool_messages(
x["intermediate_steps"]
),
"chat_history": lambda x: x["chat_history"],
}
| prompt
| llm_with_tools
| OpenAIToolsAgentOutputParser()
)
agent_executor = AgentExecutor(agent=agent, tools=tools, verbose=True)
توفير بيانات سجل المحادثات عند استدعاء الوكيل
chat_history = []
input1 = "كم عدد الحروف في كلمة 'educa'؟"
result = agent_executor.invoke({"input": input1, "chat_history": chat_history})
chat_history.extend(
[
HumanMessage(content=input1),
AIMessage(content=result["output"]),
]
)
agent_executor.invoke({"input": "هل هذه الكلمة موجودة حقًا؟", "chat_history": chat_history})
في سيناريوهات العمل الفعلية، يمكنك حفظ سجل المحادثات في قاعدة بيانات وإدراج البيانات في النص البرمجي حسب الحاجة استنادًا إلى متطلبات العمل.
نصيحة: يتم تحقيق وظيفة الذاكرة للنماذج الكبيرة (LLM) حاليًا في الغالب عن طريق إدراج محتوى المحادثات التاريخية في النص البرمجي وتقديمه إلى LLM. توفر LangChain ببساطة بعض التغليف. يمكنك اختيار عدم استخدامه ودمج سجل المحادثات يدويًا في قالب النص البرمجي.