v4.3.28: 날씨 답변 부실 원인 3종 수정 — 도구 라우팅 + 지오코딩 오지정

"내일 구미 날씨"가 75자 한 문장(기온+하늘상태)으로만 나오던 문제를 추적한 결과,
프롬프트가 아니라 도구 쪽에 원인이 세 개 있었음.

1) weather_search가 더 나은 도구를 밀어내고 있었음
   설명에 "ALWAYS use this for weather/forecast/temperature queries"라는 절대
   지시가 있어 모델이 매번 이걸 골랐는데, 이 도구는 기온 범위와 하늘 상태만
   반환함(강수확률·습도·풍속 없음). 강수확률을 주는 weather_openmeteo가 있는데도
   도달하지 못했음. 두 설명을 각자의 실제 능력에 맞게 정정하고 openmeteo를
   PREFERRED로 표시.

2) 시스템 프롬프트가 없는 데이터를 요구하고 있었음
   OUTPUT FORMAT이 "강수확률·평년대비를 서술하라"고 했으나 모델이 호출한 도구는
   그 값을 주지 않음 — 지시를 따르려면 지어내는 수밖에 없는 구조였음. "받지
   못했으면 지어내지도 말고 조용히 빼지도 말고 weather_openmeteo를 호출하라"로
   변경.

3) ⚠ 구미가 엉뚱한 지역으로 해석되고 있었음 (가장 심각)
   KR_CITY_COORDS에 구미가 없어 Open-Meteo 지오코더로 넘어갔는데, 한국 내 "구미"
   결과 10건 중 실제 구미시(36.12, 128.34)가 하나도 없음. 게다가 모든 항목의
   population 필드가 비어 있어 "인구 최대 선택" 로직이 results[0]으로 붕괴,
   강원도의 작은 마을(38.16)이 선택됐음. 위도 2도 차이 = 다른 기후대인데 에러는
   전혀 나지 않았음 — 사용자는 그동안 남의 동네 날씨를 받고 있었을 수 있음.
   구미 포함 중견도시 25곳의 좌표를 테이블에 직접 추가.

data.go.kr 키는 vault(kma.api_key)에 암호화 저장 — 평문 커밋 없음. 배포 후 확인:
기상청 초단기실황이 구미 기온 32.2°C/습도 60%/풍향 북북서로 정상 응답, 예보
답변도 75자 → 167자로 강수확률·UV지수 포함.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
kim
2026-07-29 16:55:25 +09:00
co-authored by Claude Opus 5
parent 159669ec04
commit a1c653655f
3 changed files with 41 additions and 3 deletions
+33
View File
@@ -111,6 +111,39 @@ const KR_CITY_COORDS: Record<string, [number, number]> = {
'평택': [36.9921, 127.1128], 'pyeongtaek': [36.9921, 127.1128],
'안산': [37.3219, 126.8310], 'ansan': [37.3219, 126.8310],
'용인': [37.2411, 127.1776], 'yongin': [37.2411, 127.1776],
// 2026-07-29: added after "내일 구미 날씨" silently resolved to the WRONG place. Open-Meteo's
// geocoder returns ten 구미 hits for Korea and the real 구미시 (36.12, 128.34) is not among
// them — the list is dominated by tiny hamlets, and because every entry comes back with an
// empty population field the "pick the most populous" tiebreak degrades to results[0], a
// village in 강원도 at 38.16 — two degrees of latitude away, i.e. a different climate.
// No error was ever raised; the user just got someone else's weather.
// Any mid-size Korean city the geocoder cannot pin down belongs in this table.
'구미': [36.1195, 128.3446], 'gumi': [36.1195, 128.3446],
'김해': [35.2285, 128.8894], 'gimhae': [35.2285, 128.8894],
'안양': [37.3943, 126.9568], 'anyang': [37.3943, 126.9568],
'부천': [37.5034, 126.7660], 'bucheon': [37.5034, 126.7660],
'남양주': [37.6360, 127.2165], 'namyangju': [37.6360, 127.2165],
'화성': [37.1996, 126.8310], 'hwaseong': [37.1996, 126.8310],
'시흥': [37.3800, 126.8029], 'siheung': [37.3800, 126.8029],
'파주': [37.7599, 126.7800], 'paju': [37.7599, 126.7800],
'의정부': [37.7381, 127.0337], 'uijeongbu': [37.7381, 127.0337],
'김포': [37.6152, 126.7156], 'gimpo': [37.6152, 126.7156],
'광명': [37.4786, 126.8646], 'gwangmyeong': [37.4786, 126.8646],
'군포': [37.3617, 126.9352], 'gunpo': [37.3617, 126.9352],
'이천': [37.2723, 127.4350], 'icheon': [37.2723, 127.4350],
'양산': [35.3350, 129.0372], 'yangsan': [35.3350, 129.0372],
'거제': [34.8806, 128.6212], 'geoje': [34.8806, 128.6212],
'통영': [34.8544, 128.4331], 'tongyeong': [34.8544, 128.4331],
'경주': [35.8562, 129.2247], 'gyeongju': [35.8562, 129.2247],
'안동': [36.5684, 128.7294], 'andong': [36.5684, 128.7294],
'아산': [36.7898, 127.0018], 'asan': [36.7898, 127.0018],
'충주': [36.9910, 127.9259], 'chungju': [36.9910, 127.9259],
'원주': [37.3422, 127.9202], 'wonju': [37.3422, 127.9202],
'군산': [35.9676, 126.7369], 'gunsan': [35.9676, 126.7369],
'익산': [35.9483, 126.9576], 'iksan': [35.9483, 126.9576],
'순천': [34.9506, 127.4872], 'suncheon': [34.9506, 127.4872],
'광양': [34.9407, 127.6959], 'gwangyang': [34.9407, 127.6959],
'서귀포': [33.2541, 126.5601], 'seogwipo': [33.2541, 126.5601],
};
// Same-named cities across countries (e.g. "Rome" → Rome, Italy vs Rome, Georgia US)