
보닥 앱에 넣은 AI 상담사는 마이데이터 기반 보험 정보와 진단 엔진 결과를 묶어 개인화된 답변을 만드는 기능이다. 사용자는 채팅창에서 질문하고, AI Agent는 개인의 보험 맥락을 반영한 답변을 스트림으로 내려준다.
이 글에서 다루는 파서는 그 스트림을 받아 화면에서 쓸 수 있는 구조로 바꾸는 계층이다. 단순히 텍스트를 이어 붙이는 코드가 아니다. 스트림 데이터 파싱, UI 블록 구성, 플랫폼별 렌더링 준비까지 맡도록 설계했다.
처음 부딪힌 문제
파서는 아래 흐름 사이에 들어간다.
Bodoc App ↔ Backend API ↔ AI Agent
백엔드 응답은 스트림으로 들어온다. 클라이언트는 토큰 단위로 도착하는 데이터를 누적하면서 해석해야 한다. 여기에 한 가지 요구가 더 붙었다. AI 답변을 문장 덩어리로만 보여주는 것이 아니라 카드, 안내 문구, 추천 질문, 보험 정보 블록 같은 UI 구조로 표현해야 했다.
초기 요구사항은 이랬다.
- 같은 응답 스펙을 모바일 앱과 웹에서 모두 지원해야 했다.
- 플랫폼별 UI 구현은 달라도 데이터 해석 결과는 같아야 했다.
- AI 응답 포맷이 바뀌었을 때 수정 범위가 한쪽 플랫폼에 갇히면 안 됐다.
각 플랫폼에 파서를 따로 두는 방법도 있었다. 하지만 그렇게 가면 같은 버그를 두 번 고치고, 같은 스펙 변경을 두 번 반영하게 된다. 그래서 먼저 질문을 좁혔다.
파서를 플랫폼에 종속시키지 않고, 공통 로직으로 유지할 수 있을까?
공통 구조로 나눈 이유
결국 모노레포 안에 공통 파서를 두는 구조로 갔다. React와 React Native는 실제로 렌더링하는 컴포넌트가 다르다. 그래도 스트림을 읽고, 의미 있는 블록으로 나누고, 화면 구조를 조립하는 흐름은 공유할 수 있다고 봤다.
구조는 두 계층으로 나눴다.
1. Core Parser
- 스트림 데이터 파싱
- UI를 표현할 시맨틱 구조 생성
- 플랫폼 독립적인 데이터 모델 관리
2. Renderer
- Web, React Native 렌더러 구현
- 시맨틱 구조를 실제 컴포넌트 트리로 변환
- 플랫폼별 스타일링과 상호작용 처리
파서는 "무엇을 보여줄지"를 결정한다. 렌더러는 "어떻게 보여줄지"를 맡는다. 이 경계를 나누면 AI 응답 해석 로직은 한곳에 모을 수 있고, 각 플랫폼은 자기 UI 계층만 신경 쓰면 된다.

이렇게 나누니 운영할 때도 기준이 단순해졌다.
- 응답 해석 로직은 Core Parser에서만 고친다.
- Web과 React Native는 같은 파서 결과를 기준으로 렌더링한다.
- 포맷 변경이 생기면 파서와 렌더러 중 어디를 봐야 하는지 바로 갈린다.
개발 과정
처음부터 패키지 구조를 완성해 둔 것은 아니다. 실제로는 앱 안에서 먼저 굴려 보고, 문제가 줄어든 뒤에 밖으로 빼는 순서로 진행했다.
1. React Native에서 먼저 프로토타이핑
초기에는 속도가 더 중요했다. AI Agent와 빨리 붙여 봐야 했기 때문에 앱 내부에서 직접 소켓 연결과 스트림 수신을 구현했다. 파서 로직도 처음에는 앱 코드 안에서 실험했다.
이 단계의 목표는 설계를 예쁘게 잡는 것이 아니었다. 실제 스트림 응답이 어떤 모양으로 들어오는지, 어떤 UI 패턴이 반복되는지 확인하는 쪽이 먼저였다.
2. 파서 로직을 패키지로 분리
파서 구조가 어느 정도 안정된 뒤 로컬 패키지로 추출하고 내부 dogfooding을 했다. 이때 계속 본 질문은 하나였다.
이 코드가 앱 내부 구현이 아니라, 라이브러리로서도 자연스러운가?
이 질문을 기준으로 API를 다듬었다. 플랫폼에 기대고 있던 코드를 걷어내면서 Core Parser와 Renderer의 경계도 더 분명해졌다.
3. npm 공개 패키지로 배포
검증이 끝난 뒤에는 공개 npm 패키지로 배포했다. 여기서 중요한 점은 코어와 플랫폼별 렌더러를 따로 운영할 수 있게 만드는 것이었다.
이후 운영 흐름은 이렇게 바뀌었다.
파서 수정 → 패키지 배포 → 앱/웹 동시 반영
공통 로직을 고칠 때마다 앱과 웹 구현을 따로 열어 볼 필요가 줄었다. 패키지를 올리고 각 프로젝트에서 버전만 맞추면 같은 파서 결과를 기준으로 동작했다.
4. Web 프로젝트에 동일한 파서 적용
React 웹 프로젝트에는 같은 파서 디펜던시를 추가하고 Web Renderer만 따로 구현했다. 결과적으로 하나의 파서 로직이 모바일과 웹에서 같은 방식으로 동작했다. UI 표현 차이는 렌더러 계층 안에서만 다루면 됐다.
5. QA와 릴리즈
구조를 나눠 둔 덕분에 QA 범위도 비교적 선명했다.
- Core Parser: 스트림 해석 결과와 UI 구조 생성 검증
- Platform Renderer: 실제 화면 표현과 상호작용 검증
- 앱/웹: 각 플랫폼별 통합 QA와 배포 확인
문제가 생겼을 때도 먼저 볼 곳을 좁힐 수 있었다. 응답 구조가 틀리면 Core Parser를 보고, 화면 표현이 어긋나면 Renderer를 보는 식이다.
결과 예시
아래는 스트림 기반 응답이 실제 사용자 화면에 표현된 모습이다.


화면에서는 텍스트 답변만 보여주지 않는다. 보험 정보 요약과 후속 액션이 하나의 대화 흐름 안에서 이어지도록 구성했다.
패키지 구성
현재 공개한 패키지는 아래와 같다.
@bdmakers/agent-data-parser@bdmakers/agent-data-parser-renderers@bdmakers/agent-data-parser-web@bdmakers/agent-data-parser-react-native
패키지를 이렇게 나누면 코어 로직과 플랫폼 구현을 따로 배포하고 조합할 수 있다. 새 플랫폼이 생겨도 Core Parser를 다시 만들 필요 없이 Renderer만 추가하면 된다.
마무리
이 작업에서 어려웠던 부분은 파서 자체보다 경계였다.
- 파서: 데이터 → 구조
- 플랫폼: 구조 → UI
이 경계를 잡아 두니 이후 변경이 덜 무거워졌다. AI 응답 포맷을 바꿀 때마다 앱과 웹을 따로 맞출 필요가 없고, 플랫폼별 UI 차이도 렌더러 안에 가둘 수 있었다. 결과적으로 이 작업은 "공통 모듈을 뺐다"기보다, AI 응답을 제품 화면으로 옮기는 책임을 다시 나눈 작업에 가까웠다.