4.9 KiB
4.9 KiB
뉴스 브리핑 LangGraph 워크플로우 전환
날짜: 2026-02-02
작성자: Claude
관련 파일: rb8001/app/services/skills/startup_news_skill.py, rb8001/app/services/workflows/headlines_workflow.py, rb8001/tests/test_headlines_workflow.py
원칙 참조 (구현 전 필수 확인):
311_backend_coding_principles.md: LangGraph 워크플로우 (섹션 5), 계층 분리312_writing-principles.md: 핵심만 간결, 파일명:줄번호315_테스트_원칙.md: 테스트는 TDD로 진행 (Red → Green → Refactor)
1. 현재 문제
- 원칙 위반: 뉴스 브리핑은 수집→필터→번역→포맷→전송 다단계 처리인데, 일반 함수로 구현되어 있음. 311 원칙 "복잡한 다단계 처리는 LangGraph 적극 활용" 위반.
- 추적성 부족: 각 단계별 실패 지점, 중간 상태, 실행 시간 등이 로그에 체계적으로 남지 않음.
- 복구 불가: 중간 단계 실패 시 처음부터 재실행해야 함 (체크포인트 없음).
2. LangGraph 전환 설계
2.1 상태 모델 (HeadlinesState)
| 필드 | 타입 | 설명 |
|---|---|---|
| channel_id | str | Slack 채널 ID |
| naver_items | List[Dict] | 깡프로 헤드라인(json) |
| naver_slack_text | str | 깡프로 슬랙 포맷 텍스트 |
| sea_text | str | 동남아 섹션 텍스트 (없으면 "") |
| terms | List[str] | 추출된 용어 (없으면 []) |
| formatted_text | str | 최종 Slack 텍스트 |
| message_ts | Optional[str] | 전송된 메시지 ts |
| errors | List[str] | 각 단계 에러 |
| extract_terms | bool | HEADLINES_EXTRACT_TERMS 결과 |
2.2 노드 구성 (입출력/에러 규칙 고정)
- fetch_naver_node:
SkillCommands.fetch_naver_headlines(fmt="json")→naver_items(실패 시errors추가,naver_items=[]) - fetch_sea_node:
SkillCommands.fetch_sea_headlines(fmt="json")→sea_text(실패 시errors추가,sea_text="") - extract_terms_node:
HEADLINES_EXTRACT_TERMS=true&naver_items존재 시GeminiHandler.extract_keywords()→terms(실패 시errors추가,terms=[]) - format_node:
fetch_naver_headlines(fmt="slack")로naver_slack_text확보 후_insert_sea_section_into_headlines_text()로sea_text삽입- 기존 용어 삽입 규칙(명언 앞 삽입) 유지 →
formatted_text
- send_node:
WebClient(...).chat_postMessage()→message_ts(실패 시errors추가)
2.3 워크플로우 인터페이스
create_workflow(checkpointer=None) -> CompiledGraphasync run_headlines_workflow(channel_id: str, date: Optional[str] = None) -> Dict- 반환:
{"success": bool, "message_ts": Optional[str], "errors": List[str]}
- 반환:
2.4 라우팅
START → fetch_naver → fetch_sea → extract_terms → format → send → END
fetch_sea실패 시에도 계속 진행 (graceful degradation)extract_terms환경변수 false면 skip (terms 유지)- 각 노드 실패는
errors리스트에 기록, 워크플로우 중단 금지
2.5 체크포인터
- AsyncSqliteSaver 사용 (경량 워크플로우, 서버 재시작 시 재개 불필요)
- DB 경로:
settings.LANGGRAPH_STATE_DIR+headlines_graph.sqlite - thread_id:
f"headlines:{channel_id}:{date}"(date=Asia/SeoulYYYY-MM-DD)
2.6 로깅 기준
- 노드 시작/완료 시 항목 수/문자 수 로그
- 오류는
errors누적 + logger.warning/error
3. Phase별 작업
Phase 1: 워크플로우 파일 생성
- 파일:
rb8001/app/services/workflows/headlines_workflow.py(신규) - 내용: HeadlinesState, 5개 노드, StateGraph 정의,
create_workflow()/run_headlines_workflow()제공
Phase 2: startup_news_skill.py 리팩토링
- 기존:
run_headlines_job()함수 → 변경: LangGraph 워크플로우 호출 - 로그: 각 노드별 실행 로그 + 최종 message_ts 로그
- 시그니처 유지:
run_headlines_job(channel_id)유지 (스케줄러 변경 최소화)
Phase 3: 테스트 (TDD 진행, 315_테스트_원칙.md)
- 파일:
rb8001/tests/test_headlines_workflow.py(신규) - 시나리오:
- 정상 플로우 (깡프로 + 동남아 + 용어)
- 동남아 실패 시 graceful degradation
- 용어 추출 skip
- Slack 실패 시 errors 기록
- message_ts 반환 확인 (성공 케이스)
Phase 4: 배포 및 검증
- 배포:
git push origin main(rb8001) → Gitea Actions 자동 배포 - 검증: 내일 아침 09:10 스케줄 실행 시 로그에 노드별 실행 + message_ts 확인
4. 남은 작업
headlines_workflow.py생성 (LangGraph StateGraph)startup_news_skill.py리팩토링 (워크플로우 호출)test_headlines_workflow.py작성 (TDD 진행)- 배포 및 스케줄 실행 검증
참고
book/300_architecture/311_backend_coding_principles.mdbook/300_architecture/312_writing-principles.mdbook/300_architecture/315_테스트_원칙.md