
OpenAI Build Week:
요약
OpenAI Build Week를 통해 법원 기록을 분석하여 AI 준비도 점수를 산출하는 'Verity Lex'를 구축한 사례를 소개합니다. AI가 법적 표준을 준수하며 기계적 규칙을 엄격히 따르도록 설계하는 과정과 공공 부문 AI 도입 시 고려해야 할 전략을 다룹니다.
핵심 포인트
- Verity Lex는 법원 기록을 읽고 법적 표준과 대조하여 AI 준비도 점수를 반환함
- AI가 설정된 규칙(점수 매기기 금지 등)을 엄격히 준수하도록 만드는 것이 핵심 과제임
- 공공 부문 AI 도입 시 기관의 표준과 준비 상태를 먼저 파악하는 'Bottom-up' 접근이 필요함
- Codex와 GPT 모델을 활용한 실제 빌드 경험과 교훈 공유
제 개인적인 의견으로는(IMHO), 현재 정부를 대상으로 AI를 판매하려는 움직임이 매우 급격합니다 (참고: 저는 정부에서 근무합니다). 저는 계속해서 다른 질문을 던져왔습니다. 정부가 구매할 _준비_가 되었는지 확인한 사람이 있습니까?
저는 그 질문에 답하기 위해 OpenAI Build Week 기간 동안 약 이틀에 걸쳐 Verity Lex를 구축했습니다. 그리고 한 가지 규칙이 전체 빌드의 형태를 결정하게 되었습니다. 그것은 바로 AI가 법원의 기록을 읽되, 결코 점수를 매기지는 않는다는 것입니다. 이는 사소한 설계 선택처럼 들릴 수 있습니다. 하지만 그것이 바로 빌드의 핵심이었으며, 기계가 그 규칙을 존중하도록 가르치는 것이 가장 어려운 부분이었고, 피할 수 있었던 스트레스 가득한 저녁 시간을 소모하게 만든 부분이었습니다. Verity Lex를 캘리포니아 상급 법원(Santa Barbara는 현재 라이브 상태이며, 더 많은 법원이 추가될 예정입니다)으로 향하게 하면, AI가 공개 기록을 읽고, 이를 공표된 법적 표준과 대조하여, 누구나 다시 계산할 수 있는 AI 준비도 점수(AI-readiness score)를 반환합니다.
이것은 제가 무엇을 만들었는지, 어떻게 Codex와 GPT-5.6을 지시하여 이를 구축했는지, 그리고 AI를 출시(shipping)하고 있는 Dev.to 가족들에게 전달하고 싶은 단 하나의 교훈에 대한 이야기입니다.
논지: 당신은 정부를 상대로 거꾸로 판매하고 있습니다
소프트웨어는 공공 기관에 잘못된 방식으로 판매됩니다. 공급업체는 솔루션을 들고 나타나, 자신이 판매하려는 기관을 전혀 이해하지 못한 채 문제를 찾아 나섭니다. 이 법원은 무엇을 준수해야 합니까? 그 표준을 충족하고 있습니까? 그곳의 구성원들이 당신이 팔고자 하는 것을 받아들일 준비가 되었습니까? 이러한 질문들을 건너뛴다면, 공공 부문에서 일해본 사람이라면 누구나 목격했을 법한 '선반용 소프트웨어(shelfware)'와 신뢰 저하라는 결과를 초래하게 됩니다.
AI는 대규모로 동일한 수법을 재현하려 하고 있습니다. 따라서 Verity Lex는 피라미드의 꼭대기가 아닌 바닥에서부터 시작합니다:
- 표준 (Standards). 이 기관이 준수해야 하는 기준은 무엇이며, 기관 자체의 기록은 그 기준을 충족하고 있음을 보여주는가? 이것이 바로 Verity Lex입니다.
- 구조 (Structure). 조직 자체가 준비되어 있는가? 거버넌스 (Governance), 역할, 운영 정책.
- 사람 (People). 직원들이 AI를 안전하게 사용하는 방법을 알고 있는가? 문화적 저해 요소는 어디에 있는가?
- 솔루션 (Solutions). 이 단계에 이르러서야 비로소 무언가를 판매할 수 있습니다. 이는 피치 덱 (pitch deck)의 추측이 아니라, 진단된 상황에 근거하여 처방된 솔루션입니다.
정부를 먼저 이해함으로써 정부에 판매할 권리를 얻게 됩니다. Verity Lex는 1단계(tier one)이며, 이미 출시되었습니다.
아키텍처 (Architecture): 의도적인 뉴로심볼릭 (neurosymbolic)
대부분의 AI 데모가 빠지는 함정은 다음과 같습니다: 모델에게 정답에 대한 책임을 맡기는 것입니다. LLM (거대언어모델)에게 법원의 준수 여부를 평가하라고 요청하면, 그 순간의 샘플링 (sampling)에 의해 결정된 수치와, 어쩌면 환각 (hallucination)으로 만들어낸 인용구를 얻게 됩니다. 두 번 실행하면 두 개의 답변이 나옵니다. 어떤 정부 구매자도 "AI가 우리 준수 상태에 대해 좋게 느꼈다"라는 결과물을 조달할 수는 없습니다.
그래서 저는 작업을 하나의 경계, 즉 인지 (perception) 대 판단 (judgment)을 따라 세 가지로 나누었습니다.
- 문서 찾기: GPT-5.6이 지시하고, Tavily가 검색합니다. 모델이 주도하는 ReAct 루프가 어디를 살펴볼지 결정합니다. GPT-5.6은 다음 단계에 대해 추론(reasoning)하고, Tavily는 법원의 공개 사이트를 검색하며 일반적인 fetch로는 접근할 수 없는 문서를 가져오는 검색(retrieval)을 수행합니다. Tavily는 시작할 때 저에게도 생소한 도구였는데, 모델에게 직접 만든 fetch 대신 실제 검색 및 추출(search-and-extract) 레이어를 제공한 것이 에이전트가 이동된 문서를 찾아낼 수 있었던 주요 이유 중 하나입니다.
- 문서 읽기: GPT-5.6이 추출합니다. 모델은 결과물을 읽고 증거를 엄격한 JSON 스키마(schema)로 추출합니다. 찾기와 읽기는 모두 인지 (perception)이며, 인지는 모델이 잘하는 분야입니다.
- 준비 상태 점수 매기기: 결정론적 규칙 엔진 (deterministic rule engine). 순수 TypeScript로 작성되었으며, 어디에도 모델이 포함되지 않았습니다. 이 엔진은 추출된 신호들을 받아 가중치가 부여되고 법적 근거를 가진 아티팩트(artifacts)의 공개 레지스트리에 적용합니다. 동일한 신호가 입력되면 영원히 동일한 점수가 출력됩니다. 점수 매기기는 판단 (judgment)이며, 숫자에 대한 판단은 재현 가능해야 합니다.
이 작업들 중 두 가지는 인지 (perception)이고, 하나는 판단 (judgment)이며, 설계의 핵심은 이 둘을 분리하는 데 있습니다.
AI가 자신의 숙제를 스스로 채점하는 것을 신뢰하시겠습니까? 법원도 마찬가지일 것입니다. 설계 구조상 모델은 점수에 도달할 수 있는 경로가 없습니다. 모든 발견 사항은 실제 문서와 인용된 문장을 참조합니다. 찾을 수 없는 모든 것은 _부재 (absent)_가 아니라 _위치하지 않음 (not located)_으로 표시됩니다. 공공 기록이 조용해졌다고 해서 그것이 무엇인가의 증거가 될 수는 없기 때문입니다. 또한 여러분은 감사 번들 (audit bundle)을 다운로드하여 직접 점수를 재계산할 수 있습니다. 이러한 제약 조건 자체가 곧 제품입니다.
제작 과정: Codex 지시하기
저는 VS Code에서 Codex를 사용하여, 제가 소위 '크리에이티브 디렉터(creative-director) 워크플로우'라고 부르는 방식으로 이것을 구축했습니다. 판단은 제가 내리고, Codex는 구현을 담당합니다. 우리 사이의 경계는 신뢰하는 것이 아니라 강제되는 것입니다.
실제로 이는 게이트가 설정된 블록 범위(block-scoped) 프롬프트를 의미했습니다. 모든 프롬프트는 "먼저 파일 계획을 제안할 것, 관련 없는 코드는 리팩터링(refactor)하지 말 것, PR(Pull Request) 이후에 멈출 것"으로 시작되었습니다. Codex는 규칙 엔진(rule engine), 에이전트 도구(agent tools), 루프(loop), API, 하드닝(hardening), CI, 애드온(add-ons)의 각 블록을 별도의 풀 리퀘스트(PR)로 구축했습니다. 저는 모든 PR이 머지(merge)되기 전에 검토하고 테스트했으며, CI는 빨간색(실패) PR이 메인(main) 브랜치에 도달하지 않도록 강제했습니다. 커밋 히스토리는 협업 로그입니다. 20개가 넘는 범위가 지정된 PR들이 있었으며, 각각은 논증의 개별적인 조각이었습니다.
Codex는 훌륭했습니다. next/server 임포트(import) 함정을 포착하고 웹 표준인 Response.json을 사용하여 이를 수정했습니다. Linux CI 러너(runner)에서만 나타나는 락파일(lockfile) 불일치를 진단하기도 했습니다. 그리고 Codex가 틀렸을 때는 제가 이를 기각했는데, 이것이 바로 인간을 게이트에 두는 핵심적인 이유입니다. 한때 Codex는 CI 실패를 "해결"하기 위해 결정론적 설치(deterministic installs)를 더 느슨한 명령어로 교체할 것을 제안했습니다. 그것은 우리가 진단조차 하지 못한 문제를 해결하기 위해 재현성(reproducibility)을 맞바꾸는 행위였을 것입니다. 대신 우리는 문제를 진단했습니다. 그것은 오래된 캐시(stale cache) 문제였습니다.
GPT-5.6은 출시된 제품 내부에서 실시간으로 실행되며 탐색을 지시하고 증거를 추출합니다. 그 아래에는 Tavily가 검색 레이어(retrieval layer)로 작동하며, 구조적으로 점수(score)에 접근하는 것은 차단되어 있습니다.
교훈: 내 테스트는 내내 통과(green) 상태였다. 그러다 배포를 했다.
여기서 제가 다르게 했을 부분이 있습니다. 만약 여러분이 비슷한 것을 구축하고 있다면, 아마도 제가 비용을 치렀던 그 저녁 시간을 아낄 수 있을지도 모릅니다.
처음에는 제 CI(지속적 통합)가 초록색(green)이었습니다. 규칙 엔진(Rule engine) 테스트 완료, 에이전트 루프(agent loop) 테스트 완료, 경계값(bounds) 테스트 완료, API 계약(API contract) 테스트 완료. 저는 그 초록색 신호를 "작동한다"는 의미로 읽었습니다. 그러고 나서 프로덕션 환경에 실제 API 키를 설정하고 버튼을 클릭했는데, 세 가지 서로 다른 방식으로 연속해서 실패하는 것을 지켜봐야 했습니다.
첫 번째는 모델로부터 발생한 400 에러였습니다. OpenAI의 JSON 모드(JSON mode)는 입력값 자체에 "json"이라는 단어가 포함되어야 하는데, 별도의 필드에 그렇게 하라는 제 지침(instruction)을 넣은 것은 인정되지 않았습니다. 그다음에는 에이전트의 플래너(planner)가 쿼리(query)가 첨부되지 않은 액션(action)을 반환했고, 그 결과 모든 검색이 거부되어 스캔 결과가 아무것도 나오지 않았습니다. 마지막으로 추출기(extractor)가 잘못된 형태의 JSON을 생성했고, 제 검증기(validator)가 모든 문서에서 오류를 일으켰습니다.
세 가지 버그, 하나의 근본 원인: 그 모든 버그는 제 코드와 실제 모델 사이의 경계(boundary)에 존재했으며, 제가 만든 스텁(stub)이 이 모든 것을 숨기고 있었습니다.
정확히 무엇을 놓쳤는지 말씀드리겠습니다. 제 스텁 모델은 항상 올바른 형태의 미리 만들어진(pre-baked) 응답을 반환했습니다. 따라서 제 테스트는 제 _코드_가 좋은 모델의 답변을 소비할 수 있다는 점을 증명했을 뿐입니다. 제 _프롬프트(prompts)_가 그러한 답변을 생성할 수 있다는 점은 결코 증명하지 못했습니다. 이 둘은 서로 다른 주장입니다. 제 플래너 테스트는 필요한 필드가 이미 포함된 액션을 스텁에 그대로 전달했기 때문에 통과되었지만, 실제 프롬프트는 실제 모델에게 해당 필드들이 존재한다는 사실을 알려준 적이 없었습니다. 테스트 픽스처(test fixture)는 프롬프트가 가르쳐주지 않은 무언가를 조용히 알고 있었던 것입니다.
저는 세 가지 형태(shape) 관련 버그를 수정했습니다. 그러자 더 심각한 버그가 나타났습니다. 드디어 실제로 측정하는 법을 배웠기 때문에 발생한 일이었습니다. 동일한 스캔을 다섯 번 실행했는데 매번 점수가 달랐습니다. 한 번은 59점, 다음은 67점이었습니다. 같은 경기장, 같은 날이었습니다.
제 첫 번째 추측은 예산(budget) 문제였습니다. 에이전트가 모든 것을 다 다루기 전에 단계(steps)를 다 써버린 것이라고 생각했습니다. 틀렸습니다. 넉넉한 예산을 할당했음에도 불구하고 에이전트는 여전히 방황하며 예산의 극히 일부만 사용하고 매 실행마다 서로 다른 지점에서 멈췄습니다. 문제는 리소스가 아니었습니다. 저는 비결정론적(non-deterministic) 모델에게 결정론적(deterministic)인 작업, 즉 9개의 알려진 법적 표준을 따라가며 각각을 확인하라는 요구를 하고 있었는데, 모델은 행진하지 않습니다. 산책을 할 뿐입니다. 예산을 더 늘리는 것은 그저 더 긴 활주로를 사는 것뿐이었습니다. 이런!
Verity Lex가 "신뢰할 수 있는" 이유는 제가 모델로부터 _점수(score)_를 가져와 결정론적 코드 (deterministic code)에 부여했기 때문입니다. 그래서 저의 첫 번째 본능은 다음과 같았습니다: 검색에도 똑같이 적용하자. 쿼리를 코드로 작성하고, 링크를 코드로 선택하며, 모델은 읽기만 하게 만드는 것입니다. 모델이 스스로를 반복하도록 가두는 것이죠. 저는 심지어 모델이 쉬운 길을 도와주지 않을 것이라는 점도 확인했습니다. GPT-5.6은 온도 설정 (temperature setting)을 노출하지 않기 때문에, 단순히 무작위성 (randomness)을 낮출 수도 없었습니다.
함정을 발견하기 전까지 저는 스스로에게 '가두는 틀(cage)'을 만들겠다고 설득하는 단계까지 거의 도달했습니다. 법원이 정책 PDF의 이름을 바꾸거나 새로운 페이지로 이동시키면, 하드코딩된 (hardcoded) 검색은 그것을 그냥 지나쳐 버립니다. 반면 결과를 읽고 그에 대해 추론하는 자유롭고 가두지 않은 에이전트 (agent)는 새로운 위치에서 그것을 찾아냅니다. 에이전트를 가두는 것은 그것을 반복 가능하게 만들겠지만 동시에 눈멀게 만들 것입니다. 이 제품이 포착하기 위해 존재하는 바로 그 대상, 즉 '변화'에 대해 눈멀게 만드는 것이죠. 제가 삭제하려고 했던 즉흥성 (improvisation)이야말로 바로 가치였습니다.
따라서 교훈은 "모든 것을 결정론적으로 만들어라"보다 더 신중해야 합니다. 두 번째 답변이 단순히 틀린 경우, 즉 동일한 증거에 대해 두 개의 숫자가 나오는 것이 정의상 버그인 점수 산정 (scoring)의 경우에는 보증 (guarantee)을 코드로 옮기십시오. 하지만 이동하는 문서를 찾는 것처럼 적응성 (adaptivity) 자체가 가치인 경우에는, 그것을 가두지 마십시오. 다른 방식으로 신뢰할 수 있게 만드십시오.
그리고 그 다른 방식이란, 단순함을 위해 v1에서 제가 제외했던 것, 즉 메모리 (memory)입니다. 스캔이 방황하는 이유는 그것이 상태 비저장 (stateless) 방식이기 때문입니다. 매번 아무것도 없는 상태에서 시작하여 전체 탐색을 매번 새로 즉흥적으로 수행합니다. 윽, 제 설계가 잘못되었군요. 지난번에 무엇을 찾았는지 기억하는 버전이라면 이미 알려진 정책 (policy)을 다시 탐색하는 대신 재검증 (re-verify)할 것이고, 정책이 이동했을 때 이를 조용히 놓치는 대신 이동을 감지할 것입니다. 제가 결함으로 취급해 왔던 분산 (variance)은 신호 (signal)로 변합니다. 기록이 그대로 유지될 때는 수렴 (convergence)이 되고, 그렇지 않을 때는 변경 알림이 됩니다. 신뢰할 수 없는 관찰자에 대한 해결책은 결코 그것을 가두는 것이 아니었습니다. 그것에 메모리를 부여하는 것이었습니다. 그것이 현재 로드맵의 최상단에 있으며, 이번 빌드 전체가 저에게 가르쳐준 가장 날카로운 교훈입니다. 상태 비저장 (stateless) 관찰자는 자신을 반복할 수 없으며, 적응형 에이전트 (adaptive agent)를 신뢰할 수 있게 만드는 것은 감옥이 아니라 메모리라는 사실입니다. 유레카 (EUREKA)
이 모든 것을 더 일찍 잡아낼 수 있었을 실질적인 습관들:
AI 자동 생성 콘텐츠
본 콘텐츠는 Dev.to AI tag의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기



