2026-10-09 · x.com

ChatGPT Intelligent UI를 리버스 엔지니어링했다. 실제로는 이렇게 작동한다

  1. (1)읽기 전에
  2. (2)Executive Summary
  3. (3)팩트체크
  4. (4)원본 (완역)
  5. (5)원본 링크·인용
  6. (6)기타

x.com · X 아티클

ChatGPT Intelligent UI를 리버스 엔지니어링했다. 실제로는 이렇게 작동한다

ChatGPT의 Intelligent UI가 모델 출력에서 화면까지 거치는 다섯 계층을 응답 하나로 따라간 리버스 엔지니어링 기록이다.

읽기 전에

ChatGPT의 Intelligent UI는 모델이 써 내려가는 응답을 어떻게 조작 가능한 화면으로 바꾸는가? 원문의 답은 네 단계의 분업이다. 모델은 Markdown에 JSX 비슷한 태그와 JavaScript를 섞은 전용 언어 DIL로 응답을 쓴다. 서버는 몇백 밀리초마다 모델이 그때까지 쓴 응답 전체를 다시 컴파일해 JavaScript 프로그램과 JSON 문서로 바꾼다. 브라우저에서는 샌드박스 iframe이 띄운 워커(Web Worker)가 그 프로그램을 실행해 UI 연산(operation) 목록을 낸다. ChatGPT 페이지는 그 연산을 자기 네이티브 컴포넌트에 적용한다.

모델이 내는 것은 화면이 아니라 프로그램의 소스다. React Native의 JavaScript 스레드처럼, 워커는 컴포넌트 트리를 계산할 뿐 화면을 직접 그리지 않는다. 훅 상태도 워커가 쥐고 있어서, 사용자가 슬라이더를 끌면 모델 호출 없이 워커가 다시 렌더링해 갱신 연산만 낸다.

원문은 아래 개념을 설명 없이 쓴다.

  1. Executive Summary — 원문의 주장 전체를 먼저 훑는다.
  2. 팩트체크 — 완역에 들어가기 전에 어느 주장이 외부 자료로 뒷받침되는지 본다.
  3. 원본 (완역)
    1. 「구성 요소」 — 「추론 포맷」 · 「서버 측 컴파일」 · 「클라이언트 런타임」 · 「렌더링」 · 「디자인 시스템과 카탈로그」. 앞 네 절은 팀 인원(seats) 슬라이더가 달린 예시 응답 하나를 층마다 다시 보여 준다. 그 상태 하나를 DIL 한 줄에서 연산 목록까지 따라가면 층의 경계가 보인다.
    2. 「스트리밍」 — 「서버 측 스트리밍」 · 「클라이언트 측 스트리밍」. 모델이 반쯤 쓴 프로그램은 그대로 실행할 수 없다. 서버와 클라이언트가 이 문제를 나눠 푼다.
    3. 「비상구: AppBlock, iframe 안의 앱」 — Web Audio 드럼 머신처럼 네이티브 컴포넌트가 다루지 않는 요청은 iframe 안의 독립 웹 앱으로 빠져나간다.
    4. 「전체 그림」 — 「방법론」. 짧은 「방법론」 절이 모든 관찰의 출처와 시점을 밝힌다.
  1. 모델이 반쯤 쓴 응답을 서버가 컴파일할 수 있는 이유는 무엇인가? → 완역 「추론 포맷」
  2. 새 프로그램이 도착해도 사용자가 옮긴 슬라이더 값이 처음으로 돌아가지 않는 이유는 무엇인가? → 완역 「클라이언트 측 스트리밍」
  3. 모델이 카탈로그에 없는 속성을 쓰면 그 속성은 어느 단계에서 지워지는가? → 완역 「디자인 시스템과 카탈로그」

Executive Summary

저자의 리버스 엔지니어링에 따르면 ChatGPT의 Intelligent UI는 모델이 쓴 HTML을 페이지에 넣는 방식이 아니다. 모델은 OpenAI가 DIL이라 부르는 전용 언어로 화면을 쓴다. 서버가 그 출력을 JavaScript 프로그램과 JSON 문서로 컴파일한다. 브라우저의 샌드박스 워커가 프로그램을 실행해 UI 연산(operation) 목록을 낸다. ChatGPT 페이지는 그 연산대로 자기 디자인 시스템의 네이티브 컴포넌트를 그린다.

화면이 뜬 뒤의 조작은 워커 안에서 끝난다. 슬라이더를 움직여도 모델을 다시 부르지 않는다. 모델이 HTML을 직접 쓰는 경우는 AppBlock이라는 비상구(escape hatch)뿐이다. 그 앱도 페이지가 아니라 iframe 안에서 돈다.

대상은 OpenAI가 2026-10-07(UTC) “GPT-6와 Intelligent UI를 모든 ChatGPT 사용자에게 배포하기 시작했다”고 알린 기능이다. OpenAI는 Intelligent UI를 “일상 질문은 더 시각적으로, 복잡한 주제는 더 이해하기 쉽게 만들고 작업에 맞는 인터랙티브 도구를 그 자리에서 내놓는 빠른 인터랙티브 답변”으로 소개했다. 저자는 ChatGPT가 Generative UI를 “마침내” 내놓았다고 쓴다. ChatGPT가 이 분야의 이름까지 하룻밤 새 Intelligent UI로 바꿨다고 본다. 저자의 평가로는 모델 전용 언어, 서버 컴파일 단계, 네이티브 렌더러, 모델 출력을 붙잡아 두는(grounded) 디자인 시스템이 함께 수십억 사용자에게 다음 세대 AI 네이티브 인터페이스를 제공한다.

ChatGPT Intelligent UI 아키텍처 그림. 모델 칸의 추론 포맷(DIL: Markdown, JSX, JS)이 백엔드 서버 칸의 서버 측 컴파일(부분 출력 수리, 속성 검증, 텍스트를 상수로 이동)을 거쳐 JS 프로그램과 JSON 데이터가 된다. 사용자 클라이언트 칸에서는 샌드박스 iframe과 Web Worker 안의 클라이언트 런타임이 seats = 8 상태로 프로그램을 돌려 UI 연산을 렌더링에 넘긴다. 렌더링은 Team plan estimate $232/mo 카드를 그린다. 사용자 이벤트는 콜백으로 런타임에 돌아간다. 아래 띠는 디자인 시스템과 카탈로그다.
원문의 아키텍처 그림. 모델(추론 포맷) → 백엔드 서버(서버 측 컴파일) → 사용자 클라이언트(클라이언트 런타임 → 렌더링) 순서로 흐른다. 아래 띠는 디자인 시스템과 카탈로그다.

DIL과 서버 측 컴파일: 클라이언트가 할 일을 서버가 먼저 한다

DIL이 따로 있는 이유는 모델이 화면을 토큰 하나씩 쓰기 때문이다. DIL에서 산문은 Markdown, 컴포넌트는 JSX 비슷한 태그, 상태와 로직은 JavaScript다. 모두 모델이 이미 잘 아는 표기라서 안정적으로 쓰기 쉽다. 명령문은 한 줄에 하나씩 놓인다. 열린 요소는 언제든 자동으로 닫을 수 있다. 반쯤 쓴 응답도 서버가 마지막 완결 구문에서 잘라 컴파일할 수 있는 까닭이다.

저자는 팀 요금제 견적 응답 하나를 모든 층에 걸쳐 따라간다. 제목 ## Team plan estimate와 **monthly price**를 굵게 쓴 문단은 평범한 Markdown이다. {@body …} 두 줄은 JavaScript다. 첫 줄은 DIL.useState(8)로 상태 seats를 선언한다. 둘째 줄은 거기서 price = seats*29를 끌어낸다. 카탈로그 컴포넌트 <box border padding={3} gap={2}> 안에는 슬라이더(min={1} max={50} value={seats} onChange={setSeats})와 가격을 보이는 <title size="xl">가 있어서, 슬라이더를 움직이면 가격이 바뀐다.

클라이언트는 모델 출력을 쓰인 그대로 실행하지 않는다. 서버는 컴파일 결과를 메시지와 함께 model_dil_v2로 저장한다. 프로그램은 도우미 함수 __dilSafe의 정의와 DIL.render(__dil.jsx(…, { key: "body:2" })) 호출 하나로 이뤄진다. 그 안에서 DIL.useConstants()는 상수 표를 __dilConstants에, DIL.useAppData는 appData.opGenui?.modelDataBindings를 __dilModelDataBindings에 담는다. Markdown도 컴포넌트와 같은 트리(__dil.Fragment 아래)에 들어간다. 제목은 title(크기 "lg")이, 문단은 안에 bold가 든 text가 된다.

일반 함수 호출
마크업이 __dil.jsx 호출로 바뀐다. JavaScript 런타임은 DIL 파서 없이 프로그램을 평가한다.
오류 격리
식마다 __dilSafe(evaluate, failureValue)로 감싼다. 예외를 던진 식은 실패값을 돌려준다. 요소를 만드는 식의 실패값은 null이라서 렌더 전체가 멈추는 대신 요소 하나만 빠진다.
텍스트 분리
정적 텍스트를 상수 표로 옮긴다. 스트리밍 중에 텍스트가 자라면 프로그램이 아니라 데이터가 바뀐다.
고정 상태 키
상태마다 키({ key: "seats" })를 붙인다. 값은 재컴파일을 몇 번 거쳐도 살아남는다.
수리와 검증
미완 명령문과 태그는 버린다. 닫히지 않은 요소는 닫는다. 카탈로그 검증에 실패한 속성은 지운 뒤 진단(diagnostic)으로 남긴다.

