DOCS/troubleshooting/250806_happybell80_함수형전환과LLM메모리선택.md
happybell80 725ad0876c fix: 문서 파일 실행 권한 제거
- 모든 .md, .html 파일 권한을 644로 정상화
- .gitignore 파일 권한도 644로 수정
- 문서 파일에 실행 권한은 불필요하고 보안상 바람직하지 않음
- deprecated 아이디어 폴더 생성 및 레벨별 UI 변경 아이디어 이동
2025-08-18 00:37:51 +09:00

5.4 KiB

250806 함수형 전환과 LLM 기반 메모리 선택 구현

오후 7시 00분

문제 상황

대화 저장 안되는 문제 발견

  • Slack 메시지는 수신되지만 ChromaDB에 저장 안됨
  • [대화] 로그 전무
  • 함수형 전환 후 Fire & Forget 패턴의 문제

원인 분석

  1. Fire & Forget의 위험성

    asyncio.create_task(store_memory_fn(...))  # 에러 발생해도 모름
    
    • 에러가 발생해도 전파되지 않음
    • 로그도 없어서 디버깅 불가
  2. store_memory 함수 문제

    • try-except 없음
    • 로그 없음
    • return 값 없음

오후 8시 00분

함수형 해결책 구현

완전 함수형 접근

# 데이터 준비 (순수 함수)
def prepare_memory(content: str, user_id: str, role: str) -> Dict

# 일괄 저장 (I/O 함수)  
async def save_memories(memories: List[Dict]) -> bool

결과

  • 코드 42줄 → 27줄 (35% 감소)
  • 에러 처리 추가
  • 배치 처리로 효율성 향상

오후 10시 00분

문맥 파악 문제

증상

사용자: "어떤 내용이었어?"
로빙: "김종태님, 안녕하세요..." (엉뚱한 답변)

원인

  • 메모리 검색 10000개 반환
  • 벡터 거리만 고려, 시간 무시
  • "어떤 내용"이 너무 일반적

오후 10시 30분

LLM 기반 동적 메모리 선택

Mistral 통합 (하드코딩 제거)

  1. 질문 의도 파악 (참조/새주제)
  2. 동적 임계값 계산 (백분위수 기반)
  3. 초기 선택 (거리 기반)
  4. LLM 검증 (충분성 판단)

황금비 사용

golden_ratio = (1 + 5 ** 0.5) / 2  # 수학 상수
expanded = current + (max - current) / golden_ratio

오후 11시 00분

함수형 원칙 위반 발견

문제

  • "순수 함수"라고 주석 달고 API 호출
  • 로그를 순수 함수에 포함
  • I/O와 로직 혼재

해결

  • app/llm/mistral.py로 완전 분리
  • 순수 함수: 프롬프트 생성, 파싱, 계산
  • I/O 함수: API 호출만

오후 11시 30분

최종 구조

app/llm/mistral.py (순수 함수)
├── create_intent_analysis_prompt()
├── parse_intent_response()
├── calculate_percentile_threshold()
└── filter_memories_by_threshold()

app/core/memory.py (I/O 레이어)
├── call_mistral_api()  # I/O
└── adaptive_memory_selection()  # 조정자

오후 11시 59분

배포 및 검증

서버 테스트 결과

  • 대화 저장 정상
  • 메모리 리콜 정상
  • Mistral API 연동 정상
  • 함수형 100% 달성
  • 하드코딩 0%

다음날 오전 10시 00분

await 누락 버그 발견

증상

[메모리] 검색 실패: object of type 'coroutine' has no len()
RuntimeWarning: coroutine 'adaptive_memory_selection' was never awaited

원인

# 잘못된 코드 (await 누락)
filtered_memories = adaptive_memory_selection(query, memories, mistral_key)

# 수정된 코드
filtered_memories = await adaptive_memory_selection(query, memories, mistral_key)

영향

  • Mistral API 호출 안됨
  • LLM 기반 메모리 선택 실패
  • 폴백 로직도 작동 안함

해결

  • 단순 await 누락 - 1줄 수정으로 해결

오전 11시 00분

메모리 모듈 재구조화

문제

  • memory.py 305줄 비대
  • 여러 책임 혼재

해결

app/core/memory/
├── storage.py    # ChromaDB I/O
├── identity.py   # 신원 관리
├── selection.py  # LLM 선택
└── scoring.py    # 통계/수학 (추가됨)

결과

  • 단일 책임 원칙
  • 100% 함수형 유지
  • import 하위 호환성

오후 12시 00분

베이지안 + 시간감쇠 구현

문제: 76개 여전히 과도

  • 100개 중 76개 선택
  • 과거 기억 노이즈
  • "안녕하세요" 반복

해결책 구현

  1. 시간 감쇠: e^(-t/τ)
  2. 베이지안 관련성: P(relevant|distance)
  3. 엔트로피 최적 개수: log2(n) * entropy
  4. MMR 다양성: λ=1/φ (황금비 역수)
  5. 복합 점수: 조화 평균

하드코딩 제거

  • 3 → e (자연상수)
  • 2 → φ (황금비)
  • 1/3 → 1/e

결과

  • 428줄 scoring.py
  • 선택: 100개 → 16개 후보 → 10개 MMR → 6-10개 최종
  • 메모리 개수 대폭 감소

오후 1시 00분

남은 문제와 향후 과제

개선됨

  • 88개 → 6-10개
  • 날씨 대화 문맥 유지
  • MMR 다양성 작동

미해결

  • "어떤 내용?" 구체적 답변 실패
  • 최근 대화 우선순위 부족

향후 방향

  • 표준편차 기반 "최근" 정의
  • 대화 클러스터링
  • 참조형 질문 특별 처리

교훈

  1. Fire & Forget은 위험하다

    • 명시적 await 사용
    • 에러 처리 필수
  2. 함수형 != 순수 함수만

    • I/O는 불가피
    • 중요한 건 분리
  3. 하드코딩 제거 방법

    • 수학적 상수 활용 (황금비)
    • 데이터 분포 활용 (백분위수)
    • 동적 계산
  4. LLM으로 휴리스틱 대체

    • 임의의 숫자 대신 LLM 판단
    • "충분한가?" 물어보기
  5. 모듈 분리의 중요성

    • 단일 책임 원칙
    • 테스트 용이성
    • 재사용 가능
  6. async/await 실수 방지

    • async 함수는 반드시 await와 함께
    • IDE 경고 무시하지 말 것
    • coroutine 에러 = await 누락 의심

작성자: happybell80 & Claude 프로젝트: rb10508_micro 주제: 함수형 전환과 LLM 메모리 선택