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

7.3 KiB

아키텍처와 입력 계약

책임 경계

구성요소 책임 DB 접근
search_carrier_performance 기존 HMM_CARRIER_FEDERATION_SEARCH를 통한 Bearer/VPD 기반 Select AI Federation 조회 허용
AI 웹 콘솔 도구 계약을 판별해 조회 결과를 정규화하고 렌더러를 후속 호출 없음
render_hmm_carrier_report DB CLOB 템플릿에 허용된 JSON을 매핑 템플릿만 읽음
브라우저 반환 HTML 표시·다운로드 없음
HMM portal ──► /mcp (Bearer) ──► Backoffice MCP facade ──► DB Agent Tool
                                            │
                                      VPD applied rows
                                            │
                                         Console
                                            │
                                    report MCP tool call
                                                                      │
                                                          HMM_REPORT_TEMPLATES
                                                                      │
                                                                  HTML 응답

리포트 MCP도 같은 Bearer 인증을 통과해야 하지만, 권한 판단은 조회 MCP에서 끝난다. 리포트 입력의 임의 사용자 ID를 신뢰하거나 DB를 재조회하지 않는다.

포털의 범용 순차 호출 규칙

포털은 render_hmm_carrier_report라는 이름을 조건문에 넣지 않는다. 발견한 MCP 도구가 아래 계약을 동시에 보이면 이전 결과 입력형 렌더러로 분류한다.

  • 입력 스키마에 reportJson·report_payload처럼 리포트 JSON/payload를 받는 문자열이 있다.
  • 설명에 HTML/리포트/렌더링 의도와 조회 결과, 후속 처리, already-authorized처럼 선행 결과를 사용한다는 의도가 있다.

사용자가 리포트·보고서·대시보드·차트·HTML을 요청하고 이 렌더러가 발견되면, 기존 LLM 라우터는 렌더러를 제외한 데이터 도구 중 하나를 먼저 선택한다. 첫 응답의 items, results, rows 또는 response.result 안의 JSON 배열 문자열을 같은 방식으로 구조화하고, camelCase JSON으로 정규화해 두 번째 도구에 전달한다. 포털은 렌더러의 html 응답을 iframe으로 표시한다. 이 규칙은 특정 Tool 이름, 사용자 코드나 예상 행 수를 조건으로 사용하지 않는다.

변경 금지 경계

  • search_carrier_performance의 DB target은 기존 HMM_CARRIER_FEDERATION_SEARCH다.
  • 별도 호환성 시험 서버 hmm-mcp.cloud-handson.com은 이 운영 경로를 대신하지 않는다.
  • HTML 추가를 이유로 조회 Agent Tool, Select AI profile, VPD 정책 또는 조회 package를 생성·교체하지 않는다.
  • renderer는 선행 결과만 표현하며 누락 행을 조회하거나 고정 샘플로 채우지 않는다.

reportJson 계약

최상위에는 report 객체와 rows 배열만 허용한다. report에는 id, category, title, generatedAt, requestedBy, question, answer, execution, evidence, limitation을 넣는다. 행에는 담당자·선사 식별자와 최신 KPI만 넣는다.

report.title은 사용자 질문 원문이 아니다. 포털이 모델에 다음 제목 계약을 지시해 만든 짧은 업무 제목이다.

  • HTML로 보여줘, 리포트로 만들어줘와 같은 출력 형식·행동 문구는 제거한다.
  • 사용자·팀·업무 대상처럼 범위를 구분하는 식별자는 유지한다.
  • 문장형 답변이 아니라 화면 머리글에 맞는 명사형 제목으로 만든다.
  • 템플릿이 붙이는 고정 부제와 같은 문구를 반복하지 않는다.

제목 생성이 실패하면 전체 질문을 제목으로 사용하지 않고 짧은 일반 업무 제목으로 안전하게 대체한다. 이 규칙은 특정 사용자 코드나 조회 행 수를 조건으로 사용하지 않는다.

