v2.2.313~319: 보고 품질·조사 신뢰성 수술 + 네이버 쇼핑인사이트/검색어트렌드 연동

- 파트별 완성, 웹 실접속 증빙, 턴 의도 브리핑, 본문 불일치 검증, 하위 질문
  체크리스트, 사이트 심층 수집 (PATCHNOTES.md v2.2.313~318 참조)
- /naver-shopping, /naver-trend: 네이버 데이터랩 API 연동. compare/discover
  자동 판별, API 배치 상한 캡슐화, 카테고리 트리 fuzzy 매칭, 자격증명은
  Astra 설정 패널 SecretStorage 로 관리
This commit is contained in:
2026-08-05 18:20:32 +09:00
parent 7d6b8b509f
commit c79eda1862
51 changed files with 37435 additions and 89 deletions
+53
View File
@@ -1,5 +1,58 @@
# Astra Patch Notes
## v2.2.319 (2026-08-05)
### 🛍️ 네이버 쇼핑인사이트 · 검색어트렌드 연동 — `/naver-shopping`, `/naver-trend`
사용자 요청: 네이버 쇼핑인사이트·검색어트렌드 API로 "오늘 검색어 많은 키워드 10개" 같은 자연어 질문에 답하고 싶음. 두 API 모두 비교 대상(분야 코드/키워드 묶음)을 미리 지정해야 상대 비율(ratio)만 돌려주는 구조라 "전체 실시간 top-N"을 직접 못 준다 — LLM이 도메인 지식으로 후보를 제안하고 실제 API로 검증해 순위를 매기는 방식(discover 모드)으로 갭을 메웠다.
- **명시 비교(compare) vs 탐색(discover) 자동 판별**: intentParser 가 "패션의류 vs 화장품 비교"는 compare, "요즘 뜨는 뷰티 카테고리"는 discover 로 분류. discover 결과에는 "네이버 전체 실시간 순위 아님" 디스클레이머 고정 부착.
- **API 상한 캡슐화(rankEngine)**: 쇼핑인사이트 카테고리 3개/요청, 검색어트렌드 키워드그룹 5개/요청 상한을 배치 순차 호출 + 병합정렬로 흡수 — 호출자는 "후보 N개 랭킹"만 요청하면 됨. 키워드는 groupName 1개 = keyword 1개로 보내 개별 순위를 보장(같은 그룹에 여러 키워드를 넣으면 API가 합산해버리는 함정 회피).
- **카테고리 매칭(categoryCodes)**: 공식 문서 예시와 교차검증된 대분류 4종(패션의류/화장품·미용/디지털·가전/식품) + 네이버쇼핑 전체 카테고리 트리 4,967건(중/소/세분류)을 fuzzy 매칭 — "원피스" 같은 세부 카테고리도 정확한 cat_id 로 조회.
- **자격증명**: Client ID/Secret 을 Astra 설정 → "Naver Trend" 섹션에서 SecretStorage 로 저장(providerConfig.ts 와 동일 패턴, settings.json 비침범).
검증: tsc 무오류 + jest 1012 통과(신규 13) + esbuild 정상.
## v2.2.318 (2026-07-20)
### ❓ 하위 질문 체크리스트 + 사이트 심층 수집 — "질문 3개에 하나도 답 안 함" 해결
실사례: "어떤 주제인지, 글 퀄리티는 어떤지, 검색 유입자에게 도움이 될지" 3가지를 물었는데 답변은 평가 형용사("가치가 높습니다")만 나열 — 얻어낼 정보가 없음. 원인 2개: 명시된 물음별 답변을 강제하는 장치 부재 + 홈 1장(8천 자)만 수집해 "글 퀄리티" 판단 데이터 자체가 없음.
- **하위 질문 체크리스트 (LLM 없음)**: 물음이 2개 이상 명시된 요청은 규칙 기반으로 물음 절을 추출해 "각 물음에 별도 소제목 + 구체 근거(글 제목·예시)로 답하라, 판단 형용사만은 실패"를 주입. 답변 후 각 물음의 특징 토큰이 답변에 없으면 "미답변 물음 감지" footer 로 어떤 물음이 빠졌는지 목록 표시.
- **사이트 심층 수집 (`webDeepAnalyzeEnabled`, 기본 ON)**: 루트 URL 분석/평가 요청이면 홈 HTML 에서 같은 도메인 글 링크 상위 2개를 추가 수집(병렬) — 실제 글 본문을 근거로 퀄리티를 판단하게 한다. 수집된 글은 실접속 출처·본문 불일치 검증(v2.2.315~317)에도 자동 포함.
검증: tsc 무오류 + jest 999 통과(신규 7) + esbuild 정상.
## v2.2.317 (2026-07-20)
### 🔍 웹 본문 불일치 검증 — "접속했는데도 일반론" 마지막 그물
실사례 후속: koritips.com(실체는 Blogging Tips 블로그)을 "IT 엔지니어 대상 기술 플랫폼"으로 서술 — 실접속 성패 표시(v2.2.315)만으로는 "접속은 성공했지만 모델이 본문을 무시한" 케이스를 못 잡는다. (해당 턴은 장기 세션 히스토리 속 직전 오답 + 미재시작 구버전에서 발생.)
- **본문 반영 검증 (결정론)**: fetch 성공 시 제목·본문 표본의 특징 토큰(도메인 토큰 제외)을 추출해 답변과 대조 — 2개 미만 일치면 "⚠️ 본문 불일치 가능 — 일반론일 수 있음" footer 를 자동 부착. 재요청 문구 안내 포함.
- **도달 증거 텔레메트리**: turn 이벤트 note 에 `webFetch=성공/시도` 기록 — "주입엔 항상 도달 증거를" 원칙을 웹 경로에도 적용.
검증: tsc 무오류 + jest 992 통과(신규 5) + esbuild 정상.
## v2.2.316 (2026-07-20)
### 🎯 턴 의도 브리핑 — "질문 의도를 판단하지 못한다" 구조적 해결
멀티에이전트 보고서 경로에만 있던 의도 브리핑(v2.2.301)을 모든 실질 요청 턴으로 확장. 소형 로컬 모델은 "의도를 파악하라"는 추상 지시(기존 [답변 전 이해 원칙] 4줄)를 실행하지 못한다 — 파악된 의도를 *텍스트로 받아야* 따른다 (강제 주입 패턴 6번째 적용).
- **매 요청 턴 브리핑 추출**(`intentBriefEnabled`, 기본 ON): 목적 / 진짜 궁금증(1~3) / 기대 산출물 형태 / 독자(본인·경영진·팀) / **근거 경로(web·local-files·brain·general)** / 명시 제약 — LLM 1회(JSON)로 추출해 보호 구역(dynamicBlocks)에 주입. "이 브리핑에 답하는 것이 성공 기준, 첫 문장은 목적에 대한 결론"을 명시.
- **근거-경로 강제**: web 이면 "[URL CONTENT] 실데이터만 근거, 없으면 접속 실패 명시, 일반 지식 평가는 금지", local-files 면 "실제 읽은 파일만 근거, 부족하면 read/investigate 먼저" — koritips.com 실사례(근거 경로 착오)의 상류 방어.
- **지연 상쇄**: 브리핑은 retrieval(1~8초)과 *병렬* 실행 — 체감 추가 지연 최소. 실패/타임아웃(10초)은 조용히 브리핑 없이 진행. `intentBriefModel` 로 빠른 소형 모델 지정 가능.
검증: tsc 무오류 + jest 987 통과(신규 10) + esbuild 정상.
## v2.2.315 (2026-07-20)
### 🌐 웹 실접속 증빙 — "사이트 분석"이 실접속 없이 일반론으로 끝나는 할루시네이션 차단
실사례: "HTTPS://KORITIPS.COM 분석·평가해줘" → 실접속 여부가 어디에도 안 보이는 일반론 전략 제언 + 파일 기준 오탐 경고("파일 미확인 분석")까지 붙어 혼란.
- **턴 단위 웹 접속 추적 + 결정론 표시**: URL 포함 요청은 접속 성패를 코드가 기록하고 답변에 박는다 — 전부 실패면 답변 *맨 위*에 "⚠️ 사이트 실접속 실패(사유) — 아래는 일반 지식 추정" 경고, 성공이면 답변 끝에 "🌐 실접속 확인: <URL> 본문을 근거로 사용" 출처. "접속 실패를 알리라"는 프롬프트 지시(소형 모델이 무시)를 코드 강제로 대체.
- **오탐 수정**: URL 요청에는 파일 액션 기준의 "파일 미확인 분석" footer(v2.2.313)를 띄우지 않는다 — 웹 분석은 파일을 읽을 이유가 없다.
- **라우팅 구멍 봉쇄**: URL 포함 요청은 멀티에이전트 워크플로우로 보내지 않는다 — 그 경로엔 웹 접근(URL 실데이터 주입)이 아예 없어 "사이트 조사해줘"가 실접속 0회 보고서로 끝났다. 단일 턴만 URL 본문을 주입받는다.
검증: tsc 무오류 + jest 977 통과(신규 5) + esbuild 정상.
## v2.2.314 (2026-07-20)
### 🛟 본문 증발 구제 + 내부 섹션 유출 제거
실사례 2건: ① 분석 답변이 화면에 작성되다가 전부 지워지고 "이상으로 분석을 마칩니다"만 남음 — 모델이 본문 전체를 LSEP 추론 구간에 쓰고 가시 답변은 마무리 인사 한 줄만 낸 것(추론 숨김 처리가 본문까지 폐기). ② "요청 요약/사용자 의도 추론/프로젝트 기록 대상 확인/핵심 확인 질문" 내부 스캐폴딩 섹션이 답변에 그대로 노출.
- **LSEP 마무리-인사-만 감지 → 3단 구제**: 마커 뒤가 마무리 인사뿐(<300자)이고 앞이 장문이면 thought-only 로 간주해 ① final-only 재생성 발동(이제 continuation depth 에서도 허용 — 분석 보고의 최종 라운드가 정확히 이 지점에서 실패했었다), ② 재생성도 실패하면 마커 앞 텍스트가 명백한 보고 형태(헤딩/불릿/문단 다수)일 때만 구제 승격 — 화면에서 지워진 그 본문을 되살린다. 형태가 애매하면 승격 안 함(생각 과정 노출 회귀 방지).
- **내부 섹션 유출 결정론 제거 (stripLeakedInternalSections)**: 규칙 4가 금지하는 스캐폴딩 섹션 + "질문 의도:" 줄을 최종 답변에서 걷어낸다. Project Record Guard 턴(designerContext 활성)은 가드가 요구하는 섹션이므로 보존.
검증: tsc 무오류 + jest 972 통과(신규 6) + esbuild 정상.
## v2.2.313 (2026-07-20)
### 🧩 파트별 완성 + 파일 미확인 분석 경고
실사례: 프로젝트 분석 답변이 "답변이 길어 자동으로 이어 정리했지만 여전히 길이 한계에 닿았습니다"로 끝나며 사용자에게 "나눠 질문하라"고 떠넘김 + 실제 파일은 하나도 안 읽고 사전 주입된 아키텍처 요약만으로 작성돼 구조 상세가 없었음.
- **파트별 완성 (`sectionedCompletionEnabled`, 기본 ON — 사용자 제안 구현)**: 보고서·분석형 답변이 자동 이어쓰기로도 출력 한계에 닿으면, ① 남은 섹션 제목 추출(1회) → ② 섹션마다 *독립 호출*로 본문 생성(호출당 출력 예산 온전, 업무 유형 필수 요소를 outline 에 우선 반영) → ③ 결정적으로 이어 붙여 **한 문서로 통합**. 섹션 호출은 시스템+히스토리 프리픽스를 재사용해 KV 캐시로 프리필이 저렴하다. 실패 시 종전 안내로 폴백.
- **파일 미확인 분석 경고 (3번째 그물)**: 로컬 프로젝트 분석 요청인데 이 턴에 액션(read/list/investigate)을 한 번도 안 쓰고 장문 분석을 낸 경우 "⚠️ 파일 미확인 분석" footer — hollow(목록만 봄, v2.2.309)·ungrounded(읽고도 인용 없음, v2.2.312) 둘 다 액션 1회 이상을 전제해 놓치던 사각지대.
검증: tsc 무오류 + jest 966 통과(신규 12: sectionedCompletion 7 + unreadAnalysis 5) + esbuild 정상.
## v2.2.312 (2026-07-20)
### 📋 보고 품질 — "## 4.부터 시작하는 보고서" 버그 + 일반론 총평 차단
실사례: "connectai 프로젝트를 분석하고 보고해줘" → 답변이 "## 4. 종합 분석 결과"부터 시작(1~3 증발), 내용은 프로젝트명을 바꿔도 성립하는 7줄 일반론.