01 · QUESTION
챗봇은 왜 계획에서 멈출까?
서울에서 하루 외출을 계획하려면 장소, 예약 가능 여부, 동행인의 이동 부담, 주차장, 경로와 다음 일정을 계속 함께 조정해야 합니다. 공공데이터와 지도 API에는 필요한 정보가 흩어져 있지만, 데이터가 존재한다고 해서 사용자의 계획이 완성되지는 않습니다.
일반적인 챗봇은 장소 목록을 제안할 수 있습니다. 그러나 사용자가 두 번째 후보를 고르고 “차로 갈 건데 주차도 편한 곳으로 바꿔줘”라고 말하는 순간, 이전 선택과 이동수단, 지도 위치, 공공예약 상태가 다음 답변의 전제가 됩니다.

02 · APPROACH
답변이 아닌 계획 상태
서울 어디가?는 2026 서울시 빅데이터 활용 경진대회 창업 부문 제품 및 서비스 개발 출품작입니다. 서울 열린데이터광장의 공공서비스예약·공영주차장 정보와 장소 검색, 지도, 경로, 음성 입력을 사용자의 의사결정 순서에 맞춰 연결했습니다.
agent의 결과물은 긴 추천 문장이 아니라, 사용자가 확인하고 수정할 수 있는 계획 상태입니다. 장소 후보는 지도 marker와 선택 카드로, 경로는 비교 가능한 후보로, 확정한 선택은 다음 질문에서 다시 읽을 수 있는 상태로 남깁니다.
03 · AGENT UI LOOP
대화가 UI를 움직이는 법
단일 Main Agent는 요청을 해석하고 공공데이터·장소·경로 tool을 호출합니다. 다만 결과를 그대로 채팅에 출력하지 않고, 장소 선택, 경로 후보, 지도 viewport, 공유 요약을 위한 typed UI tool로 변환합니다.
REQUEST → STATE → UI
사용자 요청 또는 음성 입력
→ Main Agent: 의도·조건 해석
→ 공공데이터 · 장소 · 경로 tool
→ typed UI state tool
→ Zustand AgentUiStore
→ Scene / Frame / Surface 렌더링
→ 사용자 선택
→ compact UI snapshot
→ 다음 agent turnNext.js App Router 위의 Zustand `AgentUiStore`는 chat, frame, route, selection, itinerary, share, planning, voice 상태를 함께 관리합니다. `frame_open`, `route_set_places`, `route_set_candidates`, `selection_set_options`, `share_set_state`처럼 허용된 tool만 store action을 실행합니다.
사용자가 marker나 후보 카드를 선택하면 결과가 store에 기록되고, 다음 요청에는 필요한 내용만 담은 UI snapshot이 전달됩니다. agent가 React component나 DOM을 직접 다루지 않도록 하면서도, 대화와 사용자의 선택이 다음 계획에 반영되게 한 feedback loop입니다.


04 · UI BOUNDARY
LLM의 화면 권한은 제한한다
자유 생성보다 제한된 화면 언어
초기에는 LLM이 2D grid에 pane을 배치하는 tiling manager도 실험했습니다. 하지만 지도, chat, 카드 목록, 일정, 공유 화면은 필요한 크기와 반응형 조건이 달랐고, 좌표와 크기까지 모델에게 맡기면 prompt와 결과가 함께 불안정해졌습니다.
그래서 제품의 기본 구조는 scene/frame preset 방식으로 옮겼습니다. agent는 “지도를 특정 좌표에 그려라”라고 지시하지 않고, route map frame을 열어 장소·경로·viewport·선택 상태만 바꿉니다. React controller가 화면의 실제 layout과 modal, 반응형 동작을 결정합니다.

