어떻게 해야할까

아래 순서를 그대로 따라가면 “내가 넘어졌던 날을 찾아줘” 같은 자연어 질의에 날짜만 깔끔히 되돌려주는 RAG 시스템을 실험 단계까지 구축할 수 있습니다.

(예시는 NestJS + TypeScript, Qdrant + pgvector 기준이지만, 다른 스택에도 그대로 매핑 가능합니다.)


1. 데이터 흐름 한눈에 보기

┌─(1) 일기 RAW ─────────┐
│ 작성·업로드           │
└───────────────────────┘
             │
             ▼
┌─(2) 전처리/사건 추출 파이프라인─────────────┐
│ ・날짜 파싱                                 │
│ ・LLM으로 “사건 요약” 생성                  │
│   (예: `"미끄러져 넘어짐"`)                 │
│ ・사건 타입/감정(선택) 태깅                 │
└────────────────────────────────────────────┘
             │
             ▼
┌─(3) 임베딩 생성──────────────────────────────┐
│ ・`text = <사건 요약>`                       │
│ ・`embedding = OpenAI/miniLM 등`             │
│ ・`metadata = {date, event_type:"넘어짐"}`   │
└────────────────────────────────────────────┘
             │
             ▼
┌─(4) Vector DB (Qdrant/pgvector)─────────────┐
│ Hybrid index  ← keyword index               │
└────────────────────────────────────────────┘
             │
             ▼
┌─(5) Hybrid Retrieval Layer──────────────────┐
│ ① 키워드 필터링  (넘어짐·미끄러짐 등 동의어) │
│ ② 벡터 유사도 K개                           │
│ ③ 날짜·메타데이터만 추출                    │
└────────────────────────────────────────────┘
             │
             ▼
┌─(6) LLM 재후처리 (RAG)──────────────────────┐
│ Prompt: “아래 문서에서 날짜만 리스트로 줘”   │
└────────────────────────────────────────────┘


2. 전처리 & 사건 추출

단계 구현 팁 예시 코드
날짜 파싱 정규식 + date-fns const date = parse('yyyy년 M월 d일', raw, new Date())
사건 요약 OpenAI /chat/completions ; system 프롬프트 “일기에서 가장 특징적인 사건을 한 문장으로 요약해줘.”
사건 타입 태깅 간단 규칙 → 미세 조정 필요 `if (/넘어

Tip

개발 초기엔 일기 20~30개만 수동으로 라벨링 → 모델이 못 잡아내는 동의어를 사전으로 추가해두면 precision 급상승합니다.


3. 벡터 DB 스키마 예시 (Qdrant)

await qdrant.createCollection({
  name: 'diary',
  vectors: { size: 384, distance: 'Cosine' },
  optimizers_config: { default_segment_number: 2 },
});

await qdrant.upsert('diary', [
  {
    id: uuidv4(),
    vector: embedding,          // Float32Array
    payload: {
      date: '2024-09-13',
      event_type: 'fall',
      text: '비 오는 날 미끄러져 넘어짐'
    }
  }
]);


4. Hybrid Search 구현

const must = [
  { key: 'event_type', match: 'fall' } // ① 키워드/태그 필터
];

const { result } = await qdrant.search('diary', {
  vector: embed('넘어짐 사건'),
  filter: { must },
  limit: 5                      // ② 벡터 유사도
});

const docs = result.map(r => `${r.payload.date}: ${r.payload.text}`);


5. LLM 후처리 (RAG 단계)