Files
vpd-permission-poc/docs/design/hmm-html-report-mcp/troubleshooting.md
2026-08-10 18:02:49 +09:00

7.9 KiB

문제 해결

텍스트만 답하고 리포트가 생성되지 않음

원인: 포털이 단일 조회만 실행했거나, MCP discovery 결과에 이전 결과 입력형 렌더러가 없다.

확인:

  1. 포털 설정 endpoint가 https://hmm-backoffice.cloud-handson.com/mcp인지 확인한다.
  2. tools/list 결과에 조회 도구와 reportJson 입력을 가진 HTML/리포트 렌더러가 모두 있는지 확인한다.
  3. 포털 실행 상세에서 실행 방식이 agent, Agent 단계가 두 번인지 확인한다.

해결: endpoint와 허용 목록을 함께 갱신한 뒤 포털 서비스를 재기동한다. 렌더러 설명에는 조회 결과 후속 처리처럼 선행 결과를 받는다는 문구를 유지한다.

재발 방지: 새 업무 리포트 도구도 reportJson류 입력과 후속 처리 의도를 설명에 선언한다. 포털 코드에 특정 도구명을 추가하지 않는다.

렌더러가 입력 형식 오류를 반환함

원인: 조회 도구가 items/results 배열을 반환하지 않거나, 렌더러가 요구하는 payload 계약과 템플릿 계약이 다르다.

확인: 첫 Agent 단계의 응답에 행 배열이 있는지, 두 번째 단계 arguments에 reportrows가 있는지 확인한다. 비밀값·Bearer token은 실행 상세에 남기지 않는다.

해결: 조회 도구는 구조화 행 배열을 반환하고, 렌더러 함수는 reportrows 계약을 유지한다.

생성된 HTML이 화면에 표시되지 않음

원인: 렌더러 응답에 html 문자열이 없거나, HTML이 유효하지 않다.

확인: 두 번째 MCP 응답의 response.html 존재와 길이를 확인한다.

해결: DB 템플릿 활성 상태와 custom Agent Tool의 반환 형식을 확인한다. 포털은 유효한 html 또는 rendered_html만 sandboxed iframe으로 표시한다.

일반 답변에 HTML 표가 반복되거나 글자가 잘 보이지 않음

원인: 최종 답변 모델이 사용자의 HTML로 보여줘를 artifact 생성이 아니라 답변 본문 형식 요청으로 해석해 <table> 또는 Markdown 표를 다시 작성했다.

확인: MCP 마지막 응답에 유효한 html이 있으면서 저장된 answer에도 HTML 태그나 표 행이 있는지 확인한다.

해결: 최종 답변 지침에 HTML artifact 우선 규칙을 적용하고, 출력 후 검사에서 일반 답변을 생성 완료·제목·조회 건수 안내로 정규화한다. iframe CSS나 조회 Tool은 변경하지 않는다.

재발 방지: renderer가 반환된 시나리오에서 일반 답변에 <table>과 Markdown 표가 없는지 회귀 테스트한다.

리포트 제목에 질문 전체 문장이 표시됨

원인: report.title에 사용자 질문을 그대로 복사했다.

확인: renderer 호출의 reportJson.report.titlequestion이 완전히 같은지 확인한다.

해결: 제목 생성 지침으로 출력 형식·행동 문구를 제거한 짧은 명사형 제목을 만들고, report.question에는 원문을 유지한다.

재발 방지: 제목과 원문 질문이 역할상 분리되고 제목 길이 제한이 적용되는지 검증한다.

사용자를 바꿨는데 이전 사용자의 이름·팀이 제목에 남음

증상: E1001로 리포트를 만든 뒤 같은 대화에서 E1002를 선택하고 내 담당 선사를 요청했는데, 데이터는 E1002의 2건이면서 제목은 E1001 팀장 ...으로 표시된다.

원인: 질문 독립화 단계가 사용자 구분 없이 이전 대화 turn을 불러와 를 이전 사용자인 E1001로 치환했다. VPD는 현재 Bearer token으로 정상 적용되므로 데이터와 제목 범위가 어긋난다.

확인:

  1. 저장된 turn의 selected_user_id, question, standalone_question을 비교한다.
  2. E1002 turn의 standalone_question 또는 renderer report.title에 E1001이 남아 있는지 확인한다.
  3. 선행 조회 행은 E1002 담당 선사만 반환되는지 별도로 확인한다.

