Experts.js是創建和部署OpenAI助手並將它們鏈接在一起的最簡單方法,以創建具有擴展記憶和關注細節的專家系統的工具。
通過自定義墨水通過支持❤️|技術
OpenAI的新助手API設定了新的行業標準,超出了廣泛採用的聊天完成API的發展。它代表了AI代理的可用性和工程師與LLMS互動的方式的重大飛躍。與尖端的GPT-4O Mini模型相結合,助手現在可以將附件和圖像作為知識源稱為託管上下文窗口中的知識來源。與自定義GPT不同,助手支持最多256,000個字符,與128個工具集成在一起,並利用創新的矢量商店API,每位助手最多10,000個文件進行有效的文件搜索。
Experts.js旨在通過消除管理運行對象的複雜性並允許將助手鍊接在一起作為工具來簡化這種新API的使用。
import { Assistant , Thread } from "experts" ;
const thread = await Thread . create ( ) ;
const assistant = await Assistant . create ( ) ;
const output = await assistant . ask ( "Say hello." , thread . id ) ;
console . log ( output ) // Hello
更重要的是,Experts.js將助手作為工具介紹,從而創建了多AI代理系統。每個工具都是由LLM支持的助手,可以代表其父母助手或工具扮演專業角色或完成複雜的任務。允許複雜的編排工作流或編舞一系列緊密編織的任務。此處顯示的是具有產品目錄工具的公司助手的示例,該工具本身俱有LLM支持的工具來創建OpenSearch查詢。
通過NPM安裝。用法非常簡單,只有三個對象可導入。
npm install experts
Experts.js支持ES6導入語法和CONCORJS需要語句。
import { Assistant , Tool , Thread } from "experts" ;
我們助理立面對象的構造函數需要名稱,描述和說明。第三個參數是一組選項,可直接映射到創建助理文檔中概述的所有請求正文選項。專家中的所有例子。默認模型是gpt-4o-mini
。
class MyAssistant extends Assistant {
constructor ( ) {
super ( {
name : "My Assistant" ,
instructions : "..." ,
model : "gpt-4o-mini" ,
tools : [ { type : "file_search" } ] ,
temperature : 0.1 ,
tool_resources : {
file_search : {
vector_store_ids : [ process . env . VECTOR_STORE_ID ] ,
} ,
} ,
} ) ;
}
}
const assistant = await MyAssistant . create ( ) ;
Experts.js async Assistant.create()
基本工廠功能是使用相同的構造函數創建助手的簡單方法。
const assistant = Assistant . create ( {
name : "My Assistant" ,
instructions : "..." ,
model : "gpt-4o-mini" ,
} ) ;
重要的
創建沒有id
參數的助手將始終創建一個新的助手。有關更多信息,請參見我們的部署部分。
ask()
函數是一個簡單的接口,可以詢問或指導您的助手。它需要一條消息和線程標識符。在下面的線程上更多。該消息可以是字符串或本機OpenAI消息對象。這是專家的真正發光的地方。您永遠不必直接管理運行對像或其運行步驟。
const output = await assistant . ask ( "..." , threadID )
const output = await assistant . ask ( { role : "user" , content : "..." } , threadID ) ;
正常的OpenAI工具和功能調用是通過我們的構造儀選項對象通過tools
和tool_resources
支持的。 Experts.js還支持添加助手作為工具。有關使用助手作為工具的更多信息,請參見下一節。使用addAssistantTool
功能添加助手作為工具。這必須在助手的構造函數中的super()
之後發生。
class MainAssistant extends Assistant {
constructor ( ) {
super ( {
name : "Company Assistant" ,
instructions : "..." ,
} ) ;
this . addAssistantTool ( ProductsTools ) ;
}
}
默認情況下,Experts.js利用助手流媒體事件。這些允許您的應用程序通過OpenAI的服務器點事件接收文本,圖像和工具輸出。我們利用Openai節點的流幫助者,並浮出這些事件以及一些自定義的事件,使您的助手可以利用運行的完整生命週期。
const assistant = await MainAssistant . create ( ) ;
assistant . on ( "textDelta" , ( delta , _snapshot ) => {
process . stdout . write ( delta . value )
} ) ;
所有OpenAI節點流媒體事件都通過我們的助手on()
函數支持。可用的事件名稱是: event
, textDelta
, textDone
, imageFileDone
, toolCallDelta
, runStepDone
, toolCallDone
和end
重要的
OpenAI的服務器點事件不是異步/等待的友好。
如果您的聽眾需要以異步方式執行工作,例如重定向工具輸出,請考慮使用我們對這些事件的擴展。運行完成後,它們被稱為此順序。可用的異步事件名稱是: textDoneAsync
, imageFileDoneAsync
, runStepDoneAsync
, toolCallDoneAsync
和endAsync
。
如果您想在調用助手的create()
函數時懶惰地站立額外的資源,請在類中實現beforeInit()
函數。這是一種異步方法,在創建助手之前將被調用。
async beforeInit ( ) {
await this . # createFileSearch ( ) ;
}
同樣,也可以使用afterInit()
函數。例如,將新創建的助手ID寫入環境文件。
async afterInit ( ) {
// ...
}
所有助理活動都將獲得額外的專家元數據論點。包含運行stream
對象。這使您可以使用OpenAi節點的助手功能,例如currentEvent
, finalMessages
等。
assistant . on ( "endAsync" , async ( metadata ) => {
await metadata . stream . finalMessages ( ) ;
} ) ;
使用助手作為工具是專家框架的核心焦點。工具是助手的子類,並封裝了其父對象的接口。通過這種方式,experts.js工具是您的代理體系結構中可重複使用的組件。我們的示例說明了簡潔的基本消息傳遞模式。您應該充分利用OpenAI的所有工具和功能呼叫功能。
class EchoTool extends Tool {
constructor ( ) {
super ( {
name : "Echo Tool" ,
instructions : "Echo the same text back to the user" ,
parentsTools : [
{
type : "function" ,
function : {
name : "echo" ,
description : description ,
parameters : {
type : "object" ,
properties : { message : { type : "string" } } ,
required : [ "message" ] ,
} ,
} ,
} ,
] ,
} ) ;
}
}
警告
至關重要的是,您的工具的函數名稱在其父母的整個工具名稱中都是唯一的。
因此,工具類名稱很重要,並幫助OpenAI的模型決定要撥打哪種工具。因此,為您的工具類選擇一個好名字。例如, ProductsOpenSearchTool
將是products_open_search
,顯然可以幫助該模型與工具的描述一起推斷。
工具通過addAssistantTool
功能添加到您的助手中。此功能將將工具添加到助手的工具陣列中,並更新助手的配置。這必須在助手的構造函數中的super()
之後發生。
class MainAssistant extends Assistant {
constructor ( ) {
super ( {
name : "Company Assistant" ,
instructions : "..."
} ) ;
this . addAssistantTool ( EchoTool ) ;
}
}
您的工具助理響應將自動提交作為父助手或工具的輸出。
默認情況下,工具由LLM model
支持,並作為助手執行所有相同的生命週期,運行等。但是,您可以通過將llm
選項設置為false
來創建不使用任何核心助手的功能的工具。這樣做時,您必須在工具中實現ask()
函數。返回值將作為工具的輸出提交。
class AnswerTwoTool extends Tool {
constructor ( ) {
super ( {
// ...
llm : false ,
parentsTools : [ ... ] ,
} ) ;
}
async ask ( message ) {
return ... ;
}
}
在復雜的工作流程中,可以使用LLM支持的工具將人類或其他LLM指令轉換為可執行的代碼,並且該代碼的結果(不是LLM輸出)需要為您的工具的父級輸出提交。例如, ProductsOpenSearchTool
可以將消息轉換為OpenSearch查詢,執行它們並返回結果。子類可以實現answered()
函數以控制輸出。在這種情況下, output
將是opensearch查詢,工具輸出現在包含該LLM生成的查詢的結果。
async answered ( output ) {
const args = JSON . parse ( output ) ;
return await this . opensearchQuery ( args ) ;
}
另外,LLM支持的工具可以選擇將自己的工具輸出重定向到其父助手或工具。因此忽略了LLM輸出。這還允許將所有工具輸出作為父級輸出提交。有關為什麼在下面的產品目錄示例中這很重要的更多信息。
class ProductsTool extends Tool {
constructor ( ) {
super ( {
// ...
temperature : 0.1 ,
tools : [ { type : "code_interpreter" } ] ,
outputs : "tools" ,
parentsTools : [ ... ] ,
} ) ;
this . addAssistantTool ( ProductsOpenSearchTool ) ;
this . on ( "imageFileDoneAsync" , this . imageFileDoneAsync . bind ( this ) ) ;
}
}
OpenAI的助手API引入了一種新資源,稱為線程,其中存儲在其中。本質上,線程是代理的託管上下文窗口(內存)。使用Experts.js創建新線程很容易:
const thread = await Thread . create ( ) ;
console . log ( thread . id ) // thread_abc123
您還可以創建一個帶有消息,文件或工具資源的線程以開始對話。我們支持OpenAI的線程創建請求主體在其線程API參考中概述的主體。
const thread = await Thread . create ( {
messages : [
{ role : "user" , content : "My name is Ken" } ,
{ role : "user" , content : "Oh, my last name is Collins" } ,
] ,
} ) ;
const output = await assistant . ask ( "What is my full name?" , thread . id ) ;
console . log ( output ) // Ken Collins
默認情況下,experts.js中的每個工具都有其自己的線程和上下文。這避免了一個潛在的線程鎖定問題,如果工具要共享助手的線程仍在等待提交工具輸出的情況。以下圖說明了專家如何代表您管理線程以避免此問題:
向您的專家提供的所有問題都需要線程ID。對於聊天應用程序,ID將存儲在客戶端上。例如URL路徑參數。使用Expert.js,不需要其他客戶端ID。當每位助手稱為LLM支持的工具時,它將根據需要找到或創建該工具的線程。 Experts.js使用OpenAI的線程元數據存儲此父級 - >子線程關係。
跑步是在助理的ask
功能後面為您管理的。但是,您仍然可以通過以兩種方式創建運行時使用的選項。
首先,您可以在助手的構造函數中指定run_options
。這些選項將用於助手創建的所有運行。這是強迫模型通過tool_choice
選項使用工具的好方法。
class CarpenterAssistant extends Assistant {
constructor ( ) {
super ( {
// ...
run_options : {
tool_choice : {
type : "function" ,
function : { name : "my_tool_name" } ,
} ,
} ,
} ) ;
this . addAssistantTool ( MyTool ) ;
}
}
另外,您可以將選項對像傳遞到用於當前運行的ask
方法。這是創建單個運行選項的好方法。
await assistant . ask ( "..." , "thread_abc123" , {
run : {
tool_choice : { type : "function" , function : { name : "my_tool_name" } } ,
additional_instructions : "..." ,
additional_messages : [ ... ] ,
} ,
} ) ;
要查看這些代碼示例,以及其他行動,請查看我們的測試套件。
在概述部分中,我們展示了一個三層代理系統,可以回答以下類型的問題。這些示例使用了大多數(如果不是全部)Experts.js Framework的功能。
使用textDelta
事件的基本示例從Express路線流式響應。
import express from "express" ;
import { MainAssistant } from "../experts/main.js" ;
const assistant = await MainAssistant . create ( ) ;
messagesRouter . post ( "" , async ( req , res , next ) => {
res . setHeader ( "Content-Type" , "text/plain" ) ;
res . setHeader ( "Transfer-Encoding" , "chunked" ) ;
assistant . on ( "textDelta" , ( delta , _snapshot ) => {
res . write ( delta . value ) ;
} ) ;
await assistant . ask ( req . body . message . content , req . body . threadID ) ;
res . end ( ) ;
} ) ;
助手的API使用image_url
或image_file
內容類型支持帶有圖像的消息。由於我們的ask()
函數支持字符串或本機openai消息對象。
const output = await assistant . ask (
{
role : "user" ,
content : [
{ type : "text" , text : "Tell me about this image." } ,
{ type : "image_file" , image_file : { file_id : file . id detail : "high" } } ,
] ,
} ,
threadID
) ;
使用矢量存儲進行文件搜索很容易使用OpenAI的界面通過我們的第三個配置選項。您可以使用我們的beforeInit()
函數在高級功能中描述的vector Store按需創建矢量存儲。
class VectorSearchAssistant extends Assistant {
constructor ( ) {
super ( {
name : "Vector Search Assistant" ,
instructions : "..." ,
tools : [ { type : "file_search" } ] ,
temperature : 0.1 ,
tool_resources : {
file_search : {
vector_store_ids : [ process . env . VECTOR_STORE_ID ] ,
} ,
} ,
} ) ;
}
}
使用流媒體和事件功能來報告令牌使用情況,您可以擁有每個輔助指標。
class MyAssistant extends Assistant {
constructor ( ) {
super ( {
// ...
} ) ;
this . on ( "runStepDone" , this . # reportUsage . bind ( this ) ) ;
}
# reportUsage ( runStep ) {
if ( ! runStep ?. usage ?. total_tokens ) return ;
const iT = runStep . usage . prompt_tokens ;
const oT = runStep . usage . completion_tokens ;
const tT = runStep . usage . total_tokens ;
console . log ( { InTokens : iT , OutTokens : oT , TotalTokens : tT } ) ;
}
}
為了將助手部署到生產環境中,我們建議採用以下配置。首先,創建或找到助手的ID。字符串將以asst_abc123
的格式為。然後將此ID傳遞到助手或工具的構造函數中。這將確保在所有部署中使用相同的助手。
class MyAssistant extends Assistant {
constructor ( ) {
super ( {
// ...
id : process . env . MY_ASSISTANT_ID
} ) ;
}
}
一旦通過ID找到助手或工具,任何不同存在的遠程配置都會被本地配置覆蓋。如果需要,例如在階段環境中,您可以通過將skipUpdate
選項設置為true
來繞過此行為。
您可以使用EXPERTS_DEFAULT_MODEL
環境變量為所有助手設置模型。這僅在您沒有明確設置助手構造函數中的模型時才能起作用。
要調試您的助手,您可以設置DEBUG=1
環境變量。這將輸出所有API調用和服務器儀事件的詳細記錄。 Delta事件可能有些冗長,默認情況下是禁用的。還請使用DEBUG_DELTAS=1
環境變量來打開這些變量。
該項目利用開發容器,這意味著您可以在任何支持IDE中打開它,以立即開始。這包括使用DEV容器的VS代碼,這是推薦的方法。
在開發容器中打開後,使用OpenAI API鍵和postimage.org api密鑰創建.env.development.local
。
OPENAI_API_KEY=sk-...
POST_IMAGES_API_KEY=...
現在您可以運行以下命令:
./bin/setup
./bin/test