A2UI와 AG-UI에서 가져온 문제의식
A2UI는 선언적 UI payload를, AG-UI는 agent와 frontend 사이의 state·tool event 전달을 다룹니다. 이 프로젝트는 두 protocol을 그대로 채택하지는 않았지만, 같은 문제의식에서 component 생성과 UI state 변경을 분리했습니다. 모델의 유연함은 자연어 이해와 tool 선택에 사용하고, 화면의 품질과 안전성은 제품 코드가 소유하도록 했습니다.
05 · HANDOFF
선택을 공유 가능한 계획으로 묶는다
계획 상태는 한 번의 답변으로 끝나지 않습니다. 사용자가 고른 장소와 이동 순서를 짧게 확인하고 다른 사람과 공유할 수 있어야, 다음 대화와 실제 외출 사이가 끊기지 않습니다.
그래서 공유 화면 역시 별도 문서를 생성하는 기능이 아니라, 현재 itinerary와 선택을 읽어 정리하는 동일한 state의 다른 surface로 다뤘습니다.

06 · VOICE
음성과 화면의 역할 분리
장소·시간·동행인·이동수단처럼 조건이 많은 요청은 여러 필터를 누르는 것보다 문장 하나로 말하는 편이 빠르고 자연스럽습니다. 음성 transcription은 별도 command 체계가 아니라 같은 prompt input과 agent loop로 들어가 계획 상태를 수정합니다.
반면 최종 답변에는 표, 후보 카드, 링크, tool 결과가 들어갈 수 있어 그대로 읽기에는 적합하지 않습니다. `voice_prepare_speech` tool은 최종 답변을 복사하지 않은 짧은 발화문만 준비하고, ElevenLabs TTS는 이 payload만 재생합니다. 화면은 비교와 근거를 보여 주고, 음성은 다음 행동을 안내하도록 역할을 나눴습니다.

07 · MODEL SELECTION
모델 하나에 너무 많은 일이 몰렸다
이 프로젝트의 Main Agent에는 자연어 해석, data tool 선택, 결과 비교, UI state 변경, 화면 설명과 음성 요약까지 많은 책임이 모였습니다. tool이 늘어날수록 사용자가 체감하는 지연은 첫 token 속도만이 아니라, tool schema 이해와 호출 순서, 다음 UI payload 생성의 안정성에 좌우됐습니다.
프로젝트에서는 OpenRouter의 `deepseek/deepseek-v4-flash`를 tool 지원 provider와 함께 기본 모델로 사용했습니다. 더 작은 모델과 이전 모델도 비교했지만, 공공데이터 결과를 UI state로 이어 붙이는 다수 tool flow에서 이 모델이 실사용 가능한 안정성의 하한에 가까웠습니다.
후속 Cerebras integration smoke test에서는 `zai-glm-4.7`과 `gpt-oss-120b`도 같은 유형의 tool flow에 연결했습니다. 빠른 생성 속도와 별개로, 필요한 tool을 건너뛰거나 호출 순서와 화면 전환 payload가 흐트러지는 사례가 있어 이 contract를 대체하지는 못했습니다. 이는 모델 일반 성능 순위가 아니라, 이 agent 구조에서 얻은 관찰입니다.
RELATED PROJECT · RODY RAG 01로디 복지 상담 에이전트 · RAG 1검색 기반과 agent 책임을 분리해, 상담 agent가 검증 가능한 근거를 읽도록 만든 다음 프로젝트08 · LIMITS
공공데이터의 운영 경계
예약·운영 정보의 최신성은 원본 provider에 달려 있고, 외부 API는 느리거나 일시적으로 응답하지 않을 수 있습니다. 추천 결과에는 원본 정보와 확인 시점을 보여 주고, 예약이나 이동 전에는 사용자가 다시 확인할 수 있어야 합니다.
또한 실제 운영 서비스에서는 provider별 quota와 cache, 장애 fallback, 위치정보와 개인정보 보관 정책을 더 구체화해야 합니다. 이 프로젝트는 공공데이터 API를 많이 연결하는 데서 끝나지 않고, data와 agent 결과를 사용자가 선택할 수 있는 상태로 바꾸는 방법을 실험했습니다.