라이프스타일 AI 챗봇 ‘열무’ 🌱 — 아키텍처 · 라이프사이클 분석

어디살지(부동산 임차) · 2026-06-01 하루 동안 구축된 풀스택 분석 · 12개 PR · ~4,400 LOC

TL;DR

‘열무’는 조건보다 “어떤 삶을 원하는지”를 먼저 묻는 라이프스타일 상담 봇(A봇)이다. 대화로 사용자의 거주 취향을 점진 수집(collection score)하다가, 핵심 조건(P0)이 차면 매물검색(B봇)으로 핸드오프한다. 백엔드는 헥사고날(domain·application·adapters·api), 실시간은 SSE 스트리밍, 세션은 Redis(휘발)+PostgreSQL(영속). 오늘 하루에 골격(#1023)부터 영속화·위치인식·이력 로그인 인지·핸드오프 새 방까지 12개 PR로 완성됐다.

1. 한눈에 — 무엇을 하는 봇인가

진입 + 웰컴/추천칩 대화 턴마다 취향 추출 collection score ↑ P0 충족 → can_handoff 스냅샷 번들 🏠 매물검색(B봇) 새 방

기존 부동산 챗봇이 “보증금/지역/평수”를 캐묻는 폼이라면, 열무는 “출근길이 편한 동네, 카페 많은 골목, 조용한 주택가…” 같은 생활 결을 먼저 묻고 그 안에서 정량 조건을 자연스럽게 추출한다.

2. 시스템 아키텍처 (헥사고날)

backend/src/app/chat_lifestyle/            ← 포트&어댑터(헥사고날)
├─ domain/
│   ├─ models.py        LifestyleProfile · P0/P1 스코어링 모델
│   └─ ports.py         LLM · 세션 · 영속 · 스냅샷 포트(인터페이스)
├─ application/         (유스케이스 — 벤더 비의존)
│   ├─ lifestyle_agent.py     SSE 스트리밍 에이전트(대화 오케스트레이션)
│   ├─ lifestyle_scorer.py    수집 점수 P0/P1 계산
│   ├─ lifestyle_tools.py     tool 신호(핸드오프 등)
│   ├─ llm_factory.py         LLM 프로바이더 팩토리(Responses/Chat)
│   └─ suggestion_engine.py   컨텍스트 기반 퀵리플라이 칩 생성
├─ adapters/           (벤더 구현 — 교체 가능)
│   ├─ llm/openai_responses_adapter.py · openai_chat_adapter.py
│   ├─ persistence/pg_profile_adapter.py · pg_thread_adapter.py · ip_region_adapter.py
│   ├─ session/redis_session.py
│   └─ snapshot/profile_snapshot.py
└─ api/lifestyle_router.py    /v1/lifestyle/{message,threads,snapshot,profile}

레이어 책임

레이어책임핵심
domain순수 규칙LifestyleProfile, P0(필수)·P1(보강) 점수
application유스케이스agent(SSE 흐름)·scorer·tools·suggestion_engine
adapters벤더 구현OpenAI(Responses/Chat)·Redis·PostgreSQL·IP 지역
api전송SSE 라우터 + DTO

프론트는 BE 미러 — useLifestyleSender(SSE 훅) · LifestyleHistoryOverlay · LifestyleProgressBar · ProfileSummaryCardAIAssistantBottomSheetchatMode='lifestyle' 분기로 매물 모드와 한 컴포넌트에 통합된다.

3. 대화 라이프사이클 (런타임)

단계동작신호
① 진입웰컴 메시지 + 추천 칩 4개suggestion_engine 초기 칩
② 수집턴마다 SSE 스트리밍 응답 + 프로필 추출updates.collection_score
③ 보강부족한 P0 필드를 자연스러운 후속 질문으로 유도missing_p0_fields
④ 준비완료P0 충족 → 핸드오프 버튼 노출can_handoff=true
⑤ 핸드오프“내 취향으로 매물 찾기” → 스냅샷 번들 생성snapshot_bundle
⑥ 전환매물검색(B봇) 새 대화방에서 프로필 기반 검색handleNewChat→search

세션 SSOT = DB. 휘발 상태(스트리밍·진행)는 Redis, 영속 프로필·대화는 PostgreSQL. 재진입 시 /threads·/profile로 복원된다.

4. SSE 스트리밍 프로토콜

POST /v1/lifestyle/message  (text/event-stream)
event:metadata    {thread_id}
event:token       {delta}            ← 응답 토큰 점진 출력
event:thinking    {text}             ← "🌱 조건 분석 중…" tool 진행
event:updates     {collection_score, can_handoff, missing_p0_fields, profile_summary}
event:suggestions {items[]}          ← 다음 턴 퀵리플라이 칩(best-effort)
event:end         {}                 ← 로딩 해제 지점
event:error       {message}

설계 함정(#1028 해소): 칩 생성용 2차 LLM 호출이 메인 스트림과 충돌(GeneratorExit)하면 suggestions/end가 누락돼 프론트가 무한 로딩에 빠진다. → end를 먼저 보장하고 칩은 best-effort로 분리, tool 진행 메시지로 “멈춘 게 아님”을 시각화.

5. 개발 타임라인 — 2026-06-01 하루 (12 PR)

시각PR내용LOC
10:16#1023풀스택 골격 — 헥사고날 BE + FE 통합 + SSE + 스코어링 + 핸드오프2,733
10:30#1024데스크탑 폰프레임 입력바 클릭 불가 + 오버레이 갇힘8
11:51#1025대화 이력 영속화/API/복원 풀스택604
11:59#1026로딩 흰 버블·하단 여백 매물 모드와 통일2
12:18#1027위치 인식 + LLM 칩 (지명 하드코딩/오버피팅 제거)256
12:43#1028SSE 멈춤 해소 + tool 진행 메시지173
13:41#1029대화 내역 오버레이를 챗봇 프레임 안으로 + 메뉴 바로 열기42
14:20#1031핸드오프 tool 신호 기반 전환 + 지명 하드코딩 제거30
14:41#1032대화 내역 오버레이 폰 프레임 레이아웃126
14:47#1033전송 후 입력창 텍스트 남는 회귀(draft 복원 레이스)55
15:21#1034이력 로그인 인지 — 회원 본인 + 비회원 anon 머지294
15:28#1035취향→매물 핸드오프 새 대화방에서 시작108

골격 #1023(2,733 LOC, 41 파일) 이후 11개 PR은 대부분 “현장 버그·UX·오버피팅 제거”의 빠른 반복. 총 ~4,400 insertions / 87 파일.

6. 핵심 기술 결정

오버피팅 제거 (#1027 #1031)

지명·핸드오프 트리거를 하드코딩 분기로 짜지 않고 위치 인식 + LLM 칩 생성·tool 신호 기반 전환으로 일반화. 특정 입력 패치가 아닌 근본 해결.

이력 로그인 인지 (#1034)

항상 anon-lifestyle 단일 버킷만 보던 구조를, 회원은 본인 user_id + 로그인 이전 anon을 머지해 노출. 순수 함수 분리 + 단위테스트 7.

핸드오프 새 방 (#1035)

sendDirect 전에 handleNewChat()로 새 threadId 동기 리셋 → 직전 검색 대화에 안 붙고 깨끗한 새 방에서 검색.

입력 draft 레이스 (#1033)

전송 후 setInputValue('')만 하면 draft 복원 effect가 텍스트를 재주입. clearInputDraft()+가드로 해소.

SSE 무한 로딩 (#1028)

2차 LLM(칩)과 메인 스트림 충돌로 end 누락 → 무한 로딩. end 보장 + 칩 best-effort 분리.

폰 프레임 레이아웃 (#1024 #1029 #1032)

데스크탑 폰프레임 안 입력/오버레이가 갇히거나 깨지던 문제를 컨테이너 기준으로 일반화(매직넘버 제거).

7. 현재 상태 · 남은 것

분석 대상: ai-real-estate-service main, 작성자 chlee 의 2026-06-01 커밋 #1023~#1035. 어제(05-31)는 라이프스타일 관련 0건 — 본 챗봇은 하루에 구축됨. 개인용 분석 산출물.