수영장(Sooyoung Archive)
홈개발일지이번캠App소개
전체보기
프로젝트
블로그 만들기그림톡캠핑 인스타
개발

© 2026 수영장 (Sooyoung Archive). All rights reserved.

개인정보처리방침연락처
개발일지 목록
그림톡

그림톡 만들기 3편: '한 번 답하는 앱'에서 '계속 대화하는 친구'로 바꾸기

2026년 3월 30일약 12분 소요60회 조회
목차
시작하며1. 가장 큰 문제는 latency보다 continuity였다2. 1턴과 후속 턴은 사실 같은 요청이 아니었다첫 턴후속 턴3. 후속 턴에서는 그림을 다시 보내지 않기로 했다1) 같은 친구를 계속 유지하고 싶었기 때문2) 속도도 줄이고 싶었기 때문3) 이미 필요한 정보는 첫 턴에서 얻었기 때문4. 캐릭터 프로필을 고정 저장했다5. 그런데 실사용 중 더 치명적인 문제가 하나 나왔다6. route 레이어에서도 방어가 필요했다1) continuity 메타를 실제로 받기2) 금지 자기소개 방어7. UX도 같이 이어지게 보여야 했다record 화면loading 화면result 화면8. 사용성 측면에서 앨범 업로드도 넣었다9. 이번에 얻은 가장 큰 감각마무리

그림톡 만들기 3편: ‘한 번 답하는 앱’에서 ‘계속 대화하는 친구’로 바꾸기

시작하며

결과 화면을 어느 정도 정리하고 나서, 그림톡을 실제로 다시 써보면 금방 보이는 문제가 하나 있었다.

첫 만남은 꽤 괜찮았다. 그림을 보여주고, 말을 걸고, 친구가 대답하는 첫 장면까지는 감정선이 살아 있었다.

그런데 그 다음이 문제였다.

대화가 이어지지 않는 느낌이 있었다.

겉으로는 다시 말을 걸 수 있었지만, 실제 체감은 “같은 친구와 이어서 말한다”보다 “다시 한 번 결과를 만든다”에 더 가까웠다. 이건 그림톡에서는 꽤 치명적인 문제였다. 그림톡의 핵심은 첫 응답 하나를 만드는 게 아니라, 내 그림 친구와 계속 말을 섞게 만드는 것이기 때문이다.

이번 글에서는 이 문제를 어떻게 봤는지, 왜 1턴과 후속 턴을 분리하게 됐는지, 그리고 사용성 측면에서 왜 앨범 업로드까지 추가하게 됐는지 정리해보려고 한다.


1. 가장 큰 문제는 latency보다 continuity였다

처음엔 응답 속도가 느린 게 더 큰 문제처럼 보였다. 물론 그것도 맞다. 아이가 기다리는 시간이 길어지면 금방 집중이 끊긴다.

그런데 계속 보다 보니 더 본질적인 문제는 따로 있었다.

느린 건 UX로 어느 정도 완화할 수 있지만, 대화가 끊겨 보이면 핵심 경험이 무너진다.

즉, 사용자가 느끼는 문제는 단순히 “오래 걸려서 답답하다”가 아니라,

  • 같은 친구가 아닌 것 같고
  • 방금 한 말을 이어서 듣는 느낌이 약하고
  • 대화를 쌓아가는 리듬이 잘 안 생긴다

는 쪽에 가까웠다.

그래서 우선순위를 다시 잡았다.

  1. 같은 친구 continuity를 강하게 만들기
  2. 후속 턴 latency 줄이기
  3. UX도 이어지는 대화처럼 보이게 만들기

2. 1턴과 후속 턴은 사실 같은 요청이 아니었다

구조를 다시 보니, 첫 턴과 후속 턴은 목적 자체가 달랐다.

첫 턴

첫 턴은 말 그대로 친구가 처음 깨어나는 순간이다.

여기서는

  • 그림 정보도 필요하고
  • 사용자가 처음 한 말도 필요하고
  • 캐릭터의 정체, 말투, 첫 인사, 첫 질문도 같이 만들어져야 했다.

그래서 첫 턴은 여전히 image + audio가 맞았다.

후속 턴

