자 오늘은 OpenAI의 Assistant라는 기능을 이용하여서 나만의 최애캐를 구현해볼 것이다.

다하면 이런 화면이 나온다~
일단 OpenAI의 Assistant를 이해하고 가야한다.
Assistant는 내가 Assistant에게 Assistant가 "누구"인지를 정의해줄 수 있다.

이런식으로 정의를 해서 그에 맞게 행동하게 할 수 있다.
또한 Assistant에게 "대화"를 하기 위해서는 Thread라는 것이 필요한데, Thread는 간단하게 주제가 있는 카톡방이라고 생각하면 된다.
Assistant와 Thread는 Dashboard에서 쉽게 만들 수 있으니 만들어보자.

Dashboard의 Assistants에 가서 Assistants를 너가 원하는 최애캐처럼 만들어봐라

나 같은 경우 설정은 이런식으로 해주었고, 그 캐릭터의 나무위키.pdf를 넣어주었다.

그리고 Playground라는 버튼을 눌러서 들어가준다.

그러면 이런 화면이 나오게 되는데, 여기서 작동하는 형식이 우리가 만들어야하는 형식이다.

아무리 Assistant가 제대로 되어 있어도, 그와 맞는 카톡방이 존재해야하기에 Thread에 pdf파일을 올려서 학습을 시켜주었다.
자기가 원하는 대답이 나온다면 끗해주고, assistand_id와 thread_id를 복사해준다.
만약 이걸 서비스화 시키고 싶다면 들어오는 사람마다 쓰레드를 동일한 형식으로 만들어줘서 하나하나 할당해줘야 할 것 같음
백엔드는 express로 함
dotenv다운 받아서 apikey값이랑 id값 넣어주셈
이제 백엔드에서 ai.js를 만들어줘서 메세지를 받고 실행하는 부분을 개발해보자.
import OpenAI from "openai";
import dotenv from "dotenv";
dotenv.config();
const openai = new OpenAI(process.env.OPENAI_API_KEY);
export async function sendMessageToAssistant(threadId, userMessage) {
const response = await openai.beta.threads.messages.create(threadId, {
role: "user",
content: userMessage,
});
return response;
}
export async function createRun(threadId, assistantId) {
const run = await openai.beta.threads.runs.create(threadId, {
assistant_id: assistantId,
});
return run;
}
export async function waitRun(run, threadId) {
// 실행 완료 될 때까지 반복
// status가 "queued" 또는 "in_progress"인 경우 계속 대기
while (run.status === "queued" || run.status === "in_progress") {
// run.status를 업데이트
run = await openai.beta.threads.runs.retrieve(threadId, run.id);
// 서버 부하 줄이기
await new Promise((resolve) => setTimeout(resolve, 500)); // 0.5초 대기
}
return run;
}
export async function receiveMessage(threadId) {
const response = await openai.beta.threads.messages.list(threadId, "asc");
return response;
}
async function main() {
const assistantId = "어시스던트 아이디";
const threadId = "쓰레드 아이디";
const userMessage = "오늘 뭐하니?";
try {
// 메시지 전송 및 응답 받기
const message = await sendMessageToAssistant(threadId, userMessage);
// console.log("질문: ", userMessage);
// Run 생성
const run = await createRun(threadId, assistantId);
// console.log("Run created:", run);
// 기다리기
await waitRun(run, threadId);
// console.log(result);
const response = await receiveMessage(threadId);
console.log(response.data[0].content[0].text.value);
} catch (error) {
console.error("Error:", error);
}
}
// main();
일단 우리 전체코드를 천천히 읽어보자.
일단 Main()부분은 테스트하기 위한 코드이기에 넘기고 함수들을 하나씩 살펴보자!
export async function sendMessageToAssistant(threadId, userMessage) {
const response = await openai.beta.threads.messages.create(threadId, {
role: "user",
content: userMessage,
});
return response;
}
이 함수는 Message를 Thread에 넣어주는 함수이다.
유저가 어떤 메세지를 서버로 넘기면 받아서 처리해주는 방식이다.
안에 내용은

API reference를 보면 뭘 넣어야 될지 알 수 있다.
우리는 유저의 입력을 넣어야 하기에 역활을 user로 해주고 content에 userMessage를 담아서 보내준다.
export async function createRun(threadId, assistantId) {
const run = await openai.beta.threads.runs.create(threadId, {
assistant_id: assistantId,
});
return run;
}
이 함수는 Thread안의 메세지를 실행시켜주는 함수이다.
어떤 Thread에서 실행시킬건지 알아야 하기에 thread_id를 넣고 어떤 Assistant를 사용할지도 골라야 하기에 assistant_id도 넣어주자.
export async function waitRun(run, threadId) {
// 실행 완료 될 때까지 반복
// status가 "queued" 또는 "in_progress"인 경우 계속 대기
while (run.status === "queued" || run.status === "in_progress") {
// run.status를 업데이트
run = await openai.beta.threads.runs.retrieve(threadId, run.id);
// 서버 부하 줄이기
await new Promise((resolve) => setTimeout(resolve, 500)); // 0.5초 대기
}
return run;
}
이 함수는 run이 완료 될 때까지 계속 코드를 돌려주는 함수이다.
처음의 createRun()함수를 통해서 데이터를 받아보면 "queued"라는 status를 가지고 있을 것이다.
queued라는 상태는 아직 메시지를 처리하지 못한 상태이기에 complete가 될 때까지 돌려주고 값을 리턴받는 것이다.
export async function receiveMessage(threadId) {
const response = await openai.beta.threads.messages.list(threadId, "asc");
return response;
}
마지막으로 이 함수는 Message를 받아오는 역활을 한다.
일단 어떤 쓰레드에서 Message를 받아오기 위해 thread_id를 넣어주면 된다.
이러면 끝이다!
만약 오류가 난다면 return 값을 하나하나 읽어보고 그에 맞게 수정하자.
app.post("/message/add", async (req, res) => {
console.log(req.body);
if (req.body.message === "") {
res.send("메세지가 없습니다.");
} else {
sendMessageToAssistant(process.env.THREAD_ID, req.body.message);
const run = await createRun(
process.env.THREAD_ID,
process.env.ASSISTANT_ID,
);
await waitRun(run, process.env.THREAD_ID);
const response = await receiveMessage(process.env.THREAD_ID);
console.log(response.data[0].content[0].text.value);
res.json({ res: response.data[0].content[0].text.value });
}
});
그리고 간단하게 post로 값을 받아오고 규칙대로 함수를 실행해주고 response를 응답해주자.
자 이제 프론트앤드에서 post를 보내기 위해 axios를 이용해서 코드를 짜주자!
axios.post("http://localhost:5000/message/add", {
message,
})
.then((response) => {
setResponse(response.data.res);
setLoading(false);
console.log(response);
})
.catch((error) => {
console.log(error);
setLoading(false);
alert("|~초 비 상~|");
});
이런 코드를 짜주었다~~
그리고 UI까지 뚝딱뚝딱해서 만들어주면

짜잔! 완성이다! 이제 호시노랑 대화를 할 수 있따ㅏㅏ
자 이제 모두들 자신만의 최애캐를 AI로 만들러 가보자ㅏㅏ
프롬프트 엔지니어로 살아가십씨오..