JSON 문서에는 텍스트 상수와 서버가 응답을 위해 가져온 데이터가 든다. 이미지 검색 결과가 그런 데이터다. 예시 응답의 JSON에는 상수 “0”~“5”(“Team plan estimate”부터 “/mo”까지)와 비어 있는 componentResults·modelDataBindings가 있다.

클라이언트: 잠긴 워커가 낸 연산을 페이지가 네이티브 컴포넌트로 그린다

클라이언트의 일은 프로그램을 실행하는 런타임과 결과를 그리는 렌더러로 나뉜다. 프로그램은 모델이 쓴 코드라서 ChatGPT 페이지에서 돌지 않는다. ChatGPT는 숨은 iframe runner.html을 띄운다. 이 iframe은 allow-scripts 샌드박스와 콘텐츠 보안 정책 default-src 'none' 아래 있다. 그 안에서 Web Worker가 뜬다.

런타임은 React 방식의 작은 리컨실러(reconciler)다. 리컨실러는 컴포넌트를 렌더링한다. 훅 상태는 키가 붙은 슬롯에 둔다. 새 트리를 이전 트리와 비교해 차이를 연산 목록으로 인코딩한다. 그리기는 하지 않는다.

저자가 예시라고 밝힌 첫 렌더의 연산은 노드마다 한 줄이다. 각 요소의 속성 이름을 나열하는 항목은 생략했다. 연산은 CREATE #1 title SET size = "lg" PLACE under root at 0부터 CREATE #13 text "/mo"까지 노드 13개를 만들어 제자리에 붙인다. 슬라이더 #9는 value = 8, onChange = fn#1을 받는다. #12의 텍스트 “232”는 8 × 29의 값이다.

함수는 워커 밖으로 나가지 않는다. 슬라이더 핸들러는 식별자 fn#1로만 건너간다. 전송 중의 연산은 정수로 된 이진 시퀀스다. 문자열은 별도 표에 담는다.

페이지는 아는 컴포넌트 종류의 연산만 받는다. 모델 출력이 임의 마크업이나 스타일을 들여올 수 없는 이유다. 예외는 일부 속성이 받는 raw CSS 값과 AppBlock 둘이다. 페이지는 연산을 자기 컴포넌트 트리에 적용한다. CREATE마다 ChatGPT 디자인 시스템의 네이티브 컴포넌트를 하나씩 만든다.

조작은 반대 방향으로 흐른다. 사용자가 슬라이더를 9로 끌면 페이지는 핸들러 식별자와 인자를 워커에 보낸다. 워커는 setSeats(9)를 호출한 뒤 다시 렌더링해 갱신 연산을 돌려준다.

카탈로그: 모델은 그리지 않고 고른다

카탈로그는 모델이 요청할 수 있는 것을 정한다. 모델은 raw 레이아웃·스타일 규칙으로 화면을 짓지 않는다. ChatGPT가 이미 그릴 줄 아는 컴포넌트를 골라 padding={3} 같은 디자인 토큰으로 꾸민다. 일부 속성은 픽셀 폭이나 hex 색 같은 raw CSS 값도 받는다. 우선하는 쪽은 디자인 토큰이다.

카탈로그 덕에 생성된 화면은 모든 플랫폼에서 ChatGPT의 나머지 화면과 같은 모습이 된다. 컴파일러도 출력을 비춰 볼 스키마를 얻는다. 검증에 걸리는 것은 컴포넌트에 없는 속성과 타입이 틀린 리터럴이다. 캡처한 응답 하나에서 컴파일러는 속성 둘을 지웠다. 아이콘의 fill은 unknown_prop 진단으로, 박스의 gap="1"은 invalid_literal 진단으로 남았다.

스트리밍: 서버는 매번 처음부터 다시 컴파일한다

텍스트 스트리밍은 새 토큰을 화면 끝에 붙이면 된다. 인터페이스는 그렇게 스트리밍할 수 없다.

ChatGPT는 원시 텍스트, 컴파일된 프로그램, 데이터를 나란히 담은 구조화된 메시지에 패치를 스트리밍한다. 응답은 서버 전송 이벤트(Server-Sent Events) 스트림 POST /backend-api/f/conversation으로 브라우저에 온다. 이벤트 하나하나가 만들어지는 메시지에 대한 JSON-Patch 형식의 업데이트다. 업데이트 하나는 대개 원시 DIL 텍스트와 그 컴파일 결과를 함께 바꾼다.

저자가 양고기 로스트 응답에서 캡처한 업데이트 하나에는 패치 항목이 다섯 개 있다. /message/content/parts/0에는 텍스트를 append한다. /message/metadata/model_dil_v2/code는 프로그램 전체를 replace한다. 같은 model_dil_v2 아래 constants에는 상수 “0”과 “1”을, fallbackMarkdown에는 텍스트를 append한다.

서버는 증분 컴파일을 하지 않는다. 수백 ms마다 모델이 지금까지 쓴 전체를 다시 컴파일해 결과를 보낸다. 저자는 그 주기가 “아마도(most likely)” 새 출력 청크마다라고 추정한다. 컴파일은 태그가 하나도 나오기 전인 첫 토큰부터 시작한다. 컴파일러가 감당할 일은 반쯤 쓴 응답의 컴파일, 텍스트 업데이트, UI 업데이트다.

페이지는 업데이트가 올 때마다 샌드박스 워커에 넘긴다. 워커는 새 프로그램을 평가한 뒤 기존 상태로 다시 렌더링해 갱신 연산을 보낸다. 새 프로그램이 평가나 렌더링에 실패하면 워커는 마지막으로 성공한 프로그램을 유지한다. 페이지는 변경이 도착하는 대로 애니메이션을 입힌다.

0.7초

텍스트가 페이드인하는 시간

0.42초

새 행과 그리드 항목이 미끄러져 들어오는 시간

1.8초

차트가 그려지는 시간

컨테이너 높이는 튀지 않고 전환 애니메이션으로 바뀐다.

AppBlock: 네이티브 컴포넌트로 안 되는 요청의 비상구

네이티브 컴포넌트가 다루도록 설계되지 않은 요청이 있다. Web Audio로 소리를 합성하는 드럼 머신이 그 예다. 이런 요청에는 모델이 AppBlock을 쓸 수 있다. AppBlock은 HTML, CSS, JavaScript로 된 독립 웹 앱이다. 응답 안에 그대로 들어간다.

저자가 줄여 보인 예는 <AppBlock title="Drum Lab" icon="app-chatgpt" variant="inline" app_block_id="drum-lab-01">으로 시작한다. 안의 스타일은 --viz-text, --viz-panel, --viz-border, --viz-card 변수로 색을 정한다. 스크립트는 window.AudioContext||window.webkitAudioContext로 오디오 컨텍스트를 만든다. X 아티클은 AppBlock이 Intelligent UI 컴포넌트와 다르게 렌더링된다고만 쓴다.

근거의 범위: 웹에서만 관찰했다

X 아티클의 관찰 경로는 웹뿐이다. 저자는 모든 관찰이 자기 팀의 ChatGPT 계정, ChatGPT 웹앱이 만드는 트래픽, chatgpt.com이 공개로 제공하는 JavaScript에서 나왔다고 밝힌다. 관찰은 2026-10에 GPT-6와 GPT-6 Thinking으로 했다. 도입부는 Web과 Mobile 양쪽의 네이티브 렌더링을 다룬다고 쓴다. 모바일 쪽 관찰은 글 어디에도 없다.

분석은 Codex와 Claude의 도움을 받았다. 글은 Codex로 썼다. 시각화는 Claude가 만들었다.

openui.com 확장판에만 있는 것

X 아티클 끝에서 저자가 더 깊은 판본으로 링크한 openui.com 글(2026-10-08)은 같은 분석에 What is Intelligent UI?, Data, Actions, Markdown fallback, Rough edges 절을 더한다. X 아티클이 “(see Data)”로 가리키는 절도 그쪽에만 있다. 이 부분의 수치와 사례는 모두 확장판에서 왔다. 아래 각 줄의 앞은 X 아티클이 설명한 설계 요소다. 뒤는 확장판이 같은 요소에서 잰 결과다.

상수 표 분리
6,341자 응답 하나가 18.7초 동안 업데이트 84개로 왔다. 텍스트를 실은 76개 가운데 52개는 구조가 바뀌어 프로그램 전체를 다시 보냈다. 상수만 바꾼 것은 14개, 미완 태그 안이라 화면이 그대로인 것은 10개다. 나머지는 메시지 생성 1개, 이미지 결과 5개, 완료 표시 2개다. 프로그램은 닫는 괄호가 재컴파일마다 바뀌는 단일 중첩 식이라서 이어 붙일 수 없다. 텍스트 6.3 KB를 보내는 데 패치가 약 275 KB 들었다. 그 83%가 다시 보낸 프로그램이다.
수백 ms 주기의 재컴파일
업데이트 간격의 중앙값은 230 ms였다. 전체 재컴파일은 290 ms마다 일어났다. 다른 캡처 두 건에서는 업데이트가 약 410 ms마다 왔다.
리컨실러의 차이 인코딩
가격 위젯을 한 번 클릭하자 연산 158개가 나왔다. 실제로 무언가를 바꾼 것은 그중 4개다. 조작 때마다 바뀌지 않은 속성도 다시 보낸다.
__dilSafe 오류 격리
논리 오류는 조용히 지나간다. 예외를 던진 식은 아무것도 그리지 않는다. 틀린 로직은 잡히지 않는다. 한 대시보드에서 차트 지표를 바꾸자 매출 수치가 $6,930에서 $256,410으로 바뀌었다.
고정 상태 키
페이지를 새로고침하면 사용자가 바꾼 값이 사라진다. 클라이언트가 그 값을 view-state 엔드포인트로 보내는데도 그렇다.
카탈로그 검증과 진단
모델은 이후 응답에서 같은 실수를 되풀이했다. 저자는 진단이 모델에 닿지 않을 수 있다고 본다.
모든 플랫폼에서 같은 모습
응답은 고정된 열 수와 픽셀 폭을 썼다. 캡처한 응답 가운데 제공되는 브레이크포인트 훅을 쓴 것은 없었다.

