Cadence

완성된 단일 장문 대신 메신저 대화 호흡에 맞춰 문장을 분할하고 조각 간 전송 타이밍을 제어하는 규칙 엔진입니다.

답변을 의미와 호흡 단위로 끊고, 조각 사이에 계산된 타자 지연을 삽입합니다. 원문 내용은 변경하지 않고 발송 직전 단계에서 독립적으로 분할을 처리합니다.
5개답변당 최대 조각 수
9자/초기준 타자 속도
12종분할용 연결어미
6초전체 지연 상한

왜 만들었나

메신저 환경에서 사용자가 메시지를 발송하는 일반적인 패턴입니다.

어제 간 카페에 사람이 없어서

공부하기 좋더라구요

또 갈까 싶어요

세 줄로 전송되었으나 첫 두 줄은 본래 연결어미 -어서로 이어진 하나의 문장입니다. 메신저에서는 문장 종결 이전이라도 절 단위나 호흡 단위에서 줄바꿈 및 전송이 일어납니다.

기존 봇 환경에서는 긴 답변이 완성된 한 덩어리로 동시에 전송되었습니다. 이 방식은 답변 생성까지 긴 침묵이 발생하고 대화의 상호작용 리듬을 해칩니다.

이전
  • 답변 전체가 한 메시지로 도착
  • 길수록 침묵이 길어지고 한 번에 쏟아짐
  • 입력 중 표시가 한 번만 켜짐
지금
  • 생각의 단위로 끊어 도착
  • 첫 조각은 기다림 없이 바로
  • 조각 사이마다 입력 중 표시가 다시 켜짐

어디서 끊는가

문장 부호마다 기계적으로 자르면 지나치게 파편화됩니다. 이를 방지하기 위해 경계 강도를 3단계로 분류합니다.

01 문단과 줄바꿈

가장 강한 경계입니다. 서리가 스스로 문단을 나눠 썼다면 이미 생각의 단위가 갈렸다는 뜻이라 무조건 존중합니다.

02 문장 끝

마침표, 느낌표, 물음표 뒤입니다. 기본적으로 열려 있지만 뒤에 공백이 없으면 소수점이나 말줄임으로 보고 넘어갑니다.

03 쉼표와 연결어미

가장 약한 경계라 평소에는 닫혀 있습니다. 조각 하나가 40자를 넘겨 한눈에 읽기 부담스러울 때만 열립니다.

짧은 답변은 분할하지 않고 원문 그대로 전송하며, 일정 길이(40자)를 초과하는 긴 답변에 한해 절 단위 경계를 열어 분할합니다.

실제로는 이렇게 나뉩니다

우산 어떻게 말려야 해?

서리

우산은 젖은 채로 접어두면 곰팡이 슬어버리니까

서리

현관에 그냥 펼쳐두지 마.

서리

물기 털고 반쯤 펴서 통풍되는 데 두고, 완전히 마르면 그때 접어.

서리

오래 쓸 생각이면 장우산이 답이야.

첫 조각은 연결어미 -니까에서, 나머지는 문장 끝에서 갈렸습니다.

어미 열두 종

연결어미 기반 분할 시 명사와 어미의 형태가 일치하는 단어에서 오탐이 발생할 수 있습니다.

예를 들어 -고를 분할 기준으로 삼으면 "밥 먹고 갈게"는 정상 분할되지만 "어제 사고 났어"의 "사고" 뒤에서 끊기는 문제가 발생합니다. -면 역시 "라면", "화면", "표면" 등의 명사와 충돌합니다.

별도의 형태소 분석 라이브러리를 추가하는 대신, 명사와 형태가 겹치지 않는 2음절 이상 어미 12종을 선별하여 경계로 사용합니다.

-니까 -는데 -은데 -어서 -아서 -여서 -지만 -거든 -잖아 -면서 -라서 -길래

2음절 이상으로 구성되어 명사와 충돌할 가능성이 낮습니다. 활용 빈도가 높은 -고와 -면은 오탐 방지를 위해 제외했습니다.

-고나 -면처럼 충돌 위험이 있는 어미는 단독 분할을 피하되, 뒤에 쉼표가 붙은 경우 쉼표 경계 규칙을 통해 안전하게 분할을 지원합니다.

언제 보내는가

분할된 조각 사이의 전송 간격을 상황에 맞게 계산하여 자연스러운 타이핑 흐름을 구현합니다.

