سرب وكيل متعدد المستخدمين لأولاما

منذ فترة طويلة ، استبدلت واجهة المستخدم الرسومية إدخال سطر الأوامر. قد يبدو أن الواجهة الفريدة الزائفة يمكن أن تحل مشكلة التفاعل للمستخدمين غير المستعدين ، ولكن هناك عامل لا يلاحظه الجميع.

مهم! يعد تطوير واجهة مستخدم رسومية أرخص من الواجهة الفجوة الزائفة. تاريخياً ، مباشرة بعد إصدار المكعب التالي ، تم تقديم OBJC مع محرر النماذج الرسومية حيث يمكن ترتيب الصفحات باستخدام الماوس. في العالم الحديث ، توفر الواجهة الأمامية تصحيح الأخطاء الرسومية من خلال أدوات DEV ، وهو نفس الشيء: الكود الاسمي بدون تفاصيل فنية ، وعندما تنشأ المشكلات ، هناك واجهة مستخدم يجعل العثور على الأخطاء أرخص.

لكن الأمر أرخص حتى عدم إنشاء واجهة مستخدم على الإطلاق. لا تحتاج إلى عنوان IP ثابت أو PCI DSS أو مجال تم ترقيته في Yandex و Google ، أو الحمولة العالية إذا قررت عدم إعادة اختراع العجلة وإنشاء منتج ويب آخر يكلف ثلاثة أضعاف جذب الزائرين بدلاً من تطويره.

