IM3-263: feat: 통합 dict + 자사매장 카테고리 매칭 + LLM 평가 framework + synthesis 톤 강화#199
Merged
Conversation
4개 사용처 일괄: - InsightTab: 9 에이전트 카드 — iconBgCls 박스 div 제거, img 만 (h-12 w-12 object-contain). 미실행 에이전트는 opacity-40 grayscale 로 구분. - AgentCard: compact (9x9) / full (14x14) 모두 박스 div 제거. - DecisionCard: 페르소나 -space-x-1.5 stack 의 둥근 박스 제거. - EnginePage: ring-1 ring-border + rounded-full + object-cover 제거 → object-contain. object-cover → object-contain 으로 변경한 이유: PNG 투명 영역이 잘리지 않게. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
원인: - density_score: SEMAS API 키 부재 시 16동 모두 None → density_norm 자체가 None → 모든 동의 density_score 결측. winner 의 경쟁강도(85)는 별도 market_report 출처라 winner 만 보이는 거였음. - closure_rate: main.py 가 winner(target_dist) 한 동에만 sim 결과를 주입 → 다른 동은 None 으로 응답 → 프론트 폐업률/생존율 결측. 해결: - _load_dong_density_fallback(business_type) — KakaoStore 카테고리별 동별 매장 수 로드. SEMAS density 가 모두 결측일 때만 fallback 으로 채워서 정규화. - _load_dong_closure_rates(business_type) — store_quarterly 최신 분기 동별 폐업률(0~1 소수) 일괄 로드. ranked row 의 closure_rate 가 None 인 동에만 주입 (winner 의 sim 결과는 main.py 가 덮어쓰므로 보존됨). - _industry_to_cs_code() — 사용자 입력 업종명 → CS 코드 헬퍼. - cache key v13 → v14 (이 변경 반영). 이로써 IndicatorGrid 의 winner 외 동(공덕동/도화동/용강동) 8지표 결측 3개 (경쟁 강도/생존율/폐업률) 가 모두 채워짐. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
API 키 등 비밀값이 들어갈 수 있는 .env.txt 가 untracked 로 노출되던 문제 방지. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
# Conflicts: # frontend/src/pages/landing/EnginePage.tsx
3개 wip 통합 commit: 1. synthesis.py — 캐시 v10 → v11 + '리스크 및 대응' 섹션 LLM 노출 제어 · caution/danger 만 LLM 에 노출, safe 는 블록 외 처리 · 블록 외 항목 hallucination 차단 2. MapSection.tsx — buildBestVacancies 에 50m 근접 중복 제거 · 같은 매물군이 다른 row 로 들어와 1·2·3위가 동일 좌표인 케이스 방어 · DEDUP_RADIUS_M=50, 상위 score 만 유지 → 화면에 #1·#4 만 보이던 회귀 차단 3. MarketMap.tsx — userBrand prop + normalizeBrand helper · sameBrandLocations 는 winner+top3 4동만 수집 — 그 외 동의 자사 매장이 competitors 로 들어오면 별표(자사) 마커로 분기 렌더 · 정규화 비교 (소문자 + 괄호/공백 제거) 로 alias 차이 흡수 (예: "메가엠지씨커피(MEGA MGC COFFEE)" vs "메가엠지씨커피") Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
_compute_synthesis_confidence(agent_attributions, overall_legal_risk,
scouting_results, legal_risks) 신규.
산식:
- base : 다른 에이전트 attribution.confidence 평균.
데이터/모델 fallback 으로 떨어진 에이전트 있으면 자연스럽게 낮아짐.
- legal_adj : danger -0.08, caution -0.03, safe 0.
추천 입지 결정의 절차적 리스크 반영.
- spread_adj : scouting 1·2위 점수 격차 ≥10점 +0.03 / ≤3점 -0.03.
winner 확정도 ↑↓.
- fallback_adj : legal_risks 중 is_fallback 비율 페널티 (최대 -0.05).
clamp [0.5, 0.95]. 이전 0.85 하드코딩으로 모든 시뮬에서 동일 표시되던
회귀 차단.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
… 마이그레이션 근본 fix — 같은 업종 정보가 5개 dict 에 흩어져 동기화 강제 불가능했던 구조적 문제 해소. 새 업종 추가 시 5곳 동기화 → 1곳 (business_type_mapping) 으로 단일화. 폐기된 분산 dict (5개): - district_ranking._industry_to_cs_code → cs_code_of() - district_ranking._VACANCY_SPOT_KAKAO_CATEGORY → kakao_category_of() (2 호출처: _load_spot_score_features + _load_dong_density_fallback) - main._BIZ_TO_KAKAO_KW → kakao_keyword_of() - competitor_intel.BUSINESS_TYPE_FALLBACK → get_entry() (cannibal_label = label_en → _CANNIBAL_LABEL 매핑) - legal.specialists._INDUSTRY_LABEL_MAP → _resolve_cannibal_industry() (label_en → cannibal industry 라벨 매핑 helper 신설) 이번 패스트푸드/중식/일식/양식 결측 회귀 같은 부분 누락 케이스가 구조적으로 차단됨 — 통합 dict 1곳에 등록하면 자동으로 5곳에서 lookup. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This reverts commit f53117a.
이전 commit f53117a (confidence 동적 산출) 의도가 사용자 의도(0.85 고정) 와 충돌해 revert (7998841). 잠시 v11 캐시에 동적 값이 섞였을 가능성 있어 v12 bump 로 강제 무효화. 사용자 의도 (재확인): - LLM 에이전트들 confidence 50%대 → 평균 내면 synthesis 도 낮아짐 - 레이더 차트 양 끝(ranking/legal 만 높음)만 튀어 사용자 신뢰 흔들림 - 마지막 보루로 synthesis 0.85 고정 유지 LLM 에이전트 confidence 산식 자체 재검토는 별도 tech debt 이슈로 분리. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
inflow / district_ranking 제외 7 에이전트 (LLM 의존) 의 출력을 측정 가능한 metric 으로 검증하는 framework. Phase 1 = 토대 + skeleton, Phase 2 (별도 sprint) = 데이터셋 수집 + 실측 백테스트. 평가 분류 (3 그룹): A. 자동 정량 (TCN 백테스트 유사) - trend_forecaster_eval: direction(growth/stable/decline) vs Naver DataLab 6m 후 실측 - competitor_intel_eval: market_entry_signal(green/yellow/red) vs 룰엔진 임계값 B. LLM-as-judge (자연어 본문, 4 차원 채점) - llm_as_judge.py: factuality/relevance/specificity/coherence (각 0~5) - market_analyst_eval: report 본문 - population_eval: report + peak_time 매칭률 가중 - demographic_depth_eval: report + match_score 분포 sanity - synthesis_eval: final_recommendation + 다른 에이전트 정합 강조 C. 인간 검수 (도메인 전문성) - legal_eval: 변호사 review_results.json 입력 → 집계 + 자동 sanity - level/articles/recommendation 가중 (0.4/0.3/0.3) - sanity: 12+ items, level 라벨, 조문 인용 형식 검증 공통 인터페이스: - BaseEvaluator: prepare_dataset / run_one / score / aggregate - EvalResult / EvalSummary (raw + 종합) - async 평가는 ascore + run override (B/C 그룹)⚠️ Phase 1 한계: - 평가 fixture (historical 시뮬 + 정답 라벨) 별도 sprint 필요. - B/C 는 평가 LLM 호출 비용 발생 — 운영 시 batch + sampling 필수. - legal C 는 변호사 외부 자원 확보 후에만 의미. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
scripts/eval/run_competitor_intel_demo.py — framework 동작 검증용. 합성 fixture 10건 (다양한 cannibal/saturation 조합 + LLM signal 오답 패턴). 실행 결과: 정확도 70% (7/10) green→yellow 1, yellow→green 1, red→yellow 1 (위험 과소평가) confusion matrix + 케이스별 ✓/✗ 출력 정상. Windows cp949 콘솔 → UTF-8 강제로 한글/유니코드 깨짐 방지. 다음 단계 (Phase 2): - Redis 캐시 dump → 실제 LLM 출력 fixture 변환 - 실제 LLM 정확도 측정 (이번 70% 는 합성, 의미 X) Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
scripts/eval/run_competitor_intel_real.py — Redis v3:competitor_intel:* 캐시 dump → fixture 변환 → CompetitorIntelEvaluator 실행. 실측 결과 (5건): 정확도 80% (4/5) 오답 1건: 카니발 -50% + saturation medium → LLM yellow (정답 red) → 카니발 50% 캡 도달 시 LLM 이 saturation level 에 가려 위험 과소평가하는 패턴 발견. 다음 개선 액션: 1. 시스템 프롬프트 순서 강화 (카니발 >15% → 즉시 red, saturation 무관) 2. signal 룰엔진 산출 + narrative 만 LLM (분류 정확도 100% 보장) Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
증상: 메가커피 계정으로 치킨 시뮬 돌려도 별표가 메가 카페 매장에 그대로 떠 '하드코딩된 것처럼' 보이는 misalign. 화면 경쟁점은 치킨인데 자사는 카페. 원인: brand_name 은 가입 회사명 자동 = 항상 메가커피. business_type 만 사용자 입력 따라 바뀌므로 두 정보 시나리오 어긋남. 수정 (옵션A — 사용자 결정): - brand_mapping_resolver.get_all_mapo_stores_by_brand: SELECT 에 category 추가 - _collect_same_brand_locations: business_type 인자 추가 + kakao_category 매칭 필터 · target_category = kakao_category_of(business_type) · 매장 category != target_category 면 결과에서 제외 (cat drop) - 4 호출처 (analyze / analyze_llm / analyze_llm_async / simulate) 모두 input_data.business_type 추가 전달 - 단계별 stats 로깅 (전체/동 drop/cat drop/좌표 drop) 효과: - 메가커피 + 커피 시뮬 → 메가 매장 별표 (자사 업종 일치) - 메가커피 + 치킨 시뮬 → 별표 0개 (자사 != 시뮬, 자연스럽게 숨김) - admin 등 업종 매핑 실패 시 카테고리 필터 비활성 (보수적 호환) Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
증상: AI 분석 요약 탭의 '리스크 및 대응' 섹션 끝에 LLM 이 인용한 법률 조문 (예: 제12조의4, 제43조) 이 자주 상권과 무관해 사용자 혼란. 수정: synthesis 프롬프트 룰 #11 강화. - '제○조' / '제○조의○' 패턴 일체 출력 금지 - 법률명만 (예: '가맹사업법') 언급 가능, 조문 번호는 LegalDrawer 가 처리 - 행동 권고만 작성, 조항 인용은 별도 영역에서 캐시 v12→v13 bump (이전 조항 인용 포함 결과 무효화). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
dev 대비 14 커밋. 5개 영역 — 통합 dict 마이그레이션 / 자사 매장 표시 정합 / LLM 평가 framework /
synthesis 프롬프트 강화 / 지도 UX.
🏗️ 통합 dict 마이그레이션 (
37d7240)_industry_to_cs_code/_VACANCY_SPOT_KAKAO_CATEGORY/_BIZ_TO_KAKAO_KW/BUSINESS_TYPE_FALLBACK/_INDUSTRY_LABEL_MAP) →config/business_type_mapping.py단일 source oftruth
🏪 자사 매장 별표 옵션A (
163ecbc)_collect_same_brand_locations카테고리 매칭필터
🎯 추천 spot 1~4위 비교 + 영업구역 룰엔진 (
1c67a06,089d3a0,7a1c806,bd1bdee)카테고리 매칭 필터
🎯 추천 spot 1~4위 비교 + 영업구역 룰엔진 (
1c67a06,089d3a0,7a1c806,bd1bdee)💬 synthesis 프롬프트 강화 (
19235dd,eb54b53,d6de292,e04d80b)🔍 LLM 정확도 평가 framework (
ac4310a,4612824,8c2c873)(market/population/demographic/synthesis) / 인간 검수 (legal)
케이스 1건 오답 패턴 발견
🗺️ 지도·confidence 정책 (
d6de292,7998841,9babf27)Test plan
[same_brand] target_cat=○○ → 4동 안 자사 매장 N개 / cat drop Mcompetitor_intel캐시 v3,district_rankingv13,synthesisv13 무효화 확인python -m scripts.eval.run_competitor_intel_real실행 → 실측 정확도 출력