A2UI가 그리는 UX의 미래, Next.js가 드러낸 보안의 미래
A2UI는 AI가 UI의 상태와 행동을 선언하고 화면이 이를 그대로 표현하는 방식으로, 사용자 인터랙션의 미래가 될 수 있으니 이를 전제로 UX를 설계·기획해야 해요. 또한 UX를 단순화하는 이 구조의 위험성을 인지하고, 설계 단계부터 보안을 함께 고려하며 관련 보안 기법을 숙지해야 해요.
🧩 ActionCard에서 시작된 고민
개인 포트폴리오 사이트를 만들면서, 저는 ActionCard라는 개념을 먼저 정의했어요.
챗봇 기반 UI를 구성하다 보니, 자연스럽게 이런 고민이 생겼거든요.
대화가 어느 정도 진행된 이후에는
사용자에게 더 이상 “아무 말이나 입력하세요”라고 맡기기보다는,
지금 이 시점에 필요한 행동을 명확히 안내하는 UI가 필요하다고 느꼈어요.
특히 연락 여부처럼,
- 선택지가 명확하고
- 결과가 이후 흐름을 바꾸는 상황에서는
자유 입력이 오히려 UX를 흐리게 만든다고 판단했어요.
그래서 그 시점부터는 Guided UX로 전환했고,
입력창 대신 버튼과 명시적인 액션을 담은 ActionCard를 노출하도록 설계했어요.
💡 ActionCard는 “버튼 UI”가 아니라 상태 표현이었어요
ActionCard는 단순히 버튼을 모아둔 컴포넌트가 아니었어요.
제가 의도했던 건 이거였어요.
“지금 이 대화는 사용자의 명시적인 행동이 필요한 상태다.”
그래서 ActionCard는 항상:
- 대화 흐름의 특정 시점에만 등장했고
- 일반 메시지와 명확히 구분되는 UI였으며
- 사용자의 선택이 이후 AI 응답 흐름에 직접적인 영향을 주는 구조였어요
이 방식은 개인적으로
Apple Siri의 대화형 UX에서 많은 영감을 받았어요.
자연스럽게 대화를 이어가다가, 중요한 순간에는 선택지를 명확히 제시하는 방식이요.
당시에는 이걸 어떤 체계적인 개념으로 정리하고 있지는 않았어요.
UX가 불편하다고 느껴졌고, 빠르게 해결해야 했기 때문에 선택한 구현이었어요.
🤖 그러다 알게 된 A2UI
이후 Google에서 제시한 A2UI(Agent-to-UI) 개념을 접하면서,
제가 만들었던 흐름과 구조적으로 유사한 지점이 많다는 걸 인식하게 되었어요.
A2UI를 한 문장으로 정리하면 이렇게 설명할 수 있어요.
Agent(LLM)가 현재 상태와 필요한 액션을 선언하고,
UI는 그 선언을 해석하지 않고 그대로 표현한다.
이 개념의 핵심은
UI가 더 이상 ‘판단의 주체’가 아니라 ‘표현의 주체’로 역할이 내려온다는 점이에요.
🤖 A2UI란?
A2UI는 단순히 “AI가 UI를 만들어준다”는 의미가 아니에요.
본질은 역할 분리에 있어요.
| 역할 | 책임 |
|---|---|
| Agent (LLM) | 상태 판단, 다음 액션 결정 |
| UI | 선언된 상태를 그대로 렌더링 |
| Server | 권한 검증, 실행 통제 |
기존 UI와 비교하면 차이가 분명해요.
| 구분 | 기존 UI | A2UI |
|---|---|---|
| 상태 판단 | 프론트 로직 | Agent |
| UI 분기 | if / switch | 선언(JSON) |
| UI 책임 | 화면 + 판단 | 화면만 |
| 확장 방식 | 컴포넌트 추가 | 스키마 확장 |
돌이켜보면,
ActionCard 역시 의도하지는 않았지만
이 구조와 유사한 방향으로 구현되어 있었어요.
🔁 ActionCard와 A2UI가 닮아 있었던 지점
1️⃣ UI가 판단하지 않는 구조
if (answerType === "promptTextMessage") {
return <ActionCard />
}
프론트엔드는
“왜 이 UI가 필요한지”를 알지 못해요.
Agent가 내려준 상태를 그대로 표현할 뿐이에요.
이는 A2UI의 핵심 원칙과 같아요.
결정은 Agent가, UI는 표현만 한다.
2️⃣ ActionCard는 컴포넌트가 아니라 ‘상태’
ActionCard는
사용자의 행동이 필요한 상태를 시각화한 결과물이었어요.
그래서 항상:
- 특정 시점에만 등장했고
- 해당 상태가 지나가면 다시 나타나지 않았어요
이 사고방식은 A2UI의 State-driven UI와 맞닿아 있어요.
3️⃣ 사용자 행동이 다시 Agent로 돌아가는 구조
metaMessage = {
type: "ACTION_RESULT",
action: "SEND_MESSAGE",
result: "CONFIRMED",
};
사용자의 선택은 다시 LLM 컨텍스트로 전달되고,
다음 UI 상태를 결정하는 입력값으로 사용돼요.
이 흐름은 Agent-driven feedback loop예요.
🔐 A2UI에서 반드시 고려해야 하는 보안 지점들
이제 중요한 부분이에요.
A2UI는 단순히 보안을 조금 더 신경 써야 하는 기술이 아니에요.
사용자를 편하게 만들기 위해 Backstage에서 처리되는 로직이 급격히 늘어나는 구조이기 때문에,
그만큼 외부로 드러나는 Attack Surface도 함께 증가할 수밖에 없어요.
UI가 단순해질수록,
상태 판단·액션 결정·권한 검증 같은 로직은
점점 더 서버와 Agent, 즉 눈에 보이지 않는 영역으로 이동하게 돼요.
그리고 이 Backstage 영역이 복잡해질수록,
공격자가 노릴 수 있는 지점 역시 자연스럽게 늘어나요.
그래서 A2UI는
“보안을 고민해야 할 기술”이라기보다는,
보안을 전제로 설계하지 않으면 안 되는 기술에 가까워요.
어떤 신기술이든지 좋다고 무작정 사용할 수는 없어요.
특히 A2UI처럼 Attack Surface가 구조적으로 커질 수밖에 없는 패턴에서는,
- 어떤 입력이 신뢰 가능한지
- 어떤 액션이 허용되는지
- 어디까지를 UI에 맡기고, 어디부터를 서버가 책임질지
를 명확히 구분하지 않으면
UX를 단순화한 대가로 시스템 전체의 안전성을 잃을 수도 있어요.
따라서 A2UI를 도입하거나 염두에 두고 설계할 때는,
기능 구현만큼이나 어떤 보안 위협이 생길 수 있는지,
그리고 그 위협을 코드와 구조로 어떻게 통제할 것인지를
처음부터 함께 고민하며 구현해야 해요.
1️⃣ UI 선언은 반드시 화이트리스트로 검증
const ALLOWED_TYPES = [
"plainMarkdown",
"promptTextMessage",
"confirmSendTextMessage",
] as const;
function validate(type: string) {
if (!ALLOWED_TYPES.includes(type as any)) {
throw new Error("Invalid UI schema");
}
}
👉 LLM 출력은 항상 불신하고 검증해요.
2️⃣ Action 실행 권한은 서버가 가져야 해요
// UI는 요청만
POST /api/action
// 서버에서 상태 + 권한 검증
if (!session.user || !isValidState(ctx)) {
return res.status(403).end();
}
👉 버튼은 트리거일 뿐, 결정권은 서버예요.
3️⃣ LLM Context에 들어가는 정보는 구조화
metaMessage = {
type: "ACTION_RESULT",
action: "CONFIRM",
result: true,
};
👉 문자열보다 구조화된 메타 정보가 안전해요.
4️⃣ A2UI는 선언적 SSR이라는 점을 인식
const COMPONENT_MAP = {
ActionCard,
MarkdownView,
} as const;
const Component = COMPONENT_MAP[schema.type];
👉 동적 실행은 막고, 명시적 매핑만 허용해요.
🚀 최종 주장 정리
1️⃣ 사용자 인터랙션이 필요한 UI의 미래는 A2UI에 가까워질 가능성이 높아요.
텍스트 입력 중심의 UI를 넘어, 음성·환경 기반 인터랙션까지 확장될 수 있어요.
2️⃣ 개발자는 화면을 설계할 때,
A2UI가 도입될 수 있다는 전제를 두고 구조를 설계해야 해요.
지금 쓰지 않더라도, 들어올 수 없는 구조는 피해야 해요.
3️⃣ A2UI는 생산성을 크게 높이지만,
보안을 설계에 포함시키지 않으면 그만큼 위험도 커져요.
🧾 한 문장으로 마무리하면
A2UI는 사용자 인터랙션의 미래가 될 가능성이 높고,
개발자는 그 가능성을 전제로 한 구조적 설계와 보안 고려를 함께 짊어져야 해요.