AI 추론과 UI의 통합: OTF Kits를 통한 온톨로지(Ontologies)의 원활한 통합
요약
에이전트용 온톨로지와 UI 스키마 간의 불일치 문제를 해결하기 위해 OTF Kits를 활용한 통합 방안을 제시합니다. 에이전트와 UI가 동일한 타입 계약을 공유함으로써 데이터 표류를 방지하고 시스템의 신뢰성을 높이는 방법을 다룹니다.
핵심 포인트
- 에이전트와 UI가 동일한 스키마를 공유하여 데이터 불일치(Drift) 방지
- 온톨로지를 통해 모델에 명시적인 의미론과 제약 조건 제공
- SHACL 검증 등을 활용해 에이전트의 환각 및 오류를 사전에 차단
- URI 기반 필드 설계를 통해 다양한 레이어에서 동일한 형태 소비 가능
당신의 에이전트는 Booking이 무엇인지 모릅니다. 추측할 수는 있고 — 보통은 잘 추측하지만 — 도구 호출(tool call)을 구성하거나, 동작을 검증하거나, 사람을 위해 결과를 렌더링하는 순간, 그 추측은 버그가 됩니다.
온톨로지(Ontology)는 모델에게 당신의 도메인에 대한 타입이 지정된 계약(typed contract)을 제공합니다: 무엇이 존재하는지, 무엇이 무엇과 연결되는지, 무엇이 허용되는지 말이죠. 또한 일반적인 앱에 온톨로지를 덧붙이는 것이 왜 잘못되는지, 그리고 이번에는 어떻게 그것을 제대로 정착시킬 수 있는지 설명해 줍니다.
문제는 온톨로지를 일반적인 코드베이스에 연결할 때 시작됩니다. 결국 두 개의 계약을 유지하게 됩니다: 하나는 에이전트를 위한 것(RDF triples, JSON-LD contexts, SHACL shapes)이고, 다른 하나는 UI를 위한 것(props, components, validation)입니다. 괴리(Drift)는 피할 수 없습니다. 에이전트는 Reservation을 생성하고, API는 Booking을 노출하며, UI는 ReservationViewModel을 기대합니다. 6개월이 지나면, 팀의 절반은 서로 일치해야 했던 레이어들 사이에 어댑터(adapters)를 작성하고 있을 것입니다. 문제는 스키마(schema)가 아니라, 두 개의 스키마를 가지고 있다는 점입니다.
이것이 논지입니다: 에이전트의 근간이 되는 스키마가 UI의 타입을 지정하는 파일과 동일해야 한다는 것입니다. 이것이 실현될 때, 온톨로지는 연구 산출물(research artifact)이 아닌 제품의 표면(product surface)이 되기 시작합니다.
온톨로지가 실제로 에이전트에게 제공하는 것
언어 모델(Language model)은 모든 프롬프트를 새로운 토큰 문자열로 취급합니다. 모델은 타입(types), 정체성(identity), 또는 관계(relations)에 대한 일급 시민(first-class) 개념이 없으며, 오직 통계적 유사성만을 가집니다. 온톨로지는 모델이 의지할 수 있는 것, 즉 명시적인 의미론(semantics)을 가진 어휘(vocabulary), 타입이 지정된 관계의 그래프, 그리고 일련의 제약 조건(constraints)을 전달합니다.
구체적으로는 다음과 같습니다:
{
"@context": {
"@vocab": "https://schema.otf-kit.dev/booking#",
...
여기서 두 가지가 중요합니다. 첫째, @context는 에이전트가 준수해야 하는 스키마를 선언하며, 이것이 바로 계약(contract)입니다. 둘째, 모든 필드는 URI입니다. 이는 SPARQL 엔드포인트, SHACL 검증기(validator), 그리고 당신의 컴포넌트 레이어가 번역 없이 모두 동일한 형태(shape)를 소비할 수 있음을 의미합니다. 에이전트는 구조를 발명하는 것이 아니라, 타입이 지정된 양식(typed form)을 채우고 있는 것입니다.
승리 지점은 "AI가 당신의 데이터를 이해한다"가 아닙니다. 진짜 승리는 에이전트의 실수가 복구 가능하다는 점에 있습니다. 잘못된 형식의 startsAt은 SHACL 검증에서 실패합니다. 누락된 Customer는 스키마(schema) 검증을 통과하지 못합니다. 환각(hallucination)된 필드는 사용자에게 도달하기 전에 거부됩니다.
일반적인 앱에서 문제가 발생하는 지점
설득력 있는 제안이 통하고 엔지니어링이 시작됩니다. 그러면 다음 세 가지가 가장 먼저 무너집니다:
- 트리플 스토어(Triple stores)는 읽기 경로(read path)에서 느립니다. SPARQL 엔드포인트와 명명된 그래프(named-graph) 저장소는 연합(federation)과 추론(inference)에는 훌륭합니다. 하지만 모바일 클라이언트가 100ms 이내에 200개의 예약 목록을 렌더링해야 할 때는 매우 비효율적입니다.
- 스키마가 표류(drift)합니다. 에이전트의
Reservation이 API의Booking이 되고, 다시 UI의ReservationViewModel이 됩니다. 수렴(convergence)을 강제하는 장치가 없기 때문에 각 계층은 자신만의 타입 별칭(type aliases)을 만들어냅니다. - 모바일 클라이언트는 그래프를 감당할 수 없습니다. 2GB 크기의 RDF 덤프는 휴대폰이 처리할 수 있는 페이로드(payload)가 아닙니다. 스키마를 준수하면서도 평탄화된(flat), 비정규화된(denormalized) 투영(projection)이 필요합니다.
이것들은 생소한 문제가 아닙니다. 모든 타입 지정 시스템(typed system)이 타입이 지정되지 않은 이웃(untyped neighbour)을 만날 때 겪는 동일한 통합 문제입니다. 해결책은 언제나 그랬듯 명확합니다. 접합부(seam)에서 계약(contract)을 고정하고, 모든 소비자가 그 계약을 읽도록 만드는 것입니다.
타입 지정 계약 패턴: 하나의 스키마, 두 명의 소비자
스키마를 두 곳에 저장하는 것을 멈추십시오. 하나의 파일에 저장하고 에이전트와 UI가 모두 이를 읽게 하십시오. 에이전트는 이를 그라운딩(grounding)을 위한 JSON-LD 컨텍스트(context)로 읽고, UI는 컴포넌트를 위한 타입 시스템(type system)으로 읽습니다.
// schema.otf.ts — 모든 계층이 임포트하는 파일
export const BookingSchema = {
"@context": "https://schema.otf-kit.dev/booking",
...
에이전트는 @context와 필드 맵(field map)을 시스템 지침(system instructions)으로 받습니다. 컴포넌트 계층은 동일한 맵을 TypeScript 타입으로 받습니다. 스키마 파일이 신뢰할 수 있는 단일 원천(source of truth)이 되며, 빌드 과정에서 이 파일로부터 두 가지 아티팩트(artifact)를 생성합니다. 하나는 모델을 위한 것이고, 다른 하나는 런타임(runtime)을 위한 것입니다.
[[DIAGRAM: schema.otf.ts → 에이전트를 위한 JSON-LD 컨텍스트, UI를 위한 TS 타입, 검증을 위한 SHACL shape — 세 소비자 모두가 하나의 파일을 읽음]]
SPARQL 엔드포인트(endpoint)가 여전히 데이터를 뒷받침할 수 있지만, UI는 결코 SPARQL을 직접 사용하지 않습니다. 스키마 파일은 투영 사양(projection specification)이 됩니다. 즉, 그래프 자체가 아니라 그래프의 타입이 지정된 뷰(typed view)가 되는 것입니다.
면역 체계로서의 SHACL
스키마가 계약(contract)이라면, SHACL shape는 그 계약의 면역 체계입니다. SHACL은 잘못된 형식의 그래프가 파이프라인(pipeline)에 들어오기 전에 거부합니다. 핵심은 앱의 깊숙한 내부가 아니라, 에이전트가 통과하는 경계(boundary)에서 검증을 실행하는 것입니다.
ex:BookingShape a sh:NodeShape ;
sh:targetClass ex:Booking ;
sh:property [
...
에이전트는 JSON-LD를 생성하고, SHACL 검증기(validator)가 이를 수락하거나 거부합니다. 컴포넌트 계층은 검증기가 반환하는 값을 신뢰합니다. 모바일 클라이언트는 검증된 페이로드(payload)만을 전달받습니다. 이것이 바로 200개의 행이 포함된 리스트가 레코드당 약 200~400개의 토큰 정도로 작고 예측 가능한 상태를 유지하며 빠르게 렌더링될 수 있는 이유입니다.
여기서 승리 효과가 복리로 작용합니다. 검증(validation), 타입 체크(type-checking), 그리고 렌더링(rendering)이 모두 동일한 스키마를 읽기 때문입니다. 서로 어긋날(drift) 수 있는 두 번째 진실의 원천(source of truth)이 존재하지 않습니다.
크로스 플랫폼 렌더링: 모든 표면에서 동일한 엔티티
UI가 자유 형식의 프롭스(freeform props) 대신 타입이 지정된 엔티티(typed entities)에 바인딩되면, 크로스 플랫폼 문제는 해결됩니다. Booking은 웹, iOS, Android 모두에서 동일한 Booking입니다. 동일한 필드 이름, 동일한 검증, 동일한 상태 열거형(status enums)을 가집니다. 컴포넌트 계층은 스키마를 읽어 엔티티를 렌더링하며, 표면(surface)은 그에 맞춰 적응합니다.
<BookingCard
booking={entity} // type: Booking (schema.otf.ts로부터)
onCancel={() => mutate(status)} // schema로부터 가져온 status enum
...
필드 기대치가 서로 다른 <BookingCardWeb>과 <BookingCardNative>를 따로 만들 필요가 없습니다. 스키마에 cancellationReason 필드가 추가되면, 타입 시스템이 에이전트의 도구 정의(tool definitions)를 포함한 모든 소비자에게 이를 알리며, 컴포넌트는 각 플랫폼에 별도의 PR을 보낼 필요 없이 이를 렌더링합니다. 하나의 코드베이스로부터 동일한 컴포넌트 이름 + 프롭스 + 외형이 모든 표면에서 렌더링됩니다.
[[COMPARE: 플랫폼마다 새로 만드는 자유 형식 프롭스 vs 하나의 파일에 고정된 스키마 기반 엔티티]]
내구성이 있는 계층(durable layer)이 존재하는 곳
모델이 바뀌어도 변하지 않는 부분이 바로 여기입니다. 스키마 파일은 특정 LLM보다 오래 지속됩니다. 컴포넌트 계층(component layer)은 특정 에이전트 프레임워크(agent framework)보다 오래 지속됩니다. 검증 규칙(validation rules)은 특정 도구 실행기(tool runner)보다 오래 지속됩니다.
이것이 바로 경계(seam)입니다. 에이전트는 스키마의 소비자이고, UI는 스키마의 소비자이며, 스키마는 내구성이 있는 표면(durable surface)입니다. 도구는 끊임없이 변합니다. 오늘의 모델, 내일의 MCP 서버, 다음 분기의 오케스트레이터(orchestrator)가 바뀌더라도, 계약(contract)은 계약입니다.
AI 설정이 컴포넌트 계층이 타입을 읽어오는 곳과 동일한 위치인 스키마 옆에 존재할 때, 에이전트는 키트(kit)를 재생성하는 대신 확장하게 됩니다. 문서화된 CLAUDE.md, .cursorrules, 그리고 테스트된 고정된 ai/prompts/ 세트는 스키마가 런타임(runtime)에 제공하는 것과 동일한 근거(grounding)를 에이전트에게 제공합니다. 결과적으로 에이전트와 앱은 동일한 세계를 바탕으로 추론하게 됩니다.
[[CONCEPT: 단일 진실 공급원(single source of truth)으로서의 스키마 파일 — 하나의 파일, 두 명의 소비자, 드리프트(drift) 제로]]
이것이 바로 변하지 않는 부분입니다. 모델을 교체해도 스키마는 유지됩니다. 에이전트 프레임워크를 교체해도 스키마는 유지됩니다. 컴포넌트는 당신이 배포하는 어떤 표면에서든 스키마가 렌더링 가능하다고 명시한 것을 렌더링합니다.
이것이 가능하게 하는 것
스키마가 계약(contract)이 될 때 얻을 수 있는 세 가지 구체적인 이점은 다음과 같습니다:
- 에이전트의 실수가 조용히 넘어가지 않고 명확하게 드러납니다. SHACL은 잘못된 형식의
startsAt이 사용자에게 도달하기 전에 거부합니다. 잘못된 데이터가 아예 도착하지 않기 때문에 UI는 잘못된 데이터에 대해 방어할 필요가 없습니다. - 모바일 환경에서도 빠른 속도를 유지합니다. 예약 정보의 평탄화되고 검증된 투영(projection)은 약 200~400 토큰입니다. 그래프(graph)를 전달하는 것이 대안이 될 수 있지만, 이는 휴대폰에 적합하지 않습니다. 또한 100ms의 리스트 렌더링은 언제나 연합 SPARQL(federated SPARQL) 쿼리보다 빠릅니다.
- 리팩터링(Refactor)이 단 하나의 파일에서 이루어집니다.
cancellationReason을 추가하면 스키마, 에이전트의 도구 정의, SHACL 셰이프(shape), 그리고 컴포넌트 타입이 한 번에 업데이트됩니다. 변경 사항(diff)은 로컬에 국한되며, 영향 범위(blast radius)는 파일 하나로 제한됩니다.
시맨틱 웹 (Semantic Web)은 연구를 위한 전환점이 아닙니다. 이는 에이전트 (Agents)를 기다려온 타입화된 계약 패턴 (Typed contract pattern)입니다. 어려운 점은 온톨로지 (Ontology)가 아닙니다. 어려운 점은 스키마 (Schema)를 그것에 닿는 모든 레이어의 신뢰할 수 있는 단일 원천 (Source of truth)으로 만드는 것입니다. 그것이 대부분의 팀이 건너뛰는 부분이며, 6개월 뒤에 비용을 치르게 만드는 부분입니다.
계약을 고정하십시오. 그 외의 모든 것은 변화하게 두십시오.
AI 자동 생성 콘텐츠
본 콘텐츠는 Dev.to AI tag의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기