하지만 두 번째 턴부터는 다르다.

이미 사용자는 그 친구를 만났고, 이제 필요한 건 “새 친구 생성”이 아니라 같은 친구의 다음 대답이었다.

그런데 기존 흐름은 이 둘을 충분히 구분하지 못하고 있었다. 그 결과 후속 턴도 어딘가 첫 턴처럼 느껴졌고, 캐릭터 continuity도 흔들렸다.

그래서 아예 구조를 분리했다.

  • first_turn
  • continue_turn

이렇게 나누고 나서야 무엇을 계속 보내고, 무엇을 보내지 말아야 하는지가 또렷해졌다.


3. 후속 턴에서는 그림을 다시 보내지 않기로 했다

이번 구조 변경에서 가장 중요한 결정 중 하나는 이거였다.

후속 턴에서는 이미지를 다시 보내지 않는다.

이유는 명확했다.

1) 같은 친구를 계속 유지하고 싶었기 때문

매 턴 이미지를 다시 보내면, 모델 입장에서는 같은 친구를 이어서 말하기보다 이미지를 다시 해석하는 쪽으로 흐를 수 있다.

그림톡에서 원하는 건 그게 아니었다.

2) 속도도 줄이고 싶었기 때문

후속 턴에서 이미지를 매번 다시 보내는 건 비용도 크고, 응답 시간에도 영향을 준다.

3) 이미 필요한 정보는 첫 턴에서 얻었기 때문

첫 턴이 끝난 시점에는 이미 이 친구의 기본 프로필을 알고 있다.

  • 이름
  • 정체
  • 성격
  • 목소리 톤
  • 첫 인사 톤
  • 질문 톤

그러면 후속 턴에서 더 중요한 건 이미지 재전송이 아니라, 고정 캐릭터 프로필 + 최근 대화 문맥이었다.

그래서 후속 턴은 이렇게 정리했다.

  • 입력: audio only
  • 숨은 문맥:
    • character profile
    • 최근 1턴(user / assistant)

이 구조가 훨씬 맞았다.


4. 캐릭터 프로필을 고정 저장했다

후속 턴 continuity를 만들기 위해선, “같은 친구”가 어떤 친구인지 앱이 잊지 않아야 했다.

그래서 첫 턴 성공 시 캐릭터 정보를 store에 고정 저장하게 만들었다.

예를 들면 이런 정보들이다.

  • name
  • identity
  • traits
  • voiceTone
  • greeting
  • question

이후 후속 턴에서는 새 캐릭터를 다시 만들지 않고, 이 고정 프로필을 기준으로 응답하게 했다.

이게 중요한 이유는 단순하다. 모델이 매번 자유롭게 다시 만들게 두면, 말투나 정체가 조금씩 흔들릴 수밖에 없다.

반대로 프로필을 고정하면,

  • 같은 이름으로 말하고
  • 같은 정체를 유지하고
  • 비슷한 말투와 질문 리듬을 유지하기 쉬워진다.

결과적으로 대화가 “새로 생성된 응답들”이 아니라, 같은 친구의 이어진 말들처럼 느껴지게 된다.


5. 그런데 실사용 중 더 치명적인 문제가 하나 나왔다

continuity를 붙이고 나서도, 직접 써보면 가끔 이상한 응답이 튀어나왔다.

예를 들어 사용자가 처음에 “너 누구야?”라고 물었을 때, 그림 속 친구가 자기 이름을 말해야 하는 대신,

  • “나는 카카오에서 온 AI 카나나야”
  • “나는 카나나야”

같은 식으로 대답하는 경우가 있었다.

이건 완전히 잘못된 응답이었다.

그림톡의 친구는 AI 비서가 아니라, 그림 속에서 막 깨어난 존재여야 한다. 사용자가 처음 묻는 “누구야?”에 대한 정답은 이런 쪽이어야 한다.

  • 나는 루루야
  • 나는 별여우야
  • 아직 이름이 없다면 네가 지어줄래?
  • 나는 네 그림에서 방금 깨어난 친구야

즉, 이건 단순한 문구 취향 문제가 아니라, 제품 정체성을 깨는 버그에 가까웠다.


6. route 레이어에서도 방어가 필요했다

