feat(growth): 자기 지식 자동화 + 회귀 경보 + 충돌 스캔 + Critic 게이트 확장 (v2.2.225)

[근본 수정 — 자가검증 구식 정보 버그]
ASTRA 자기 지식이 사람이 쓴 스냅샷(selfIdentity 블록·아키텍처 위키 문서)에
의존해 릴리스마다 구식이 됐고, 자기 개선 제안에서 이미 있는 기능을 신규
제안하는 오류가 반복됨. 수정:
- featureInventory.ts: 활성화 시 package.json(contributes.commands/configuration)
  + POST_ANSWER_HOOKS 레지스트리에서 "ASTRA 기능 인벤토리" 문서를 두뇌에
  기계 생성 (버전 변경 시 자동 재생성 — 사람이 갱신을 잊을 수 없는 구조).
- selfIdentity: "자기 기능 평가·제안 전 인벤토리와 대조, 기억 의존 서술 금지" 규칙.

[검증-피드백-재설계 파이프라인 보강 — 의견 검토 후 역제안 3건]
- A-1 골든셋 회귀 경보: 주간 사이클이 metrics-history.jsonl 적립 + 직전 대비
  recall@1 -10%p 또는 MRR -0.08 하락 시 ⚠️ + 그 기간 추가된 문서를 용의자로
  제시(regression-alert.md). 자동 롤백 없음 — 판단은 사람.
- A-2 신규 지식 충돌 스캔(conflictScan.ts): 일일(사전 소화와 같은 슬롯) 신규/변경
  문서를 기존 유사 top-2와 LLM 모순 비교 → 충돌 시 conflict-report.md +
  "기존 A vs 신규 B" 알림. 쓰기 주체(Datacollect/수동/Research) 무관 포착.
  런당 비교 ≤5건·최초 실행 24h 한정 (폭주 방지).
- A-3 criticLoop 게이트 확장: 업무 turn 외에도 "근거 약함(top<0.25) + 단정
  표현(수치·날짜·확언)" 트리거 추가. 전 답변 강제 2-pass 는 기각 — intrinsic
  self-correction 은 외부 신호 없이 효과 없음(arXiv 2310.01798).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-06-12 11:44:58 +09:00
parent 7584c6bbc1
commit b03a49bfc3
10 changed files with 369 additions and 8 deletions
+13 -5
View File
@@ -174,20 +174,28 @@ const criticLoopHook: PostAnswerHook = {
if (cfg.criticLoopEnabled === false) return;
if (!ctx.userPrompt.trim() || !ctx.assistantAnswer.trim()) return;
// 게이트 — 결정론적 검사가 문제 신호한 업무 turn 에만 LLM 검수 1회
// (로컬 모델 latency 보호: 깨끗한 답변에는 안 돈다).
// 게이트 — 문제 신호가 있는 turn 에만 LLM 검수 1회 (로컬 latency 보호).
// 트리거 2종:
// (a) 업무 turn: 결정론적 검사가 요소 누락 또는 저확신(<70)을 신호
// (b) 일반 turn: 두뇌 근거 약함(topScore<0.25)인데 답변이 수치·날짜·단정
// 표현을 포함 — intrinsic self-correction 은 효과 없으므로(2310.01798)
// 검수는 외부 신호(근거 약함이라는 검색 측정값)가 있을 때만 발동.
const task = detectTaskType(ctx.userPrompt);
if (!task) return;
const coverage = checkRequirementCoverage(ctx.userPrompt, ctx.assistantAnswer);
const retrievalSignals = ctx.confidenceSignals ?? {
chunkCount: 0, topScore: 0, conflictCount: 0, ambiguityDetected: false,
};
const ASSERTIVE_RE = /\d{4}년|\d+월\s*\d+일|\d+(\.\d+)?\s*(%|배|건|개|원|달러)|입니다|확실|반드시|분명히/;
const weakAssertive = retrievalSignals.topScore < 0.25
&& ctx.assistantAnswer.length > 200
&& ASSERTIVE_RE.test(ctx.assistantAnswer);
if (!task && !weakAssertive) return;
const coverage = checkRequirementCoverage(ctx.userPrompt, ctx.assistantAnswer);
const answerSignals = extractAnswerSignals(
ctx.assistantAnswer,
coverage.ran ? coverage.missing.length : null,
);
const confidence = computeConfidence(retrievalSignals, answerSignals);
const needsReview = (coverage.ran && coverage.missing.length > 0) || confidence.score < 70;
const needsReview = (coverage.ran && coverage.missing.length > 0) || confidence.score < 70 || weakAssertive;
if (!needsReview) return;
const critique = await runCriticReview({