ตัวแทนผู้ใช้หลายคนสำหรับ Ollama

นานมาแล้วอินเทอร์เฟซผู้ใช้กราฟิกแทนที่อินพุตบรรทัดคำสั่ง อาจดูเหมือนว่าอินเทอร์เฟซแบบหลอก-กราฟิกสามารถแก้ปัญหาการโต้ตอบสำหรับผู้ใช้ที่ไม่ได้เตรียมตัว แต่มีปัจจัยที่ไม่ใช่ทุกคนที่สังเกตเห็น

สำคัญ! การพัฒนาส่วนต่อประสานผู้ใช้แบบกราฟิกนั้นถูกกว่าแบบปลอม ในอดีตหลังจากการเปิดตัวคิวบ์ถัดไป OBJC ได้รับการแนะนำด้วยตัวแก้ไขแบบฟอร์มกราฟิกที่สามารถจัดเตรียมหน้าด้วยเมาส์ได้ ในโลกสมัยใหม่ Frontend ให้รูปแบบกราฟิกดีบักผ่านเครื่องมือ Dev ซึ่งเป็นสิ่งเดียวกัน: รหัสเล็กน้อยโดยไม่มีรายละเอียดทางเทคนิคและเมื่อปัญหาเกิดขึ้นมี GUI ที่ทำให้การค้นหาข้อผิดพลาดถูกกว่า

แต่มันก็ถูกกว่าที่จะไม่สร้างส่วนต่อประสานผู้ใช้เลย คุณไม่จำเป็นต้องมี IP แบบคงที่, PCI DSS, โดเมนที่ได้รับการโปรโมตใน Yandex และ Google หรือ Highload หากคุณตัดสินใจที่จะไม่คิดค้นล้อและสร้างผลิตภัณฑ์เว็บอื่นที่มีค่าใช้จ่ายมากกว่าสามเท่าเพื่อดึงดูดผู้เข้าชมมากกว่าที่จะพัฒนา

