diff --git a/plans/251016_ontology_coldmail_implementation.md b/plans/251016_ontology_coldmail_implementation.md index 4bd5610..bbd6078 100644 --- a/plans/251016_ontology_coldmail_implementation.md +++ b/plans/251016_ontology_coldmail_implementation.md @@ -64,9 +64,23 @@ ## Phase 2: 기억 시스템 온톨로지 통합 (1개월) ### Neo4j 도입 -**위치**: 51123 서버 (별도 컨테이너) +**위치**: 51123 서버 (192.168.219.45) +**설치 상태**: ✅ 이미 설치됨 (시스템 직접 설치, Docker 아님) -**스키마**: +**설치 정보**: +- 버전: Neo4j 2025.06.2 Community Edition +- 서비스 상태: Active (running) since 2025-08-20 +- 가동 시간: 1개월 26일 +- HTTP 포트: 7474 (브라우저 접속) +- Bolt 포트: 7687 (드라이버 연결) +- 인증: 활성화 (비밀번호 변경됨) + +**연결 정보**: +- Bolt URI: `neo4j://192.168.219.45:7687` +- HTTP API: `http://192.168.219.45:7474` +- 데이터베이스: neo4j (기본 DB), system (시스템 DB) + +**스키마** (설계안): ``` (사건)-[:발생시각]->(시간) (사건)-[:관련감정]->(감정) @@ -213,8 +227,9 @@ Phase 1: ✅ 완료 (2025-10-16) - [ ] Slack 피드백 → 관계 가중치 베이지안 업데이트 (Phase 1.5) Phase 2: -- [ ] Neo4j 컨테이너 배포 (51123 서버) -- [ ] ChromaDB + Neo4j 하이브리드 쿼리 +- [x] Neo4j 설치 확인 (51123 서버) - ✅ 이미 설치됨 (2025.06.2) +- [ ] Neo4j Python 드라이버 연동 (neo4j 패키지) +- [ ] ChromaDB + Neo4j 하이브리드 쿼리 구현 - [ ] "1년 전 비슷한 상황" 회상 테스트 Phase 3: diff --git a/troubleshooting/251016_ontology_filter_validation.md b/troubleshooting/251016_ontology_filter_validation.md new file mode 100644 index 0000000..de76853 --- /dev/null +++ b/troubleshooting/251016_ontology_filter_validation.md @@ -0,0 +1,292 @@ +# 온톨로지 필터 검증 결과 + +**날짜**: 2025-10-16 +**작성자**: Claude (51124 서버 전담) +**관련 파일**: +- `rb8001/app/services/coldmail_ontology_reasoner.py` +- `rb8001/app/services/coldmail_hybrid_filter.py` +- `rb8001/app/services/workflows/coldmail_workflow.py` + +--- + +## 검증 목적 + +파인티처 메일 누락 문제 해결을 위해 구현한 온톨로지 기반 콜드메일 필터가 실제 운영 환경에서 정상 작동하는지 검증. + +--- + +## 검증 환경 + +| 항목 | 값 | +|------|-----| +| 서버 | 51124 (192.168.219.52) | +| 컨테이너 | rb8001 | +| 환경변수 | USE_ONTOLOGY_FILTER=true | +| 배포 커밋 | 88636cf (hotfix), 7a122f4 (통합), 48aacfa (파일럿) | +| 검증 일시 | 2025-10-16 14:50 KST | + +--- + +## 검증 방법 + +### 1단계: 온톨로지 필터 단독 테스트 +**파일**: `rb8001/test_ontology_validation.py` + +**테스트 케이스** (6개): +1. 파인티처 유사 케이스 (투자검토 + 회사소개서 첨부) +2. IR Deck 케이스 (IR 자료 + PDF 첨부) +3. 투자 키워드만 (첨부 없음) +4. Normal - 행사 초대 +5. Normal - 영수증 발급 +6. Normal - 회의 안내 + +**실행 결과**: +``` +정확도: 6/6 (100.0%) +온톨로지 판정: 6/6 (100.0%) +🎉 모든 테스트 통과! +``` + +--- + +## 상세 결과 + +### Coldmail 케이스 (3건) + +#### 1. 파인티처 유사 케이스 +``` +제목: 투자검토요청 관련하여 회사소개서 첨부드립니다_에듀테크스타트업 +발신: ceo@edutechstartup.com +첨부: 회사소개서.pdf +본문: 시드 투자를 희망하며... + +결과: ✅ coldmail +신뢰도: 0.90 +매칭 규칙: R1, R2, R3 +- R1_investment_keywords_with_pdf (0.90) +- R2_ir_attachment_filename (0.85) +- R3_review_request_with_attachment (0.80) +``` + +**의미**: 파인티처 케이스와 동일한 패턴 (투자검토 + 회사소개서)을 0.90 신뢰도로 정확히 감지. + +#### 2. IR Deck 케이스 +``` +제목: IR 자료 공유드립니다 +발신: contact@startup.kr +첨부: IR_Deck_2025.pdf + +결과: ✅ coldmail +신뢰도: 0.90 +매칭 규칙: R1, R2, R4 +``` + +#### 3. 투자 키워드만 (첨부 없음) +``` +제목: 벤처캐피탈 투자 제안 +발신: newvc@ventures.com +본문: 시리즈A 투자 유치... 밸류에이션 100억원 + +결과: ✅ coldmail +신뢰도: 0.75 +매칭 규칙: R3B, R5, R6 +- R3B_investment_title_only (0.65) +- R5_funding_keywords (0.75) +- R6_venture_domain (0.60) +``` + +**의미**: 첨부파일이 없어도 본문의 투자 관련 키워드 ("시리즈A", "투자 유치", "밸류에이션")로 콜드메일 판정 가능. + +### Normal 케이스 (3건) + +#### 4. 행사 초대 +``` +제목: 스타트업 네트워킹 행사 초대 +결과: ✅ normal +신뢰도: 0.90 (normal) +매칭 규칙: R7_event_keywords (0.90) +``` + +#### 5. 영수증 발급 +``` +제목: 세금계산서 발급 요청 건 +결과: ✅ normal +신뢰도: 0.95 (normal) +매칭 규칙: R8_receipt_keywords (0.95) +``` + +#### 6. 회의 안내 +``` +제목: 주간 회의 안내 +결과: ✅ normal +신뢰도: 0.90 (normal) +매칭 규칙: R9_work_keywords (0.90) +``` + +--- + +## 환경변수 확인 + +```bash +docker exec rb8001 printenv | grep ONTOLOGY +USE_ONTOLOGY_FILTER=true +``` + +✅ 온톨로지 필터 활성화 상태 + +--- + +## 스케줄 확인 + +``` +Coldmail briefing scheduled: 5 9 * * mon-fri +``` + +**다음 실행**: 2025-10-17 (목) 09:05 KST + +--- + +## 파라미터 전달 확인 + +### Phase 1.5 개선 사항 (커밋 7a122f4) + +**문제**: 초기 구현에서는 제목(subject)과 발신자(sender)만 전달 +**해결**: 본문(body)과 첨부파일(attachments) 파라미터 추가 + +**변경된 파일**: +1. `coldmail_hybrid_filter.py`: 함수 시그니처에 `body`, `attachments` 추가 +2. `coldmail_workflow.py`: filter_node에서 첨부파일 정규화 로직 추가 + +**정규화 로직**: +```python +# 첨부파일 정규화 (dict/string 모두 처리) +attachments = [] +if attachments_raw and isinstance(attachments_raw, list): + for att in attachments_raw: + if isinstance(att, dict): + attachments.append({"filename": att.get("name", att.get("filename", ""))}) + elif isinstance(att, str): + attachments.append({"filename": att}) +``` + +**검증 결과**: R2 (첨부파일명 규칙), R5 (본문 키워드 규칙) 정상 작동 확인 + +--- + +## 롤백 준비 + +### 3단계 롤백 시나리오 + +#### 시나리오 1: 환경변수 롤백 (즉시, 5초) +```bash +cd /home/admin/ivada_project/rb8001 +# .env 파일 수정 +USE_ONTOLOGY_FILTER=false + +# Docker 재시작 +docker compose down && docker compose up -d +``` + +#### 시나리오 2: Git 부분 롤백 +```bash +git rm app/services/coldmail_ontology_reasoner.py +git checkout 48aacfa^ -- app/services/coldmail_hybrid_filter.py +git commit -m "Rollback: Remove ontology reasoner" +git push origin main +docker compose down && docker compose up -d --build +``` + +#### 시나리오 3: 전체 롤백 +```bash +git checkout 28ef36c # Phase 1 이전 +git push origin main --force +docker compose down && docker compose up -d --build +``` + +**롤백 포인트 커밋**: +- **28ef36c**: Phase 1 이전 (안전한 복귀 지점) +- **48aacfa**: Phase 1 파일럿 완료 +- **7a122f4**: Hybrid Filter 통합 +- **88636cf**: UnboundLocalError 핫픽스 (현재) + +--- + +## 실전 검증 계획 + +### 2025-10-17 (목) 09:05 Coldmail Daily Briefing + +**확인 사항**: +- [ ] 로그에서 "Stage 1 (Ontology)" 메시지 출력 +- [ ] 콜드메일 후보 검출 개수 (기존 대비 증가 예상) +- [ ] Slack Lists 전송 성공 +- [ ] 오류 없이 정상 동작 +- [ ] 응답 속도 측정 (온톨로지 vs 기존 임베딩) + +**모니터링 명령**: +```bash +# 실시간 로그 +docker logs rb8001 -f | grep -i "stage 1\|ontology\|coldmail" + +# 09:05 이후 로그 확인 +docker logs rb8001 --since "2025-10-17T09:05:00" | grep -i "coldmail" +``` + +--- + +## 성능 지표 + +### 기대 개선 효과 + +| 항목 | 기존 (임베딩) | 현재 (온톨로지) | +|------|--------------|----------------| +| 정확도 | 75% | 100% (테스트 기준) | +| 파인티처 케이스 | 0.28 (실패) | 0.90 (성공) | +| Stage 1 판정 | 임베딩 유사도 | 명시적 규칙 | +| LLM fallback | 낮음 | 중간값에서만 | +| 설명 가능성 | 낮음 | 높음 (규칙 ID) | + +### 온톨로지 장점 +1. **투명성**: 어떤 규칙이 매칭되었는지 명확히 추적 가능 +2. **재현성**: 동일 입력에 대해 항상 동일한 결과 +3. **롤백 용이**: 환경변수 하나로 즉시 복귀 +4. **학습 가능**: Slack 피드백으로 규칙 가중치 베이지안 업데이트 (Phase 1.5 예정) + +--- + +## 남은 작업 (Phase 1.5) + +- [ ] **Slack 피드백 → 베이지안 업데이트** + - 사용자가 "콜드메일 아님" 클릭 시 해당 규칙 가중치 감소 + - "콜드메일 맞음" 클릭 시 가중치 증가 + - Naive Bayes와 동일한 학습 루프 적용 + +- [ ] **known_contacts 연동** + - R4, R10 규칙에서 실제 DB 확인 + - PostgreSQL `known_contacts` 테이블 조회 + +- [ ] **첨부파일 상세 정보** + - 현재: filename만 + - 추가: MIME type, 파일 크기 + +--- + +## 결론 + +✅ **온톨로지 필터 검증 완료** + +- 6개 테스트 케이스 모두 100% 정확도 +- 파인티처 케이스 재현 성공 (0.28 → 0.90) +- 환경변수 활성화 확인 (USE_ONTOLOGY_FILTER=true) +- 롤백 시나리오 3단계 준비 완료 +- 내일 09:05 실전 검증 예정 + +**다음 단계**: 2025-10-17 09:05 실제 브리핑 실행 시 로그 모니터링 및 결과 분석 + +--- + +## 참고 + +- **구현 계획**: DOCS/plans/251016_ontology_coldmail_implementation.md +- **문제 배경**: DOCS/troubleshooting/251014_claude_coldmail_filter_tokenization_issue.md +- **구현 커밋**: rb8001 88636cf (hotfix), 7a122f4 (통합), 48aacfa (파일럿) +- **설계 원칙**: DOCS/200_core_design/225_온톨로지_기반_지식_표현.md diff --git a/troubleshooting/251016_phase2_hybrid_memory_implementation.md b/troubleshooting/251016_phase2_hybrid_memory_implementation.md new file mode 100644 index 0000000..198c77f --- /dev/null +++ b/troubleshooting/251016_phase2_hybrid_memory_implementation.md @@ -0,0 +1,378 @@ +# Phase 2: ChromaDB + Neo4j 하이브리드 기억 회상 시스템 구현 + +**날짜**: 2025-10-16 +**작성자**: Claude (51124 서버 전담) +**관련 파일**: +- `rb8001/app/memory/neo4j_client.py` +- `rb8001/app/services/memory_hybrid_retrieval.py` +- `rb8001/app/router/memory_ontology.py` +- `rb8001/tests/test_memory_hybrid.py` + +--- + +## 목표 + +Phase 1 (Coldmail 온톨로지)의 성공을 바탕으로, 기억 시스템에 온톨로지 기반 의미적 연결을 도입하여 "1년 전 비슷한 상황"을 회상할 수 있는 하이브리드 시스템 구축. + +--- + +## 구현 내용 + +### 1. Neo4j Python 드라이버 연동 + +**파일**: `app/memory/neo4j_client.py` (300줄) + +**주요 기능**: +- Neo4j Bolt 연결 관리 (uri, auth, database) +- 사건(Event) 노드 저장 및 관계 생성 +- 그래프 추론 (감정, 결과 관계 가중치 계산) + +**스키마** (설계안): +``` +(사건:Event) -[:PARTICIPANT]-> (사용자:User) +(사건:Event) -[:HAS_EMOTION]-> (감정:Emotion) +(사건:Event) -[:HAS_RESULT]-> (결과:Result) +``` + +**관계 가중치**: +| 감정 | 가중치 | 결과 | 가중치 | +|------|--------|------|--------| +| joy (기쁨) | 1.2 | success | 1.5 | +| fear (긴장) | 1.3 | failure | 0.8 | +| sadness (슬픔) | 1.5 | neutral | 1.0 | +| 기타 | 1.0 | - | - | + +**시간 가중치**: +- 최근 → 1.0 +- 1년 전 → 0.5 +- 공식: `max(0.5, 1.0 - (days_diff / 365) * 0.5)` + +### 2. ChromaDB + Neo4j 하이브리드 Retrieval + +**파일**: `app/services/memory_hybrid_retrieval.py` (350줄) + +**3단계 알고리즘**: + +#### Stage 1: ChromaDB 벡터 검색 (빠른 필터링) +```python +# 입력: 사용자 쿼리 (예: "작년 프레젠테이션 때 어떻게 했지?") +# 1. skill-embedding (8515) /embed 호출로 쿼리 임베딩 +# 2. ChromaDB 유사도 검색: top_k=20 (충분한 후보) +# 3. 출력: 20개 후보 대화 (벡터 점수 포함) + +vector_candidates = await chroma_manager.search_memories( + query=query, + n_results=top_k * 4 # 20개 +) + +# distance를 점수로 변환 +for mem in memories: + mem["vector_score"] = max(0.0, 1.0 - distance) +``` + +#### Stage 2: Neo4j 그래프 추론 (의미적 연결) +```python +# 입력: ChromaDB 후보 20개 +# Cypher 쿼리 (자동 실행): +MATCH (e:Event) +WHERE e.id IN $event_ids +OPTIONAL MATCH (e)-[:HAS_EMOTION]->(emotion:Emotion) +OPTIONAL MATCH (e)-[:HAS_RESULT]->(result:Result) +RETURN e.id, e.timestamp, emotion.name, result.type + +# 우선순위: +# - [:HAS_RESULT]->(success) 관계 있는 사건 우선 (가중치 1.5배) +# - [:HAS_EMOTION]->(fear) 매칭 시 가중치 1.3배 +# - 시간적 근접성: 1년 전 > 2년 전 (거리 역수) + +graph_score = emotion_weight * result_weight * time_weight +``` + +#### Stage 3: 점수 통합 및 순위 결정 +```python +# 최종 점수 = (벡터 0.4 + 그래프 0.6) +final_score = (vector_score * 0.4) + (normalized_graph * 0.6) + +# normalized_graph = min(1.0, graph_score / 2.0) +# graph_score는 0.5 ~ 3.0 범위 → 0~1로 정규화 + +# 최종 점수순 정렬 후 상위 top_k 반환 +``` + +### 3. Memory Ontology API 엔드포인트 + +**파일**: `app/router/memory_ontology.py` (200줄) + +**API 엔드포인트**: + +#### POST /api/v1/memory/event +**사건 저장 (ChromaDB + Neo4j 동시 저장)** + +**Request**: +```json +{ + "content": "프레젠테이션 성공했다", + "emotion": "joy", + "result": "success", + "metadata": {"category": "work"} +} +``` + +**Response**: +```json +{ + "event_id": "06f45509...", + "message": "Event stored to ChromaDB and Neo4j" +} +``` + +#### POST /api/v1/memory/recall +**쿼리 기반 기억 회상 (3단계 하이브리드)** + +**Request**: +```json +{ + "query": "작년 프레젠테이션 때 어떻게 했지?", + "top_k": 5 +} +``` + +**Response**: +```json +{ + "memories": [ + { + "id": "06f45509...", + "content": "프레젠테이션을 성공적으로 마쳤다. 청중 반응이 좋았다.", + "vector_score": 0.85, + "graph_score": 1.8, + "final_score": 0.94, + "emotion": "joy", + "result": "success", + "timestamp": "2024-10-16T09:00:00" + } + ], + "query": "작년 프레젠테이션 때 어떻게 했지?", + "count": 1 +} +``` + +#### GET /api/v1/memory/stats +**하이브리드 시스템 통계** + +**Response**: +```json +{ + "robeing_id": "rb8001", + "user_id": "test_user_ontology", + "chroma": { + "collection_name": "rb8001_test_user_ontology_memory", + "user_id": "test_user_ontology" + }, + "neo4j": { + "connected": true, + "uri": "neo4j://192.168.219.45:7687", + "database": "neo4j", + "event_count": 42 + } +} +``` + +### 4. 테스트 및 검증 + +**파일**: `tests/test_memory_hybrid.py` + +**테스트 결과** (2025-10-16 15:06): +``` +✅ ChromaDB 저장: 4건 +⚠️ Neo4j 연결: 실패 (환경변수 NEO4J_PASSWORD 미설정) + ChromaDB 단독 모드로 fallback 동작 확인 +``` + +**테스트 시나리오**: +1. 4개 사건 저장 (프레젠테이션, 프로젝트, 회의, 점심) +2. 3개 쿼리 회상 테스트 + - "프레젠테이션 때 어떻게 했지?" + - "긴장했을 때 어떻게 대처했나?" + - "성공한 경험이 뭐가 있지?" + +**결과**: +- ChromaDB 저장: ✅ 정상 +- Neo4j 연결: ⚠️ 실패 (localhost → 192.168.219.45로 변경 필요) +- Fallback 동작: ✅ 정상 (Neo4j 연결 실패 시 ChromaDB 단독 모드) + +--- + +## 배포 상태 + +### 코드 배포 +- **커밋**: 714a132 "Phase 2: ChromaDB + Neo4j 하이브리드 기억 회상 시스템" +- **날짜**: 2025-10-16 15:05 +- **서버**: 51124 (192.168.219.52) +- **컨테이너**: rb8001 (재시작 완료) + +### Dependencies +- **neo4j**: 5.27.0 (requirements.txt 추가, Docker 이미지에 설치 완료) + +### 환경변수 설정 필요 +**.env 파일 추가 필요**: +```bash +# Neo4j 연결 설정 +NEO4J_URI=neo4j://192.168.219.45:7687 +NEO4J_USER=neo4j +NEO4J_PASSWORD=<비밀번호> +``` + +**현재 상태**: +- NEO4j_URI: bolt://localhost:7687 (기본값, 잘못됨) +- NEO4J_PASSWORD: 미설정 + +**수정 후 재시작**: +```bash +cd /home/admin/ivada_project/rb8001 +# .env 파일 수정 +docker compose down && docker compose up -d +``` + +--- + +## API 등록 + +**파일**: `main.py` (53-54줄) + +```python +# 기억 온톨로지 엔드포인트 등록 (Phase 2) +from app.router.memory_ontology import router as memory_router +app.include_router(memory_router) +``` + +**FastAPI Swagger UI**: `http://localhost:8001/docs#/Memory%20Ontology` + +--- + +## 아키텍처 + +### 데이터 흐름 + +``` +사용자 쿼리 "작년 프레젠테이션 때 어떻게 했지?" + ↓ +[ Stage 1: ChromaDB ] + 벡터 검색 → 20개 후보 + ↓ +[ Stage 2: Neo4j ] + 그래프 추론 → 감정/결과 가중치 + ↓ +[ Stage 3: 점수 통합 ] + (벡터 0.4 + 그래프 0.6) → 상위 5개 + ↓ +응답: [ + {content: "프레젠테이션 성공", final_score: 0.94, emotion: "joy", result: "success"}, + ... +] +``` + +### 저장 흐름 + +``` +사건 저장 요청 {content, emotion, result} + ↓ +[ ChromaDB ] + 임베딩 생성 (skill-embedding 8515) → 벡터 저장 + ↓ +[ Neo4j ] + Event 노드 생성 + → [:HAS_EMOTION]→(Emotion) + → [:HAS_RESULT]→(Result) + → [:PARTICIPANT]→(User) + ↓ +응답: event_id +``` + +--- + +## 성능 지표 (예상) + +| 항목 | 기존 (ChromaDB 단독) | Phase 2 (하이브리드) | +|------|---------------------|---------------------| +| 검색 속도 | ~100ms | ~200ms | +| 의미 정확도 | 70% | 90% (목표) | +| 관계 추론 | 불가능 | 가능 | +| 설명 가능성 | 낮음 | 높음 (그래프 경로) | + +**예상 개선 효과**: +- "긴장했을 때" 쿼리 → emotion=fear인 사건 우선 (가중치 1.3배) +- "성공한 경험" 쿼리 → result=success인 사건 우선 (가중치 1.5배) +- 시간 가중치로 최근 경험 우선 + +--- + +## 남은 작업 + +### 즉시 필요 +- [ ] **.env 파일에 Neo4j 환경변수 추가** + - NEO4J_URI=neo4j://192.168.219.45:7687 + - NEO4J_PASSWORD=<비밀번호> +- [ ] **Docker 재시작 후 재테스트** + +### Phase 2 완료 +- [ ] **Neo4j 연결 성공 확인** +- [ ] **API 엔드포인트 테스트** (curl 또는 Swagger UI) +- [ ] **실제 사용자 데이터로 회상 테스트** + +### Phase 3 (감정-윤리 온톨로지, 1개월) +- [ ] 감정-우도 온톨로지 (7가지 감정) +- [ ] 윤리 제약 온톨로지 (사랑 기반 원칙) +- [ ] HermiT 일관성 검사 자동화 +- [ ] 추론 과정 추적 및 설명 생성 + +--- + +## 교훈 + +### 1. Neo4j 이미 설치되어 있음 +- **문제**: Phase 2 계획서에서 "Neo4j 설치 필요"로 명시 +- **실제**: 51123 서버에 2025.06.2 Community Edition 이미 설치됨 (1개월 26일 가동) +- **교훈**: 사전 조사로 중복 작업 방지 + +### 2. Fallback 설계의 중요성 +- **문제**: Neo4j 연결 실패 시 전체 시스템 중단 가능성 +- **해결**: `if not self.driver: return []` 로직으로 ChromaDB 단독 모드 fallback +- **교훈**: 외부 의존성은 항상 fallback 준비 + +### 3. 환경변수 기본값의 함정 +- **문제**: NEO4J_URI 기본값 localhost:7687 (51123 서버는 192.168.219.45) +- **교훈**: 기본값은 문서에 명시, 배포 시 환경변수 체크리스트 필수 + +--- + +## 참고 + +- **Phase 2 계획**: DOCS/plans/251016_ontology_coldmail_implementation.md (Phase 2 섹션) +- **Phase 1 검증**: DOCS/troubleshooting/251016_ontology_filter_validation.md +- **설계 원칙**: DOCS/200_core_design/225_온톨로지_기반_지식_표현.md +- **Neo4j 설치 정보**: 251016_ontology_coldmail_implementation.md (66-82줄) +- **구현 커밋**: rb8001 714a132 + +--- + +## 다음 단계 + +1. **.env 파일 수정** (NEO4J_URI, NEO4J_PASSWORD) +2. **Docker 재시작** +3. **테스트 재실행** (`python tests/test_memory_hybrid.py`) +4. **API 엔드포인트 curl 테스트**: + ```bash + # 사건 저장 + curl -X POST http://localhost:8001/api/v1/memory/event \ + -H "Content-Type: application/json" \ + -H "X-User-Id: test_user" \ + -d '{"content": "프레젠테이션 성공", "emotion": "joy", "result": "success"}' + + # 회상 + curl -X POST http://localhost:8001/api/v1/memory/recall \ + -H "Content-Type: application/json" \ + -H "X-User-Id: test_user" \ + -d '{"query": "성공한 경험", "top_k": 5}' + ``` +5. **Phase 3 시작 여부 결정**