5.7 KiB
5.7 KiB
운영 안정화 · 예외 처리 · 보안
원본 요구 3단계: "예상 가능한 상황을 확인하고, 각 예외에서 재시도 · 실행 중단 · 담당자 이관 · 알림 중 어떤 처리가 실행되는지 설정하고, 개인정보와 접근 권한이 흐름과 로그에 반영되는지 점검합니다." 이 문서는 그 표를 미리 채운 출발점입니다. 팀은 자기 워크플로우에 맞게 고치고 실제로 일으켜 보고 결과를 결과서에 씁니다.
1. 예외 처리 표 (설계서 7절의 출발점)
| 상황 | 알아채는 법 | 처리 | 사용자에게 | 기록 | 시나리오 | 64~79일차 |
|---|---|---|---|---|---|---|
| 잘못된 입력 | Code 검사 | 즉시 400 | codes |
형식 오류 수 | WF-13 | 73 |
| 인증 실패 (Webhook 키) | n8n Header Auth | 401 (n8n) | — | n8n 실행 기록 | 팀 | — |
| 인증 실패 (외부 API 401 · 403) | HTTP 상태 | 재시도 없이 중단 → 이관 | "담당자에게 연결합니다" | 알림 severity: high |
팀 | 76 |
| 호출 한도 초과 (429) | HTTP 상태 | Retry-After만큼 기다려 재시도 (최대 N회) → 이관 |
이관 안내 | 재시도 수 | 팀 | 72 · 75 |
| 외부 서비스 장애 (5xx) | HTTP 상태 · 오류 출력 | 재시도 1~2회 → DLQ + 알림 → 이관 | 이관 안내 (ticket: null이어도 200) |
DLQ · 알림 | WF-04 | 72 · 76 |
| 외부 서비스 느림 | timeout |
시간 초과 → 대체 경로 | 정해진 시간 안 답 | reason |
WF-11 | 72 |
| LLM 멈춤 · 시간 초과 | Agent 오류 출력 | 근거 원문 안내 또는 이관 (fail-closed: 판별 · 검증이 멈추면 자동 답변하지 않음) | 이유 있는 안내 | reason: llm_down |
WF-10 | 72 · 73 |
| 검색 결과 없음 · 점수 미달 | Code (점수 기준) | 답 생성 중단 → 이관 | "확인 후 담당자가 연락" | reason: no_evidence |
WF-03 | 71 |
| 검증 실패 (근거 밖 내용) | 검증 Agent + Code | 이관 (또는 한 번 다시 쓰기) | 이관 안내 | issues |
팀 | 69 |
| 중복 요청 | request_id 캐시 · 티켓 key |
저장된 결과 그대로, 티켓 하나 | 같은 답 | duplicate |
WF-09 | 72 · 76 |
| 프롬프트 주입 | 규칙 · 판별 | 차단 (LLM 앞에서) | 정해진 안내 | security |
WF-08 | 73 |
| 권한 없음 | 데이터 API 403 · 메타데이터 | 권한 없음 | 정해진 안내 | security |
WF-05 · 06 | 73 |
| 처리 못 한 예외 (버그) | Error Workflow | 알림 + DLQ | (n8n이 500) | 알림 | 팀 | 76 |
재시도 원칙 (72 · 76일차)
| 다시 해도 되는 것 | 다시 하면 안 되는 것 |
|---|---|
| timeout, 5xx, 429 (기다린 뒤) | 400 · 401 · 403 · 404 (요청 · 권한이 틀림, 몇 번 해도 같음) |
| 조회 (GET) | 같은 생성(POST)을 key 없이 (티켓이 두 개 생김) → 중복 방지 key를 달면 다시 해도 됨 |
- 최악의 시간 = 시도 수 × timeout + 기다림. 응답 시간 기준(예: 6초) 안에 들어오게 정합니다 (72일차).
- 재시도도 실패하면 DLQ에 남깁니다: 무엇을(요청 요약 · 개인정보 없이), 왜(사유), 몇 번(시도 수). 나중에 다시 처리(76일차 replay)할 수 있어야 합니다.
- 알림은 실패마다가 아니라 사람이 할 일이 있을 때 보냅니다. 같은 장애로 알림이 100개 오면 아무도 보지 않습니다 (76일차 묶어 보내기).
2. Error Workflow (원본 "실행 중단 · 알림")
- n8n 워크플로우 설정의 Error Workflow에 팀의
<팀>-errors를 지정하고, 그 워크플로우는 Error Trigger → 알림(POST /alerts) → DLQ로 둡니다 (76일차). - 오류 출력(
onError: continueErrorOutput)으로 예상한 실패를 처리하고, Error Workflow는 예상하지 못한 실패의 마지막 그물입니다. 둘 다 둡니다. - Error Workflow는 게시(활성화)되어 있어야 동작합니다.
3. 보안 기준 (73일차를 프로젝트에)
| 기준 | 확인 방법 |
|---|---|
| 입력 검증은 LLM 앞에서 | WF-13 400, LLM 호출 0 |
| 주입 차단 (규칙 + 판별, 글자 정리) | WF-08, 팀 시나리오에 숨긴 공격 하나 |
| 정상 질문을 막지 않음 | 팀 시나리오 "지나치게 막지 않음" |
권한의 근거는 시스템 (user → /employees의 dept, requester=user) |
WF-05 · WF-06 |
| 지시문(systemMessage)에 비밀 없음 | 워크플로우 JSON grep |
| 출력 필터 (전화 · 메일 · 주민번호 가림) | WF-07, security.masked |
| 티켓 본문 · 알림 · 로그에도 개인정보 가림 | GET /tickets-created, GET /alerts, 로그에 연락처 모양 0 |
| 키는 Credential에만 | 워크플로우 JSON · 문서 · 저장소에 키 없음 (tscan scan .) |
4. 실행 기록 (원본 결과서 2절 "실행 로그")
요청마다 한 줄을 남깁니다 (POST /logs, 73일차 감사 로그 · 77일차 실행 기록).
{"request_id": "req-001", "user": "박서연", "started_at": "...", "ended_at": "...", "route": "자동 답변",
"agents": ["triage", "retriever", "writer", "verifier"], "nodes": 14, "llm_calls": 3,
"sources": [{"doc": "remote-work-vpn", "score": 0.71}], "retries": 0, "external": {"tickets": "ok"},
"error_code": null, "masked": 0, "total_ms": 2840}
| 남김 | 남기지 않음 |
|---|---|
| 원본 요구 결과서 2절의 칸: request_id · 시각 · 실행 노드 · 외부 API 상태 · 재시도 수 · 검색 문서 ID와 점수 · 최종 분기 · 오류 코드 · 마스킹 여부 | 질문 · 답 글자 전체, 연락처 (가린 것도) |
- 결과서의 "노드별 입력 · 출력 요약"은 n8n 실행 화면(Executions)에서 시나리오마다 한 번 캡처하거나 복사합니다 (개인정보를 가리고).