Data. 도구 결과에는 사용자가 행동의 근거로 삼을 값이 들어 있다. 소매점 가격, 장소 주소, 페이지의 이미지가 그렇다. 이런 값이 모델을 거치면 옮겨 적다 틀리거나 없는 세부가 끼어들 위험이 있다. ChatGPT는 그래서 일부 데이터를 모델 출력과 따로 공급한다. 모델은 요청이나 참조만 쓴다. 값은 서버가 컴파일된 프로그램 옆 appData에 채운다.

모든 도구 데이터가 이 길로 오지는 않는다. 웹 검색에서 얻은 날씨 수치는 모델이 직접 응답에 썼다. 이미지 검색은 빗나갈 수 있다. 모델은 쿼리만 쓴다. 결과는 보지 못한다. 핸들바 변속기 클로즈업을 찾은 쿼리에 전기자전거 판매 페이지의 이미지가 왔다.

Actions. 응답 밖으로 닿는 조작만 액션이다. 프로그램은 호스트가 주는 작은 GenUI 객체로 액션을 부른다. 확장판이 예로 든 함수는 issueNewTurn(text), copy(text), openUrl(url), openEntityDetail(ref) 넷이다. 인터페이스가 모델과 통하는 길은 issueNewTurn 하나다. 이 함수는 프로그램이 상태로 조립한 문장을 새 사용자 메시지로 보낸다. 강아지 조끼 무드보드에서 스타일과 색을 고르자 버튼이 “… Style: cozy. Main color: sand. Features: Reflective details, Adjustable straps. …”라는 메시지를 만들었다.

이 메시지는 직접 친 메시지와 똑같이 저장된다. 인터페이스에서 왔다는 표시는 없다. 폼도 <form onSubmit={…}>과 <button submit>으로 폼 값을 담아 issueNewTurn을 부른다. 모델은 인터페이스 상태를 보지 못한다. 모델이 받는 것은 issueNewTurn으로 보낸 메시지의 텍스트뿐이다. 물어보자 모델은 사용자가 바꾼 값을 말하지 못했다.

후속 질문은 새 프로그램을 가진 새 응답을 만든다. 기존 인터페이스를 고치는 일은 없다.

Markdown fallback. 응답은 한 번만 저장된다. 그 응답을 실행하지 못하는 클라이언트도 응답을 연다. 저자는 그런 클라이언트를 아마 구버전 앱으로 본다. 서버는 컴파일된 프로그램마다 일반 Markdown판 fallbackMarkdown을 함께 만든다. 스트리밍 패치에 나온 바로 그 경로다.

