AI 챗봇
규칙
- Vercel AI SDK(
ai 패키지)를 스트리밍에 사용 — 클라이언트에서 useChat() 훅, 서버에서 streamText() 사용
text/event-stream으로 응답 스트리밍 — 전체 응답을 버퍼링하지 않고 전송
- 메시지 형식:
{ role: "user" | "assistant" | "system", content: string }
- 컨텍스트 윈도우 관리: 토큰 한도에 근접하면 가장 오래된 메시지 정리, 시스템 프롬프트는 항상 유지
- RAG 패턴: 사용자 쿼리 임베딩 → 벡터 검색 → 상위 k개 결과를 사용자 메시지 전에 컨텍스트로 주입
- 채팅 UI: 자동 스크롤, 애니메이션 점 로딩 인디케이터, 어시스턴트 메시지에 마크다운 렌더링
- 대화 기록은 서버 측에 저장 —
chatId, role, content, createdAt 컬럼을 가진 messages 테이블 사용
- 시스템 프롬프트는 메시지 배열의 첫 번째에 위치 — 사용자 메시지가 덮어쓰지 못하게 함
- YepAPI 채팅 엔드포인트:
POST /v1/ai/chat — { messages, model?, stream? } 형식
- 생성 중단 버튼 —
AbortController를 사용하여 진행 중인 스트림 취소
패턴
const { messages, input, handleInputChange, handleSubmit, isLoading, stop } = useChat({
api: "/api/chat",
});
import { streamText } from "ai";
export async function POST(req: Request) {
const { messages } = await req.json();
const result = streamText({ model, messages });
return result.toDataStreamResponse();
}
주의 사항
- 전체 대화 기록을 정리하지 않고 전송하지 않음 — 컨텍스트 윈도우를 초과함
- 전체 응답을 기다리는 동안 UI를 차단하지 않음 — 항상 스트리밍
- 클라이언트 상태에만 메시지 저장 금지 — 서버 측에 저장하여 기록 유지
- 모델 이름을 하드코딩하지 않음 — 환경 변수 또는 config 사용