채팅 메시지 저장
채팅 메시지 저장 (Chatbot Message Persistence)
대부분 AI 챗봇에서 채팅 메시지를 저장하고 불러오는 능력은 필수예요. 이 가이드에서는 useChat과 streamText로 메시지 지속성을 구현하는 방법을 보여줍니다. 인증·에러 처리 같은 실무 고려사항은 다루지 않고, 단순한 예시에 집중해요. 채팅 ID를 기준으로 새 채팅을 만들고, 기존 채팅을 불러오고, 서버에서 메시지를 검증하는 흐름을 살펴볼게요.
출처: 공식문서
본문
새 채팅 시작
사용자가 채팅 ID 없이 채팅 페이지에 접근하면, 새 채팅을 만들고 새 채팅 ID가 있는 페이지로 리다이렉트해야 해요.
import { redirect } from 'next/navigation';
import { createChat } from '@util/chat-store';
export default async function Page() {
const id = await createChat(); // 새 채팅 만들기
redirect(`/chat/${id}`); // 채팅 페이지로 리다이렉트
}
예시의 채팅 저장소 구현은 메시지를 파일로 저장해요. 실제 애플리케이션에서는 데이터베이스나 클라우드 저장소를 쓰고 채팅 ID도 DB에서 가져오겠죠. 그래도 함수 인터페이스가 다른 구현으로 쉽게 교체되도록 설계되어 있어요.
import { generateId } from 'ai';
import { existsSync, mkdirSync } from 'fs';
import { writeFile } from 'fs/promises';
import path from 'path';
// 파일 경로에 쓰기 전에 채팅 ID를 불투명 토큰으로 취급
const chatIdRegex = /^[A-Za-z0-9_-]+$/;
export async function createChat(): Promise<string> {
const id = generateId(); // 고유 채팅 ID 생성
await writeFile(getChatFile(id), '[]'); // 빈 채팅 파일 생성
return id;
}
function getChatFile(id: string): string {
if (!chatIdRegex.test(id)) {
throw new Error('Invalid chat ID');
}
const chatDir = path.resolve(process.cwd(), '.chats');
const chatFile = path.resolve(chatDir, `${id}.json`);
// 방어적 코딩: 해석된 파일이 채팅 디렉터리 안에 유지되도록
if (!chatFile.startsWith(`${chatDir}${path.sep}`)) {
throw new Error('Invalid chat ID');
}
if (!existsSync(chatDir)) mkdirSync(chatDir, { recursive: true });
return chatFile;
}
채팅 ID는 URL이나 요청 본문에서 올 수 있으므로, 파일 경로에 쓰기 전에 불투명 토큰으로 검증해야 해요. 해석된 경로 확인은 파일이 의도한 .chats 디렉터리 안에 머무르도록 보장합니다.
기존 채팅 불러오기
사용자가 채팅 ID와 함께 페이지에 오면 저장소에서 메시지를 불러와야 해요.
import { UIMessage } from 'ai';
import { readFile } from 'fs/promises';
export async function loadChat(id: string): Promise<UIMessage[]> {
return JSON.parse(await readFile(getChatFile(id), 'utf8'));
}
서버에서 메시지 검증
사용자 요청으로 들어온 메시지를 처리할 때는 서버에서 검증해야 해요. 신뢰할 수 없는 입력을 그대로 저장하지 않고, 구조를 확인한 뒤 처리하는 게 안전합니다. 이 가이드는 실무 보안 고려사항 전체를 다루는 대신 지속성 구현의 핵심 흐름에 초점을 맞춥니다.
더 알아보기
- 챗봇 UI 구축 자체는 Chatbot 문서를 참고하세요.
- 중단된 스트림을 이어받는 방법은 Chatbot Resume Streams 문서를 확인하세요.