해결: 대화 문맥을 현재 selected_user_id로 필터링하고, 질문 독립화와 제목 생성에 현재 사용자 ID를 명시적으로 전달한다. 1인칭은 현재 사용자만 가리키며 이전 사용자의 관리자·팀 범위를 재사용하지 않도록 공통 지침을 적용한다. report.requestedBy도 현재 선택 사용자 ID를 사용한다.

재발 방지: 한 대화에서 E1001→E1002로 연속 전환하는 회귀 테스트를 유지한다. 제목과 행 수를 사용자별로 고정하지 말고 E1002 결과에 E1001 식별자가 포함되지 않는지를 검사한다.

reportJson.rowshtmlRow<tr>만 포함함

원인: 포털이 HTML로 보여줘가 포함된 원문을 첫 Select AI 데이터 조회에 그대로 전달해, 조회 Tool이 컬럼별 구조화 행 대신 HTML 조각을 반환했다.

확인: 첫 Agent 단계의 MCP argument와 원본 결과를 확인한다. 조회 질문에 표현 형식이 남아 있고 행 key가 htmlRow뿐이면 이 문제다.

해결: 포털의 데이터 질문 재작성 instruction이 업무 대상·필터·지표는 유지하면서 HTML·리포트· 차트 생성 요청만 제거하도록 한다. renderer나 DB 조회 Tool을 변경하지 않는다.

재발 방지: HTML로 보여줘가 포함된 통합 질문으로 실제 연속 호출하고, 조회 결과와 reportJson.rows 모두 업무 필드를 가지며 HTML 태그가 없는지 검증한다.

리포트는 생성됐지만 행이 0건임

원인: 다음 둘 중 하나다.

  1. 선행 조회가 실제로 0건이다.
  2. 선행 Select AI Tool은 행을 반환했지만 포털이 response.result 안의 JSON 배열 문자열을 reportJson.rows로 구조화하지 못했다.

확인: Agent 첫 단계의 원본 response.result 배열 건수와 두 번째 단계 reportJson.rows를 비교한다. 원본이 8건이고 rows가 0건이면 권한이나 Select AI 문제가 아니라 결과 전달 문제다.

해결: 포털의 범용 결과 해석기가 items, results, rows, response, result wrapper와 JSON 배열 문자열을 재귀적으로 처리하는지 확인한다. 조회 Tool, endpoint, VPD 정책, DB package를 교체하지 않는다.

재발 방지: 중첩 JSON 배열 회귀 테스트와 운영 연속 호출 검증을 유지한다. 같은 Bearer 문맥에서 조회 원본 행 수와 renderer 입력 행 수가 같아야 배포를 완료한다.

첫 리포트는 정상인데 두 번째부터 값이 비거나 깨짐

원인: Select AI가 컬럼 label을 underscore 대신 공백 또는 혼합 대소문자로 반환했고, 포털이 underscore만 camelCase로 변환했다.

확인: 연속 호출의 reportJson.rows에서 LATEST_REVENUE_USD, LATEST REVENUE USD, latest Revenue Usd가 모두 latestRevenueUsd로 정규화되는지 확인한다.

해결: 공백, underscore, hyphen을 공통 단어 경계로 처리한다. 대화 상태나 업무 컬럼 이름을 조건문에 하드코딩하지 않는다.

재발 방지: 서로 다른 컬럼 label 표기의 두 응답을 연속 정규화하는 회귀 테스트를 유지한다.

두 번째 리포트의 컬럼이 한글 alias로 바뀌어 깨짐

원인: Select AI가 첫 호출에는 CARRIER_CODE, 두 번째 호출에는 선사코드처럼 의미는 같지만 번역된 alias를 생성했다. 구분자 정규화만으로는 서로 다른 언어의 key를 같은 필드로 판단할 수 없다.

확인: 선행 조회 2건은 정상인데 두 번째 reportJson.rows선사명, 선사코드, 최신매출Usd 등을 가지는지 확인한다.

해결: 선사 Select AI query contract에 renderer가 요구하는 ASCII uppercase underscore 출력 alias를 선언한다. 실제 SQL, 직원 코드, 결과 값은 고정하지 않는다.

재발 방지: 같은 팀원 질의를 두 번 호출해 두 응답의 key 집합과 renderer HTML을 비교한다.