원인을 보니 프롬프트만의 문제가 아니었다.

실제로는 서버 라우트에서 continuity 메타를 제대로 읽지 않고 있었고, 모델이 자기 정체를 이상하게 말해도 그대로 assistant text로 통과될 여지가 있었다.

그래서 route 레벨에서 두 가지를 고쳤다.

1) continuity 메타를 실제로 받기

이제 서버는 아래 정보를 실제로 읽는다.

  • turnMode
  • character
  • previousUserText
  • previousAssistantText

2) 금지 자기소개 방어

응답 안에 이런 표현이 들어오면 그대로 노출하지 않게 했다.

  • 카나나
  • 카카오에서 온 AI
  • 카카오의 도우미
  • AI 비서
  • 인공지능

이런 패턴이 감지되면, 캐릭터 프로필 기반 fallback 문장으로 치환하게 만들었다.

이건 조금 투박해 보일 수 있지만, 실제 제품 관점에서는 꽤 중요한 안전장치였다. 그림톡은 모델의 정체를 설명하는 앱이 아니라, 친구를 믿게 만드는 앱이기 때문이다.


7. UX도 같이 이어지게 보여야 했다

요청 구조만 바꾼다고 해서 사용자가 continuity를 바로 느끼는 건 아니다. 화면도 같이 바뀌어야 한다.

그래서 후속 턴 쪽 UX도 조금 손봤다.

record 화면

다시 말 걸기를 누르면 완전히 새 단계로 끊기는 느낌 대신, 직전 대화가 남아 있는 상태에서 이어서 말을 걸게 했다.

  • “이어서 한마디 더 해볼까?”
  • “방금 만난 같은 친구가 네 말을 기다리고 있어.”

이런 식으로 문구도 조정했다.

loading 화면

기존 로딩 카피는 첫 턴에는 맞았지만, 후속 턴에는 어색했다.

그래서 후속 턴일 때는

  • 친구가 방금 네 말을 듣고 있어
  • 같은 친구가 이어서 대답을 생각하고 있어
  • 금방 다시 말을 걸어줄 거야

처럼 더 대화적인 느낌으로 바꿨다.

result 화면

후속 턴 결과는 “처음 인사했어”가 아니라 “이어서 대답했어”라는 식으로 분기했다.

작은 차이지만, 이런 문장 하나가 전체 경험을 꽤 다르게 만든다.


8. 사용성 측면에서 앨범 업로드도 넣었다

또 하나 느낀 건, 사용자가 꼭 실시간으로 사진을 찍기만 하진 않는다는 점이었다.

오히려 이런 경우가 많다.

  • 이미 찍어둔 그림 사진이 있음
  • 전에 그린 그림으로도 해보고 싶음
  • 부모 폰 갤러리에 저장된 그림을 쓰고 싶음
  • 카메라를 바로 켜는 게 번거로움

그래서 카메라 메인 흐름은 유지하되, 보조 액션으로 **‘앨범에서 가져오기’**를 추가했다.

여기서 중요한 건 구조를 새로 만드는 게 아니라, 선택한 이미지도 기존 capturedImage 구조로 태워서 뒤 플로우를 그대로 재사용하는 것이었다.

즉,

  • 찍든
  • 고르든

결국은 같은 preview → record → loading → result 흐름으로 들어간다.

이 방식이 좋은 이유는 두 가지였다.

  1. 감정선은 그대로 유지된다
  2. 진입 마찰은 확실히 줄어든다

그리고 구현 후에는 object URL revoke까지 같이 넣어서 메모리 누수 가능성도 정리했다.


9. 이번에 얻은 가장 큰 감각

이번 작업을 하면서 가장 크게 배운 건, 그림톡은 “좋은 첫 응답”보다 좋은 이어짐이 더 중요하다는 점이었다.

첫 응답은 누구나 어느 정도 만들 수 있다. 하지만 두 번째, 세 번째 턴에서도 같은 친구가 살아 있는 것처럼 느끼게 만드는 건 전혀 다른 문제였다.

그리고 그건 단순히 모델 품질의 문제가 아니라,

  • 요청 구조
  • 캐릭터 상태 관리
  • 응답 방어
  • 로딩 카피
  • 입력 UX