يأتي الهاتف من كلمة "الهاتف" ، الصوت الصوتي - الصوت. بدلاً من تعلم عدد كبير من مجموعات الأزرار لل Figma و Blender و Photoshop و Unreal Engine ، من الأسهل التعبير عن الأمر. كيف تدور الرسم في أرشيكاد؟
يشبه Agent Swarm شظايا في Android أو جهاز التوجيه في React: فهي تسمح لك بتحديد نطاق المهام (الأزرار على الشاشة) بناءً على إدخال المستخدم السابق. على سبيل المثال ، عندما تأتي مكالمة على هاتف SIP ، تحتاج أولاً إلى فهم ما إذا كان الشخص يريد شراء عنصر أو إرجاعه من حيث المبدأ ، ثم تقدم لهم قائمة بالمنتجات المتاحة.
سيطلب مكتب الضرائب دائمًا الحصول على الخصم/الائتمان في شكل جدولي ، لذلك لن تذهب أنظمة CRM إلى أي مكان. تتمثل مهمة LLM في تحليل النص الطبيعي من الدردشة أو التعرف على الصوت وتحويله إلى توقيع دالة مع الاسم والوسائط بحيث يمكن استدعاؤه ويمكن كتابة البيانات إلى قاعدة البيانات.
لحل هذه المشكلة ، من المهم معرفة العديد من الفروق الدقيقة:
بالنسبة لكل جلسة دردشة مفتوحة ، يجب تنفيذ سرب سرب مع شجرة من الوكلاء الذين لديهم سجل دردشة مشتركة بينهم وبين منفصلة لمستخدمي مختلفين. في هذا الرمز ، يتم تنفيذه تحت غطاء محرك السيارة من قبل الوكيل.
import { addSwarm } from "agent-swarm-kit" ;
export const ROOT_SWARM = addSwarm ( {
swarmName : 'root_swarm' ,
agentList : [
TRIAGE_AGENT ,
SALES_AGENT ,
] ,
defaultAgent : TRIAGE_AGENT ,
} ) ;
...
app . get ( "/api/v1/session/:clientId" , upgradeWebSocket ( ( ctx ) => {
const clientId = ctx . req . param ( "clientId" ) ;
const { complete , dispose } = session ( clientId , ROOT_SWARM )
return {
onMessage : async ( event , ws ) => {
const message = event . data . toString ( ) ;
ws . send ( await complete ( message ) ) ;
} ,
onClose : async ( ) => {
await dispose ( ) ;
} ,
}
} ) ) ;عند إنشاء وكيل ، نحدد رسالة نظام واحدة على الأقل تصف ما يجب القيام به. نحدد الموصل إلى نموذج اللغة ، والذي سيتيح لمعالجة بعض الوكلاء محليًا مجانًا ، مع تفويض تلك المعقدة إلى خدمة Openai Cloud. إذا لم ينجح شيء ما ، فإننا نضيف مطالبات إلى صفيف النظام ، على سبيل المثال ، إصلاحات استدعاء الوظائف لـ Ollama.
const AGENT_PROMPT = `You are a sales agent that handles all actions related to placing the order to purchase an item.
Tell the users all details about products in the database by using necessary tool calls
Do not send any JSON to the user. Format it as plain text. Do not share any internal details like ids, format text human readable
If the previous user messages contains product request, tell him details immidiately
It is important not to call tools recursive. Execute the search once
` ;
/**
* @see https://github.com/ollama/ollama/blob/86a622cbdc69e9fd501764ff7565e977fc98f00a/server/model.go#L158
*/
const TOOL_PROTOCOL_PROMPT = `For each function call, return a json object with function name and arguments within <tool_call></tool_call> XML tags:
<tool_call>
{"name": <function-name>, "arguments": <args-json-object>}
</tool_call>
` ;
export const SALES_AGENT = addAgent ( {
agentName : "sales_agent" ,
completion : OLLAMA_COMPLETION ,
system : [ TOOL_PROTOCOL_PROMPT ] ,
prompt : AGENT_PROMPT ,
tools : [ SEARCH_PHARMA_PRODUCT , NAVIGATE_TO_TRIAGE ] ,
} ) ;في هذا المثال ، أستخدم Ollama لمعالجة طلبات المستخدم. بالنسبة لأولئك الذين ليسوا على دراية بالمصطلحات: العملية التي يتلقى فيها نموذج اللغة سجل الدردشة مع مستخدم كمدخلات وإخراج رسالة جديدة تسمى الإكمال. يستخدم وكيل SWARR-KIT واجهة مجردة تعمل بشكل مشابه مع أي مزود سحابة أو نموذج محلي. استخدم هذه المقالة لربط Deepseek.
import { addCompletion , IModelMessage } from "agent-swarm-kit" ;
const getOllama = singleshot ( ( ) => new Ollama ( { host : CC_OLLAMA_HOST } ) ) ;
export const OLLAMA_COMPLETION = addCompletion ( {
completionName : "ollama_completion" ,
getCompletion : async ( {
agentName ,
messages ,
mode ,
tools ,
} ) => {
const response = await getOllama ( ) . chat ( {
model : "nemotron-mini:4b" , // "mistral-nemo:12b";
keep_alive : "1h" ,
messages : messages . map ( ( message ) => omit ( message , "agentName" , "mode" ) ) ,
tools ,
} ) ;
return {
... response . message ,
mode ,
agentName ,
role : response . message . role as IModelMessage [ "role" ] ,
} ;
} ,
} ) ; يتم تغيير الوكيل النشط والحصول على البيانات من قاعدة البيانات من خلال مكالمات الأدوات: يقوم نموذج اللغة بإرجاع XML الخاص الذي تتم معالجته بواسطة إطار عمل النماذج المحلية أو بواسطة مزود {"role": "tool", "content": "Product Paracetamol found in database: fever reducer for fighting flu"} لـ Openai للاتصال بالرمز الخارجي في Python/JS ، إلخ. من رسالة المستخدم التالية ، يعمل نموذج اللغة مع البيانات من الأداة.
import { addTool , changeAgent , execute } from "agent-swarm-kit" ;
const PARAMETER_SCHEMA = z . object ( { } ) . strict ( ) ;
export const NAVIGATE_TO_SALES = addTool ( {
toolName : "navigate_to_sales_tool" ,
validate : async ( clientId , agentName , params ) => {
const { success } = await PARAMETER_SCHEMA . spa ( params ) ;
return success ;
} ,
call : async ( clientId , agentName ) => {
await commitToolOutput (
"Navigation success`,
clientId ,
agentName
) ;
await changeAgent ( SALES_AGENT , clientId ) ;
await execute ( "Say hello to the user" , clientId , SALES_AGENT ) ;
} ,
type : "function" ,
function : {
name : "navigate_to_sales_tool" ,
description : "Navigate to sales agent" ,
parameters : {
type : "object" ,
properties : { } ,
required : [ ] ,
} ,
} ,
} ) ;لتجنب ترميز رسائل الوكيل الأولية ، عند تبديل الوكلاء ، تحدث محاكاة طلب المستخدم طلبًا لقول مرحبًا.
import {
addTool ,
commitSystemMessage ,
commitToolOutput ,
execute ,
getLastUserMessage ,
} from "agent-swarm-kit" ;
const PARAMETER_SCHEMA = z
. object ( {
description : z
. string ( )
. min ( 1 , "Fulltext is required" )
} )
. strict ( ) ;
export const SEARCH_PHARMA_PRODUCT = addTool ( {
toolName : "search_pharma_product" ,
validate : async ( clientId , agentName , params ) => {
const { success } = await PARAMETER_SCHEMA . spa ( params ) ;
return success ;
} ,
call : async ( clientId , agentName , params ) => {
let search = "" ;
if ( params . description ) {
search = String ( params . description ) ;
} else {
search = await getLastUserMessage ( clientId ) ;
}
if ( ! search ) {
await commitToolOutput (
str . newline ( `The products does not found in the database` ) ,
clientId ,
agentName
) ;
await execute (
"Tell user to specify search criteria for the pharma product" ,
clientId ,
agentName
) ;
return ;
}
const products = await ioc . productDbPublicService . findByFulltext (
search ,
clientId
) ;
if ( products . length ) {
await commitToolOutput (
str . newline (
`The next pharma product found in database: ${ products . map (
serializeProduct
) } `
) ,
clientId ,
agentName
) ;
await commitSystemMessage (
"Do not call the search_pharma_product next time!" ,
clientId ,
agentName
) ;
await execute (
"Tell user the products found in the database." ,
clientId ,
agentName
) ;
return ;
}
await commitToolOutput (
`The products does not found in the database` ,
clientId ,
agentName
) ;
await execute (
"Tell user to specify search criteria for the pharma product" ,
clientId ,
agentName
) ;
} ,
type : "function" ,
function : {
name : "search_pharma_product" ,
description :
"Retrieve several pharma products from the database based on description" ,
parameters : {
type : "object" ,
properties : {
description : {
type : "string" ,
description :
"REQUIRED! Minimum one word. The product description. Must include several sentences with description and keywords to find a product" ,
} ,
} ,
required : [ "description" ] ,
} ,
} ,
} ) ;يمكن أن تشكل نماذج اللغة قاموسًا للمعلمات المسماة لمكالمات الأدوات. ومع ذلك ، فإن نماذج OpenSource تتعامل مع هذا بشكل سيء إذا كان هناك شرط فني لدائرة مغلقة ؛ من الأسهل تحليل المحادثة نفسها.
جلسات chatgpt متعددة (الوكلاء) إجراء مكالمات الأدوات. يمكن لكل وكيل استخدام نماذج مختلفة ، على سبيل المثال ، Mistral 7B للاتصال اليومي ، Nemoton للمحادثات التجارية.
يقوم Swarm Agent بتوجيه الرسائل إلى جلسة ChatGPT النشطة (Agent) لكل قناة WebSocket باستخدام معلمة URL ClientID. لكل محادثة جديدة مع شخص ما ، يتم إنشاء قناة جديدة مع سربها من الوكلاء.
يمكن تغيير جلسة chatgpt النشطة (الوكيل) في Swarm عن طريق تنفيذ أداة.
تستخدم جميع جلسات العميل سجل رسالة دردشة مشتركة لجميع الوكلاء. يخزن سجل دردشة كل عميل آخر 25 رسالة مع التناوب. بين جلسات chatgpt (الوكلاء) ، يتم إرسال رسائل نوع المساعد ونوع المستخدم فقط ، بينما تقتصر رسائل النظام والأدوات على نطاق الوكيل ، بحيث يعرف كل وكيل فقط الأدوات التي تتعلق بها. نتيجة لذلك ، كل جلسة chatgpt (الوكيل) لديها موجه نظام فريد من نوعه.
إذا فشل إخراج الوكيل في التحقق من الصحة (استدعاء الأداة غير الموجود ، أو استدعاء الأداة مع وسيطات غير صحيحة ، أو إخراج فارغ ، أو علامات XML في الإخراج ، أو JSON في الإخراج) ، ستحاول خوارزمية الإنقاذ إصلاح النموذج. أولاً ، سوف يخفي الرسائل السابقة من النموذج ؛ إذا لم يساعد ذلك ، فسوف يعيد عنصرًا نقيًا مثل "آسف ، لم أفهم. هل يمكن أن تكرر من فضلك؟"
addAgent - سجل وكيلًا جديدًاaddCompletion - سجل نموذج لغة جديد: السحابة أو المحلية أو الوهميةaddSwarm - سجل مجموعة من الوكلاء لمعالجة دردشات المستخدمaddTool - قم بتسجيل أداة لدمج نماذج اللغة في أنظمة خارجيةchangeAgent - تغيير العامل النشط في Swarmcomplete - اطلب استجابة لرسالة تم تمريرها إلى سرب الوكيلsession - إنشاء جلسة دردشة ، وقدم عمليات الاسترجاعات لإنجاز الجلسة وإرسال رسالة جديدةgetRawHistory - احصل على تاريخ النظام الخام لتصحيح الأخطاءgetAgentHistory - احصل على تاريخ مرئي للعامل المعدل لآلية استرداد الذات ومستفيدي الرسائلcommitToolOutput - إرسال نتيجة تنفيذ الوظيفة إلى التاريخ. إذا تم استدعاء وظيفة ، يتجمد العامل حتى يتلقى ردcommitSystemMessage - موجه نظام الملحق مع مدخلات جديدةcommitFlush - محادثة واضحة للوكيل إذا تم استلام ردود غير صحيحة أو أن النموذج يتصل خطأً بالأداة بشكل خاطئexecute - اطلب من الشبكة العصبية أن تأخذ المبادرة والكتابة إلى المستخدم أولاًemit - أرسل رسالة مستعدة مسبقًا إلى المستخدمgetLastUserMessage - احصل على الرسالة الأخيرة من المستخدم (دون النظر في التنفيذ)commitUserMessage - حفظ رسالة المستخدم في سجل الدردشة دون استجابة. إذا قام المستخدم بإرسال رسائل البريد العشوائي دون انتظار معالجة الطلبgetAgentName - احصل على اسم الوكيل النشطgetUserHistory - احصل على تاريخ رسائل المستخدمgetAssistantHistory - احصل على تاريخ رسائل نموذج اللغةgetLastAssistantMessage - احصل على الرسالة الأخيرة من نموذج اللغةgetLastSystemMessage - احصل على ملحق موجه النظام الأخير