Experts.js는 OpenAI의 어시스턴트를 생성하고 배포하고 메모리가 확장되고 세부 사항에 대한 관심을 가진 전문가 시스템을 만드는 도구로 서로 연결하는 가장 쉬운 방법입니다.
사용자 정의 잉크별로지지를 통해 제작되었습니다. | 기술
OpenAI의 새로운 어시스턴트 API는 새로운 업계 표준을 설정하여 널리 채택 된 채팅 완료 API를 넘어서 크게 발전합니다. AI 에이전트의 유용성과 엔지니어가 LLM과 상호 작용하는 방식의 주요 도약을 나타냅니다. 최첨단 GPT-4O 미니 모델과 짝을 이루는 조수는 이제 첨부 된 파일 및 이미지를 관리 컨텍스트 창 내에서 스레드라고하는 지식 소스로 참조 할 수 있습니다. Custom 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 지원 조수입니다. 복잡한 오케스트레이션 워크 플로우를 허용하거나 일련의 엄격한 니트 작업을 안무합니다. 여기에는 OpenSearch 쿼리를 만들기위한 LLM 후원 도구가있는 제품 카탈로그 도구가있는 회사 비서의 예가 있습니다.
NPM을 통해 설치하십시오. 사용법은 매우 간단하며 가져올 객체는 세 개뿐입니다.
npm install experts
Experts.js는 ES6 가져 오기 구문을 모두 지원하고 CommonJS는 진술이 필요합니다.
import { Assistant , Tool , Thread } from "experts" ;
보조 외관 객체의 생성자는 이름, 설명 및 지침이 필요합니다. 세 번째 인수는 어시스턴트 문서 작성에 요약 된 모든 요청 본문 옵션에 직접 매핑하는 일련의 옵션입니다. 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 ( ) ;
Experts.js Async Assistant.create()
Base Factory 함수는 동일한 생성자 옵션을 사용하여 비서를 만드는 간단한 방법입니다.
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-Node의 스트림 헬퍼를 활용하고 이러한 이벤트와 함께 몇 가지 커스텀 이벤트를 표면하여 조수가 달리기의 전체 수명주기를 활용할 수 있도록 제공합니다.
const assistant = await MainAssistant . create ( ) ;
assistant . on ( "textDelta" , ( delta , _snapshot ) => {
process . stdout . write ( delta . value )
} ) ;
모든 OpenAi-Node 스트리밍 이벤트는 Assistant 's 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-Node의 헬퍼 기능을 currentEvent
, finalMessages
등과 같은 사용할 수 있습니다.
assistant . on ( "endAsync" , async ( metadata ) => {
await metadata . stream . finalMessages ( ) ;
} ) ;
어시스턴트를 도구로 사용하는 것은 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 ) ;
}
}
도구 보조 응답은 부모 비서 또는 도구의 출력으로 자동으로 제출됩니다.
기본적으로 도구는 LLM model
에 의해 뒷받침되며 모든 동일한 라이프 사이클 이벤트, 실행 등을 보조원으로 수행합니다. 그러나 llm
옵션을 false
로 설정하여 Core Assistant의 기능을 사용하지 않는 도구를 만들 수 있습니다. 그렇게 할 때는 도구에서 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의 각 도구에는 자체 스레드 및 컨텍스트가 있습니다. 이는 도구가 도구 출력이 제출되기를 기다리는 비서의 스레드를 공유 해야하는 경우 발생하는 스레드 잠금 문제를 피합니다. 다음 다이어그램은 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 : [ ... ] ,
} ,
} ) ;
이들과 더 많은 행동의 코드 예를 보려면 테스트 스위트를 살펴보십시오.
개요 섹션에서 우리는 다음 유형의 질문에 답할 수있는 3 계층 에이전트 시스템을 보여주었습니다. 이 예제는 Experts.js 프레임 워크의 기능을 모두 사용하지 않습니다.
기본 예제 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()
함수를 사용하여 주문형 벡터 저장소를 만들 수 있습니다.
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
Environment 변수를 사용하여 모든 보조원의 모델을 전 세계적으로 설정할 수 있습니다. 조수 생성자에 모델을 명시 적으로 설정하지 않은 경우에만 작동합니다.
어시스턴트를 디버그하려면 DEBUG=1
환경 변수를 설정할 수 있습니다. 이것은 모든 API 호출 및 서버 센드 이벤트의 장점 로깅을 출력합니다. 델타 이벤트는 다소 장황 할 수 있으며 기본적으로 비활성화됩니다. DEBUG_DELTAS=1
환경 변수를 사용하여이를 켤 수 있습니다.
이 프로젝트는 DEV 컨테이너를 활용하여 지원하는 IDE에서 시작하여 즉시 시작할 수 있습니다. 여기에는 권장되는 접근법 인 DEV 컨테이너와 함께 VS 코드 사용이 포함됩니다.
개발 컨테이너에 열리면 OpenAI API 키 및 postimage.org API 키로 .env.development.local
파일을 만듭니다.
OPENAI_API_KEY=sk-...
POST_IMAGES_API_KEY=...
이제 다음 명령을 실행할 수 있습니다.
./bin/setup
./bin/test