Skip to content

AI 문서 안내 실패 진단 ​

관리자·직원 앱·인사 시트에서 답변이 제공되지 않을 때, 문서 검색과 답변 생성 중 어디서 실패했는지 확인하는 방법입니다. 이 진단은 배포 이후의 요청부터 기록됩니다. 과거의 동일한 실패 문구만으로 원인을 소급 확정할 수는 없습니다.

구현 기준: PR #1246의 chat-intent-v11-state-check / docs-guide-v21-state-check입니다. 색인·문서 스냅샷·10개 안내 기능의 범위와 호출 수는 현재 구조 문서를 따릅니다. 운영 로그는 실제 배포 버전을 먼저 확인합니다.

사용자에게 보이는 결과 ​

상황동작
안내할 기능을 선택하지 못했습니다.화면과 기능 이름을 구체적으로 질문하도록 안내합니다. 등록된 사용법은 한 번에 최대 3개까지 안내하며, 그보다 많거나 목록 밖 기능이 섞이면 일부만 답하지 않습니다.
권한이 없거나 기능·문서 버전 확인이 필요합니다.기존 권한 요청 또는 검토 중 안내를 표시하며 문서 링크는 제공하지 않습니다.
검색 서비스 호출이 실패했습니다.잠시 후 다시 시도하도록 안내합니다.
허용된 문서 근거를 확보하지 못했습니다.관련 안내 문서를 찾지 못했다고 표시합니다.
처리 결과를 화면만으로 추정하는 질문으로 분류됐습니다.실제 내역을 조회하지 않았음을 알리고 결과 확인 전 재실행하지 않도록 안내합니다. 문서 근거가 검증된 경우에만 링크를 함께 반환합니다.
문서는 검증됐지만 답변을 완성하지 못했습니다.답변 실패 안내와 검증된 문서 링크를 함께 제공합니다. 생성 중 텍스트는 노출하지 않습니다.

복합 안내는 모든 기능의 권한을 확인한 뒤 기능별 검색을 병렬 실행하고 답변은 한 번 생성합니다. 각 기능의 검증된 출처를 하나 이상 인용해야 하며, 합친 근거는 5개 출처·12,000자 제한을 유지합니다. 권한 부족이나 검색 실패가 하나라도 있으면 실패한 기능 이름과 사유를 안내하고 부분 답변을 만들지 않습니다. 복합 답변에는 capabilityIds를 저장하며, 다시 열 때 한 기능의 권한이라도 회수됐으면 전체 본문과 링크를 숨깁니다. 복합 답변은 하나의 위치로 연결할 수 없어 위치 보기 버튼을 제공하지 않습니다. 기능 하나를 다시 질문하거나 기능 목록에서 위치를 선택할 수 있습니다.

문서 링크만 제공한 답변도 다시 열 때 현재 권한·기능·문서 버전·링크를 확인합니다. 권한이 회수되거나 문서가 바뀌면 이전 링크를 복원하지 않습니다. 문서 링크 유지가 검증을 생략한다는 의미는 아닙니다.

요청 한 건 확인하기 ​

  1. 실패한 ai.chat 요청의 응답 헤더 x-request-id를 확인합니다. 응답의 messageId는 저장된 대화 메시지 ID입니다.
  2. 서버 로그에서 메시지가 AI guidance diagnostic이고 trace_id가 해당 요청 ID인 기록을 확인합니다. 로그 수집기의 필드 평탄화에 따라 context.trace_id 또는 context_trace_id로 보일 수 있습니다.
  3. 필요한 경우 해당 병원 범위의 ai_messages 한 건에서 toolCalls를 조회합니다. guideAnswer.input에 requestId, capabilityId 또는 capabilityIds, searchStatus, outcome, diagnostics가 있습니다. 처리 중 예외로 종료된 요청은 guideDiagnostics.input에 진단을 보존합니다.
  4. diagnostics는 처리 순서대로 읽습니다. 청크 추가 조회 중 section_incomplete가 나왔어도 나중에 validated가 나오면 문서 검증은 완료된 것입니다. 이후 answer 단계가 실패했다면 검색 실패로 분류하지 않습니다.

DB에서는 병원과 메시지 ID를 모두 지정하고 진단 필드만 조회합니다. 아래 $1, $2는 각각 확인할 조직 ID와 메시지 ID에 바인딩하는 매개변수이며, 해당 병원의 DB 스키마를 선택한 연결에서 실행합니다. 실제 업무 데이터 본문은 조회하지 않습니다.

