オラマのマルチユーザーエージェントスウォーム

昔、グラフィカルユーザーインターフェイスはコマンドライン入力を置き換えました。疑似グラフィカルインターフェイスは、準備ができていないユーザーの相互作用の問題を解決できるように思われるかもしれませんが、誰もが気付かない要因があります。

重要!グラフィカルユーザーインターフェイスの開発は、擬似グラフィカルよりも安価です。歴史的に、次のキューブリリースの直後に、OBJCはグラフィカルフォームエディターで導入され、ページをマウスで配置できました。現代の世界では、FrontEndはDEVツールを介したグラフィカルフォームのデバッグを提供します。これは本質的に同じものです。技術的な詳細のない名目コードと、問題が発生すると、バグが安くなるGUIがあります。

しかし、ユーザーインターフェイスをまったく作成しないことはさらに安いです。静的IP、PCI DSS、YandexとGoogleで宣伝されているドメイン、またはホイールを再発明せず、開発するよりも訪問者を引き付けるために3倍の費用がかかる別のWeb製品を作成することにした場合、ハイロードは必要ありません。

電話は「電話」という言葉から来ています - 音声 - 音。 Figma、Blender、Photoshop、Unrealエンジンの膨大な数のボタンの組み合わせを学習する代わりに、コマンドを表明するだけが簡単です。 Archicadの図面をどのように回転させますか?
エージェントスウォームは、AndroidのフラグメントやReactのルーターのようなものです。以前のユーザー入力に基づいて、タスク(画面上のボタン)の範囲を指定できます。たとえば、SIP電話で電話がかかる場合、まず、その人が原則としてアイテムを購入または返却したいかどうかを理解し、利用可能な製品のリストを提供する必要があります。
税務署は常に表形式のデビット/クレジットを要求するため、CRMシステムはどこにも行きません。 LLMのタスクは、チャットまたは音声認識のいずれかから自然なテキストを解析し、名前と引数を持つ関数署名に変換して、それを呼び出し、データをデータベースに書き込むことができるようにすることです。
この問題を解決するには、いくつかのニュアンスを知ることが重要です。
オープンチャットセッションごとに、群れのオーケストレーションを実行する必要があります。エージェントのツリーは、それらの間で共有チャットの履歴があり、異なるユーザーのために別々のチャット履歴があります。このコードでは、Agent-Swarm-Kitのボンネットの下に実装されています。
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 ( ) ;
} ,
}
} ) ) ;エージェントを作成するとき、それが何をすべきかを説明する少なくとも1つのシステムメッセージを指定します。コネクタを言語モデルに指定します。これにより、一部のエージェントを無料でローカルで処理できるようになり、複雑なものをOpenAIクラウドサービスに委任します。何かが機能しない場合は、システムアレイにプロンプトを追加します。たとえば、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を使用してユーザーリクエストを処理します。用語に慣れていない人のために:言語モデルがユーザーとのチャット履歴を入力と出力するプロセスと新しいメッセージは完了と呼ばれます。 Agent-Swarm-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" ] ,
} ;
} ,
} ) ;アクティブなエージェントを変更し、データベースからデータを取得することは、ツールコールを介して行われます。言語モデルは、ローカルモデルのフレームワークまたはOpenAIのクラウドプロバイダーによって処理される特別なXMLを返し、Python/JSの外部コードを呼び出すために、実行結果はチャット履歴に{"role": "tool", "content": "Product Paracetamol found in database: fever reducer for fighting flu"}されました。次のユーザーメッセージから、言語モデルはツールのデータで動作します。
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は、ClientID URLパラメーターを使用して、各WebSocketチャンネルのActive ChatGPTセッション(エージェント)にメッセージを向けます。人との新しいチャットごとに、新しいチャンネルが独自のエージェントの群れで作成されます。
ツールを実行することで、群れのアクティブなChatGPTセッション(エージェント)を変更できます。
すべてのクライアントセッションは、すべてのエージェントに共有チャットメッセージ履歴を使用します。各クライアントのチャット履歴は、最後の25のメッセージを回転で保存します。 ChatGPTセッション(エージェント)の間では、アシスタントとユーザータイプのメッセージのみが送信されますが、システムとツールメッセージはエージェントの範囲に限定されているため、各エージェントはそれに関連するツールのみを知っています。その結果、各chatGPTセッション(エージェント)には、独自のシステムプロンプトがあります。
エージェントの出力が検証に失敗し(存在しないツールコール、誤った引数を備えたツールコール、空の出力、出力のXMLタグ、または出力のJSON)、救助アルゴリズムはモデルを修正しようとします。まず、モデルから以前のメッセージを非表示にします。それが役に立たない場合、「ごめんなさい、私は理解していませんでした。繰り返しますか?」のようなプレースホルダーを返します。
addAgent新しいエージェントを登録しますaddCompletion新しい言語モデルを登録:クラウド、ローカル、またはモックaddSwarmユーザーチャットを処理するためにエージェントのグループを登録するaddTool言語モデルを外部システムに統合するためのツールを登録するchangeAgent群れのアクティブエージェントを変更しますcomplete - エージェントの群れに渡されたメッセージへの応答をリクエストsession - チャットセッションを作成し、セッションの完了と新しいメッセージの送信のためのコールバックを提供しますgetRawHistoryデバッグのための生システム履歴を取得しますgetAgentHistory自己回復メカニズムとメッセージ受信者のために調整されたエージェントに履歴を表示するcommitToolOutput関数の実行結果を履歴に送信します。関数が呼び出された場合、応答を受信するまでエージェントがフリーズしますcommitSystemMessage新しい入力を備えたサプリメントシステムプロンプトcommitFlush誤った応答が受信された場合、またはモデルがツールを再帰的に誤って呼び出す場合、エージェントの明確な会話execute - ニューラルネットワークにイニシアチブを取り、最初にユーザーに書き込むように依頼しますemit事前に準備されたメッセージをユーザーに送信しますgetLastUserMessageユーザーから最後のメッセージを取得します(実行を検討せずに)commitUserMessage応答せずにチャット履歴にユーザーメッセージを保存します。ユーザーがリクエスト処理を待たずにメッセージをスパムする場合getAgentNameアクティブなエージェント名を取得しますgetUserHistoryユーザーメッセージの履歴を取得しますgetAssistantHistory言語モデルメッセージの履歴を取得しますgetLastAssistantMessage言語モデルから最後のメッセージを取得しますgetLastSystemMessage最終システムプロンプトサプリメントを取得します