DOCS/journey/troubleshooting/251021_admin_slack_doc_analysis_pipeline_langgraph.md

5.8 KiB
Raw Permalink Blame History

rb8001: Slack 문서분석 흐름 개선 + LangGraph 파이프라인 적용

개요

  • 서비스: rb8001 (포트 8001), skill-rag-file (포트 8508)
  • 이슈 묶음: 파일 분석 미반영, 안내문 반복, 이전 문서 혼입, 윤리문구 노출 및 모델 중복 초기화(선행 이슈 포함)
  • 일시(KST): 2025-10-21 22:4023:10

증상

  • 새 PDF 첨부 후에도 “텍스트를 붙여넣어주세요/분석해 드릴게요” 같은 안내 문구가 반복 노출됨.
  • 문서분석 재질의 시 이전 문서(AIdol deck) 내용이 혼입되어 이어받아 응답됨.
  • 파일 분석 진행 표시가 없어 사용자 체감상 “멈춤”처럼 보임.

원인

  1. 파일 처리 비동기 흐름
  • Slack 이벤트 수신 후 즉시 LLM 호출, 파일 업로드/추출/인덱싱은 백그라운드로 처리 → 최초 응답이 파일 내용 반영 전 생성.
  1. 이벤트 필터 부족
  • Slack message_changed 등 비텍스트/봇 시스템 이벤트까지 처리 루프로 유입 → 빈 텍스트 기반 LLM 호출로 안내문 반복.
  1. 문서 컨텍스트 혼입
  • 스레드 기준의 ‘현재 문서’ 고정이 없어 RAG 검색 시 최근/이전 문서 결과가 섞여 들어와 응답 문맥 오염.
  1. (선행 이슈) 윤리 설명 노출/모델 중복 초기화
  • 사용자 본문에 윤리 경고가 포함되고, Gemini 모델이 중복 초기화되던 문제(별도 문서에 정리)도 함께 개선.

조치 (코드)

  • LangGraph 파이프라인 도입: 업로드→추출→임베딩/인덱싱→검색을 동기 대기(최대 45초) 후 상위 스니펫을 컨텍스트에 주입.
    • 파일: rb8001/app/pipelines/langgraph_document.py
  • Slack 진행 표시: context 블록(작은 회색 텍스트)로 “파일 분석 중…” → “로빙 중…” 업데이트, 최종 응답 시 삭제.
    • 파일: rb8001/app/router/slack_handler.py
  • 이벤트 필터 강화: message_changed 등 비텍스트/봇 이벤트 무시, empty 이벤트 무시, 내부 message 정규화.
    • 파일: rb8001/app/router/slack_handler.py
  • 스레드별 문서 고정: thread_ts → {team_id, document_ids} 캐시 저장, 후속 질의 RAG 검색 결과를 해당 문서로 제한.
    • 파일: rb8001/app/router/thread_doc_cache.py, rb8001/app/router/slack_handler.py
  • PDF 추출 품질 개선: 품질 휴리스틱(len, garbage_ratio, unique_chars)로 저품질 텍스트 시 강제 OCR(pytesseract) 후 재청킹/인덱싱, 메타 기록(ocr_used, quality)
    • 파일: skill-rag-file/app/api/upload.py, skill-rag-file/app/services/text_extractor.py
  • 텍스트 직접 조회: /api/text/{document_id}로 전체 본문+메타 제공 → rb8001 LangGraph가 업로드 직후 doc_id 고정 후 본문 직접 분석(스니펫은 보조)
    • 파일: skill-rag-file/app/api/text.py, skill-rag-file/app/main.py
  • LangGraph 보강: 업로드 직후 /api/reindex(force_ocr)→/api/text/{doc}→검색 순으로 대기 처리, 분석은 fulltext 우선
    • 파일: rb8001/app/pipelines/langgraph_document.py, rb8001/app/router/slack_handler.py
  • (선행) 윤리 노출/모델 고정/메모리 위생:
    • 윤리 설명 사용자 비노출, 공정성 오탐 감소, 정적 대안 제거.
    • gemini-2.5-flash-lite 단일 모델 고정 및 중복 초기화 제거.
    • 정책성 고정 문구 메모리 저장/컨텍스트/검색에서 필터링.
    • 파일: app/router/router.py, app/services/ethics_constraints_ontology.py, app/llm/llm_service.py, app/skills/startup_news_skill.py, app/state/conversation_repository.py, app/router/message_router.py, app/llm/gemini_handler.py

검증 절차

  1. PDF 첨부 DM 테스트
  • 기대 로그 흐름:
    • “파일 분석 중…” → “로빙 중…” 진행 메시지 표시
  • LangGraph 업로드/인덱싱 완료 후 [Graph] Injected … snippet(s) 로그
  • PDF 저품질 케이스: 업로드 로그에 ocr_used: true, quality.garbage_ratio 개선 확인
    • Router result의 content가 문서 스니펫 기반 분석으로 생성
  1. 비텍스트/변경 이벤트 무시 확인
  • message_changed 전송 시 non_text_subtype_ignored 기록, LLM 호출 없음.
  1. 스레드 문서 고정 확인
  • 같은 thread_ts 내 후속 질문에서 RAG 검색 결과가 고정된 document_id로 필터됨.
  1. 윤리/모델/메모리 위생
  • 윤리 설명 본문 비노출, Gemini API model initialized: gemini-2.5-flash-lite 1회만 출력, 고정 문구(“중립적이고 …”) 메모리 저장/주입/검색 제외.

결과 (요약)

  • 새로 첨부한 PDF의 내용이 최초 응답부터 반영.
  • 안내 문구 반복/비텍스트 이벤트 유입 해소.
  • 동일 스레드에서는 동일 문서에 고정된 RAG 검색으로 문맥 혼입 방지.

로그 발췌 (예시)

[Graph] uploaded Service_Process_ReverseMountain.pdf -> 062bf6... (15 chunks)
[Graph] Injected 2 snippet(s) from RAG search
Non-text message subtype ignored: message_changed

교훈 ✍️

  • 파일 기반 RAG는 업로드/인덱싱 완료 시점까지 대기하지 않으면 초기 응답이 빈약해진다 → 사용자 경험 저하.
  • Slack 이벤트는 message_changed/봇/빈 본문 등의 예외 케이스를 강하게 필터링해야 루프/중복 안내를 방지할 수 있다.
  • 스레드 단위 문서 고정은 RAG 문맥 혼입을 실질적으로 줄인다.
  • 내부 진단/윤리 설명은 사용자 본문과 분리하고, 정책성 고정 문구는 메모리 위생 대상이다.

관련 커밋

  • rb8001@397afab langgraph: sync upload/index/search + thread pinning
  • rb8001@705eef4 slack: ignore non-text/bot events
  • rb8001@23385c2 progress indicators
  • rb8001@d4039f4 memory hygiene filters
  • rb8001@c9ac22f ethics fairness tuning
  • rb8001@daad1bd single gemini + hide ethics text

문서 규칙: DOCS/300_architecture/312_writing-principles.md 준수