에이전트에게 HTML을 제공하지 마세요

발행: (2025년 12월 5일 오전 12:49 GMT+9)
9 분 소요
원문: Dev.to

Source: Dev.to

TL;DR — AI에게 블랙 박스가 아닌 화이트 박스를 제공하라

대부분의 AI 에이전트는 블랙 박스 방식으로 웹 앱과 상호작용합니다: DOM 덤프나 스크린샷을 소비하고, 클릭할 대상을 추측합니다. HTML은 기계용으로 설계된 것이 아닙니다. AI 입장에서 DOM은 비즈니스 로직이 희미하게 숨어 있는 잡음에 불과합니다.

이 에세이는 화이트 박스 접근법을 주장합니다: 시맨틱 상태 레이어를 노출하여 애플리케이션의 구조, 규칙, 상태 및 유효한 전이를 직접 드러냅니다. 이는 UI를 대체하는 것이 아니라 전통적인 사용자 인터페이스와 함께 인텔리전스 인터페이스 (II) 를 제공하는 것입니다.

Manifesto Playground Demo

직접 사용해 보기 → Manifesto Playground

Source:

1. 블랙 박스: 현재 AI + 웹 앱 상황

오늘날 대부분의 팀이 웹 앱에 “AI를 추가”하는 방식은 다음과 같습니다:

  • LangChain, AutoGPT, 혹은 브라우저 자동화 사용
  • Playwright 또는 Puppeteer 구동
  • DOM이나 스크린샷을 모델에 투입
  • 무엇을 클릭해야 할지 모델이 알아내길 기대

이것이 블랙 박스 접근 방식입니다. 에이전트는 렌더링된 화면만 보고 나머지는 모두 추론해야 합니다.

DOM 덤프의 문제점은?

<div class="product-name">
  <label>Product Name</label>
  <input type="text" name="name" />
  <span class="error">This field is required.</span>
</div>

에이전트 입장에서 보면:

문제영향
토큰 낭비토큰의 90 %가 클래스 이름과 래퍼에 사용됨
제약 조건 누락필수 입력인가? 최대 길이는 얼마인가?
의존성 없음이 필드가 다른 필드에 의존하고 있는가?
인과 관계 부재제출 버튼이 비활성화되어 있는데 — 그런가?

에이전트는 추측을 강요받습니다. CSS 리팩터링만으로도 모든 것이 깨지고, 레이아웃 변경만으로도 모델이 혼란스러워집니다. 논리는 절대 노출되지 않았으며, 오직 시각적 투영만이 제공되었습니다.

시그널 90 %.

2. White Box: 애플리케이션의 두뇌 노출

대안은 White Box 프로토콜입니다. HTML을 보여주는 대신, 엔진은 Semantic Snapshot — 에이전트가 직접 읽을 수 있는 애플리케이션 내부 상태의 구조화된 표현 — 을 노출합니다.

{
  "topology": {
    "viewId": "product-create",
    "mode": "create",
    "sections": [
      { "id": "basic", "title": "Basic Info", "fields": ["name", "productType"] },
      { "id": "shipping", "title": "Shipping", "fields": ["shippingWeight"] }
    ]
  },
  "state": {
    "form": { "isValid": false, "isDirty": false },
    "fields": {
      "name": {
        "value": "",
        "meta": { "valid": false, "hidden": false, "disabled": false, "errors": ["Required"] }
      },
      "productType": {
        "value": "PHYSICAL",
        "meta": { "valid": true, "hidden": false, "disabled": false, "errors": [] }
      },
      "shippingWeight": {
        "value": null,
        "meta": { "valid": true, "hidden": false, "disabled": false, "errors": [] }
      }
    }
  },
  "constraints": {
    "name": { "required": true, "minLength": 2, "maxLength": 100 },
    "shippingWeight": { "min": 0, "max": 2000, "dependsOn": ["productType"] }
  },
  "interactions": [
    { "id": "updateField:name", "intent": "updateField", "target": "name", "available": true },
    { "id": "updateField:productType", "intent": "updateField", "target": "productType", "available": true },
    { "id": "submit", "intent": "submit", "available": false, "reason": "Name is required" }
  ]
}