조각 간 지연 시간은 기준 타자 속도(초당 9자)를 기반으로 산출되며, 관계 단계, 대화 여유, 감정 상태 세 가지 가중치를 곱해 보정합니다.

가까운 사이 (신뢰, 애정, 각별)×1.2 빠르게
낯선 사이 (남, 경계)×0.85 느리게
대화 여유 많음×1.15 빠르게
대화 여유 없음 (수업 중, 자는 중)×0.7 느리게
들뜬 기분×1.2 빠르게
졸리거나 지친 기분×0.8 느리게

세 가지 보정 계수는 곱연산으로 적용됩니다. 문장 길이가 같더라도 관계와 대화 상황에 따라 도착 간격이 달라집니다.

상대와의 친밀도가 높을수록 지연 시간이 단축되고, 서리의 일상 시뮬레이션에서 여유가 없는 상태(수업, 수면 등)일 때는 답장 간격이 길어집니다.

조각 간 지연 시간 동안에는 디스코드 입력 중(Typing) 상태를 다시 활성화하여 전송 대기 상태임을 명시합니다.

잘리면 안 되는 것

문장을 자르는 도구는 자르면 안 되는 것까지 자르기 쉽습니다.

URL 안에는 마침표가 있습니다. https://example.com/a.b.c를 문장 끝으로 오해하면 링크가 두 동강 나서 클릭할 수 없게 됩니다. 코드 블록 안에도 마침표와 줄바꿈이 잔뜩 들어 있습니다. 디스코드 커스텀 이모지와 멘션은 중간에서 끊기면 그냥 깨진 텍스트가 됩니다.

링크 코드 블록 인라인 코드 커스텀 이모지 멘션과 채널 링크

이런 구간은 먼저 찾아 원자 단위로 표시해두고, 그 안쪽은 아예 후보에서 제외합니다. 코드 블록은 닫히지 않은 경우에도 끝까지 보호합니다.

원문 보존 원칙

분할 과정에서 텍스트를 직접 슬라이싱해 이어붙이지 않고, 분할 인덱스 목록만 계산한 뒤 최종 단계에서 일괄 분할합니다. 분할된 조각들을 결합했을 때 항상 원문과 동일함을 단위 테스트로 검증합니다.

모델에게 맡기지 않은 이유

가장 단순한 접근은 모델에게 '끊고 싶은 위치에 마커를 남기라'고 지시하는 방식입니다.

하지만 이 방식은 다음과 같은 문제로 인해 채택하지 않았습니다.

01

형식 지시는 페르소나를 훼손합니다

프롬프트에 출력 형식 제약이 추가되면 캐릭터 고유 어투와 페르소나 지침이 훼손됩니다. 글자 수나 포맷을 강제하는 프롬프트가 대화 품질을 떨어뜨렸던 문제를 방지합니다.

02

출력 오류 가능성 차단

모델이 구분자를 누락하거나 특수 기호를 원문에 그대로 노출하는 등의 출력 오류를 원천 차단합니다.

03

독립적인 기능 제어

답변 텍스트 생성과 전송 타이밍 제어가 분리되어 있어, 기능 비활성화 시에도 원문 답변 생성 로직에 아무런 영향을 주지 않습니다.

답답해지지 않도록

지연 시간 누적으로 인한 피로감을 막기 위해 상한선과 예외 규칙을 둡니다.

조각 상한

한 답변은 최대 다섯 조각까지만 나뉩니다.

시간 예산

전체 지연의 합이 예산을 넘으면 각 간격을 비례해서 줄입니다. 조각이 많아질수록 하나하나가 빨라져 총 시간은 일정하게 유지됩니다.

첫 조각 즉시 전송

초기 응답 지연을 방지하기 위해 첫 번째 조각은 타자 지연 없이 즉시 발송합니다.

동시 발화 시 즉시 전송

조각 전송 도중 채널 내 새 메시지가 수신되면 지연을 중단하고 잔여 조각을 즉시 전송합니다.

아직 못 한 것

현재 Cadence 엔진은 완성된 문장을 후처리로 분할합니다. 사람이 메신저에서 사용하는 미완성 절 단위의 실시간 발화 구조는 지원하지 않습니다.

타자 속도 및 관계별 가중치 수치는 실제 대화 로그와 피드백을 기반으로 지속 보정하고 있습니다.

대화 리듬이나 분할 위치에 관한 피드백은 Lab 공식 디스코드로 제보해 주시기 바랍니다. 기술적 배경은 엔지니어링 블로그에서 확인할 수 있습니다.