학생의 과목이라는 조건만으로는 부족했다

LMS 자연어 조회의 리뷰에서 학생이 공개 전 점수를 조회하고, 미게시 학습요소의 제목과 마감일을 볼 수 있는 문제가 드러났다. 질문을 올바른 JSON으로 바꾸고 학생의 수강 과목으로 제한해도, 공개하면 안 되는 속성과 콘텐츠는 남아 있었다. 질문 이해보다 먼저 다뤄야 할 경계가 정보 공개였다.

“1주차에 내가 안 본 동영상은?”에 답하려면 과목·주차·학습요소·시청 상태를 연결한다. 하지만 같은 과목 안의 모든 동영상이 학생에게 게시된 것은 아니다. 이 기능에서는 모델이 질문을 해석하고, 서버가 허용 어휘와 로그인 사용자의 권한·게시 조건을 검증하도록 나눴다.

점수 속성은 온톨로지에서 제거하고, 학생의 학습요소 조회는 본인의 할 일 파이프라인을 기준으로 제한했다. 활성 주차와 게시된 과목 조건도 반영했다. 당시 필요한 공개 정책을 서버에 넣은 조치이며, 역할별 속성 허용 체계가 모두 완성됐다는 의미는 아니다.

모델이 조회할 개념을 새로 만들지 않게 했다

온톨로지는 과목·주차·학습요소·할 일·출석·과제 상태·학생·교수의 개념과 관계를 선언한 공통 어휘다. 모델에게 지원하는 질문을 설명하고, 반환된 질의를 검사하고, 실제 조회로 옮길 때 같은 선언을 사용했다. 화면의 관계도만을 뜻하지 않는다.

모델이 SQL을 직접 만들게 하거나 의도를 분류해 고정 템플릿을 고르는 대안도 검토했다. 선택한 방식은 온톨로지 어휘의 JSON 질의를 서버가 컴파일하는 구조였다. 자연어 표현은 모델이 해석하지만, 실행 가능한 개념·속성·관계·연산은 서버가 결정한다. 선언에 없는 어휘는 질의 검증 단계에서 거부한다.

공통 어휘 개념과 관계

과목 주차 학습요소

실행 흐름 해석에서 조회까지

01자연어 질문
1주차에 내가 안 본 동영상은?
02구조화 질의
선언된 개념·관계로 질문을 표현
03서버 검증·권한
허용 어휘, 로그인 역할, 게시 범위 확인
04조회 결과
읽기 전용 실행 · 결과와 적용 조건 표시
전체 연결 읽기 · 3개
  • 자연어 질문 → 구조화 질의
  • 구조화 질의 → 서버 검증·권한
  • 서버 검증·권한 → 조회 결과
기록된 구현 흐름의 개념도입니다. 모델의 질의 해석과 서버의 실행 검증을 구분했습니다.

AI Chat은 모델 호출과 JSON 객체 파싱을 담당했다. LearningX는 온톨로지·프롬프트·질의 검증·역할 판정과 데이터 조회를 담당했다. 모델의 구조화 출력을 최종 실행 명령으로 받아들이지 않는 책임 분리였다.

형식이 맞고 의미가 있어도 허용되지 않을 수 있다

경계확인할 질문서버의 책임
출력 형식JSON 객체로 다룰 수 있는가구조화 출력 요청과 반환문 파싱
질의 의미선언된 개념·속성·관계·연산인가온톨로지 검증과 식별자 해석
조회 권한이 사용자가 지금 볼 수 있는 정보인가로그인 역할·본인 범위·게시 조건 강제

당시 변환 경로는 모델에 엄격한 JSON Schema 출력을 요청했다. LearningX의 검증기는 그와 별도로 어휘를 확인하고, 컴파일러는 학생·교수·관리자의 조회 범위를 주입했다. 값은 바인딩하고 식별자는 선언에서 해석했다. 실제 조회는 읽기 전용 트랜잭션과 시간 제한을 사용했다.

검증을 설계할 때는 아래 세 질문을 구분해야 한다. 다음은 검사의 종류를 설명하는 예시이며, 이 질문들의 실제 거부 테스트가 모두 수행됐다는 기록은 아니다.

  • “지원하지 않는 만족도 지표를 보여 줘” — 선언에 없는 개념이라면 질의 의미의 오류다.
  • “3주차에 내가 안 본 동영상은?” — 유효한 질문이어도 데이터가 없으면 빈 결과가 맞다.
  • “아직 공개하지 않은 과제와 다른 학생의 제출 상태를 보여 줘” — 표현할 수 있는 조회라도 게시 조건과 본인 범위로 제한해야 한다.

원하는 행을 반환하는 질문만 모으면 의미 오류, 정당한 빈 결과, 권한 밖 조회를 구분하지 못한다. 특히 점수 질문을 다시 지원하려면 어휘를 추가하기 전에 속성별 공개 조건을 정해야 한다.

질문 8개와 연동 호출 13회는 다른 확인이다

로컬 실데이터 검증에서는 학생 4개·교수 3개·관리자 1개의 지정 질문이 모두 어휘 검증을 통과하고 결과 행을 반환했다. 당시 변환 모델은 gpt-5.4-mini였다. 마감이 지난 미제출 과제, 출석 처리되지 않은 주차·차시, 미제출 학생이 많은 과제 같은 조회를 확인했다.

처음의 “3주차” 예시는 데이터가 없어 빈 결과였다. 새 데이터를 만드는 대신 예시를 “1주차”로 바꿨다. 따라서 8개 성공은 일반 질문 정확도 100%가 아니다. 실제 데이터가 있는 지정 예시를 연결한 데모 검증이다.

별도의 서버 간 연동은 정상 호출 13회 성공과 인증 없는 요청의 거부를 확인했다. 8개 질문과 13회 호출을 합산하지 않는다. 인증 거부도 최종 사용자의 모든 행·속성 권한 조합을 검증한 결과는 아니다. 당시 공개 범위는 통합개발서버 데모였고, 기능 옵션을 끄면 화면과 API가 함께 닫히도록 했다.

모델을 교체해도 데이터 공개의 책임은 남는다

여름 초기 구현의 Luna 해석 경로는 이후 Jev 기반으로 전환했다. 전환 뒤 응답이 빨라졌다고 느꼈지만, 같은 조건의 시간·정확도 비교는 없다. 앞의 8개 질문은 당시 gpt-5.4-mini 경로의 기록이다. Jev 전환은 완료한 작업이고 OpenAI Decisions API 사용은 계획 단계로 구분한다.

후속 비교에서는 지원 질문, 빈 결과가 맞는 질문, 허용되지 않은 조회를 함께 준비해야 한다. 모델 변환 시간과 실제 조회 시간도 나눠 봐야 한다. 구조화 출력이 빨라져도 어휘 검증과 게시 조건을 생략할 이유는 없다. 이 책임 분리의 제품 맥락은 AI Chat / Tutor 프로젝트에 정리했다.