부서마다 다른 매출 계산식, 승인된 용어집 정의만 질문 앞에 싣는다

「지난달 매출」을 물으면 영업팀은 수주 금액을, 재무팀은 반품을 뺀 세금계산서 발행 금액을 떠올립니다. 매출 원장 테이블에는 두 계산에 필요한 컬럼이 다 있으니 모델이 어느 쪽으로 SQL을 써도 오류 없이 실행되고, 경우에 따라서는 둘 다 아닌 세 번째 숫자가 나옵니다. 어느 계산이 이 회사의 매출인지는 조직이 정한 일이라 DDL에도 컬럼 주석에도, 분석이 만든 테이블 카드에도 적혀 있지 않습니다.
그래서 업무 정의는 조직 용어집에 계산식과 연결 테이블까지 함께 적어 두고, 질문에 그 용어가 나오면 그 항목만 질문 바로 앞에 싣습니다. 용어집에 오르는 정의는 관리자가 승인한 것뿐입니다. 이 글은 용어집 항목에 무엇을 담는지, 질문에서 용어를 어떻게 찾아 싣는지, 누가 정의를 정하는지 다룹니다.
매출의 정의는 데이터가 아니라 조직의 결정이다
「컬럼의 뜻은 DDL에 없다, 질문 전에 값을 읽어 둔다」의 스키마 분석은 컬럼의 뜻을 실제 값에서 읽어 냅니다. AMT가 부가세를 뺀 공급가인지, STATUS_CODE의 C가 취소인지는 값 분포와 코드 테이블을 보면 정해집니다. 매출은 이와 다릅니다. 「발행 금액에서 반품을 빼고 계열사 간 내부 거래도 뺀다」는 계산식은 여러 컬럼과 조건을 묶은 것이고, 이 묶음은 경영 보고 기준을 정한 회의에서 나왔습니다. 값을 아무리 들여다봐도 내부 거래를 빼야 한다는 사실은 나오지 않습니다.
「활성 고객」, 「신규 거래처」, 「가동률」도 사정이 같습니다. 이름은 하나인데 부서마다 계산식이 조금씩 다르고, 정의는 대개 보고서 각주나 담당자의 머릿속에 있습니다. 모델에게 이 정의를 주지 않으면 모델은 매출처럼 보이는 컬럼을 골라 합계를 내고, 그 숫자는 표 모양까지 멀쩡해서 정의를 아는 사람만 틀린 줄 압니다.
용어집을 통째로 싣거나 테이블 메모에 맡기면 생기는 일
가장 단순한 방법은 용어집 전체를 시스템 프롬프트에 붙이는 것입니다. 용어가 수십 개라면 잘 됩니다. 수백 개가 되면 질문 하나와 관계있는 용어는 몇 개뿐이고, 나머지 계산식은 모델을 엉뚱한 테이블로 끌고 갑니다. 「매출」을 물었는데 「매출채권 회전율」의 계산식이 함께 실려 있으면, 모델은 채권 테이블까지 열어 볼 이유를 찾습니다. 관리자가 용어 하나를 고칠 때마다 시스템 프롬프트가 바뀌어 모든 사용자의 프롬프트 캐시가 다시 계산된다는 비용도 있습니다(「시스템 프롬프트 한 줄에 캐시 읽기가 0이 된다, 바뀌는 블록은 뒤로 보낸다」).
다른 방법은 테이블 메모에 맡기는 것입니다. 테이블 메모는 사용자가 대화 중에 알려 준 사실을 모델이 그 테이블에 붙여 두는 공유 기록이고, 그 테이블을 쓰는 모든 사람의 답에 힌트로 실립니다(「테이블을 잘못 고른 SQL도 실행된다, 검색이 후보부터 좁힌다」). 메모는 빨리 쌓이지만 누구의 승인도 거치지 않습니다. 영업 담당자의 대화에서 「매출은 수주 금액」이, 재무 담당자의 대화에서 「매출은 발행 금액에서 반품을 뺀 값」이 같은 테이블에 나란히 남으면, 모델은 두 메모 가운데 하나를 골라야 하고 어느 쪽이 조직의 기준인지 알 길이 없습니다.
정의에는 정해 둔 사람과 정해 둔 범위가 있어야 합니다. 그래서 업무 정의는 메모와 따로 두고, 승인을 거친 항목만 질문에 나왔을 때 싣기로 했습니다.
용어집 항목은 정의와 계산식과 연결 테이블을 함께 담는다
회의와 데이터 질의와 문서 생성은 조직 용어집 하나를 함께 씁니다. 회의록이 고유명사를 바로 적도록 쓰던 용어집(「받아쓰기가 틀린 사내 이름은 회의록 모델이 용어집을 보고 고친다」)에 데이터 질의가 쓰는 칸을 더한 것입니다. 같은 회사에서 「순매출」이 회의록과 채팅 답에서 다른 뜻이면 곤란하기 때문입니다. 항목 하나는 다음 칸으로 이뤄집니다.
| 칸 | 담는 것 | 쓰는 곳 |
|---|---|---|
| 용어 | 「순매출」 | 전부 |
| 뜻 | 사람이 읽는 한두 문장 | 전부 |
| 동의어·약어 | 같은 개념의 다른 이름(「NS」, 「반품 차감 매출」) | 데이터 질의·문서 |
| 계산식 | SQL 조각(SUM(ISSUE_AMT) - SUM(RETURN_AMT))이나 문장(「최근 90일 안에 주문이 한 건 이상 있는 고객」) |
데이터 질의·문서 |
| 연결 테이블 | DB 연결·테이블·컬럼의 위치 목록. 한 용어가 여러 DB의 여러 테이블에 걸칠 수 있습니다 | 데이터 질의 |
| 오답 | 받아쓰기가 잘못 적는 표기(「순매추」) | 회의록 |
동의어와 오답은 다른 칸입니다. 동의어는 사람이 실제로 쓰는 맞는 이름이고, 오답은 음성 인식이 틀리게 적는 표기입니다. 섞어 두면 회의록이 「NS」를 오타로 보고 「순매출」로 고쳐 버립니다.
부서마다 기준이 정말 다르다면 용어를 나눠 각각 정의합니다. 「수주 매출」과 「발행 매출」을 따로 두고, 경영 보고에 쓰는 「매출」은 그 가운데 하나를 가리키도록 뜻에 적습니다. 같은 표기의 용어는 한 용어집에 하나만 둘 수 있어서, 「매출」이 두 뜻을 동시에 가질 수는 없습니다.
질문에 나온 용어만 찾아 질문 바로 앞에 싣는다
턴이 시작되면 턴 실행부는 사용자 질문에서 용어집의 용어와 동의어를 찾습니다. 턴은 질문 하나를 받아 답을 내기까지의 한 번의 질의응답입니다. 찾는 방법은 문자열 일치입니다. 앞 경계는 엄격하게 봐서 「총순매출」 안의 「순매출」은 잡지 않고, 한글로 끝나는 용어는 뒤 경계를 열어 두어 「순매출을」, 「순매출은」도 같은 용어로 잡습니다. 같은 자리에서는 긴 용어가 먼저 잡혀서 「순매출」로 물으면 「매출」 항목이 함께 실리지 않습니다. 대소문자와 공백 차이는 같은 표기로 봅니다.
찾은 항목은 뜻, 계산식, 연결 테이블과 함께 용어집 블록 하나로 묶여 사용자 메시지의 질문 바로 앞에 붙습니다. 질문마다 바뀌는 내용이라 시스템 프롬프트가 아니라 사용자 메시지 쪽에 두었고, 덕분에 캐시된 시스템 프롬프트 앞부분은 용어집이 바뀌어도 그대로입니다. 한 턴에 싣는 항목 수에는 상한이 있고, 상한에 밀려 빠진 수는 로그로 남깁니다.
연결 테이블도 권한을 거칩니다. 사용자의 역할로 볼 수 없는 테이블은 용어가 가리켜도 블록의 목록에서 빠지고, 뜻과 계산식만 실립니다. 원천 DB에서 테이블이 사라지거나 연결 계정이 더는 볼 수 없게 되면(「DB가 바뀌면 분석은 낡는다, 바뀐 테이블만 찾아 다시 분석한다」) 연결 테이블은 지워지지 않고 비활성으로 표시됩니다. 용어집 화면에는 「연결된 테이블을 쓸 수 없음」이 뜨고, 관리자가 정의는 그대로인데 가리키는 데이터만 사라졌다는 것을 보고 고칩니다.
같은 문자열 일치를 회의록은 다르게 씁니다. 회의록은 받아쓰기에서 실제로 찾은 오답만 힌트로 싣고, 용어집의 표기와 뜻은 시스템 프롬프트에 전부 싣습니다(「받아쓰기가 틀린 사내 이름은 회의록 모델이 용어집을 보고 고친다」). 받아쓰기는 어떤 용어든 아직 등록하지 않은 꼴로 틀리게 적을 수 있어서 문자열로 미리 골라낼 수 없기 때문입니다. 채팅 질문은 사람이 직접 친 글이라 용어가 대개 맞는 표기로 나오고, 그래서 질문에 나온 항목만 골라 실을 수 있습니다.
모델은 계산식을 테이블 카드의 실제 컬럼에 맞춰 SQL로 옮긴다
계산식이 SQL을 대신 써 주지는 않습니다. SUM(ISSUE_AMT) - SUM(RETURN_AMT)는 컬럼 이름을 담고 있지만, 그 컬럼이 어느 테이블에 있는지, 기간 조건을 어느 날짜 컬럼에 걸지는 질문마다 다릅니다. 그래서 모델은 블록의 연결 테이블에서 테이블 카드(「컬럼의 뜻은 DDL에 없다, 질문 전에 값을 읽어 둔다」)를 열어 컬럼을 확인한 뒤 계산식을 SQL에 녹입니다. 연결 테이블이 있으면 테이블 검색(「테이블을 잘못 고른 SQL도 실행된다, 검색이 후보부터 좁힌다」)을 거치지 않고 바로 카드를 열 수 있어, 「순매출」이라는 말이 카드 어디에도 없는 테이블도 첫 라운드에 찾아갑니다. 계산식이 가리키는 컬럼이 카드에 없으면 모델은 짐작으로 다른 컬럼을 쓰지 않고 그 사실을 답에 밝힙니다. 만든 SQL은 다른 SQL과 똑같이 읽기 전용 실행 도구를 지납니다(「읽기 전용과 쿼리 취소는 DB 서버에 닿아야 한다」).
용어집과 테이블 메모가 같은 용어를 다르게 말하면 용어집을 따르도록 시스템 프롬프트가 순서를 정해 둡니다. 용어집은 조직이 승인한 정의이고, 메모는 확인해서 쓸 힌트로 실리는 현장 기록입니다.
답에는 어느 정의로 셌는지가 드러납니다. 「매출」 항목의 뜻이 「경영 보고 기준: 발행 금액에서 반품과 내부 거래를 뺀 값」이면, 모델은 그 기준으로 센 숫자라고 밝히고 답합니다. 영업 담당자가 수주 기준을 원했다면 답을 읽는 순간 차이를 알고 「수주 매출로 다시」라고 물을 수 있습니다.
조직 정의는 관리자가 승인하고, 대화에서 나온 정의는 본인 용어집에서 멈춘다
조직 용어집을 고치는 사람은 관리자입니다. 매출 정의 하나가 조직의 모든 데이터 답에 실리기 때문에, 누구나 고칠 수 있는 테이블 메모와 권한을 다르게 두었습니다. 관리자가 직접 넣은 항목은 바로 쓰이고, 추가·수정·삭제는 조직의 감사 기록에 남습니다.
AI가 후보를 찾아 주기도 합니다. 관리자가 AI로 용어 찾기로 조직의 문서 모음과 DB 분석 결과를 고르면, AI가 그 자료에서 용어 후보를 뽑아 검토 목록에 올립니다. 후보는 사용 중인 용어가 아니라서 프롬프트에 실리지 않고, 관리자가 고쳐서 승인해야 용어집에 들어갑니다.
정의는 대부분 대화에서 처음 나옵니다. 사용자가 「우리는 활성 고객을 최근 90일 안에 주문한 고객으로 봐」라고 말하면, 모델은 용어·뜻·계산식·연결 테이블이 붙은 후보를 냅니다. 이 후보는 조직 검토 목록이 아니라 말한 사람의 개인 용어집 검토 목록에 쌓입니다. 대화는 그 사람만 보는 기록이고, 관리자도 남의 대화를 열지 않습니다. 대화에서 뽑은 정의를 조직 목록에 올리면 대화 조각이 다른 사람에게 보이게 됩니다. 본인이 승인한 개인 항목은 그 사람의 질문에만 실리고, 팀의 기준으로 삼아야 할 정의라면 관리자가 조직 용어집에 등록합니다.
조직 용어집과 개인 용어집에 같은 표기가 있으면 데이터 질의에서는 조직 항목을 씁니다. 개인 항목은 조직 용어집에 없는 표기만 채웁니다. 회의록은 반대로 회의 주인의 개인 항목을 먼저 쓰는데(「받아쓰기가 틀린 사내 이름은 회의록 모델이 용어집을 보고 고친다」), 회의록은 그 사람의 기록이고 매출 숫자는 보고서에 실려 여러 사람이 맞춰 보는 값이기 때문입니다. 누가 물어도 「매출」은 같은 식으로 셉니다.
설계에서 고른 것
용어는 문자열 일치로 찾습니다. 임베딩으로 의미가 가까운 항목을 찾으면 「반품 뺀 매출」처럼 용어집에 없는 말로 물어도 「순매출」이 잡힙니다. 그 대신 비슷하지만 다른 항목(「반품률」)도 함께 실릴 수 있고, 같은 질문에 어떤 항목이 실릴지가 임계값과 모델 버전에 따라 달라집니다. 정의는 같은 말에 같은 항목이 매번 실려야 해서 문자열 일치를 골랐습니다. 다른 말로 같은 개념을 가리키는 표현은 동의어 칸에 넣으면 같은 항목으로 잡히고, 그 밖의 표현은 테이블 검색과 테이블 메모가 받칩니다.
뒤 경계를 열어 둔 대가도 있습니다. 「매출채권」은 조사가 아니라 합성어인데도 「매출」로 잡힙니다. 조사 목록으로 경계를 가르면 어미와 합성어의 경계 사례가 끝없이 나와서, 이 경우는 「매출채권」을 따로 등록하는 것으로 풉니다. 같은 자리에서는 긴 용어가 먼저 잡히므로, 등록하고 나면 「매출채권」을 물을 때 「매출」 항목은 실리지 않습니다.
용어집은 승인을 거칩니다. 조직의 공식 정의가 되는 자리라 속도보다 정확성을 골랐습니다. 그 대가로 한 사람이 찾아낸 좋은 정의도 관리자가 등록하기 전까지는 그 사람의 질문에만 쓰입니다. 대화에서 바로 쓰여야 하는 현장 지식은 테이블 메모가 맡고, 메모는 힌트로만 실립니다.
부서마다 같은 이름으로 다른 숫자를 세는 조직이라면, 먼저 경영 보고에 쓰는 지표 몇 개를 골라 계산식과 연결 테이블까지 등록하고, 기준이 갈리는 용어는 이름을 나눠 각각 정의합니다. 용어집에 등록하는 일은 사람이 하고, 질문할 때마다 그 정의를 싣는 일은 턴 실행부가 합니다.
어떤 문제를 해결하나요?
정형 데이터와 NL2SQL의 다른 글

엔지니어링 노트 · 정형 데이터와 NL2SQL
테이블을 잘못 고른 SQL도 실행된다, 검색이 후보부터 좁힌다
테이블이 수천 개인 업무 DB에는 주문 테이블 옆에 ORDMSTBAK, ORDMST202312 같은 백업·작업용 사본이 흔히 함께 남아 있습니다.

엔지니어링 노트 · 정형 데이터와 NL2SQL
컬럼의 뜻은 DDL에 없다, 질문 전에 값을 읽어 둔다
주문 테이블의 STATUSCODE CHAR(1)에는 S, D, C가 들어 있습니다. 모델이 C를 완료(complete)로 짐작하면 「지난달 완료 주문 매출」에 취소 주문이 섞여 나옵니다.

엔지니어링 노트 · 정형 데이터와 NL2SQL
읽기 전용과 쿼리 취소는 DB 서버에 닿아야 한다
OwlAI의 SQL 실행 도구는 모델이 쓴 SQL을 고객의 운영 DB에서 실행합니다. 이때 클라이언트 쪽에서 건 제한은 걸린 것처럼 보여도 DB 서버에 닿지 않는 경우가 있습니다.
