多用户代理人群

很久以前,图形用户界面替换了命令行输入。伪图接口似乎可以解决未准备好的用户的交互问题,但是并非每个人都注意到一个因素。

重要的!开发图形用户界面比伪图纸便宜。从历史上看,在下一个立方体发行版之后,将OBJC引入了图形形式的编辑器,可以在其中用鼠标安排页面。在现代世界中,Frontend提供了通过开发工具进行调试的图形表单,这本质上是相同的:没有技术细节的名义代码,并且当出现问题时,有一个GUI使错误找到便宜。

但是,完全不制作用户界面甚至更便宜。您不需要静态IP,PCI DSS,在Yandex和Google中推广的域,或者如果您决定不重新发明轮子并创建另一个Web产品,它将花费三倍以吸引访客而不是开发。

电话来自“电话”语音 - 声音。与其学习有关无花果,搅拌器,Photoshop,虚幻引擎的大量按钮组合,而是简单地表达命令。您如何在Archicad旋转图纸?
代理群就像Android或React中的路由器中的片段一样:它们允许您根据先前的用户输入指定任务范围(屏幕上的按钮)。例如,当在SIP手机上打来电话时,您首先需要了解该人是否要原则上购买或返回商品,然后为他们提供可用产品的列表。
税务局将始终以表格形式要求借方/信用,因此CRM系统将不会到任何地方。 LLM的任务是从聊天或语音识别中解析自然文本,并将其转换为带有名称和参数的函数签名,以便可以将其调用并可以将数据写入数据库。
要解决这个问题,重要的是要了解几个细微差别:
对于每个开放的聊天会话,需要使用具有共享聊天历史记录的代理和不同用户分开的聊天历史记录的代理树进行群。在此代码中,它是在Agent-Warm-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 ( ) ;
} ,
}
} ) ) ;创建代理时,我们至少指定了一个系统消息,描述了它应该做什么。我们将连接器指定到语言模型,该连接器将允许某些代理免费在本地处理,同时将复杂的代理委派给OpenAI Cloud Service。如果某件事不起作用,我们将提示提示为系统阵列,例如,函数调用for for 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-warm-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,或者由OpenAI供OpenAI调用Python/js中的外部代码等。执行结果在聊天历史记录中记录为chat历史记录为{"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进行业务对话。
代理人使用客户端IRL参数将消息引导到每个WebSocket频道的活动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获取最后一个系统提示补充