AI가 숫자를 직접 작성하지 못하게 하는 방법 (듀얼 채널 렌더링)
요약
LLM이 재무 데이터를 요약할 때, 숫자를 직접 생성하게 하면 '그럴듯한 오답'을 만들 위험이 있습니다. 이를 방지하기 위해 '듀얼 채널 렌더링' 기법을 도입했습니다. 이 방식은 데이터는 외부 소스에서 가져오고, LLM은 설명(주석)만 작성하도록 분리하여 정확성을 높입니다.
핵심 포인트
- LLM의 숫자 직접 산출 방지: 재무 정보의 신뢰성 확보가 핵심입니다.
- 듀얼 채널 렌더링 구조: 데이터는 외부 소스에서, LLM은 설명(주석)만 담당합니다.
- 사실 패키지 기반 작성: FMP 등 전문 데이터 제공업체의 사실을 유일한 출처로 사용합니다.
- 숫자 게이트 도입: 초안의 모든 숫자는 원본 데이터와 반올림 허용 오차 내에서 일치해야 합니다.
어닝 리포트를 요약하도록 요청받은 언어 모델(LLM)은 결국 거의 맞는 매출 수치를 산출할 것입니다. 자릿수는 그럴듯해 보이고, 문장도 잘 읽히며, 출력물 어디에서도 어떤 숫자가 복사된 것인지 어떤 숫자가 재구성된 것인지를 알려주지 않습니다. 주식 점수화 사이트에서 이는 최악의 실패 모드입니다: 모든 올바른 숫자처럼 보이는 자신감 있는 오답 수치입니다.
저희는 Stock Expert AI를 운영하고 있으며, 이 사이트는 품질(quality), 안전성(safety), 가치 평가(valuation), 성장(growth), 모멘텀(momentum)의 다섯 가지 기둥을 기반으로 MoonshotScore를 생성하여 21,000개 이상의 미국 주식을 0점에서 100점까지 점수화합니다. 저희가 '그럴듯한 오답 숫자 문제'에 대한 해답으로 제시하는 것이 바로 듀얼 채널 렌더링(dual-channel rendering)이라는 규칙입니다: 모델은 절대로 수치를 직접 산출하도록 허용되지 않습니다. 이 글에서는 이것이 실제로 무엇을 의미하며, 어느 부분에서 효과적인지를 다룹니다.
두 개의 채널, 하나의 페이지
규칙 자체는 간단합니다. AI는 주석(commentary)만 작성할 수 있습니다. 페이지의 모든 숫자는 시장 데이터 제공업체(Financial Modeling Prep, FMP)로부터 있는 그대로 렌더링됩니다. 이것이 바로 두 개의 채널입니다:
- 데이터 채널 (Data channel): FMP에서 가져와 일반 코드로 렌더링되는 값들. 제공업체의 응답과 화면의 픽셀 사이에 모델이 개입하지 않습니다.
- 주석 채널 (Commentary channel): 무언가를 설명하고, 맥락화하며, 연결하는 데 사용되는 모델 작성 산문(prose).
이 둘을 분리한 목적은
저널 파이프라인: 증거가 먼저, 그 다음 산문
저희 뉴스 섹션(저널)은 모델이 가장 많은 텍스트를 작성하는 곳이며, 따라서 주변에 가장 많은 장치들을 가지고 있습니다.
스토리는 모델에 의해 선택되지 않습니다. FMP 데이터에서 가져옵니다: 실적 발표 일정(earnings calendar), 시가총액 $1B 이상인 두 세션 동안의 주요 변동 종목(top movers), 그리고 섹터 테마입니다. 저희는 7일 이내에 같은 티커를 두 번 다루지 않습니다.
각 스토리에 대해 FMP 엔드포인트에서 사실 패키지(fact pack)를 만듭니다: 재무제표(statements), 추정치(estimates), 등급(ratings), 부문별 실적(segments), 내부자 거래(insider trades), 그리고 실적 발표 콜 녹취록(earnings-call transcript). 그런 다음 중규모 모델이 이 사실 패키지를 유일한 출처로 삼아 초안을 작성합니다.
그 후, 그 초안은 다른 어떤 것이 보기 전에 게이트를 통과해야 합니다.
숫자 게이트
게이트는 초안에서 모든 숫자를 추출하고, 반올림 허용 오차(rounding tolerance)와 함께 사실 패키지와 비교합니다. '$46.06B'라고 적힌 초안은 작가(writer)가 소수점 둘째 자리까지 반올림했기 때문에, 46,061,000,000이라는 사실 패키지 값과 일치해야 합니다. 그런데 '$47B'라고 적힌 초안은 일치해서는 안 됩니다.
유용한 트릭은 숫자가 어떻게 작성되었는지로부터 허용 오차를 도출하는 것입니다. 만약 초안에 수십억(billions) 단위로 소수점 둘째 자리가 표시된다면, 허용되는 오류는 마지막으로 기록된 값의 절반 단위가 스케일업 된 것입니다. 여기에는 단순화되고 일반적인 버전이 있습니다:
interface Parsed {
value: number;
tolerance: number;
...
이는 의도적으로 순진합니다(deliberately naive). 실제 운영 게이트는 또한 백분율, 연도, 분기 레이블, 범위, 그리고
숫자 게이트(number gate)는 존재하지 않는 수치를 잡아냅니다. 이 게이트는 실제 수치가 잘못된 기간에 연결되었는지, 문장이 조언으로 흐르는지, 또는 인용문이 왜곡되었는지를 판단할 수는 없습니다. 따라서 더 큰 모델이 초안을 검토하지만, 오직 좁은 목록만을 위해 수행합니다: 잘못된 숫자, 잘못된 기간, 조언, 그리고 왜곡된 인용문입니다. 우리는 이 기사가 좋은지 여부를 묻지 않습니다. 좁은 체크리스트가 평가하기 쉽고 검토자가 벗어나기 어렵게 만듭니다.
기사가 통과하면, 사이트는 승인된 텍스트와 증거의 SHA-256 해시를 저장합니다. 기사는 두 해시가 여전히 일치하는 동안에만 색인화(indexable)될 수 있습니다. 누군가 텍스트를 편집하거나 근본적인 증거가 변경되면, 해당 기사는 다시 승인될 때까지 색인 가능한 집합에서 제외됩니다. 이는 '이것은 어느 시점에 검증되었다'라는 속성을 시스템이 모든 요청마다 확인하도록 만듭니다.
긴 녹취록과 원본 소스 규칙
실적 발표 콜(Earnings-call) 녹취록은 길기 때문에, 작가가 보기 전에 저렴한 모델이 이를 요약합니다. 이는 명확한 위험을 초래합니다: 요약기가 수치를 꾸며내거나 왜곡할 수 있고, 작가는 죄책감 없이 이를 반복하게 됩니다.
해결책은 순서 규칙입니다. 숫자 게이트는 항상 원본 녹취록(raw transcript)을 대상으로 실행되며, 요약본이 아닙니다. 만약 요약본이 소스에 없는 수치를 도입한다면, 게이트가 일치시킬 대상이 없으므로 초안은 실패합니다. 요약 과정의 오류로는 출판된 텍스트에 숫자를 도입할 수 없습니다. 왜냐하면 요약본은 우리가 신뢰하지 않는 것이기 때문입니다.
같은 아이디어는 다른 손실성(lossy) 단계에도 적용됩니다: 증거를 압축하거나 다시 작성하는 모든 과정에서, 검증은 압축되지 않은 원본을 가리켜야 합니다.
서비스하기: 크롤러용 HTML, AI 크롤러용 Markdown
크롤러는 서버 렌더링된 HTML을 받습니다. 모든 기사에는 동일한 URL에 .md를 붙인 형태로 일반 Markdown 사본이 있으며, 이는 AI 크롤러를 위한 것입니다. 스택은 프론트엔드에서 React + Vite + TypeScript, 백엔드에서 Express + TypeScript, Neon PostgreSQL의 Drizzle ORM을 사용하고, Cloudflare Worker가 앞에 위치하며 Replit VM에 호스팅됩니다. 이 중 어느 것도 특이한 것은 아닙니다. 중요한 점은 Markdown 사본이 HTML과 동일한 승인된 텍스트에서 온다는 것이므로, 둘 다 해시 검사 안에 머무른다는 것입니다.
모델 호출은 모두 플랫 구독 기반으로 헤드리스(headless)로 실행되며, 작업별로 가장 저렴하고 적절한 모델을 선택합니다. 요약에는 저가 모델을, 작성에는 중형 모델을, 리뷰에는 대형 모델을 사용합니다.
트레이드오프 및 다르게 할 부분
산문이 더 평범해집니다. 팩트 패크에 포함된 수치가 아니면 그림을 인용할 수 없는 모델은 생생한 비교를 적게 작성합니다. 일부 초안은 기술적으로는 사실이지만 모델 스스로 계산한 성장률과 같은, 유도된(derived) 숫자가 포함되어 있어 거부됩니다. 우리는 유도된 수치를 모델이 산술 연산을 수행하는 것으로 간주하며, 이는 규칙이 정확히 금지하는 것이므로, 해결책은 코드로 계산하여 팩트 패크에 넣는 것입니다.
게이트는 팩트 패크만큼만 좋습니다. FMP에 필드가 누락되면 참인 진술도 게이트를 통과하지 못합니다. 우리는 잘못된 승인보다는 거짓 거부를 받아들이지만, 이는 처리량(throughput)을 소모합니다.
추출이 취약한 부분입니다. 정규 표현식 기반의 숫자 추출은 형식에 대해 지속적인 주의가 필요합니다. 만약 처음부터 다시 시작한다면, 그림의 구조화된 표현을 더 일찍 정의하여 작성자가 태그가 지정된 플레이스홀더를 내보내고 코드가 값을 채우도록 할 것입니다. 이렇게 하면 두 채널이 현재보다 훨씬 더 엄격해질 것입니다.
해싱은 저렴하지만 용서가 없습니다. 승인된 텍스트의 공백 수준 변경이라도 이를 무효화합니다. 이것이 우리가 원하는 동작이지만, 정규화 규칙을 사전에 결정해야 함을 의미합니다.
마무리
핵심 아이디어는 간단합니다. 틀릴 경우 감당하기 어려운 일은 모델에게 맡기지 말고, 다른 모델의 요약본이 아닌 원본 소스를 통해 검증해야 합니다. 숫자 게이트(number gate), 좁은 리뷰어(narrow reviewer), 그리고 두 개의 해시값(hashes) 조합은 정교하지 않지만, 함께 사용하면 우리가 확인할 수 있는 특정한 약속을 만듭니다. 즉, 페이지의 수치들이 모델이 아닌 데이터 제공자로부터 왔다는 것입니다.
AI 자동 생성 콘텐츠
본 콘텐츠는 Dev.to AI tag의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기