fix: 재해 질문을 news_search로 유도 — web_search 기본 쿼리가 실제 사건을 놓침
실제 사고(2026-08-10): "태풍 돌핀 지금 어디 있지?"에 web_search가 자체 생성한 "태풍 돌핀 현재 위치 실시간 정보" 쿼리로 검색해 일반적인/내용없는 결과 3개(기상청 빈 포털, 오래된 지도 SPA, 무관한 결과 1개)만 받았다. 모델은 정직하게(좌표를 지어내지 않고) "검색결과가 없으니 이미 소멸했을 가능성이 높다"고 추론했다 — 추론 자체는 멀쩡했지만 전제(검색해도 안 나온다)가 검색 실패 때문에 거짓이었다. 실제로는 돌핀이 막 중국에 상륙해 500mm 폭우 경보, 100만명 이상 대피 중이었고, 같은 사건을 다룬 국내 언론사 기사가 6개 이상 있었다 — "태풍 돌핀 중국 상륙 피해"처럼 상황어를 넣은 쿼리로는 바로 찾아졌다. news_search(NewsData.io, 실제 발행일 보장)가 정확히 이런 "지금 벌어지고 있는 일" 질문을 위한 도구인데, 재해 질문은 뉴스로 분류되지 않아 (isNewsRequest는 "뉴스/속보" 키워드가 있어야 걸림) 이 라우팅을 안 탔다. isLiveDataRequest 안에 있던 재해 정규식을 isDisasterRequest로 분리해 handle-chat.ts의 사전 리마인더와 AUTO-RECOVER 재시도 리마인더 양쪽에 재사용했다 — 이 파일 헤더의 원칙대로, 검증을 강제하는 게이트끼리 어긋나면 한쪽만 고친 게 무의미해진다. 재해 질문엔 news_search를 우선 권하고, web_search를 쓰더라도 "현재 위치/실시간 정보" 같은 일반 쿼리 대신 "...상륙 피해", "...대피" 같은 상황어를 쓰도록 안내한다. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -28,6 +28,7 @@ import {
|
||||
isMessagingRequest,
|
||||
isCancelIntent,
|
||||
isRerunIntent,
|
||||
isDisasterRequest,
|
||||
} from '../src/gateway/guards/prompt-gates';
|
||||
|
||||
describe('looksLikeUnverifiedSpecClaim — 출력에서 검증 안 된 수치 감지', () => {
|
||||
@@ -277,6 +278,36 @@ describe('isNewsRequest / isLiveDataRequest', () => {
|
||||
});
|
||||
});
|
||||
|
||||
// [2026-08-10] isLiveDataRequest의 인라인 재해 정규식을 분리한 것 — handle-chat.ts의 검색
|
||||
// 리마인더가 재해 질문에도 news_search를 권하도록 재사용하기 위함. 실제 사고: "태풍 돌핀 지금
|
||||
// 어디 있지?"에 web_search가 자체 생성한 "현재 위치 실시간 정보" 쿼리로 검색해 일반적인/내용없는
|
||||
// 결과 3개만 받았고, 모델은 정직하게(수치를 지어내지 않고) "이미 소멸했을 가능성이 높다"고
|
||||
// 추론했다 — 틀린 결론이었다. 같은 날 같은 사건을 다룬 국내 언론사 기사가 6개 이상 있었는데,
|
||||
// "태풍 돌핀 중국 상륙 피해"처럼 상황어를 넣은 쿼리로는 바로 찾아졌다. 추론 자체는 멀쩡했지만
|
||||
// 전제(검색해도 안 나온다)가 검색 실패 때문에 거짓이었다 — news_search(NewsData.io, 실제
|
||||
// 발행일 보장)가 정확히 이런 "지금 벌어지고 있는 일" 질문을 위한 도구다.
|
||||
describe('isDisasterRequest — 재해 질문을 news_search로 유도', () => {
|
||||
test('태풍/지진 등 재해 키워드를 잡는다', () => {
|
||||
assert.equal(isDisasterRequest('태풍 돌핀 지금 어디 있지?'), true);
|
||||
assert.equal(isDisasterRequest('방금 지진 났어?'), true);
|
||||
assert.equal(isDisasterRequest('산불 피해 상황 어때'), true);
|
||||
});
|
||||
|
||||
test('재해 키워드 없는 일반 질문은 안 잡는다', () => {
|
||||
assert.equal(isDisasterRequest('오늘 서울 날씨 어때'), false);
|
||||
assert.equal(isDisasterRequest('파이썬 리스트 정렬법'), false);
|
||||
});
|
||||
|
||||
test('긴 붙여넣기 문서 한가운데의 우연한 재해 키워드로는 안 잡힌다', () => {
|
||||
const doc = '회의록을 정리해주세요.\n'
|
||||
+ '참석자 발언을 순서대로 기록했습니다.\n'.repeat(20)
|
||||
+ '작년 태풍 피해 복구 예산 집행 내역을 참고자료로 첨부합니다.\n'
|
||||
+ '이후 논의는 다음 안건으로 넘어갔습니다.\n'.repeat(20);
|
||||
assert.ok(doc.length > 600);
|
||||
assert.equal(isDisasterRequest(doc), false);
|
||||
});
|
||||
});
|
||||
|
||||
describe('isUsableGroundingResult — 빈 검색결과 판별', () => {
|
||||
test('실제 내용이 있으면 사용 가능', () => {
|
||||
assert.equal(isUsableGroundingResult({ result: '[1] 어떤 기사 제목' }), true);
|
||||
|
||||
Reference in New Issue
Block a user