이 판에서 산문은 그대로 남는다. 이미지, 상품, 인용, 지도는 ChatGPT 클라이언트가 이미 그리는 인라인 마크업으로 바뀐다. 인터랙티브 부분은 정적 텍스트로 줄어든다. 상태에서 계산한 값과 {#each} 안의 내용은 빠진다.

AppBlock. 확장판에 따르면 컴파일러는 AppBlock을 번역하지 않는다. 컴파일된 프로그램에는 자리표시자 __chatgptClientDefinedWidget만 남는다. 클라이언트는 앱 소스를 원시 응답 텍스트에서 읽는다. ChatGPT는 앱을 별도 도메인 codex-inline-visualization-<hash>.web-sandbox.oaiusercontent.com의 보이는 iframe에서 돌린다. 호스트는 ChatGPT가 앱(apps)에 쓰는 것과 같은 “Skybridge”다. 모델의 HTML은 그 안쪽 프레임에 써 넣는다.

호스트가 앱을 주변 대화에 맞추는 수단은 Tailwind 기본 스타일 주입, 라이트·다크 테마를 따르게 하는 변수(예: --viz-text, --viz-panel, --viz-accent), 내용에 맞춘 iframe 크기다. 앱 상태는 앱의 JavaScript 변수에만 있어서 새로고침하면 사라진다. 캡처에서 앱은 ChatGPT를 한 번도 호출하지 않았다.

방법론. 확장판은 샌드박스 runner와 워커(프로토콜 버전 14)의 코드를 읽었다고 쓴다. 수정하지 않은 runner를 로컬 테스트 페이지에서 돌려 실제로 내는 연산도 기록했다. 서버 컴파일러는 DIL 원문과 컴파일 결과의 쌍으로 재구현했다. 저자는 재구현한 컴파일러의 출력이 스트리밍 중간본과 완성본 모두에서 OpenAI의 출력과 바이트 단위로 일치했다고 쓴다.

확장판도 모바일 구현은 살피지 않았다. 워커 샌드박스는 React Native의 JavaScript 엔진 Hermes의 전역도 허용한다. 저자는 이를 근거로 모바일 앱도 같은 런타임을 돌려 연산을 자기 네이티브 렌더러로 적용한다고 추정한다. 이 추정은 직접 확인하지 않았다고 쓴다.


팩트체크

신뢰도 A

정합성 한줄평: 기술 서술은 OpenAI가 공개로 서빙하는 런타임·번들 코드와 맞물린다. 과장은 출시 프레이밍과 적용 범위 표현에 몰려 있다.

내부 구조 주장의 출발점은 저자 팀의 관찰이다. OpenAI가 공식 문서로 밝힌 내부 구조는 네이티브 스트리밍 컴포넌트 라이브러리와 생성 중에 동작하는 컴파일러 두 가지뿐이다. 나머지 주장 대부분은 chatgpt.com이 서빙하는 공개 JavaScript·CSS와 OpenAI CDN의 런타임 코드와 맞는다. 공개 코드는 2026-10-11 배포본 기준이다. 저자와 무관한 제3자의 트래픽 캡처도 하나 있다. GitHub 저장소 Disdjj/intelligent-ui-demo로, X 원문보다 약 7시간 반 앞선 2026-10-08 09:21 UTC에 공개됐다. 아래에서 '독립 캡처'는 이 저장소를 가리킨다. 이 캡처도 같은 구조에 도달했다. 서버 컴파일러 내부, 진단 코드 이름, 모바일 구현은 독립 근거가 없다. 재컴파일 간격은 독립 캡처의 값이 저자 값과 다르다.

이해관계: 저자의 회사 Thesys는 OpenUI를 판다. OpenUI는 Generative UI용 언어와 런타임으로, ChatGPT의 Intelligent UI와 같은 범주의 제품이다. 원문의 확장판도 openui.com에 실렸다. 이 이해관계는 공개 코드로 맞춰 볼 수 있는 기술 주장보다 '분야 이름이 바뀌었다', '수십억 사용자' 같은 프레이밍에서 드러난다.

범례: 사실 = 공식 문서·공개 코드·독립 캡처 가운데 하나 이상이 뒷받침하는 주장 · 부분 사실 = 핵심은 맞지만 범위·수치·표현이 근거와 다른 주장 · 불확실 = 저자 측 진술 밖의 근거가 없는 주장 · 거짓 = 근거와 어긋나는 주장 · 등급 A–F = 주장 전체의 신뢰도. A는 거짓 없이 핵심 주장 대부분이 독립 근거와 맞는다. B는 핵심은 맞지만 부분 사실이 많다. C는 핵심 일부가 근거 없거나 틀리다. D는 핵심 다수가 틀리다. F는 날조다.

출시와 프레이밍

부분 사실

ChatGPT가 마침내 Generative UI를 출시했다. 하룻밤 새 이 분야의 이름도 Intelligent UI로 바꿨다.

OpenAI는 2026-10-07 GPT-6와 함께 Intelligent UI를 발표했다. 발표문에는 'Generative UI'라는 말이 한 번도 나오지 않는다. OpenAI가 이름을 붙인 대상은 분야가 아니라 자사 기능이다. Generative UI는 Vercel이 2024-03-01에, Google Research가 2025-11-18에 이미 쓴 업계 용어다. 새 이름을 따라간 사례로 확인되는 곳은 openui.com이다. 웹 아카이브 사본에서 이 사이트의 제목은 2026-10-05 'The Open Standard for Generative UI'였다. 2026-10-08 사본에서는 'The Open Standard for Intelligent UI'다.

OpenAI 발표문(2026-10-07) · Vercel 블로그(2024-03-01) · Google Research 블로그(2025-11-18) · openui.com 아카이브(2026-10-05) · openui.com 아카이브(2026-10-08)

부분 사실

원문이 인용한 OpenAI 공지(X, 2026-10-07 18:05 UTC): "GPT-6와 Intelligent UI가 이제 ChatGPT의 모든 사용자에게 배포되고 있다."

인용 문구는 원 게시물과 같다. 배포는 단계식이다. Plus·Pro·Business·Enterprise는 2026-10-07, Free·Go는 2026-10-08부터다. Intelligent UI는 웹과 최신 버전 앱에서 Instant부터 Extra High 단계까지만 켜진다. Pro 단계(GPT-6 Astra)와 구형 macOS·Windows 데스크톱 앱은 지원하지 않는다. 2026-10-10에 갱신된 OpenAI 도움말은 여전히 '배포 중'이라고 쓴다. 같은 도움말의 Free·Go 항목에는 GPT-5.6 Luna가 남아 있다. 2026-10-11까지 확인되는 배포 중단 보도는 없다. 2026-10-11 기준 '모두'는 진행 중인 배포를 가리킨다.

OpenAI X 게시물(2026-10-07) · ChatGPT 릴리스 노트 · OpenAI 도움말: GPT-6 and other models in ChatGPT · Fello AI(2026-10-09)

부분 사실

원문은 웹과 모바일 양쪽의 네이티브 렌더링까지 연구했다고 소개한다. 생성된 인터페이스가 모든 플랫폼에서 ChatGPT의 나머지 화면과 같아 보인다고도 쓴다.

원문 방법론이 밝힌 관찰 대상은 ChatGPT 웹앱과 chatgpt.com의 공개 JavaScript다. 같은 저자들의 확장판은 "Mobile implementations were not examined"라고 적었다. OpenAI 발표문은 웹과 모바일 모두에서 빠르고 익숙한 경험을 목표로 한다고 쓴다. 공개 런타임의 전역 허용 목록에는 React Native용 JavaScript 엔진 Hermes의 전역(HermesInternal)이 있다. 모바일 앱이 같은 런타임을 쓴다는 정황일 뿐 확인은 아니다.

OpenUI 블로그 확장판(2026-10-08) · OpenAI 발표문 · DIL 런타임 번들(OpenAI CDN)

부분 사실

이 구조가 전 세계 수십억 사용자에게 차세대 AI 네이티브 인터페이스를 제공한다.

OpenAI가 2026-10-07 발표문에 밝힌 규모는 'ChatGPT를 매주 쓰는 12억 명 이상'이다. '수십억'은 이 공식 수치를 부풀린 표현이다.

OpenAI 발표문(2026-10-07)

전체 구조와 DIL

사실

작업은 모델, 백엔드 서버, 클라이언트가 나눠 맡는다. 모델은 카탈로그의 컴포넌트를 골라 인터페이스를 쓴다. 컴파일러가 이를 처리한다. ChatGPT는 자체 네이티브 컴포넌트로 그린다.

OpenAI 발표문이 직접 밝힌 범위가 여기까지다. OpenAI는 네이티브 스트리밍 컴포넌트 라이브러리와 '모델이 생성하는 동안 인터페이스를 처리하는 컴파일러'를 만들었다고 썼다. 모델이 이 컴포넌트 라이브러리를 쓰도록 훈련했다고도 밝혔다. 컴파일러의 위치, DIL, iframe, 워커 같은 세부는 OpenAI 문서에 없다. 이 세부의 근거는 공개 코드와 독립 캡처다.

OpenAI 발표문: How Intelligent UI works

사실

모델은 OpenAI가 DIL이라고 부르는 언어로 인터페이스를 쓴다. 산문은 Markdown, 컴포넌트는 JSX식 태그, 상태와 로직은 JavaScript로 쓴다.

DIL이라는 이름은 OpenAI의 공개 설명에 없다. OpenAI 코드에는 있다. chatgpt.com이 서빙하는 공개 JavaScript 번들에 model_dil_v2 필드와 dilVersion "2.0" 값이 있다. 다른 번들에는 *.dil.tsx 소스 영역 5개가 문자열로 들어 있다. OpenAI CDN에 있는 런타임 문서의 제목은 "DIL Runner"다. 독립 캡처에 담긴 DIL 원문 23,422자도 Markdown, 소문자 컴포넌트 태그, JavaScript 문장이 섞인 형태다.

chatgpt.com 번들 200429 · chatgpt.com 번들 805171 · DIL runner.html · 독립 캡처 저장소

사실

{@body …} 줄은 JavaScript 문장이다. 예시의 첫 줄은 DIL.useState로 상태 seats를 선언한다. 둘째 줄은 seats에서 price를 계산한다.

chatgpt.com 번들의 진단 스키마가 지시어 종류를 body, module, each로 정의한다. 공개 런타임은 DIL.useState 훅을 구현한다. 독립 캡처의 DIL 원문에는 {@body} 문장이 40개 있다.

chatgpt.com 번들 200429 · DIL 런타임 번들 · 독립 캡처 DIL 원문

사실

DIL은 반쯤 쓴 상태로도 컴파일된다. 서버는 미완성 응답을 마지막 완결 구문에서 잘라 컴파일한다. 미완성 문장과 태그는 버린다. 닫히지 않은 요소는 닫는다. 카탈로그 검증에 실패한 속성은 지운 뒤 진단으로 남긴다.

chatgpt.com 번들의 model_dil_v2 스키마에 recoveryDiagnostics 목록이 있다. 기록하는 조치는 dropped_expression, dropped_prop, omitted_node, recovered_parse, replaced_with_fallback 다섯 종이다. 진단마다 줄·열 번호와 지시어 종류가 붙는다. 독립 캡처에서는 응답 하나를 스트리밍하는 동안 이 진단 관련 패치가 338건 나왔다.

chatgpt.com 번들 200429 · 독립 캡처 분석 노트

서버 컴파일

사실

클라이언트는 모델 출력을 쓰인 그대로 실행하지 않는다. 서버가 이를 JavaScript 프로그램과 JSON 문서로 컴파일한다. 결과는 메시지에 model_dil_v2로 저장된다.

chatgpt.com 번들은 model_dil_v2를 code(문자열), constants, appData 필드를 가진 객체로 검증한다. 컴파일 결과에 들어가는 보조 함수 __dilSafe는 chatgpt.com 첫 화면이 불러오는 번들 168개 어디에도 없다. 클라이언트가 완성된 코드를 받는다는 정황이다. 독립 캡처에서도 코드는 /message/metadata/model_dil_v2/code 경로의 패치로 내려왔다.

chatgpt.com 번들 200429 · 독립 캡처 분석 노트

사실

컴파일된 프로그램은 __dil.jsx 호출 트리다. DIL.useConstants와 DIL.useAppData로 데이터를 읽는다. 루트에는 { key: "body:2" } 같은 키를 단다. 제목과 문단 같은 Markdown도 같은 트리의 title, text, bold로 들어간다.

독립 캡처의 컴파일 결과는 원문 예시와 같은 __dilSafe 정의로 시작한다. __dilConstants에는 DIL.useConstants()를 담는다. __dilModelDataBindings는 appData.opGenui?.modelDataBindings에서 읽는다. 루트 키는 {"key":"body:40"}이다. 그 응답의 {@body} 문장 수와 같은 숫자다. 공개 런타임은 루트 키를 /^body:\d+$/ 패턴으로 검사한다. 네이티브 컴포넌트 레지스트리에는 title, text, bold가 있다.

독립 캡처 컴파일 결과 · DIL 런타임 번들 · chatgpt.com 번들 913894

사실

정적 텍스트는 상수 테이블로 옮겨진다. 스트리밍 중 늘어나는 텍스트는 프로그램이 아니라 데이터를 바꾼다.

model_dil_v2 스키마에서 constants는 code와 별도 필드다. 독립 캡처에서는 constants 패치가 109건 나왔다. 최종 상수는 108개였다. 컴파일 결과는 상수를 __dilConstants["0"]처럼 번호로 가리킨다.

chatgpt.com 번들 200429 · 독립 캡처 분석 노트

사실

표현식을 __dilSafe로 감싸 둔다. 예외를 던진 표현식은 요소 하나만 지운다. 렌더링 전체는 멈추지 않는다.

독립 캡처의 컴파일 결과에 원문과 같은 __dilSafe 정의가 있다. try로 평가하고 실패하면 대체값을 돌려주는 한 줄 함수다. 요소 호출은 대체값 null로 감싼다.

독립 캡처 컴파일 결과

사실

상태마다 { key: "seats" } 같은 키를 붙인다. 재컴파일을 거쳐도 값이 유지된다.

공개 런타임의 DIL.useState는 두 번째 인자인 옵션을 상태 저장 계층(createStateHook)에 넘긴다. 독립 캡처의 컴파일 결과는 DIL.useState("overview",{key:"tab"})처럼 변수 이름을 키로 쓴다. 같은 캡처는 이 키가 view_state 저장 요청의 키와 하나씩 맞는다고 기록했다.

DIL 런타임 번들 · 독립 캡처 컴파일 결과 · 독립 캡처 분석 노트

불확실

저자가 캡처한 응답 하나에서 컴파일러가 속성 두 개를 지웠다. icon의 fill(unknown_prop 진단)과 box의 gap="1"(invalid_literal 진단)이다.

진단 스키마에는 속성 제거 조치(dropped_prop)와 속성 이름 필드(prop)가 있어 이런 기록이 들어갈 자리는 있다. 진단 코드는 서버가 정하는 자유 문자열이다. unknown_prop와 invalid_literal은 chatgpt.com 번들과 독립 캡처 어디에도 없다. 이 사례의 근거는 저자 캡처뿐이다.

chatgpt.com 번들 200429 · 독립 캡처 저장소

사실

JSON 문서에는 텍스트 상수와 함께 서버가 응답용으로 채운 데이터가 들어간다. 이미지 검색 결과가 그 예다.

chatgpt.com 번들은 model_dil_v2.appData.opGenui.componentResults를 컴포넌트 해석 ID(component_resolution_id)로 조회한다. 서버가 채운 결과가 프로그램과 별도로 appData에 실린다는 구조다.

chatgpt.com 번들 200429

클라이언트 런타임과 샌드박스

사실

모델이 쓴 코드는 ChatGPT 페이지에서 돌지 않는다. ChatGPT는 숨은 iframe(runner.html)을 띄운다. 이 iframe의 sandbox 속성은 allow-scripts다. 콘텐츠 보안 정책(Content Security Policy, CSP)은 default-src 'none'이다. 이 iframe이 워커(Web Worker)를 시작한다.

chatgpt.com 첫 화면의 DOM에는 대화를 시작하기 전부터 iframe 하나가 있다. src는 cdn.platform.openai.com/deployments/dil/v14/runner.html이다. sandbox 속성은 allow-scripts 하나다. 화면에는 보이지 않는다. 번들은 이 프레임을 prewarmDilFrame으로 미리 띄운다. runner.html의 CSP는 default-src 'none'으로 시작한다. 워커 출처로는 blob:과 data:만 연다. 공개 런타임은 워커 코드를 Blob으로 만들어 시작한다.

chatgpt.com 첫 화면 · DIL runner.html · chatgpt.com 번들 416001 · DIL 런타임 번들

부분 사실

워커는 프로그램을 평가하기 전에 전역 범위에서 네트워크, 타이머, 메시징, 동적 코드 평가를 지운다. 남은 전역은 동결한다.

공개 런타임의 harden_worker 단계는 워커 전역의 프로토타입 체인에서 브라우저 기능을 모두 지운다. 하나라도 남으면 "Failed to remove browser capability" 오류를 던진다. 허용 목록에는 fetch, setTimeout, postMessage가 없다. eval은 "DIL policy blocked dynamic code evaluation" 예외를 던지는 함수로 바뀐다. 함수·비동기 함수·제너레이터의 constructor 경로도 같은 함수로 막는다. 마지막으로 전역 객체 그래프를 깊이 동결한다. 동적 코드 평가 차단에는 빈틈이 하나 있다. 허용 목록에 전역 Function이 남는다. runner.html의 CSP도 'unsafe-eval'을 허용한다.

DIL 런타임 번들 · DIL runner.html

사실

워커는 프로그램을 new Function으로 평가한다. 런타임 객체 DIL, __dil, GenUI와 카탈로그의 합성 컴포넌트를 매개변수로 넘긴다.

공개 런타임은 매개변수 이름 목록과 "use strict"를 붙인 프로그램 문자열로 new Function을 만든다. 만든 함수는 값 목록을 인자로 받아 실행된다. 넘기는 객체에는 GenUI, DIL, __dil, Date가 있다. 합성 컴포넌트(dilComponents)도 함께 들어간다. 합성 컴포넌트 이름은 대문자로 시작해야 한다.

DIL 런타임 번들

사실

제한 시간 안에 응답하지 않는 프로그램은 격리(quarantine)된다. 워커는 재시작된다.

공개 런타임에는 상태 확인 요청과 제한 시간 상수(4,000ms, 500ms)가 있다. 응답이 없으면 quarantineSession이 세션을 격리한다. restartWorker가 워커를 다시 띄운다. 격리된 세션은 "The DIL runner request timed out" 오류로 끝난다.

DIL 런타임 번들

사실

런타임은 React 방식의 작은 리컨실러(reconciler)다. 훅 상태를 키 슬롯에 둔다. 새 트리를 이전 트리와 비교해 차이를 연산 목록으로 만든다. 그리는 일은 하지 않는다.

공개 런타임 번들의 모듈 경로에 dil_renderer의 DILHookRuntime·DILRenderFunctionRuntime과 dil_sandbox의 DILRenderOperations가 있다. 렌더러 상태에는 keyedComponents가 있다. 출력은 노드 생성, 속성 변경, 이동 같은 연산이다. 워커에는 DOM이 없다.

DIL 런타임 번들

사실

첫 렌더링은 CREATE·SET·PLACE 연산의 열로 나타난다. 원문은 이 목록이 예시라고 밝힌다. 가격 노드의 값은 "232"다.

실제 코드의 연산은 번호 7종이다. 요소 생성(1), 텍스트 생성(2), 삭제(3), 이동(4: 노드·부모·위치), 속성 변경(5), 텍스트 변경(6), 불투명 자식 변경(7)이다. CREATE·SET·PLACE는 1·5·4번 연산을 풀어 쓴 설명용 이름으로 읽힌다. 232는 좌석 8개 × 29달러와 맞는다.

DIL 런타임 번들

사실

함수는 워커 밖으로 나가지 않는다. 슬라이더 핸들러는 식별자(fn#1)로만 전달된다. 연산은 정수의 바이너리 열로 인코딩된다. 문자열은 별도 테이블에 담긴다.

공개 런타임의 인코더는 연산 번호와 노드 번호를 Uint32 정수로 버퍼에 쓴다. 문자열은 attachedValues 배열에 중복 없이 모은다. 버퍼에는 그 번호만 들어간다. 함수 값은 functionsById에 보관한다. 바깥에는 1부터 매기는 ID만 나간다.

DIL 런타임 번들

렌더링과 카탈로그

사실

ChatGPT 페이지는 연산을 자기 컴포넌트 트리에 적용한다. CREATE마다 ChatGPT 디자인 시스템의 네이티브 컴포넌트가 하나씩 생긴다.

chatgpt.com 번들의 디코더는 연산 속 타입 번호를 등록된 타입으로 바꾼다. 소문자 이름을 React 컴포넌트에 잇는 레지스트리 객체가 그 타입을 그린다. 각 컴포넌트는 data-d-component 속성을 단 ChatGPT 자체 마크업을 낸다.

chatgpt.com 번들 171425 · chatgpt.com 번들 913894

부분 사실

페이지는 알려진 컴포넌트 타입의 연산만 받는다. 모델 출력은 임의 마크업이나 스타일을 넣을 수 없다. 예외는 일부 속성이 받는 원시 CSS 값과 iframe에서 도는 AppBlock 앱 두 가지다.

런타임과 페이지 모두 등록되지 않은 타입을 "Unknown DIL element type" 오류로 거부한다. 원문이 꼽지 않은 경로가 레지스트리 안에 하나 더 있다. html-view 컴포넌트는 html 문자열을 받아 sandbox="allow-scripts" iframe의 srcDoc으로 그린다. 그 문서의 CSP는 인라인 스크립트와 공개 CDN 6곳의 스크립트를 허용한다. 모델이 이 컴포넌트를 실제로 쓸 수 있는지는 확인되지 않는다.

DIL 런타임 번들 · chatgpt.com 번들 171425 · chatgpt.com 번들 913894

사실

상호작용은 반대 방향으로 흐른다. 사용자가 슬라이더를 9로 옮기면 페이지가 핸들러 ID와 인자를 워커에 보낸다. 워커는 setSeats(9)를 부른다. 워커는 다시 렌더링한 뒤 갱신 연산을 돌려준다. 모델 호출은 없다.

공개 런타임은 받은 ID로 functionsById에서 원래 함수를 찾아 인자와 함께 부른다(invokeFunction). 모델에 닿는 통로는 GenUI 객체의 issueNewTurn이다. 이 함수는 질의 문자열 하나를 받아 새 대화 턴 요청(issue_new_turn)을 보낸다. 상태 변경만으로는 이 경로를 타지 않는다.

DIL 런타임 번들

사실

ChatGPT 클라이언트 코드의 컴포넌트 레지스트리에 컴포넌트 약 70개가 정의돼 있다. 그중 39개가 저자 캡처에 나왔다.

chatgpt.com 번들 913894의 네이티브 레지스트리 객체에는 키가 68개 있다. chart와 pie-chart는 번들 74115에 따로 정의돼 있다. 합치면 70개다. 39개라는 사용 수의 근거는 저자 캡처뿐이다.

chatgpt.com 번들 913894 · chatgpt.com 번들 74115

사실

모델은 padding={3} 같은 디자인 토큰으로 스타일을 지정한다. 일부 속성은 픽셀 너비나 hex 색 같은 원시 CSS 값도 받는다. 토큰은 간격, 모서리 반경, 색, 크기를 다룬다.

레지스트리 코드는 숫자 간격 값을 calc(var(--spacing, 0.25rem) * n)으로 바꾼다. 기본 글자 크기 16px에서 0.25rem은 4px이다. padding={3}은 12px이 된다. 숫자가 아닌 값은 그대로 CSS로 넘긴다. 같은 코드에 blue-a100 같은 색 토큰이 있다. 3xl·xl 반경 토큰과 lg·sm 크기 값도 있다.

chatgpt.com 번들 913894

사실

카탈로그에는 OpenAI가 DIL로 작성해 미리 빌드한 합성 컴포넌트가 있다. 이미지와 상품 컴포넌트가 그 예다. 저자 캡처에서 모델은 이 컴포넌트를 쓰기만 했다. 자기 컴포넌트를 정의한 적은 없다.

chatgpt.com 번들에 SourceCards.dil.tsx, WebSearch.dil.tsx를 포함한 DIL 소스 영역 5개가 문자열로 들어 있다. 이미지용 DIL 함수 GroupImageTile, ImageFallbackFrame도 있다. 모두 DIL.useState와 __dil.jsx로 쓰였다. 런타임은 이 소스를 dilComponents로 받아 평가한다. 상품 컴포넌트는 첫 화면이 불러오는 번들에 없다. 모델이 자기 컴포넌트를 정의하지 않았다는 관찰은 저자 캡처에만 근거한다.

chatgpt.com 번들 805171 · chatgpt.com 번들 74115 · DIL 런타임 번들

스트리밍

사실

응답은 서버 전송 이벤트(Server-Sent Events, SSE) 스트림(POST /backend-api/f/conversation)으로 브라우저에 온다. 이벤트마다 JSON-Patch식 패치가 실린다. 이벤트 하나가 원문 DIL과 컴파일 결과를 함께 갱신하는 경우가 많다.

chatgpt.com 번들은 /f/conversation에 스트리밍 POST를 보낸다. /f/conversation/prepare와 /f/conversation/resume도 함께 쓴다. 독립 캡처의 스트림도 {"p": 경로, "o": append 또는 replace, "v": 값} 형태의 패치였다. 패치 경로 /message/content/parts/0, /message/metadata/model_dil_v2/code, fallbackMarkdown이 원문 예시와 같다.

chatgpt.com 번들 200429 · 독립 캡처 분석 노트

부분 사실

서버는 증분 컴파일을 하지 않는다. 몇백 ms마다, 아마도 모델 출력 조각이 올 때마다, 지금까지 쓴 전체를 다시 컴파일해 보낸다. 컴파일은 첫 토큰부터 시작한다.

전체 재컴파일은 독립 캡처와 맞는다. 그 캡처에서 응답 하나 동안 model_dil_v2/code가 134번 통째로 교체됐다. 크기는 446바이트에서 30,932바이트로 커졌다. 간격은 캡처마다 다르다. 저자 확장판은 갱신 간격 중앙값 230ms, 전체 재컴파일 290ms, 다른 캡처 410ms를 적었다. 독립 캡처는 약 120ms로 적었다. '출력 조각마다'는 저자도 추정이라고 밝힌 부분이다.

독립 캡처 분석 노트 · OpenUI 블로그 확장판

사실

페이지는 새 프로그램을 샌드박스 워커에 넘긴다. 워커는 기존 상태로 다시 렌더링한다. 새 프로그램이 평가나 렌더링에 실패하면 마지막으로 성공한 프로그램을 유지한다.

공개 런타임의 updateSource는 새 소스 적용에 실패하면 restoreSource로 직전 소스(lastSource)를 되돌린다. 렌더링이 실패해도 같다. lastSource는 렌더링이 성공했을 때만 바뀐다.

DIL 런타임 번들

사실

변화는 애니메이션으로 들어온다. 텍스트는 0.7초 동안 나타난다. 새 행과 그리드 항목은 0.42초 동안 미끄러져 들어온다. 차트는 1.8초 동안 그려진다. 컨테이너 높이는 튀지 않고 부드럽게 바뀐다.

chatgpt.com의 공개 CSS에 세 값이 그대로 있다. [data-d-stream-word] 요소에 .7s 애니메이션이 걸린다. grid-item, table-row, box 안 row에는 .42s 등장 애니메이션이 걸린다. recharts의 선·영역에는 1.8s 그리기 애니메이션이 걸린다. 높이는 번들 74115의 코드가 이전 높이에서 새 높이로 320ms 동안 애니메이션한다.

chatgpt.com CSS 651844 · chatgpt.com 번들 74115

AppBlock

사실

네이티브 컴포넌트로 만들 수 없는 요청에는 모델이 AppBlock을 쓴다. 원문의 예는 Web Audio로 소리를 합성하는 드럼 머신이다. AppBlock은 HTML·CSS·JavaScript로 된 자체 완결 웹 앱이다. iframe 안에서 돈다. Intelligent UI 컴포넌트와는 렌더링 경로가 다르다.

chatgpt.com 번들은 AppBlock 타입을 category가 app_block인 클라이언트 정의 위젯으로 바꾼다. DIL 위젯 판정에서는 app_block을 뺀다. 컴파일 결과 안의 자리표시자 __chatgptClientDefinedWidget을 읽는 코드도 있다. app_block 항목은 전용 컴포넌트가 따로 그린다. 같은 번들 묶음에는 web-sandbox.oaiusercontent.com 도메인의 샌드박스 iframe에 앱을 띄우는 호스트 코드가 있다. AppBlock이 이 호스트를 쓴다는 연결과 드럼 머신 사례는 저자 관찰이다.

chatgpt.com 번들 106979 · chatgpt.com 번들 807489 · chatgpt.com 번들 945902

방법론과 저자

사실

모든 관찰은 저자 팀의 ChatGPT 계정, ChatGPT 웹앱이 만든 트래픽, chatgpt.com이 공개로 서빙하는 JavaScript에서 나왔다. 관찰 시점은 2026-10이다. 모델은 GPT-6와 GPT-6 Thinking이다.

공개 JavaScript 부분은 재현된다. 위 항목의 식별자가 chatgpt.com 번들과 OpenAI CDN의 런타임에 실제로 있다. 계정과 트래픽 캡처는 저자만 가진 자료다. 독립 캡처의 요청 본문에도 모델 이름 gpt-6-thinking이 있다.

chatgpt.com · 독립 캡처 분석 노트

사실

저자 Rabi Shanker Guha는 Generative UI API를 파는 Thesys(thesys.dev)의 CEO다.

Sessionize 연사 프로필이 그를 Thesys 공동창업자·CEO로 소개한다. Thesys 회사 소개도 그를 창업자로 올린다. 경력은 Google과 DevRev 인도 엔지니어링 총괄이다. thesys.dev는 자사를 'The Generative UI Company'로 부른다. 자사가 OpenUI를 만든다고도 쓴다.

thesys.dev · Thesys 회사 소개 · Sessionize 연사 프로필

불확실

저자는 구글에 인수된 결제 스타트업을 세웠다. IIT Kanpur 출신이다.

Thesys 회사 소개는 그가 'Google이 인수한 핀테크 스타트업 Payzie'를 공동 창업했다고 쓴다. 인수 시점과 조건을 다룬 보도나 Google 발표는 확인되지 않는다. IIT Kanpur 학력은 X 자기소개 말고는 확인되지 않는다. 두 내용 모두 본인 측 진술에만 근거한다.

Thesys 회사 소개 · Sessionize 연사 프로필


원본 (완역)

Rabi Shanker Guha @rabi_guha · 2026-10-09 01:49 KST · X 아티클

파스텔 그라데이션 배경에서 빛줄기가 반투명 유리판을 지나고, 그 앞에 OpenAI 로고와 Intelligent UI 글자가 놓인 커버 이미지

ChatGPT Intelligent UI를 리버스 엔지니어링했다. 실제로는 이렇게 작동한다

ChatGPT가 (마침내) Generative UI를 출시했고, 하룻밤 사이에 이 분야의 이름을 Intelligent UI로 바꿔 버렸다. 우리는 그들이 이것을 어떻게 구현했는지 직접 봐야 했다.

OpenAI @OpenAI · 2026-10-08 03:05 KST

GPT-6와 Intelligent UI가 이제 ChatGPT의 모든 사용자에게 배포되기 시작했다.

ChatGPT의 Intelligent UI는 일상적인 질문을 더 시각적으로, 복잡한 주제를 더 이해하기 쉽게 만들고, 작업에 필요한 인터랙티브 도구를 그 자리에서 쓸 수 있게 하는 빠르고 인터랙티브한 답변을 제공한다.

이 글은 OpenAI가 대표 기능인 Intelligent UI를 어떻게 구현했는지, 즉 그 계층과 포맷, 그리고 Web과 Mobile에 걸친 네이티브 렌더링을 깊이 들여다본 연구다.

구성 요소

ChatGPT의 구현은 모델, 백엔드 서버, 클라이언트 사이에 작업을 나눈다:

  • 추론 포맷: 모델은 Markdown에 JSX 비슷한 태그와 JavaScript를 결합한 DIL로 인터페이스를 쓴다.
  • 서버 측 컴파일: 서버는 부분 응답 하나하나를 JavaScript 프로그램 하나와, 텍스트와 데이터를 담은 JSON 문서 하나로 변환한다.
  • 클라이언트 런타임: 샌드박스 런타임이 프로그램을 실행해 UI 연산(operation)을 만들어 낸다.
  • 렌더링: ChatGPT는 그 연산을 자신의 네이티브 컴포넌트에 적용한다.
  • 디자인 시스템과 카탈로그: 모델이 쓸 수 있는 컴포넌트, 속성, 디자인 토큰.
ChatGPT Intelligent UI 구조도. 모델 칸의 추론 포맷이 DIL을 백엔드 서버로 보내고, 서버 측 컴파일이 부분 출력을 고치고 속성을 검증하고 텍스트를 상수로 옮겨 JS 프로그램과 JSON 데이터를 만든다. 사용자 클라이언트에서는 샌드박스 iframe과 Web Worker의 클라이언트 런타임이 seats = 8 상태로 프로그램을 돌려 트리를 비교하고, UI 연산을 받은 렌더링 칸이 네이티브 컴포넌트로 Team plan estimate $232/mo 슬라이더를 그린다. 사용자 이벤트는 콜백으로 런타임에 돌아간다. 아래 띠의 디자인 시스템과 카탈로그는 모델이 고르고 컴파일러가 검증하고 렌더러가 그리는 기준이다
ChatGPT Intelligent UI 아키텍처 다이어그램

추론 포맷

이것이 모델이 쓰는 것이다. ChatGPT에서 그것은 OpenAI가 DIL이라 부르는 언어다. 산문에는 Markdown, 컴포넌트에는 JSX 비슷한 태그, 상태와 로직에는 JavaScript를 쓴다. 작은 응답 하나를 모든 계층에 걸쳐 따라가 보겠다:

## Team plan estimate
Drag the slider to see the **monthly price** for your team.
{@body const [seats,setSeats] = DIL.useState(8)}
{@body const price = seats*29}
<box border padding={3} gap={2}>
  <slider min={1} max={50} value={seats} onChange={setSeats}/>
  <title size="xl">${price}/mo</title>
</box>

제목과 문단은 평범한 Markdown이다. 태그는 ChatGPT 카탈로그의 컴포넌트다. 두 개의 {@body …} 줄은 JavaScript다. 첫 줄은 상태 하나, seats를 선언하고, 둘째 줄은 거기서 price를 끌어낸다. 슬라이더가 seats에 묶여 있으므로 슬라이더를 움직이면 가격이 갱신된다.

전용 포맷이 필요한 이유는 모델이 인터페이스를 토큰 하나씩 쓰기 때문이다.

  • 안정적으로 쓰기 쉬워야 한다. 그래서 모델이 이미 잘 아는 표기법으로 만들었다.
  • 반쯤 쓴 상태에서도 쓸 수 있어야 한다. 명령문은 각자 한 줄을 차지하고, 열린 요소는 어느 것이든 자동으로 닫을 수 있다. 덕분에 서버는 부분 응답을 마지막 완결 구문에서 잘라 내고도 컴파일할 수 있다.

서버 측 컴파일

클라이언트는 모델의 출력을 쓰인 그대로 실행하지 않는다. OpenAI의 서버가 그 출력을 JavaScript 프로그램과 JSON 문서로 컴파일하고, 둘은 메시지와 함께 (model_dil_v2로) 저장된다. 위 응답은 다음과 같이 컴파일된다 (읽기 쉽게 정리했다):

javascript
function __dilSafe(evaluate, failureValue) {
  try { return evaluate(); } catch { return failureValue; }
}

DIL.render(__dil.jsx(() => {
  const __dilConstants = DIL.useConstants();
  const __dilModelDataBindings = DIL.useAppData((appData) => appData.opGenui?.modelDataBindings ?? {});
  const [seats, setSeats] = DIL.useState(8, { key: "seats" });
  const price = __dilSafe(() => seats * 29, undefined);
  return __dil.jsx(__dil.Fragment, null,
    __dil.jsx("title", { size: "lg" }, __dilConstants["0"]),
    __dil.jsx("text", null, __dilConstants["1"], __dil.jsx("bold", null, __dilConstants["2"]), __dilConstants["3"]),
    __dil.jsx("box", { border: true, padding: 3, gap: 2 },
      __dilSafe(() => __dil.jsx("slider", { min: 1, max: 50, value: seats, onChange: setSeats }), null),
      __dil.jsx("title", { size: "xl" }, __dilConstants["4"], __dilSafe(() => price, null), __dilConstants["5"])));
}, { key: "body:2" }));
json
{
  "constants": {
    "0": "Team plan estimate",
    "1": "Drag the slider to see the ",
    "2": "monthly price",
    "3": " for your team.",
    "4": "$",
    "5": "/mo"
  },
  "appData": { "opGenui": { "componentResults": {}, "modelDataBindings": {} } }
}

Markdown은 컴포넌트와 같은 트리로 컴파일된다. 제목은 title이, 문단은 안에 bold를 품은 text가 되고, 그 단어들은 상수 표로 옮겨진다.

컴파일은, 그렇지 않았다면 모든 클라이언트가 되풀이해야 했을 일을 대신 한다:

  • 평범한 함수 호출. 마크업이 __dil.jsx 호출로 바뀐다. 그래서 JavaScript 런타임은 DIL 파서 없이도 프로그램을 평가할 수 있다.
  • 오류 격리. 식은 __dilSafe로 감싸여 있다. 그래서 예외를 던지는 식은 렌더 전체를 중단시키는 대신 요소 하나만 없앤다.
  • 텍스트는 별도 표에. 정적 텍스트가 상수 표로 옮겨진다. 그래서 응답이 스트리밍되는 동안 늘어나는 텍스트는 프로그램이 아니라 데이터를 바꾼다.
  • 안정된 상태 키. 각 상태에는 키({ key: "seats" })가 붙는다. 그래서 그 값은 매번의 재컴파일에도 살아남는다.
  • 수리와 검증. 미완성 명령문과 태그는 버리고, 닫히지 않은 요소는 닫는다. 카탈로그 대비 검증에 실패한 속성은 제거하고 진단(diagnostic)으로 기록한다.

JSON 문서에는 텍스트 상수와 함께, 서버가 그 응답을 위해 가져온 데이터가 담긴다. 이미지 검색 결과가 그런 예다 (Data 참고).

클라이언트 런타임

클라이언트는 컴파일된 프로그램과 JSON 문서를 받는다. 클라이언트의 일은 프로그램을 실행하는 런타임과 결과를 그리는 렌더러로 나뉜다.

프로그램은 모델이 쓴 코드이므로 ChatGPT 페이지 안에서 실행되지 않는다. ChatGPT는 숨겨진 iframe(runner.html)을 띄운다. 이 iframe은 allow-scripts로 샌드박스 처리되어 있고 콘텐츠 보안 정책이 default-src 'none'이며, Web Worker 하나를 시작한다.

  • 잠금(Lockdown). 프로그램을 평가하기 전에 워커는 자신의 전역 범위에서 네트워크 접근, 타이머, 메시징, 동적 코드 평가를 제거하고, 남은 전역을 동결한다.
  • 평가(Evaluation). 그런 다음 워커는 new Function으로 프로그램을 평가한다. 런타임 객체(DIL, __dil, GenUI)와 카탈로그의 컴포지트 컴포넌트는 매개변수로 전달된다.
  • 감시(Watchdog). 제한 시간 안에 응답하지 않는 프로그램은 격리되고, 워커는 재시작된다.

런타임은 React 방식의 작은 리컨실러(reconciler)다. 리컨실러는 컴포넌트를 렌더링하고, 훅 상태를 키가 붙은 슬롯에 보관한다. 그런 다음 결과 트리를 이전 트리와 비교해 차이를 연산 목록으로 인코딩한다. 무언가를 그리지는 않는다.

다음은 첫 렌더에서 나오는 연산을 노드 하나당 한 줄로 보여 주는 예시다. 각 요소의 속성 이름을 나열하는 항목은 생략했다:

CREATE #1  title   SET size = "lg"                                    PLACE under root at 0
CREATE #2  text "Team plan estimate"                                  PLACE under #1 at 0
CREATE #3  text                                                       PLACE under root at 1
CREATE #4  text "Drag the slider to see the "                         PLACE under #3 at 0
CREATE #5  bold                                                       PLACE under #3 at 1
CREATE #6  text "monthly price"                                       PLACE under #5 at 0
CREATE #7  text " for your team."                                     PLACE under #3 at 2
CREATE #8  box     SET border = true, padding = 3, gap = 2            PLACE under root at 2
CREATE #9  slider  SET min = 1, max = 50, value = 8, onChange = fn#1  PLACE under #8 at 0
CREATE #10 title   SET size = "xl"                                    PLACE under #8 at 1
CREATE #11 text "$"                                                   PLACE under #10 at 0
CREATE #12 text "232"                                                 PLACE under #10 at 1
CREATE #13 text "/mo"                                                 PLACE under #10 at 2

함수는 워커를 떠나지 않는다. 슬라이더의 핸들러는 식별자(fn#1)로만 전송된다. 전송 구간에서 연산은 정수로 된 이진 시퀀스로 인코딩되고, 문자열은 별도의 표에 담긴다.

렌더링

ChatGPT 페이지는 연산을 자신의 컴포넌트 트리에 적용한다. CREATE 하나하나가 ChatGPT 디자인 시스템의 네이티브 컴포넌트를 하나씩 생성하고, 페이지는 변경이 도착하는 대로 애니메이션을 입힌다. 페이지는 알려진 컴포넌트 타입에 대한 연산만 받아들이므로, 모델 출력은 임의의 마크업이나 스타일을 들여올 수 없다. 예외는 일부 속성이 받아들이는 raw CSS 값(디자인 시스템과 카탈로그 참고)과 iframe 안에서 실행되는 AppBlock 앱(비상구 참고)이다.

상호작용은 반대 방향으로 흐른다. 사용자가 슬라이더를 9로 끌면 페이지는 핸들러의 식별자와 인자를 워커에 보낸다. 워커는 setSeats(9)를 호출하고, 다시 렌더링한 뒤, 갱신 연산을 돌려준다. 모델 호출은 전혀 끼어들지 않는다.

디자인 시스템과 카탈로그

카탈로그는 모델이 무엇을 요청할 수 있는지를 정한다. 카탈로그가 필요한 이유는 모델이 raw 레이아웃·스타일 규칙으로 인터페이스를 짓지 않기 때문이다. 모델은 ChatGPT가 이미 그릴 줄 아는 컴포넌트 중에서 고르고, padding={3} 같은 디자인 토큰으로 스타일을 입힌다. 픽셀 폭이나 hex 색상 같은 raw CSS 값도 일부 속성에는 허용되지만, 디자인 토큰이 우선이다. 그 결과:

  • 생성된 인터페이스는 ChatGPT의 나머지 화면과 똑같아 보인다. 모든 플랫폼에서 그렇다.
  • 컴파일러가 출력을 대조할 스키마를 갖는다. 컴포넌트에 존재하지 않는 속성이나 타입이 틀린 리터럴은 컴파일 중에 제거되고 진단으로 기록된다.

우리가 캡처한 응답 하나에서 컴파일러는 두 속성을 제거했다. 아이콘의 fill(unknown_prop 진단)과 박스의 gap="1"(invalid_literal 진단)이다.

카탈로그는 세 부분으로 이뤄진다:

  • 네이티브 컴포넌트. ChatGPT 클라이언트 코드의 컴포넌트 레지스트리에 약 70개의 컴포넌트가 정의돼 있다. 우리가 캡처한 응답에는 그중 39개가 등장한다.
  • 간격, 반경, 색상, 크기에 대한 디자인 토큰.
  • OpenAI가 DIL로 작성해 미리 빌드한 상태로 샌드박스에 보내는 컴포지트 컴포넌트. 이미지 컴포넌트와 상품 컴포넌트가 그런 예다. 우리 캡처에서 모델은 이 컴포넌트를 사용했지만 자기 컴포넌트를 정의한 적은 없다.

스트리밍

텍스트 스트리밍은 간단하다. 새 토큰 하나하나를 이미 화면에 있는 것 뒤에 덧붙이면 된다. 인터페이스 스트리밍은 세 가지 이유로 더 어렵다:

  • 출력은 대개 아직 실행할 수 없다. 대부분의 순간에 출력은 태그나 식이 아직 열려 있는 미완성 프로그램이고, 쓰인 그대로는 실행할 수 없다.
  • 인터페이스는 자라는 동안에도 계속 작동해야 한다. 사용자가 이미 만진 컴포넌트는 자기 상태를 유지해야 한다.
  • 일부 내용은 따로 도착한다. 이미지 같은 데이터는 텍스트가 아니라 서버에서 온다.

서버 측 스트리밍

덧붙여지는 토큰의 단순한 스트림으로는 이것을 표현할 수 없다. 그래서 ChatGPT는 원시 텍스트, 컴파일된 프로그램, 그 데이터를 나란히 담은 구조화된 메시지에 대한 패치를 스트리밍한다.

응답은 서버 전송 이벤트 스트림(POST /backend-api/f/conversation)으로 브라우저에 도착한다. 각 이벤트는 만들어지고 있는 메시지에 대한 JSON-Patch 방식의 업데이트다. 이벤트 하나가 대개 원시 DIL 텍스트와 그 컴파일된 형태를 함께 갱신한다. 다음은 캡처한 응답에서 나온 업데이트 하나를 줄인 것이다:

json
{"o": "patch", "v": [
  {"p": "/message/content/parts/0", "o": "append", "v": " Sunday lamb roast with friends — generous food, …"},
  {"p": "/message/metadata/model_dil_v2/code", "o": "replace", "v": "DIL.render(__dil.jsx(()=>{…"},
  {"p": "/message/metadata/model_dil_v2/constants", "o": "append", "v": {"0": "Here's a plan for a proper Sunday lamb roast with friends — …"}},
  {"p": "/message/metadata/model_dil_v2/constants", "o": "append", "v": {"1": "Since you're"}},
  {"p": "/message/metadata/model_dil_v2/fallbackMarkdown", "o": "append", "v": " Sunday lamb roast with friends — …"}
]}

서버는 증분 컴파일을 하지 않는다. 몇백 밀리초마다, 아마도 모델 출력의 새 청크가 올 때마다, 모델이 지금까지 쓴 모든 것을 다시 컴파일해 그 결과를 보낸다. 컴파일은 어떤 태그도 나타나기 전인 첫 토큰부터 시작된다.

컴파일러가 감당해야 하는 일:
- 반쯤 쓴 응답 컴파일하기
- 텍스트 갱신하기
- UI 갱신하기

타임라인은 대략 이렇다:

클라이언트 측 스트리밍

페이지는 새 업데이트가 올 때마다 샌드박스 워커에 넘긴다. 워커는 그것을 평가하고, 기존 상태로 다시 렌더링한 뒤, 갱신 연산을 페이지에 보낸다. 컴파일 중에 붙은 키 덕분에 상태는 재컴파일을 거쳐도 값을 유지한다. 새 프로그램이 평가나 렌더링에 실패하면 워커는 마지막으로 작동했던 프로그램을 유지한다.

그다음 페이지는 각 변경에 애니메이션을 입힌다:

  • 텍스트는 0.7초에 걸쳐 페이드인한다.
  • 새 행과 그리드 항목은 0.42초에 걸쳐 미끄러져 들어온다.
  • 차트는 1.8초에 걸쳐 그려진다.
  • 컨테이너 높이는 튀지 않고 전환 애니메이션으로 바뀐다.

비상구: AppBlock, iframe 안의 앱

ChatGPT 응답 안에 생성된 DRUM / LAB 01 드럼 머신 앱. Play·Stop 버튼과 808 Analog 킷 선택, 템포 120 BPM·스윙 0%·볼륨 75% 슬라이더, 킥·스네어·클로즈드 햇·오픈 햇·클랩·톰 6개 트랙의 16스텝 시퀀서 격자, 키보드 단축키가 붙은 연주 패드 6개, 그루브 프리셋 선택과 패턴 내보내기 버튼이 있다
ChatGPT가 생성한 인라인 앱

어떤 요청은 네이티브 컴포넌트가 다루도록 설계되지 않은 것을 요구한다. Web Audio로 소리를 합성하는 드럼 머신 같은 것이다. 이런 경우 모델은 AppBlock을 쓸 수 있다. AppBlock은 HTML, CSS, JavaScript로 된 독립형 웹 앱으로, 응답 안에 임베드된다. 다음은 그런 앱 하나의 시작 부분을 줄인 것이다:

http
<AppBlock title="Drum Lab" icon="app-chatgpt" variant="inline" app_block_id="drum-lab-01">
<div id="dl" class="w-full min-w-0 space-y-4 text-base">
  <style>
    #dl{color:var(--viz-text)}#dl button{touch-action:manipulation}#dl .panel{background:var(--viz-panel);border:1px solid var(--viz-border);border-radius:15px}…
  </style>
  …
      <button id="dl-play" class="btn" style="background:var(--viz-text);color:var(--viz-card);min-width:100px">▶ Play</button>
  …
</div>
<script>
(function(){
const root=document.getElementById('dl');if(root.dataset.init)return;root.dataset.init="yes";
…
function audioInit(){if(!audio){const C=window.AudioContext||window.webkitAudioContext; if(!C)return false;audio=new C();…
…
})();
</script>
</AppBlock>

AppBlock은 Intelligent UI 컴포넌트와 다른 방식으로 렌더링된다.

전체 그림

당신이 프롬프트를 입력한다. 모델이 인터페이스를 쓰기 시작하고, 서버는 그것을 ChatGPT가 실행할 수 있는 형태로 바꾸며, 페이지는 응답이 스트리밍되어 들어오는 대로 그것을 한 조각씩 짓는다. 일단 화면에 뜨고 나면, 슬라이더를 옮기거나 체크박스에 표시하는 일은 모델에게 다시 묻지 않고 인터페이스를 로컬에서 갱신한다.

모델 전용 언어, 서버 컴파일 단계, 네이티브 렌더러, 그리고 근거에 묶인(grounded) 디자인 시스템이 이 모든 것을 하나로 묶는다. 각 부분이 핵심적인 역할을 맡고, 함께 모여 전 세계 수십억 사용자에게 차세대 AI 네이티브 인터페이스를 제공한다. 참 대단한 시대에 살고 있다!

ChatGPT Intelligent UI 화면 세 개. 왼쪽은 강아지 조끼 무드보드로 디자인 방향 사진 세 장과 원단·부자재 사진, 색상 견본이 있다. 가운데는 양고기 로스트 모임 메뉴와, 손님 수와 채식 손님 수를 바꾸면 따라 바뀌는 장보기 수량표다. 오른쪽은 PULSE / Mission Control 제품 분석 대시보드로 매출·활성 사용자·전환율 지표, 성과 꺾은선 차트, 성장 투자 슬라이더가 있다
ChatGPT Intelligent UI 스크린샷

방법론

모든 관찰은 우리 자신의 ChatGPT 계정, ChatGPT 웹앱이 만들어 내는 트래픽, 그리고 chatgpt.com이 공개적으로 서빙하는 JavaScript에서 나왔다. 관찰은 2026년 10월에 GPT-6와 GPT-6 Thinking으로 이뤄졌다.

분석은 Codex와 Claude의 도움을 받았다. 글은 Codex로 썼고, 시각화는 Claude가 했다.

(더 깊이 다룬 판본은 https://www.openui.com/blog/how-chatgpt-intelligent-ui-works에 있다)


원본 링크·인용

원문 X 아티클과 그 안의 링크 11개다. 순서는 원문에 나온 순서이고, 같은 링크가 완역 본문의 제자리에도 있다.

  1. x.com/rabi_guha/status/2108238432355123572 X 게시물(원문) · 원문 퍼머링크
  2. @rabi_guha X 프로필 · 저자 프로필
  3. 커버 이미지 (X 미디어 뷰어) X 이미지 뷰어 · 커버 이미지
  4. @OpenAI X 프로필 · 인용 게시물을 올린 계정
  5. x.com/OpenAI/status/2107894997538525580 X 게시물 · 인용된 OpenAI 게시물
  6. 아키텍처 다이어그램 (X 미디어 뷰어) X 이미지 뷰어 · 아키텍처 다이어그램
  7. @body X 자동 링크(오링크) · 「추론 포맷」 문단의 X 자동 링크
  8. AppBlock 화면 (X 미디어 뷰어) X 이미지 뷰어 · AppBlock 화면 캡처
  9. 화면 모음 (X 미디어 뷰어) X 이미지 뷰어 · Intelligent UI 화면 모음
  10. chatgpt.com 웹 서비스 · 「방법론」 문단
  11. openui.com/blog/how-chatgpt-intelligent-ui-works 블로그 글(확장판) · 같은 분석의 확장판

기타

용어

DIL
OpenAI가 Intelligent UI 응답에 쓰는 모델 전용 언어다. Markdown, JSX 비슷한 태그, JavaScript 문장을 섞는다.
model_dil_v2
컴파일된 프로그램과 상수, 데이터를 담아 메시지와 함께 저장되는 필드다.
UI 연산(operation)
워커가 페이지에 보내는 화면 변경 명령이다. 노드 생성, 속성 변경, 배치가 여기에 든다.
컴포지트 컴포넌트
OpenAI가 DIL로 미리 써서 샌드박스에 보내는 상위 컴포넌트다. 이미지 컴포넌트와 상품 컴포넌트가 그 예다.
디자인 토큰
간격, 모서리 반경, 색, 크기를 이름이나 단계 값으로 정한 스타일 단위다. padding={3}의 3이 그 예다.
AppBlock
네이티브 컴포넌트로 만들 수 없는 요청에 모델이 쓰는 HTML·CSS·JavaScript 독립 앱이다. iframe 안에서 돈다.

고지