현재 선택 사용자와 대화 문맥

포털의 데모 사용자 선택값은 Bearer token 선택뿐 아니라 질문 해석과 제목 범위의 기준이다. , , 우리 같은 1인칭 표현은 현재 선택 사용자 ID를 기준으로 독립 질문으로 바꾼다. 대화 이력은 같은 selected_user_id로 저장된 turn만 불러오며, 제목 생성 모델에도 현재 선택 사용자 ID를 별도 입력으로 전달한다. 이전 사용자의 질문에 명시된 팀장·팀 범위가 현재 사용자의 제목으로 전파되어서는 안 된다.

현재 사용자 E1001 + "E1001 팀장의 팀원별 ..." → E1001 팀 범위 제목 → VPD 결과 8건
현재 사용자 E1002 + "내 담당 선사 ..."       → E1002 개인 범위 제목 → VPD 결과 2건

제목 문자열이나 예상 행 수를 사용자별로 하드코딩하지 않는다. 사용자 ID, 독립 질문, 실제 선행 조회 결과를 모델 입력으로 제공하고 공통 제목 지침으로 생성한다. report.requestedBy는 질문에서 추측하지 않고 현재 선택 사용자 ID를 사용한다.

포털 표시 계약

renderer 응답에 유효한 html 또는 rendered_html이 있으면 HTML artifact가 최종 표현물이다. 포털의 일반 답변 생성 지침은 HTML 태그, Markdown 표, 업무 행 전체를 다시 만들지 않고 제목과 조회 건수, 아래 리포트 확인 안내만 반환한다. 포털은 같은 조건을 출력 후에도 검사해 모델이 HTML을 반환하더라도 안전한 짧은 안내문으로 정규화한다.

조회 질문과 표현 요청 분리

사용자의 한 문장에는 데이터 요구와 표현 요구가 함께 있을 수 있다. 포털은 Agent instruction으로 두 의도를 분리한다.

원문: E1001 팀 선사 KPI를 HTML로 보여줘
조회 단계: E1001 팀 선사 KPI를 보여줘
표현 단계: 조회된 구조화 행을 HTML 리포트로 렌더링

조회 단계 재작성은 직원·팀·기간·지표·필터를 모두 유지하고 HTML, 리포트, 차트, 대시보드 같은 출력 형식과 생성 행동만 제거한다. 원문은 report.question에 보존한다. Select AI가 만든 htmlRow, HTML 태그 또는 Markdown 표는 구조화 업무 행으로 간주하지 않으며 renderer 입력으로 전달하지 않는다.

서버는 JSON 크기, 행 수, 문자열 길이, 숫자 형식을 제한하고, 템플릿에 주입할 JSON에서 </script>를 이스케이프한다. payload는 저장하지 않는다.

배포 도구 계약

BACKOFFICE_MCP_TOOLS에 다음과 같이 등록한다. 실제 환경 변수에는 비밀값을 넣지 않는다.

{
  "name": "render_hmm_carrier_report",
  "label": "HMM 선사 실적 HTML 리포트",
  "description": "VPD 적용 선사 실적 조회 결과를 HMM HTML 리포트로 표현합니다.",
  "argumentName": "reportJson",
  "argumentDescription": "정규화된 선사 실적 리포트 JSON입니다.",
  "executionType": "AGENT_TOOL",
  "targetName": "HMM_CARRIER_REPORT_RENDERER",
  "targetParameterName": "P_REPORT_JSON"
}

targetName은 DBMS_CLOUD_AI_AGENT custom tool HMM_CARRIER_REPORT_RENDERER다.

템플릿에는 const reportData = __REPORT_DATA__; 자리만 둔다. DB 함수는 호출 시 전달받은 JSON을 이 자리에 삽입하고, 조회 Tool을 호출하거나 기본 업무 행을 보충하지 않는다.