RCA (근본 원인)
알림 발화 시 Ongrid 는 incident-investigator persona 에 대해 그래프 커널 기반 ReAct 에이전트를 구동하는 LLM worker 를 스폰하고, 증거 수집을 위해 도구를 호출하며, 구조화된 보고서를 investigation_reports 에 다시 씁니다.
보고서는 SPA 의 /alerts/incidents/:id 페이지에 발화 시리즈 옆에 렌더링됩니다 — 인간 SRE 는 "빈 prompt 에서" 시작할 필요가 없습니다.
HLD-013
현재 파이프라인은 HLD-013 의 Phase 1+2 인과 모델을 안착합니다. 단순한 "무엇이 발화했는지 요약" 접근 (PR-2) 은 운영자가 알람 텍스트 요약이 아닌 zero patient — 캐스케이드를 시작한 특정 프로세스 / 컨테이너 / 라인 — 을 원한다는 것이 명확해진 후 교체되었습니다.
생명주기
incident.fire (isNew=true)
└─ alert.Usecase.RecordFiring
└─ Investigator.InvestigateAsync(incident)
└─ Enqueue → Gate 1-3 (severity, inflight, semaphore)
└─ repo.Create(pending row) ← UI shows "investigating…"
└─ go run(reportID, incident, dedupKey, locale)
├─ spawner.SpawnWorker(incident-investigator persona)
├─ worker drives the ReAct loop with tools
├─ Pass-2 structured extraction (cheap model)
└─ repo.MarkReady(report fields) ← UI shows readyInvestigateAsync 는 alert.Usecase 가 호출하는 공개 seam — usecase.go:301 참고.
게이트
worker 가 스폰되기 전 세 게이트가 필터링. 각 거부는 status=skipped 행으로 영속화되어 SPA 가 운영자에게 "절대 시작 안 됨" 대신 이유를 보여 줍니다.
| Gate | 기본 | Miss 시 동작 |
|---|---|---|
Severity floor (Config.MinSeverity) | warning | 조용한 skip, 행 미작성 |
In-process inflight (incident_id 별) | 항상 on | 조용한 병합 |
동시성 상한 (Config.MaxConcurrent) | 5 | skipped: concurrency limit reached (N workers in flight) 행 |
동시성 상한은 LLM provider rate-limit 을 방어하고 한 번에 100 incident 가 발화할 때 RAM 을 제한. 상한 초과 호출자는 큐가 아닌 명시적 skipped 행을 받음.
Worker
런타임이 chatruntime.SpawnRequest 로 worker 스폰:
// internal/manager/biz/alert/investigator/usecase.go:571
worker, err := uc.spawner.SpawnWorker(ctx, chatruntime.SpawnRequest{
AgentName: uc.cfg.AgentName, // "incident-investigator"
Prompt: prompt,
Background: false,
SessionKind: "investigation",
})prompt 는 renderAlertPrompt 가 렌더링하며 포함:
- Incident 메타데이터 (규칙, 심각도, device_id, 값, 임계값, 요약).
- 명시적 시작 지시:
Start with correlate_incident to pull metrics + logs + traces + topology around the fire window. - 하드 예산: 최대 10 도구 호출, 호출 #7 까지 보고서 작성 시작해야 함. 이 예산은 사용자 메시지에 있는 이유 — 비 frontier 모델 (GLM, DeepSeek) 이 system 메시지 제약보다 사용자 메시지 제약을 더 신뢰성 있게 따르기 때문. 없으면 eino MaxStep 상한이 매번 다른 실행 마다 도달했습니다.
- 운영자의 UI 로케일로 persona 의 암묵적 언어를 오버라이드하는 locale 지시 (로케일이 어떻게 전파되는지는 Models / Routing 참고).
도구 예산 + salvage
eino ReAct 그래프가 총 단계를 상한. worker 가 최종 답 작성 없이 상한을 소진하면 investigator 는 부분 흔적을 salvage:
MessageReader.ListMessages(sessionID, limit=100)가 모든 턴을 풀.- Assistant + 도구 메시지가 합성 "우리가 찾은 것" markdown 으로 연결.
- Salvage 는 같은 Pass-2 추출기를 통해 공급.
- 보고서는 낮은 신뢰도 노트가 prepend 된
ready로 표시:工作器超出最大步数预算(exceeds max steps);以下为根据已收集工具结果的局部分析,置信度偏低。
Salvage 없이는 운영자가 유용한 데이터 없이 status=failed 를 봤습니다 — worker 가 보통 10+ 도구를 호출하고 답을 모았지만 합성 턴을 절대 작성하지 않았습니다.
구조화 추출 (Pass 2)
Worker 의 최종 assistant 메시지는 markdown — SPA 는 구조화 필드가 필요. 두 번째, 저렴한 LLM 호출이 추출:
root_cause— 한 문단 TL;DR.affected_window— 증상 span 이 언제 시작 / 정지.pinpointed_target— 변경된 특정 프로세스 / 컨테이너 / 파일.related_alerts— 공동 발화 incident (RelatedAlertQuerier경유).evidence— 불릿 소스 인용 (PromQL 출력, 로그 라인 등).suggested_actions— 운영자 실행 가능한 다음 단계.confidence+confidence_factors.tool_call_count—chat_messages에서 다시 읽어 UI 가 worker 가 실제로 호출한 도구 수를 표시 (하드코딩 0 아님).
Config.SummarizerProvider / Config.SummarizerModel 로 구성 가능한 모델 + provider. 기본 30 초 타임아웃 (짧은 prompt, 짧은 답, 도구 루프 없음).
추출기가 미배선이거나 에러일 때 폴백은 root_cause 채우기를 위해 worker 의 markdown 위에 firstParagraphOneLine 을 사용하고 전체 markdown 을 그대로 findings_md 로 출하.
Bold 헤더 함정
firstParagraphOneLine (usecase.go:846) 은 순수 markdown scaffolding (헤딩, 구분선, 완전 bold 섹션 제목) 을 건너뛰어 root_cause 가 **현상** 이 아닌 문장으로 읽히게 합니다. 이전 버그는 선행 ** 만 제거하고 후행 쌍을 남겼습니다 — 같은 함수에서 수정됨.
수동 재트리거
POST /v1/alerts/incidents/{id}/investigation
Accept-Language: enForceEnqueue 가 수동 경로 실행:
- 이 incident 에 대해 현재 실행 중인 worker 중지 (best-effort — 재시작 후 worker_id 가 만료되어 있으면 경고하고 계속).
- 이전
investigation_reports행 하드 삭제 (이전 force-enqueue 에서 soft 삭제된 행을 커버하여 고유incident_id인덱스가 다음 Create 를 거부하지 않도록). - inflight 가드 해제.
Accept-Language에서 파싱된 locale 로EnqueueWith호출하여 재생성된 보고서가 운영자의 UI 언어로 돌아오게.
Severity floor 는 여전히 적용 — info 레벨 incident 에 대한 수동 트리거는 severity below floor 에러를 반환.
부팅 시점 백필
신규 설치는 닭과 달걀 문제를 만남: 구조화 RCA 체인은 최소 하나의 LLM provider 가 구성되어야 배선되지만 incident 는 운영자가 provider 를 추가하기 전에 발화할 수 있습니다. BackfillUnstartedIncidents 는 부팅 시 실행되어 ListIncidentsWithoutReport(since, limit) 를 워크하고 윈도우에서 발화한 모든 것을 재 enqueue. 일반 게이트는 여전히 적용되어 해결된 incident 와 floor 초과 incident 는 건너뜀.
배선은 cmd/ongrid/main.go 참고 — 24 시간 윈도우로 시작 시 실행.
같이 보기
- 알림 — 무엇이 발화하나.
- 토폴로지 —
expand_topology가 investigator 의 영향 범위 워크에 노출하는 것. - 기능 —
correlate_incident,get_incident_detail,query_promql,search_logs: worker 가 호출하는 도구. - Models / Routing — investigation 별 로케일 + provider 가 어떻게 해석되는지.
- Models / Budget — investigation 비용을 제한하는 전역 일일 토큰 상한.