Files
vpd-permission-poc/docs/design/739-game-target-contract/README.md
2026-08-03 12:31:49 +09:00

5.9 KiB

Smilegate 게임 대상 계약 통합 설계

1. 배경

현재 game_query_plan은 게임을 찾지 못하면 STOP_NO_MATCH, 여러 게임이면 FAN_OUT을 반환한다. Portal의 ReAct 모델이 이 지시를 종료 조건으로 해석하거나 일부 게임만 다음 도구로 전달하면서 다음 문제가 발생했다.

  • 게임명이 없는 전체 매출 질의가 SQL 생성 전에 중단된다.
  • 여러 게임 중 일부만 매칭되면 매칭된 게임의 조회도 생략될 수 있다.
  • 계획 결과를 전달해도 NL2SQL worker가 질문 전체를 다시 단일 게임 벡터검색하여 범위를 축소할 수 있다.
  • 게임별 사용자 마스터 물리 객체를 모델이 추측해야 한다.

2. 목표

질문의 게임 대상을 NONE, SINGLE, MULTI, ALL 네 가지로 통일하고, 모든 유형에서 원 질문과 전체 계획 결과를 smilegate_fewshot_nl2sql에 한 번 전달한다. 계획 단계는 조회 중단이나 SQL 조립을 결정하지 않는다.

3. 계약

game_query_plan은 다음 필드를 반환한다.

필드 내용
targetType NONE, SINGLE, MULTI, ALL
status NO_TARGET, SUPPORTED, PARTIAL, UNMATCHED
targets 언급 순서를 보존한 게임 대상 배열
nextAction 항상 CALL_FEWSHOT
executionMode UNSCOPED, SINGLE, COMBINED, ALL

targets 항목은 다음 값을 가진다.

필드 내용
mention 질문에서 추출한 게임명. NONEnull
status NONE, MATCHED, UNMATCHED, CATALOG
gameKey, gameId DB 카탈로그가 반환한 게임 식별자
gamePrefix DB 카탈로그가 반환한 prefix
gameName, aliases 표시명과 별칭
userMasterObjectName 현재 Select AI 승인 객체 중 해당 게임의 사용자 마스터 물리 객체. 없으면 null
cosineDistance 후보 검색 거리. 적용되지 않으면 null
reasonCode, reason 매칭 또는 미매칭 근거

유형별 처리 방식은 다음과 같다.

  • NONE: 게임 대상 항목 하나를 모든 게임 필드가 null인 상태로 전달한다. 공통 거래·기준 객체 질의는 계속하되 prefix 전용 객체를 임의 선택하지 않는다.
  • SINGLE: 질문에서 언급된 대상 한 건을 전달한다. 미매칭이면 게임 필드가 null인 대상도 그대로 다음 도구에 전달한다.
  • MULTI: 언급된 대상 모두를 전달한다. 매칭·미매칭을 함께 보존한다.
  • ALL: 게임 카탈로그의 활성 게임을 모두 반환한다. 사용자 마스터 물리 객체가 없는 게임도 null로 보존한다.

4. DB 설계

SG_GAME_CATALOGUSER_MASTER_OBJECT_NAME을 추가한다.

  • 값은 COMN_GAME_ALIAS_BAS/운영 게임 registry의 GAME_PREFIX와 현재 USER_CLOUD_AI_PROFILE_ATTRIBUTES.object_list, USER_OBJECTS를 조합해 계산한다.
  • 공통 정책이나 애플리케이션 코드에는 특정 게임명, prefix, 테이블명을 넣지 않는다.
  • 운영 registry에만 존재하는 게임도 카탈로그에 동기화하고 임베딩을 생성한다.
  • 게임별 물리 객체가 없으면 컬럼은 null이다.

SG_GAME_CATALOG_SEARCH는 물리 객체명을 후보 결과에 포함한다. SG_GAME_QUERY_PLAN은 추출된 mention마다 후보 선택 결과를 targets로 만들며, ALL은 벡터 선택 없이 전체 카탈로그를 사용한다.

5. MCP와 NL2SQL 설계

game_query_plan 도구 설명은 “항상 먼저 호출하고 결과를 원 질문과 함께 다음 도구에 전달”하도록 바꾼다. smilegate_fewshot_nl2sql의 입력은 다음과 같다.

  • prompt: 사용자가 입력한 원 질문
  • queryPlan: 바로 앞 game_query_plan의 전체 JSON
  • scopeGameKey: 하위 호환용 선택 값. 새 흐름에서는 사용하지 않는다.

NL2SQL worker는 전달된 queryPlan을 권위 있는 게임 범위로 사용한다. 계획이 있으면 질문 전체를 다시 게임 카탈로그 벡터검색하지 않는다.

  • 공통 객체에 게임 식별 컬럼이 있으면 질문 의미에 따라 INGROUP BY를 사용할 수 있다.
  • 대상별 물리 객체가 다르면 제공된 객체만 사용해 UNION ALL할 수 있다.
  • 물리 객체가 null인 대상을 임의 객체로 대체하지 않는다.
  • NONE에서 생성 SQL이 prefix 전용 객체를 참조하면 실행 전에 차단한다.
  • 최종 SQL은 기존과 같이 단일 SELECT/WITH, read-only transaction, 최대 행수와 timeout 제한을 적용한다.

6. Portal ReAct 설계

Portal은 도구 호출 순서를 Java/Python 조건문으로 강제하지 않는다. 외부 환경변수의 system prompt와 MCP 도구 설명으로 다음 절차를 안내한다.

  1. game_query_plan을 호출한다.
  2. targetType과 상관없이 원 질문, 전체 queryPlan으로 smilegate_fewshot_nl2sql을 한 번 호출한다.
  3. SQL, 실행 결과, 매칭·미매칭 대상을 함께 설명한다.

7. 검증

운영 MCP에서 다음 네 질문군을 실제 호출한다.

유형 검증 내용
NONE 게임명이 없는 전체 매출 질의가 공통 테이블로 실행되고 게임 필터가 임의 추가되지 않는다.
SINGLE 한 게임의 AU 질의가 해당 게임 식별자/물리 객체로 실행된다.
MULTI 지원·미지원 게임을 함께 질문해 지원 결과와 미지원 상태가 한 답변에 보존된다.
ALL 전체 게임 질의가 전체 카탈로그 대상을 받아 공통 객체 그룹 또는 게임별 객체 결합 SQL로 실행된다.

추가 검증:

  • Maven 테스트
  • Portal Python 테스트
  • MCP tools/list schema/description 확인
  • 생성 SQL에서 NONE의 prefix 전용 객체 차단 확인
  • 운영 서비스 health와 Portal ReAct 실제 응답 확인

8. 변경 이력

  • Redmine: #739
  • Backoffice branch: smilegate
  • Portal branch: main