โทรศัพท์มาจากคำว่า "โทรศัพท์" การออกเสียง - เสียง แทนที่จะเรียนรู้การผสมผสานปุ่มจำนวนมากสำหรับ Figma, Blender, Photoshop, Unreal Engine มันง่ายกว่าที่จะใช้เสียงคำสั่ง คุณหมุนภาพวาดใน Archicad ได้อย่างไร?
Agent Swarm เป็นเหมือนชิ้นส่วนใน Android หรือเราเตอร์ใน React: พวกเขาอนุญาตให้คุณระบุขอบเขตของงาน (ปุ่มบนหน้าจอ) ตามอินพุตของผู้ใช้ก่อนหน้า ตัวอย่างเช่นเมื่อมีการโทรเข้ามาในโทรศัพท์ SIP คุณต้องเข้าใจก่อนว่าบุคคลนั้นต้องการซื้อหรือส่งคืนสินค้าในหลักการแล้วเสนอรายการผลิตภัณฑ์ที่มีอยู่ให้พวกเขา
สำนักงานภาษีจะขอเดบิต/เครดิตในรูปแบบตารางเสมอดังนั้นระบบ CRM จะไม่ไปทุกที่ ภารกิจของ LLM คือการแยกข้อความธรรมชาติจากการแชทหรือการจดจำเสียงและแปลงเป็นลายเซ็นฟังก์ชั่นที่มีชื่อและอาร์กิวเมนต์เพื่อให้สามารถเรียกได้และข้อมูลสามารถเขียนลงในฐานข้อมูล
เพื่อแก้ปัญหานี้เป็นสิ่งสำคัญที่จะต้องทราบความแตกต่างหลายประการ:
สำหรับการแชทแบบเปิดแต่ละครั้งจะต้องดำเนินการ orchestration Swarm กับต้นไม้ของตัวแทนที่มีประวัติการแชทที่ใช้ร่วมกันระหว่างพวกเขาและแยกสำหรับผู้ใช้ที่แตกต่างกัน ในรหัสนี้มันถูกนำไปใช้ภายใต้ประทุนของ 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 ( ) ;
} ,
}
} ) ) ;เมื่อสร้างเอเจนต์เราระบุข้อความระบบอย่างน้อยหนึ่งข้อความที่อธิบายถึงสิ่งที่ควรทำ เราระบุตัวเชื่อมต่อกับโมเดลภาษาซึ่งจะช่วยให้ตัวแทนบางรายได้รับการประมวลผลในเครื่องฟรีในขณะที่มอบหมายที่ซับซ้อนให้กับ OpenAI Cloud Service หากสิ่งที่ไม่ได้ผลเราจะเพิ่มพรอมต์ลงในอาร์เรย์ระบบเช่นการแก้ไขการเรียกใช้ฟังก์ชันสำหรับ 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" ] ,
} ;
} ,
} ) ; การเปลี่ยนเอเจนต์ที่ใช้งานอยู่และรับข้อมูลจากฐานข้อมูลทำได้ผ่านการเรียกใช้เครื่องมือ: โมเดลภาษาส่งคืน XML พิเศษที่ประมวลผลโดยเฟรมเวิร์กสำหรับโมเดลท้องถิ่นหรือโดยผู้ให้บริการคลาวด์สำหรับ {"role": "tool", "content": "Product Paracetamol found in database: fever reducer for fighting flu"} ใน 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 จัดการได้ไม่ดีหากมีข้อกำหนดทางเทคนิคสำหรับวงจรปิด มันง่ายกว่าที่จะวิเคราะห์การสนทนาเอง
Sessions CHATGPT หลายรายการ (ตัวแทน) โทรออกเครื่องมือ ตัวแทนแต่ละคนสามารถใช้โมเดลที่แตกต่างกันได้เช่น Mistral 7B สำหรับการสื่อสารในชีวิตประจำวัน Nemoton สำหรับการสนทนาทางธุรกิจ
Agent Swarm นำข้อความไปยังเซสชัน Active ChatGPT (Agent) สำหรับแต่ละช่องทาง WebSocket โดยใช้พารามิเตอร์ URL ClientID สำหรับการแชทใหม่แต่ละครั้งกับบุคคลช่องใหม่จะถูกสร้างขึ้นด้วยกลุ่มตัวแทนของตัวเอง
เซสชัน Active ChatGPT (Agent) ใน Swarm สามารถเปลี่ยนแปลงได้โดยการดำเนินการเครื่องมือ
เซสชันลูกค้าทั้งหมดใช้ประวัติข้อความแชทที่ใช้ร่วมกันสำหรับตัวแทนทั้งหมด ประวัติการแชทของลูกค้าแต่ละรายเก็บข้อความ 25 ข้อความสุดท้ายด้วยการหมุน ระหว่าง SESSIONS CHATGPT (ตัวแทน) มีเพียงผู้ช่วยและข้อความประเภทผู้ใช้จะถูกส่งในขณะที่ข้อความระบบและเครื่องมือถูก จำกัด ขอบเขตของตัวแทนดังนั้นตัวแทนแต่ละคนจึงรู้เฉพาะเครื่องมือที่เกี่ยวข้องกับมัน เป็นผลให้แต่ละเซสชัน chatgpt (เอเจนต์) มีพรอมต์ระบบที่ไม่ซ้ำกัน
หากเอาต์พุตของเอเจนต์ล้มเหลวการตรวจสอบความถูกต้อง (การเรียกเครื่องมือที่ไม่มีอยู่จริงการเรียกเครื่องมือที่มีอาร์กิวเมนต์ที่ไม่ถูกต้องเอาต์พุตว่างเปล่าแท็ก XML ในเอาต์พุตหรือ JSON ในเอาต์พุต) อัลกอริทึมกู้ภัยจะพยายามแก้ไขโมเดล อันดับแรกมันจะซ่อนข้อความก่อนหน้าจากโมเดล หากไม่ได้ช่วยมันจะส่งคืนตัวยึดเช่น "ขออภัยฉันไม่เข้าใจคุณช่วยทำซ้ำได้ไหม"
addAgent - ลงทะเบียนตัวแทนใหม่addCompletion - ลงทะเบียนโมเดลภาษาใหม่: คลาวด์ท้องถิ่นหรือจำลองaddSwarm - ลงทะเบียนกลุ่มตัวแทนสำหรับการประมวลผลการแชทของผู้ใช้addTool - ลงทะเบียนเครื่องมือสำหรับการรวมโมเดลภาษาเข้ากับระบบภายนอกchangeAgent - เปลี่ยน Active Agent ในฝูงcomplete - ขอตอบกลับข้อความที่ส่งไปยัง Swarm ตัวแทนsession - สร้างเซสชันการแชทจัดเตรียมการโทรกลับเพื่อให้เซสชันเสร็จสิ้นและการส่งข้อความใหม่getRawHistory - รับประวัติระบบดิบสำหรับการดีบักgetAgentHistory - ให้ประวัติปรากฏแก่ตัวแทนที่ปรับสำหรับกลไกการกู้คืนตนเองและผู้รับข้อความcommitToolOutput - ส่งผลการดำเนินการฟังก์ชั่นไปยังประวัติ หากมีการเรียกฟังก์ชั่นตัวแทนจะค้างจนกว่าจะได้รับการตอบกลับcommitSystemMessage - ระบบเสริมพร้อมอินพุตใหม่commitFlush - การสนทนาที่ชัดเจนสำหรับตัวแทนหากได้รับการตอบกลับที่ไม่ถูกต้องหรือโมเดลเรียกใช้เครื่องมือซ้ำ ๆexecute - ขอให้เครือข่ายประสาทใช้ความคิดริเริ่มและเขียนถึงผู้ใช้ก่อนemit - ส่งข้อความที่เตรียมไว้ล่วงหน้าไปยังผู้ใช้getLastUserMessage - รับข้อความสุดท้ายจากผู้ใช้ (โดยไม่ต้องพิจารณาดำเนินการ)commitUserMessage - บันทึกข้อความผู้ใช้ในประวัติการแชทโดยไม่ต้องตอบกลับ หากผู้ใช้สแปมข้อความโดยไม่ต้องรอการดำเนินการตามคำขอgetAgentName - รับชื่อตัวแทนที่ใช้งานอยู่getUserHistory - รับประวัติของข้อความผู้ใช้getAssistantHistory - รับประวัติของข้อความรูปแบบภาษาgetLastAssistantMessage - รับข้อความสุดท้ายจากรูปแบบภาษาgetLastSystemMessage - รับ System Promptement Last System