이런 것들이 같이 맞물려야 가능한 일이었다.

결국 continuity는 프롬프트 한 줄이 아니라, 제품 전체가 같은 친구를 믿게 만드는 방식에 더 가까웠다.


마무리

3편에서는 그림톡을 “한 번 대답하는 앱”에서 “같은 그림 친구와 계속 대화하는 앱” 쪽으로 바꾸는 과정과, 그 과정에서 발견한 실사용 문제들을 정리해봤다.

특히 continuity를 구조적으로 분리한 것, 카나나 정체 누수를 막는 방어를 넣은 것, 그리고 앨범 업로드를 통해 진입 방식을 넓힌 것은 모두 같은 방향을 향하고 있었다.

그 방향은 꽤 분명하다.

그림톡은 결과를 만드는 앱이 아니라, 아이가 자기 그림 친구와 계속 놀게 만드는 앱이어야 한다.

다음 단계에서는 이 흐름 위에서, 더 긴 대화에서 캐릭터가 얼마나 안정적으로 유지되는지, 그리고 실제 아이 사용 상황에서 어떤 리듬이 자연스러운지를 더 다듬게 될 것 같다.

클릭할 때마다 작가에게 따뜻한 응원이 전달됩니다 ❤️

이 글이 유익하셨나요?
동료 개발자들과 경험과 노하우를 공유해 보세요.
이전 글그림톡
그림톡 만들기 2편: 결과 화면을 '정보 화면'에서 '첫 만남 장면'으로 바꾸기
개발다음 글
vercel.app 도메인의 한계와 개인 도메인(.pe.kr) 도입기 (feat. 구글 서치 콘솔 색인 문제 해결)

함께 읽으면 좋은 다른 개발일지

'그림톡' 및 추천 아카이브 글 모음

그림톡 만들기 2편: 결과 화면을 '정보 화면'에서 '첫 만남 장면'으로 바꾸기
그림톡
그림톡 만들기 2편: 결과 화면을 '정보 화면'에서 '첫 만남 장면'으로 바꾸기
그림톡 결과 화면을 정보 카드가 아니라 첫 만남 장면처럼 느껴지도록 다시 설계하고 사용자 경험을 개선한 과정을 정리한 개발 일지.
2026. 3. 27.

댓글

목차
시작하며1. 가장 큰 문제는 latency보다 continuity였다2. 1턴과 후속 턴은 사실 같은 요청이 아니었다첫 턴후속 턴3. 후속 턴에서는 그림을 다시 보내지 않기로 했다1) 같은 친구를 계속 유지하고 싶었기 때문2) 속도도 줄이고 싶었기 때문3) 이미 필요한 정보는 첫 턴에서 얻었기 때문4. 캐릭터 프로필을 고정 저장했다5. 그런데 실사용 중 더 치명적인 문제가 하나 나왔다6. route 레이어에서도 방어가 필요했다1) continuity 메타를 실제로 받기2) 금지 자기소개 방어7. UX도 같이 이어지게 보여야 했다record 화면loading 화면result 화면8. 사용성 측면에서 앨범 업로드도 넣었다9. 이번에 얻은 가장 큰 감각마무리
43회
그림톡 만들기 1편: 아이의 그림이 말을 걸기까지 (MVP 기획과 프로토타입)
그림톡
그림톡 만들기 1편: 아이의 그림이 말을 걸기까지 (MVP 기획과 프로토타입)
아이의 그림을 기반으로 소통하는 인터랙션 서비스 그림톡(GrimTalk)의 초기 기획과 프로토타입 구현 과정.
2026. 3. 26.44회
Next.js App Router에서 구글 서치 콘솔 '적절한 표준 태그가 포함된 대체 페이지' 해결기
개발
Next.js App Router에서 구글 서치 콘솔 '적절한 표준 태그가 포함된 대체 페이지' 해결기
Next.js App Router의 메타데이터 상속 구조로 인해 모든 블로그 포스트의 canonical URL이 홈으로 고정되어 검색 색인에서 누락되던 문제를 self-referencing canonical과 한글 슬러그 인코딩으로 해결한 실전 트러블슈팅 기록.
2026. 9. 7.0회