sql
SELECT m.id,
       item->>'name' AS operation,
       item->>'ok' AS ok,
       item->'input'->>'requestId' AS request_id,
       item->'input'->>'capabilityId' AS capability_id,
       item->'input'->>'outcome' AS outcome,
       item->'input'->'diagnostics' AS diagnostics
FROM ai_messages AS m
CROSS JOIN LATERAL jsonb_array_elements(COALESCE(m."toolCalls", '[]'::jsonb)) AS item
WHERE m."organizationId" = $1
  AND m.id = $2
  AND item->>'name' IN ('guideAnswer', 'guideDiagnostics');

outcome은 answered(출처·형식 검사를 통과한 생성 답변), insufficient_evidence(모델이 근거 부족으로 제출), state_check_required(실제 처리 내역 확인 안내), docs_only(생성 실패 뒤 검증된 출처만 제공), not_answered(그 밖의 미응답)로 기록합니다. 상태 확인 안내는 출처 유무와 관계없이 별도 결과이며, 생성 답변의 정답이나 모델 생성 실패로 합산하지 않습니다. searchStatus=found는 문서를 찾았다는 뜻이며 답변 성공을 보장하지 않습니다.

사유별 확인 순서 ​

단계와 주요 사유확인할 내용
selection: unsupported_request, ambiguous_request, invalid_selection지원 기능을 최대 3개까지 중복 없이 선택했는지, 사용법과 실제 업무 요청이 섞였는지 확인합니다.
authorization: permission_required, feature_unavailable현재 기능·조직·시트 접근 권한과 안내 활성화를 확인합니다.
document: document_unavailable선택한 기능에 연결된 검토 문서와 절이 존재하는지 확인합니다.
configuration: missing_configuration, invalid_queryVoyage 키, 벡터 버킷·인덱스·리전 설정과 검색어 생성 경로를 확인합니다. 로그에는 설정 값을 기록하지 않습니다.
embedding, vector_query, vector_fetch: request_failed, invalid_response, timeout각각 Voyage 임베딩, S3 검색, 누락 청크 추가 조회의 호출 실패·응답 형식·시간 제한을 구분합니다.
vector_query: repeated_page_token, pagination_limit검색 페이지 토큰 반복 또는 조회 한도 초과를 확인합니다.
vector_fetch: neighbor_limit누락 청크를 보충하다 허용된 키 수를 넘었는지 확인합니다.
source_validation: no_results검증에 전달된 청크가 없는지 확인합니다.
source_validation: source_version_mismatch현재 검토 문서와 저장된 청크의 문서 해시가 같은지 확인합니다.
source_validation: source_text_mismatch, section_incomplete본문 비교 불일치인지, 필요한 절 전체를 청크로 증명하지 못했는지 구분합니다.
source_validation: metadata_rejected청크 스키마, 문서 경로, 키 형식의 거절 개수를 확인합니다.
source_validation: invalid_docs_url, invalid_sections, invalid_exclusions, evidence_limit허용 문서 주소, 절 구성, 제외 구간 또는 근거량 제한을 확인합니다.
selection, answer: model_response모델 응답의 종료 사유, 도구 호출 수, 반복 번호, 응답 처리 시간과 토큰 사용량을 확인합니다.
selection, answer: tool_input_rejected모델이 도구를 호출했지만 SDK의 입력 형식 검사에서 거절됐는지 확인합니다. 도구 실행 함수에 도달하기 전의 실패입니다.
selection, answer: tool_completed, tool_execution_failed등록된 도구의 실행 완료 또는 실행 중 예외와 실행 시간을 확인합니다. 도구 완료만으로 최종 안내 성공을 판단하지 않습니다.
answer: missing_submission, multiple_submissions유효하게 접수된 답변 제출이 없거나 두 번 이상 접수됐는지 확인합니다. missing_submission만으로 도구 미호출이라고 단정하지 않으며 직전의 모델·입력 검사 진단을 함께 확인합니다.
answer: invalid_source_ids, missing_feature_sources, unsafe_answer_format검증되지 않은 출처 ID, 복합 질문 중 한 기능의 출처 누락, 또는 허용하지 않는 URL·HTML·Markdown 링크가 답변에 포함됐는지 확인합니다.
answer: state_check_required실제 처리 결과를 추정하는 질문으로 분류돼 고정 안내를 반환했는지 확인합니다. 이 안내는 실제 내역 조회나 모델 답변 생성이 아닙니다.
answer: insufficient_evidence모델이 질문에 답할 근거가 부족하다고 제출했는지 확인합니다. 문서 검색 성공과 답변 가능 여부를 구분합니다.
answer: answer_timeout답변과 형식 복구가 공유하는 제한 시간을 넘었는지 확인합니다. 검색 단계 시간 초과와 구분합니다.
answer: generation_failed문서 검증 이후 모델 호출 또는 답변 제출 처리 중 예외가 발생했는지 확인합니다.

