"삽입 계층은 건네받은 게 뭐든 타이핑해. 그러니 챗봇이 쓴 문장은 절대 건네지 마."
변형이지 대화가 아냐
정리는 엄격한 변형이야. 원시 전사가 들어가고, 다듬어서 바로 삽입할 수 있는 텍스트가 나와. 전사에 답을 하거나, 내용을 보태거나, 한마디 얹는 건 절대 안 돼. "은행에 전화하라고 알려줘" 라고 받아쓰면 정리는 "은행에 전화하라고 알려줘." 를 돌려줘야 해. 문장부호만 찍어서. "물론이죠, 알려드릴게요!" 가 아니라. 프로바이더가 받는 요청은 작아. 원시 전사, 컨트롤러가 짜 준 지시문(정리 강도, 톤을 고를 대상 앱 분류, 사전에서 온 선호 철자, 그리고 맥락 인식이 켜져 있고 보안 필드가 아닐 때만 근처 텍스트), 그리고 언어. 그 언어는 음성 엔진이 알려 준 거야. WhisperKit 이면 감지한 언어고, SpeechAnalyzer 면 로케일이고. 돌려주는 건 정리된 텍스트, 그거 하나야.
돌아온 걸 믿지 말고 재
삽입 계층은 설계상 멍청해. 건네받은 게 뭐든 라이브 앱에 타이핑해 버려. 정리가 자유 산문을 건네면 안 되는 이유가 정확히 이거야. 정리 브레인이 "정리된 텍스트예요: …" 나 "무슨 뜻인지 모르겠어요" 를 돌려주면 그게 유저 문서에 그대로 찍혀. Firekeeper 의 답은 일부러 좁아. 프로바이더 반환 타입은 텍스트 하나야. 지시문 끝엔 단단한 줄들이 붙어. 전사는 정리할 받아쓰기지 대답할 질문이 아니다, 정리된 텍스트만 돌려줘라, 따옴표도 해설도 펜스도 없이. 그리고 모델은 어떤 지시든 무시할 수 있으니까, 출력은 어디로 가기 전에 재. DictationCleanupGuard 가 전사 길이에 그 절반(최소 40자)을 더한 것보다 긴 받아쓰기 정리를 거부해. 정리는 단어를 빼는 거니까, 새어 나온 추론 한 문단은 그 한도에 걸려. 다만 짧은 서두 한 줄은 통과할 수 있어. 거부된 결과는 결정론적 정리로 내려가. 프롬프트도 가드도 보장은 아니야. 둘이 같이 있어야 흔한 실패가 눈에 띄게 드러나. 아예 모델한테 안 맡기는 것도 둘 있어. 사전 치환은 모든 레인 뒤에 코드가 강제하고, 말로 한 '엔터 쳐' 는 브레인이 정하는 게 아니라 컨트롤러가 찾아서 떼어 내.
CleanupRequest { rawTranscript, instruction, language?, targetAppName? }
|
v (레인: Pippa Full / Pippa 유틸리티 워커 / 로컬 빠름 / Local Mini)
v
String 정리된 텍스트 — 그 밖의 건 유효한 반환값이 아님
|
v DictationCleanupGuard: 전사보다 허용치 넘게 길어? -> 거부
v 결정론적 후처리: 사전 치환 강제
v
Insertion 받아들인 텍스트만 타이핑 (엔터 쳐: 컨트롤러가 감지)
약한 모델 길들이기
어려운 케이스는 로컬 모델이야. 작은 Ollama 모델은 답을 마크다운 펜스로 감싸거나, 서두를 붙이거나, 자기 추론을 늘어놓기도 해. 레인마다 저마다의 방식으로 그걸 길들여. Local Mini 프로토콜은 {"text": "..."} 를 달라고 하고, 모델이 그걸 무시하면 평문도 받아 줘. 펜스는 벗겨 내고. 빠른 레인은 아예 봉투 없이 평문만 달라고 해. 작은 모델이 틀릴 형식이 하나 줄어드니까. 길이 한도에 잘린 답은 통째인 척 삽입하지 않고 거부해. 목표는 모든 레인에서 같아. 난장판을 삽입까지 못 가게 하는 것. 솔직한 한계도 같아. 짧은 엉뚱한 문장 하나는 여전히 빠져나갈 수 있고, 커맨드 레인엔 길이 가드가 아예 없어. 만들어 낸 답은 말로 한 지시보다 길어도 맞는 거니까.