챗봇은 사용자와 자동화된 상호작용을 제공하는 다양한 산업 분야에서 필수적인 도구입니다. 요즘 세상에 Chat GPT(또는 다른 AI 기반 챗봇)를 한 번 이상 시도하지 않은 사람은 없습니다. OpenAI의 GPT 모델과 LangChain 라이브러리를 사용하여 스트리밍 응답 시스템을 통해 세션을 처리하고 사용자 메시지를 처리하는 챗봇을 구축할 수 있습니다. 이후 게시물에서는 API와 통신하고 특정 작업에 특화된 에이전트를 만들 것입니다.
우리가 다룰 내용은 다음과 같습니다.
먼저 몇 가지 주요 종속성이 필요합니다.
가장 먼저 할 일은 새 프로젝트를 초기화하고 사용할 필수 모듈을 설치하는 것입니다.
npm init -Y npm install express langchain openai uuid class-validator class-transformer mutex
시작하려면 두 가지 주요 경로를 정의하겠습니다.
첫 번째 경로는 새 채팅 세션을 생성하고, 두 번째 경로는 기존 세션에 메시지를 보냅니다.
router.post('/session', APIKeyMiddleware, createSession); router.post('/session/:id/message', APIKeyMiddleware, postMessage);
APIKeyMiddleware는 인증된 요청만 이러한 경로에 액세스하도록 보장합니다. 귀하의 필요에 맞는 미들웨어를 구현할 수 있습니다.
채팅 상담원을 처리하기 위해 AgentManager 클래스를 생성하겠습니다. 이 클래스는 새 에이전트를 생성하고 활성 세션을 관리하는 역할을 담당하므로 이 클래스가 채팅을 담당할 에이전트를 포함하므로 API의 주요 진입점이라고 상상해 보세요. 첫 번째 사용자는 세션을 생성해야 하며 나중에 해당 세션이 채팅에 사용됩니다.
export class AgentManager { private __lock = new Mutex(); private __agents: Map<string, AgentInstance> = new Map(); async createAgent(authorization: string): Promise<string> { const uuid = uuidv4(); const release = await this.__lock.acquire(); try { this.__deleteExpiredAgentsLockless(); let agent: ChatAgent | null = agent = new GeneralChatAgent(authorization); this.__agents.set(uuid, { agent, createdAt: Date.now() }); return uuid; } finally { release(); } } async getAgent(uuid: string): Promise<ChatAgent | null> { const release = await this.__lock.acquire(); try { this.__deleteExpiredAgentsLockless(); const agentInstance = this.__agents.get(uuid); return agentInstance ? agentInstance.agent : null; } finally { release(); } } private __deleteExpiredAgentsLockless(): void {} }
이제 일반 채팅 에이전트를 만들어야 합니다. 이 에이전트는 인증이나 기타 필요한 매개변수를 가져오고 API와 통신할 수 있지만 지금은 기존 ChatAgent를 확장하겠습니다. 이 단계에서는 더 이상 아무것도 없습니다.
export class GeneralChatAgent extends ChatAgent { constructor() { super(); } }
createAgent 메소드는 에이전트를 초기화하고 프로세스를 잠근 후 고유한 세션 ID에 할당합니다. 에이전트는 지정된 세션 기간이 지나면 만료됩니다. 이는 __deleteExpiredAgentsLockless 메소드로 처리되지만 다음 반복에서는 이를 구현하므로 지금은 이를 방지할 수 있습니다.
다음으로 세션 생성 및 메시지 처리 경로를 정의해 보겠습니다.
export const createSession = async (req: Request, res: Response): Promise<void> => { const authorization = req.headers['authorization'] as string; try { const sessionId = await agentManager.createAgent(authorization, AgentType.WEB); res.json({ sessionId }); } catch (err) { if (err instanceof Error) { res.status(400).json({ error: err.message }); } else { res.status(500).json({ error: 'An unknown error occurred' }); } } } export const postMessage = async (req: Request, res: Response): Promise<void> => { const { id } = req.params; const { message } = req.body; if (!id || !message) { return res.status(400).json({ error: 'Bad request. Missing session ID or message' }); } try { const agent = await agentManager.getAgent(id); if (!agent) { return res.status(400).json({ error: `No agent found with id ${id}` }); } const iterable = await agent.invoke(message); await streamResponse(res, iterable); } catch (err) { res.status(500).json({ error: err instanceof Error ? err.message : 'An unknown error occurred' }); } }
여기서 createSession은 새 세션을 설정하고 postMessage는 사용자의 메시지를 에이전트에 보냅니다. 세션이나 메시지가 제공되지 않으면 400 Bad Request 오류가 반환됩니다.
스트리밍 응답
이제 채팅 봇의 반응성과 대화형 느낌을 만드는 핵심은 응답 스트리밍입니다.
async invoke(input: string): Promise<AsyncIterable<Chunk>> { const release = await this.__lock.acquire(); try { const tool = this.determineTool(input); if (tool) { const toolOutput = await tool.call(input); this.callbackQueue.enqueue({ type: ChunkType.TOKEN, value: toolOutput }); this.callbackQueue.enqueue({ type: ChunkType.FINISH, value: '' }); } else { await this.chat.invoke([new HumanMessage(input)], { callbacks: [ { handleLLMNewToken: (token: string) => { this.callbackQueue.enqueue({ type: ChunkType.TOKEN, value: token }); }, handleLLMEnd: () => { this.callbackQueue.enqueue({ type: ChunkType.FINISH, value: '' }); }, handleLLMError: (error: Error) => { this.callbackQueue.enqueue({ type: ChunkType.ERROR, value: error.message }); } } ] }); } return this.createAsyncIterable(this.callbackQueue); } finally { release(); } } private createAsyncIterable(callbackQueue: AgentCallbackQueue): AsyncIterable<Chunk> { return { [Symbol.asyncIterator]: async function* () { let finished = false; while (!finished) { const chunk = await callbackQueue.dequeue(); if (chunk) { yield chunk; if (chunk.type === ChunkType.FINISH || chunk.type === ChunkType.ERROR) { finished = true; } } else { await new Promise(resolve => setTimeout(resolve, 100)); } } } }; }
invoke 메서드에서 에이전트는 사용자의 입력을 처리하고 응답을 청크로 다시 스트리밍합니다. 각 청크는 모델의 토큰이거나 스트림의 끝을 나타내는 메시지입니다.
createAsyncIterable 메소드를 사용하면 이러한 청크를 하나씩 생성하고 클라이언트로 다시 스트리밍할 수 있습니다.
결국 우리는 응답을 수신하면서 클라이언트에 스트리밍하고 싶습니다. 완료될 때까지 잠시 기다리지 않고 전체 응답을 반환하고 싶지 않습니다. 더 나은 해결책은 응답을 청크로 스트리밍하는 것입니다.
const delay = (ms: number): Promise<void> => new Promise(resolve => setTimeout(resolve, ms)); export async function streamResponse(res: Response, iterable: AsyncIterable<Chunk>) { res.setHeader('Content-Type', 'application/x-ndjson'); res.setHeader('Transfer-Encoding', 'chunked'); try { let buffer = ''; for await (const chunk of iterable) { switch (chunk.type) { case ChunkType.TOKEN: buffer += chunk.value; res.write(buffer); if (res.flush) res.flush(); buffer = ''; break; case ChunkType.ERROR: console.error('Error chunk:', chunk.value); if (!res.headersSent) { res.status(500).json({ error: 'Streaming failed.' }); } return; case ChunkType.FINISH: if (buffer.trim()) { res.write(`${buffer.trim()}\n`); } return; } } } catch (err) { console.error('Error during streaming:', err); if (!res.headersSent) { res.status(500).json({ error: 'Streaming failed.' }); } } finally { res.end(); } }
축하합니다! 이제 채팅 세션을 처리하고 클라이언트에게 응답을 스트리밍하는 기본 챗봇이 생겼습니다. 이 아키텍처는 추가 도구, 더 정교한 로직 또는 다양한 GPT 모델을 사용하여 쉽게 확장할 수 있지만 현재로서는 더 복잡한 챗봇을 위한 뼈대만 있습니다.
OpenAI의 강력한 언어 모델과 LangChain의 도구 관리를 사용하면 다양한 도메인에 대한 더욱 발전된 대화형 챗봇을 만들 수 있습니다. 챗봇 기능을 확장하고 원하는 방식으로 만들 수 있지만, 반면에 그럴 필요는 없습니다. Langchain을 사용하면 OpenAI를 사용하여 원하는 경우 훨씬 더 간단한 채팅 봇을 만들 수 있습니다.
더 많은 내용을 기대해 주세요. 다음 게시물에서는 우리가 만든 채팅 에이전트용 도구 구축에 대해 이야기하겠습니다.
즐거운 코딩하세요!
원본을 확인해주세요
위 내용은 OpenAI와 LangChain을 사용하여 강력한 챗봇 구축의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!