문서 검증 기록에는 검증 대상으로 전달된 retrievedChunks, 일치가 확인된 matchedChunks, 잘못된 형식의 invalidChunks, 다른 문서의 wrongDocumentChunks, 다른 버전의 wrongVersionChunks, 본문 불일치의 unmatchedChunks, 요청한 절 수 requestedSections, 완성된 출처 수 verifiedSources가 있습니다. 중간 검증 결과의 개수를 합산하면 같은 청크를 중복 계산하므로 마지막 검증 기록을 기준으로 판단합니다.

모델 응답과 제출 거절 구분하기 ​

submitGuidance는 Claude가 답변 본문과 출처 ID를 서버에 제출하는 도구입니다. Anthropic SDK는 입력 형식 검사 오류를 모델에게 돌려주는 도구 결과로 변환할 수 있습니다. 따라서 바깥의 예외 처리만 관찰하면 실제 도구 호출이 있었어도 입력 거절을 놓칠 수 있습니다. SDK가 파싱하는 지점의 tool_input_rejected와 실행 함수의 완료·실패를 별도로 기록합니다.

모델 진단의 iteration은 분류 또는 답변 생성 호출 안에서 1부터 시작하므로 요청 ID와 stage를 함께 봅니다. model_response의 durationMs는 해당 응답 스트림을 처리한 시간이며 전체 요청 시간은 아닙니다. tool_completed와 tool_execution_failed의 같은 필드는 도구 실행 시간입니다. inputTokens, outputTokens, cacheReadTokens는 해당 모델 응답의 사용량입니다.

stopReason은 알려진 종료 사유만 기록하고 그 밖의 값은 other로 기록합니다. toolUseCount는 모델이 요청한 도구 수, unknownToolUseCount는 그중 서버에 등록되지 않은 도구 수입니다. toolName에는 서버에 등록된 이름만 기록합니다. 질문·답변·문서 청크·도구 입력·외부 오류 원문과 모델이 만든 임의 도구 이름은 새 진단에 포함하지 않습니다.

최종 missing_submission이 있으면 같은 단계의 앞선 기록을 다음과 같이 해석합니다.

앞선 기록확인할 내용
tool_input_rejected도구 호출은 있었으나 입력 형식 검사에서 거절됐습니다. 이후 정상 제출이 없는지 확인합니다.
model_response, stopReason=end_turn, toolUseCount=0해당 응답은 도구 제출 없이 종료됐습니다. 같은 단계의 다른 반복도 확인합니다.
model_response, stopReason=max_tokens해당 응답이 토큰 한도로 종료됐습니다. 이것만으로 모든 제출 실패의 원인을 토큰 한도로 일반화하지 않습니다.
tool_execution_failed도구 실행 함수에서 예외가 발생했습니다. 입력 형식 검사 실패와 구분합니다.
unknownToolUseCount가 0보다 큽니다.등록되지 않은 도구 호출이 포함됐습니다. 임의 도구 이름 자체는 진단에 저장하지 않습니다.

Grafana에서 API 서버 로그를 수집하고 있다면 같은 trace_id의 AI guidance diagnostic 기록으로 Voyage의 embedding, S3의 vector_query·vector_fetch, Claude의 selection·answer를 함께 확인할 수 있습니다. 이번 모델 진단은 해당 코드가 배포된 후의 요청에만 추가됩니다. 과거 기록을 보충하거나 Grafana 대시보드·자동 알림을 생성하는 변경은 아닙니다.

검증 범위와 운영 확인 ​

회귀 테스트는 외부 전송 부분을 대체하고 실제 검색 결과 검증·답변 처리·이력 권한 검사를 실행합니다. 외부 API를 호출하지 않으므로 비용이나 업무 데이터 변경 없이 실패별 동작을 확인할 수 있습니다. 이 결과는 실제 Voyage·S3·Claude 연동의 성공 증거가 아닙니다.