이제 에이전트는 다음을 갖게 됩니다:

  • Topology – 화면 구조, 섹션, 필드 계층
  • State – 현재 값, 유효성, 가시성, 필드별 오류
  • Constraints – 필수 여부, 최소/최대값, 의존 관계
  • Interactions – 어떤 행동이 가능한지와 일부가 차단되는지

추측이 필요 없습니다. 추론이 필요 없습니다. 에이전트는 애플리케이션의 두뇌를 직접 읽습니다.

3. 실제 사용 사례: “주를 어디서 선택하나요?”

🎮 실제 동작 보기: Manifesto Playground – 필드 값을 변경하고 의미론적 상태가 실시간으로 업데이트되는 모습을 확인해 보세요.

시나리오

사용자: “날짜 선택기는 보이는데, 주는 어디서 선택하나요?”

AI 챗봇: “주 선택기는 frequency를 ‘Weekly’로 설정했을 때만 나타납니다. 현재는 ‘Daily’로 설정돼 있네요. 대신 바꿔드릴까요?”

이를 위해 AI가 알아야 할 내용:

  • weekSelector라는 필드가 존재하며 현재는 숨겨져 있다
  • frequency === 'WEEKLY'일 때 보이게 된다
  • 현재 frequency 값은 'DAILY'이다

DOM‑만으로는 이 정보를 신뢰성 있게 제공할 수 없지만, 의미론적 스냅샷을 사용하면 가능합니다:

{
  "fields": {
    "frequency": {
      "value": "DAILY",
      "meta": { "hidden": false }
    },
    "weekSelector": {
      "value": null,
      "meta": { "hidden": true },
      "visibleWhen": "frequency === 'WEEKLY'"
    }
  }
}

AI는 이를 읽고 추론 없이 필드가 숨겨진 정확한 이유와 어떤 조건에서 나타나는지를 알 수 있습니다.

4. 프로토콜 루프

Manifesto는 엔진과 AI 에이전트 사이에 지속적인 피드백 루프를 구현합니다:

┌─────────────────────────────────────────────────────────────────────┐
│                                                                     │
│  [Context Injection] → [Reasoning] → [Action Dispatch] → [Delta]    │
│          ▲                                                  │       │
│          └─────────────── Continuous Snapshots ────────────────┘       │
│                                                                     │
└─────────────────────────────────────────────────────────────────────┘

단계별 설명

  1. 컨텍스트 주입 – 엔진은 토폴로지, 상태, 제약 조건 및 상호작용을 포함한 시맨틱 스냅샷을 내보냅니다.
  2. 추론 – 에이전트는 스냅샷을 기반으로 다음 행동을 계획합니다.
  3. 액션 디스패치 – 에이전트는 원시 DOM 이벤트 대신 추상 인텐트(예: updateField, submit, reset, validate)를 호출합니다.
  4. 델타 피드백 – 엔진은 단순히 “성공”이 아니라 무엇이 변했는지를 반환합니다. 차이는 인과관계를 보여줍니다(예: “X를 변경했더니 Y가 숨겨졌다”).
  5. 루프는 업데이트된 스냅샷으로 반복되어 에이전트에게 “클릭하고 기대”가 아닌 예측 가능하고 구조화된 피드백을 제공합니다.

5. API: 탐색 및 실행

Manifesto는 이 프로토콜을 @manifesto-io/ai를 통해 노출합니다.

탐색 모드 – “여기서 무엇을 할 수 있나요?”

import { createInteroperabilitySession } from '@manifesto-io/ai'

const session = createInteroperabilitySession({
  runtime,       // FormRuntime instance
  viewSchema,   // View definition
  entitySchema, // Entity definition
})

// Get the current semantic snapshot
const snapshot = session.snapshot()

// snapshot.interactions tells the agent:
// - submit: available = false, reason = "Name is required"

여기서 에이전트는 사용 가능한 상호작용을 조회하고, 필드를 업데이트하며, 폼을 제출하고, 증분 차이를 받아올 수 있습니다. 모두 화이트‑박스 의미론적 표현에 의해 구동됩니다.

Back to Blog

관련 글

더 보기 »