
Experts.js - самый простой способ создать и развернуть помощников Openai и связать их вместе как инструменты для создания панели системы экспертов с расширенной памятью и вниманием к деталям.
Сделано через поддержку ❤ на пользовательские чернила | Технический
Новые помощники API от Openai устанавливают новый отраслевой стандарт, значительно выходя за рамки широко принятых API за завершение чата. Он представляет собой большой скачок в удобстве использования агентов ИИ и способами взаимодействия инженеров с LLMS. В паре с передовой мини-моделью GPT-4O, помощники теперь могут ссылаться на прикрепленные файлы и изображения в качестве источников знаний в управляемом окне контекста, называемого потоком. В отличие от пользовательских GPT, помощники поддерживают инструкции до 256 000 символов, интегрируются с 128 инструментами и используют API инновационного векторного хранилища для эффективного поиска файлов до 10 000 файлов на одного помощника.
Experts.js стремится упростить использование этого нового API путем удаления сложности управления объектами Run и позволить помощникам соединяться вместе как инструменты.
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Эксперты.
import { Assistant , Tool , Thread } from "experts" ; Конструктор нашего помощника объекта фасада требует названия, описания и инструкций. Третий аргумент - это набор параметров, которые непосредственно отображаются со всеми параметрами корпуса запроса, изложенными в документации «Создать помощник». Все примеры в экспертах. JS написаны в классах ES6 для простоты. Модель по умолчанию- 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 ( ) ; Assistant.create() .
const assistant = Assistant . create ( {
name : "My Assistant" ,
instructions : "..." ,
model : "gpt-4o-mini" ,
} ) ; Важный
Создание помощников без id параметра всегда создаст нового помощника. Смотрите наш раздел развертывания для получения дополнительной информации.
Функция ask() - это простой интерфейс, чтобы спросить или инструктировать вашего помощника (ов). Это требует сообщения и идентификатора потока. Подробнее о потоках ниже. Сообщение может быть строкой или нативным объектом сообщения Openai. Вот где эксперты. JS действительно сияет. Вам никогда не придется управлять объектами запуска или их шаги.
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 ) ;
}
}По умолчанию эксперты. Они позволяют вашим приложениям получать выходы текста, изображения и инструментов через события Severai's Send Send. Мы используем помощники потока Openai-Node и выдвигаем эти события вместе с несколькими пользовательскими, которые дают вашим помощникам подключиться к полному жизненному циклу.
const assistant = await MainAssistant . create ( ) ;
assistant . on ( "textDelta" , ( delta , _snapshot ) => {
process . stdout . write ( delta . value )
} ) ; Все события потоковой передачи Node OpenAI поддерживаются через функцию нашего помощника on() . Доступные имена событий: event , textDelta , textDone , imageFileDone , toolCallDelta , runStepDone , toolCallDone и end
Важный
События Openai по серверу не являются асинхронными/ожидающими дружелюбными.
Если ваши слушатели должны выполнять работу в асинхронном виде, например, перенаправление выходов инструментов, рассмотрите возможность использования наших расширений на эти события. Они вызываются в этом порядке после завершения пробега. Доступные имена событий Async: textDoneAsync , imageFileDoneAsync , runStepDoneAsync , toolCallDoneAsync и endAsync .
Если вы хотите лениво стоять дополнительные ресурсы, когда вызывается функция Assistant's create() , реализуйте функцию beforeInit() в вашем классе. Это асинхронный метод, который будет вызван до создания помощника.
async beforeInit ( ) {
await this . # createFileSearch ( ) ;
} Аналогичным образом, функция afterInit() может быть использована. Например, написать вновь созданные идентификаторы помощников в файл среды.
async afterInit ( ) {
// ...
} Все помощники мероприятия получают дополнительный аргумент метаданных экспертов. Объект, который содержит stream прогона. Это позволяет использовать вспомогательные функции Openai-Node, такие как currentEvent , finalMessages и т. Д.
assistant . on ( "endAsync" , async ( metadata ) => {
await metadata . stream . finalMessages ( ) ;
} ) ; Использование помощника в качестве инструмента является центральным фокусом Framework Experts.js. Инструменты являются подклассом помощника и инкапсулируют интерфейс для их родительских объектов. Таким образом, 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 ) ;
}
}Ваш ответ на инструмент будет автоматически представлен в качестве вывода для родительского помощника или инструмента.
По умолчанию инструменты подкреплены model LLM и выполняют все те же события жизненного цикла, пробеги и т. Д., Как и помощники. Тем не менее, вы можете создать инструмент, который не использует какую -либо из функций основного помощника, установив опцию 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 ) ) ;
}
} API Assi OpenAI представляет новый ресурс, называемый потоками, какие сообщения и файлы хранятся внутри. По сути, потоки представляют собой управляемое окно контекста (память) для ваших агентов. Создать новую ветку с Experts.js так же просто, как:
const thread = await Thread . create ( ) ;
console . log ( thread . id ) // thread_abc123Вы также можете создать поток с сообщениями, файлами или ресурсами инструментов, чтобы начать разговор. Мы поддерживаем поток Openai Create Запрос, описанный в их ссылке 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 имеет свой собственный поток и контекст. Это позволяет избежать потенциальной проблемы блокировки потока, которая происходит, если инструмент должен был поделиться потоком помощника, все еще ожидая отправки выходов инструментов. Следующая диаграмма показывает, как experts.js управляет потоками от вашего имени, чтобы избежать этой проблемы:

Все вопросы для ваших экспертов требуют идентификатора потока. Для приложений в чате идентификатор будет храниться на клиенте. Такие как параметр пути URL. С Expert.js не требуется других идентификаторов на стороне клиента. Как каждый помощник вызывает инструмент, поддерживаемый LLM, он найдет или создаст поток для этого инструмента по мере необходимости. Эксперты.
Забеги управляются для вас за функцией Asse Asse 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 : [ ... ] ,
} ,
} ) ; Чтобы увидеть примеры кода и многое другое в действии, посмотрите на наш набор тестов.
В разделе обзора мы показали трехуровневую систему агента, которая может ответить на следующие типы вопросов. Примеры используют большинство, если не все, функции Framework Experts.js.
Основной пример использования события textDelta для потоковой передачи ответов из экспресс -маршрута.
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 Assistant поддерживает сообщения с изображениями, используя типы контента 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() описанную в расширенных функциях.
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 } ) ;
}
} Чтобы помощник был развернут в производственной среде, мы рекомендуем следующие конфигурации. Во -первых, создайте или найдите идентификатор вашего помощника. Строка будет в формате asst_abc123 . Затем передайте этот идентификатор в конструктор помощника или инструментов. Это гарантирует, что один и тот же помощник используется во всех развертываниях.
class MyAssistant extends Assistant {
constructor ( ) {
super ( {
// ...
id : process . env . MY_ASSISTANT_ID
} ) ;
}
} После того, как помощник или инструмент обнаружен ID, любые удаленные конфигурации, которые отличаются, перезаписываются локальными конфигурациями. При необходимости, например, в стадии, вы можете обойти это поведение, установив опцию skipUpdate на true .
Вы можете глобально установить модель для всех помощников, используя переменную среды EXPERTS_DEFAULT_MODEL . Это работает только в том случае, если вы не явно установили модель в конструкторе вашего помощника.
Чтобы отлаживать своего помощника, вы можете установить DEBUG=1 переменная среды. Это выведет многословное ведение журнала всех вызовов API и событий сервера. Дельта -события могут быть несколько словесными и отключены по умолчанию. Пожалуйста, также используйте переменную среды DEBUG_DELTAS=1 чтобы включить их.
Этот проект использует контейнеры Dev, что означает, что вы можете открыть его в любой вспомогательной IDE, чтобы начать сразу же. Это включает в себя использование кода VS с контейнерами Dev, который является рекомендуемым подходом.
После открытия в вашем контейнере разработки создайте файл .env.development.local с вашим ключом API OpenAI и ключом API Postimage.org:
OPENAI_API_KEY=sk-...
POST_IMAGES_API_KEY=...
Теперь вы можете запустить следующие команды:
./bin/setup
./bin/test