모델 제출 진단 테스트는 외부 HTTP만 대체하고 실제 Anthropic SDK의 입력 파싱과 도구 실행 루프를 사용합니다. 잘못된 제출 입력, 제출 없는 정상 종료, 제출 없는 토큰 한도 종료, 정상 제출의 네 가지 경우를 확인하며 진단에 본문이 포함되지 않는지도 검사합니다.

원인 코드와 문서 링크 보존은 실패를 진단하고 사용자가 문서를 확인할 수 있게 합니다. 현재 답변 경로에는 상시 의미 검토 모델 호출이 없으며, 제출 누락·일부 형식 오류의 기존 한 차례 복구는 유지합니다. 복구 전후 모두 같은 출처·형식 기준과 답변 제한 시간을 적용합니다. 배포 후 실제 요청의 마지막 실패 단계로 원인을 좁히고 그 원인에 맞는 수정을 진행합니다.

제출 후 대기 줄이기 ​

질문 분류와 문서 답변은 도구에 제출된 구조화 결과를 사용하므로, 제출 후 모델이 생성하는 추가 설명을 사용하지 않습니다. 이 두 경로와 명시적 안내의 기능 선택 경로는 stopAfterToolResult를 사용하여 SDK가 한 응답의 모든 도구 입력 검사·실행을 완료한 뒤 후속 모델 호출을 생략합니다. 정상 자동 안내의 모델 응답 수는 분류 2회·답변 2회에서 각각 1회로 줄어듭니다.

입력 거절·도구 실행 예외·알 수 없는 도구가 있으면 기존 최대 반복 횟수 안에서 SDK 오류 처리를 계속합니다. 같은 응답의 중복 제출은 모두 접수한 뒤 기존 중복 검사로 거절하고, refusal로 끝난 응답의 도구는 실행하지 않습니다. 일반 업무 채팅은 도구 결과를 설명해야 하므로 이 옵션을 사용하지 않습니다. 최종 답변의 출처·형식 검사와 권한·문서 버전 검사는 유지합니다.

시간을 비교할 때는 마지막 진단이 answered인지 먼저 확인합니다. source_version_mismatch 등으로 답변 생성 전에 끝난 요청의 짧은 시간을 개선 성과로 집계하지 않습니다. 같은 모델·질문·검증된 문서로 전체 처리 시간, 단계별 모델 응답 수, 토큰 사용량을 함께 비교하며 모델 응답 시간의 변동을 고려합니다. 이 변경은 게이트웨이 제한을 바꾸거나 504가 발생하지 않음을 보장하지 않습니다.

2026-10-06에 확인한 세 가지 수정 ​

이 절은 당시 버전의 변경 기록입니다. 아래 v2 버전명과 당시 검증 범위를 현재 배포·품질 상태로 해석하지 않습니다. 현재 구현과 검증 범위는 현행 문서를 따릅니다.

S3 본문의 <, >, &, ", ',  는 문서 스냅샷 생성기와 같은 방식으로 한 번만 해석합니다. 문자 표기만 맞추며 문서 해시·경로·본문 전체 일치 검증은 유지합니다. 기존 벡터를 다시 청킹하거나 색인할 필요가 없습니다.

chat-intent-v2와 docs-guide-v2는 복합 사용법을 처리합니다. 실제 업무 실행과 사용법이 섞인 요청은 기존처럼 재질문하고 실행하지 않습니다. 일반 채팅의 chat-v4와 시트의 sheet-explain-v11은 공통 보안 규칙을 공유하지만 다른 어시스턴트로 이동하는 문구는 일반 채팅에만 있습니다. 시트에서 지원하지 않는 실행 요청은 한계를 설명하며, 메뉴 위치를 추측하거나 같은 어시스턴트로 다시 이동하도록 안내하지 않습니다.

새 DB 테이블·마이그레이션·환경 변수는 없습니다. 기존 ai_messages.guidance JSON에 복합 기능 목록을 선택적으로 추가하므로 단일 기능 이력도 계속 읽을 수 있습니다. 구버전 서버는 새 복합 이력을 엄격한 스키마에서 거절하여 상세 답변을 숨길 수 있으므로 같은 버전으로 배포해야 합니다.

별도로 관찰한 CloudFront 504와 30초 응답 제한은 이번 세 가지 수정으로 해결됐다고 보지 않습니다. 로컬 서비스 호출 성공과 dev에 배포된 브라우저 동작을 구분하고, 배포 후 관리자 직원 등록·휴가 승인, 직원 앱 출퇴근, 시트 복합 질문 및 필터 실행 한계 안내를 다시 확인해야 합니다.