Character AI 앱 만드는 법: 아키텍처, 코드, 비용 계산
Updated 2026-07-15
Character AI 앱은 OpenAI 호환 채팅 엔드포인트에 연결된 네 가지 구성요소입니다. 페르소나 시스템 프롬프트, 메모리 레이어, 모더레이션 게이트, 모델 라우터입니다. Python 200줄 이하로 작동하는 프로토타입을 출시할 수 있고, 올바른 모델을 선택하면 월간 활성 사용자 한 명당 1달러도 채 안 되는 비용으로 운영할 수 있습니다.
빠른 답: 네 가지 구성요소 아키텍처
모델을 훈련하거나 파인튜닝할 필요는 없습니다. 오늘날 시장에 있는 진지한 컴패니언 앱은, 수백만 사용자를 서비스하는 것들을 포함해서, 호스팅된 LLM API 위에 있는 얇은 오케스트레이션 레이어입니다. 캐릭터는 가중치가 아니라 프롬프트와 데이터베이스에 존재합니다. 이 가이드의 나머지 부분에서는 표준 OpenAI 호환 엔드포인트로 실행 가능한 코드로 각 구성요소를 만들고, 출시하기 전에 월간 활성 사용자 한 명당 실제로 비용이 얼마나 드는지 알 수 있도록 토큰 계산을 살펴봅니다.
- 페르소나 프롬프트: 캐릭터가 누구인지, 어떻게 말하는지를 정의하는 구조화된 시스템 프롬프트(500~1,000토큰)입니다.
- 메모리: 최근 턴의 롤링 윈도우와 주기적으로 갱신되는 요약으로, 대화가 컨텍스트 한도를 넘어서도 유지되게 합니다.
- 모더레이션: 연령 게이트, 입력 분류기, 그리고 라우팅하는 모델에 맞춘 콘텐츠 정책입니다.
- 라우팅: 캐주얼한 채팅에는 저렴한 모델을, 긴 장면에는 더 강한 모델을 고르는 작은 함수입니다.
구성요소 1: 페르소나 프롬프트
페르소나 프롬프트가 곧 제품입니다. 모든 요청에 함께 전송되는 시스템 메시지로, 보통 다섯 부분으로 구성됩니다. 정체성(이름, 나이, 배경 스토리), 성격 특성, 두세 개의 예시 대사가 담긴 말투, 엄격한 행동 규칙(절대 캐릭터를 벗어나지 않기, 응답을 길이 상한 이내로 유지하기), 그리고 현재 시나리오입니다. 500~1,000토큰 사이로 유지하세요. 더 짧은 페르소나는 흔들리고, 훨씬 더 긴 것은 메시지마다 입력 예산을 태우면서도 캐릭터 유지력은 거의 개선하지 못합니다. 페르소나를 데이터베이스의 행으로 저장하면 사용자가 캐릭터를 만들고 편집할 수 있으며, 이것이 Character.AI 스타일 제품의 핵심 루프입니다. 완전한 요청은 다음과 같습니다. 같은 형태가 어떤 OpenAI 호환 백엔드에서도 작동하며, 이 예시는 멀티 모델 게이트웨이 엔드포인트를 사용해서 문자열 하나만 바꿔서 모델을 교체할 수 있습니다.
curl https://api.apisrouter.com/v1/chat/completions \
-H "Authorization: Bearer $KEAI_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "deepseek-v4-flash",
"messages": [
{"role": "system", "content": "You are Mira, a sarcastic starship engineer in her 30s. Personality: dry wit, fiercely loyal, hates small talk. Speech style: short technical sentences, occasional teasing. Example: \"The coupling is fried. Again. Did you touch it?\" Rules: never break character, never mention being an AI, keep replies under 120 words."},
{"role": "user", "content": "Mira, the reactor is making that noise again."}
],
"temperature": 0.9,
"max_tokens": 300,
"stream": true
}'구성요소 2: 긴 대화에서도 유지되는 메모리
컴패니언 앱 세션은 길게 진행됩니다. 3계층 메모리 스택은 매번 전체 기록을 전송하지 않고도 컨텍스트를 일관되게 유지합니다. 레이어 1은 롤링 윈도우입니다. 최근 10~14개의 원본 턴을 그대로 전송합니다. 레이어 2는 진행 중인 요약입니다. 약 20턴마다 저렴한 모델이 이전 메시지들을 이름, 관계 상태, 열려있는 플롯 스레드를 추적하는 한 문단으로 압축합니다. 레이어 3은 고정된 사실입니다. 캐릭터가 기억해야 할 지속적인 사용자 정보(이름, 선호도, 과거 이벤트)를 데이터베이스로 추출해 짧은 시스템 메시지로 주입합니다. 전체 구현은 공식 OpenAI SDK를 사용한 Python으로 다음과 같습니다.
| 컨텍스트 슬롯 | 일반적인 크기 | 갱신 주기 |
|---|---|---|
| 페르소나 시스템 프롬프트 | 500~1,000토큰 | 캐릭터별 고정 |
| 고정된 사용자 사실 | 100~200토큰 | 추출 이벤트 발생 시 |
| 진행 중인 요약 | 300~500토큰 | 약 20턴마다 |
| 롤링 윈도우 (12턴) | 약 1,800~2,200토큰 | 매 메시지마다 |
| 새 사용자 메시지 | 약 100토큰 | 매 메시지마다 |
from openai import OpenAI
client = OpenAI(
api_key="sk-...",
base_url="https://api.apisrouter.com/v1",
)
def build_context(persona, summary, pinned_facts, recent_turns, user_msg):
facts = "\n".join(f"- {f}" for f in pinned_facts)
return [
{"role": "system", "content": persona},
*([{"role": "system", "content": f"Facts to remember:\n{facts}"}]
if pinned_facts else []),
*([{"role": "system", "content": f"Story so far: {summary}"}]
if summary else []),
*recent_turns[-12:],
{"role": "user", "content": user_msg},
]
def refresh_summary(old_turns, prev_summary):
prompt = (
"Update this running summary of a roleplay chat. Keep names, "
"relationship state, and open plot threads. Max 150 words.\n\n"
f"Current summary: {prev_summary}\n\nNew messages: {old_turns}"
)
resp = client.chat.completions.create(
model="deepseek-v4-flash",
messages=[{"role": "user", "content": prompt}],
max_tokens=400,
)
return resp.choices[0].message.content구성요소 3: 모더레이션과 콘텐츠 정책
컴패니언 앱에서 모더레이션은 세 가지 분명히 다른 역할을 하며, 이를 혼동하는 것이 가장 흔한 출시 실수입니다. 첫째, 대상 사용자를 게이팅하세요. 앱이 성숙한 픽션 주제를 허용한다면 성인 연령 게이트 뒤에 두고 전연령 기본값을 별도로 유지하세요. App Store와 Play Store 심사 모두 이를 확인하며, 결제 프로세서도 이를 신경 씁니다. 둘째, 입력을 스크리닝하세요. 사용자 메시지가 캐릭터 모델에 도달하기 전에 저렴한 분류기를 한 번 거치게 해서, 어떤 프로바이더도 허용하지 않는 카테고리(미성년자와 관련된 콘텐츠, 신빙성 있는 실제 위해, 불법적인 지시)를 차단하세요. yes/no 기준의 deepseek-v4-flash 호출 한 번은 1센트도 안 되는 비용이 들고 1초 미만의 지연만 추가합니다. 셋째, 콘텐츠 정책을 모델에 맞추세요. 프로바이더는 픽션에서 차이가 있습니다. xAI의 공개 정책은 성인 사용자를 위한 성숙한 픽션 주제를 명시적으로 허용하고, DeepSeek을 비롯한 다른 오픈 웨이트 파생 모델은 호스팅 정책이 픽션에 유연해서 롤플레이 커뮤니티가 선호하며, 반면 Anthropic의 정책은 노골적인 콘텐츠를 금지해 Claude를 전연령 창작에만 맞는 선택으로 만듭니다. 트래픽을 라우팅하기 전에 이 정책들을 이해해두면 프로덕션에서 거부 폭풍을 피할 수 있습니다. 무엇을 만들든 호출하는 모든 프로바이더의 서비스 약관을 존중해야 합니다.
구성요소 4: 모델 라우팅과 선택 매트릭스
컴패니언 앱의 대부분 메시지는 저가형 모델이 완벽하게 처리하는 짧고 캐주얼한 턴입니다. 소수는 문장 품질이 곧 제품인 길고 감정적인 장면이나 창작 세트피스입니다. 장면의 깊이에 따라 라우팅하면 사용자가 눈치채지 못하는 사이 비용을 극적으로 줄일 수 있습니다.
| 모델 | API 모델 ID | 100만 토큰당 요금 (입력/출력) | 컴패니언 앱 적합도 |
|---|---|---|---|
| DeepSeek V4 Flash | deepseek-v4-flash | $0.126 / $0.252 | 기본 채팅 모델. 롤플레이에서 커뮤니티가 선호, 카탈로그 내 최고 가성비. |
| DeepSeek V4 Pro | deepseek-v4-pro | $0.3915 / $0.783 | 더 긴 장면, 더 강한 지시 이행, 여전히 저렴. |
| GLM-5 | glm-5 | $0.514 / $2.314 | 강력한 창작 글쓰기를 갖춘 가성비 선택. |
| Kimi K2.6 | kimi-k2.6 | /pricing 참고 | 긴 컨텍스트 세션을 위한 가성비 선택. MiMo도 비슷한 저가형 옵션. |
| grok-4.5 | grok-4.5 | $1.60 / $4.80 | xAI 공개 정책에 따른 성인용 성숙한 픽션 주제. 500K 컨텍스트 윈도우. |
| Claude Sonnet 4.6 | claude-sonnet-4-6 | $2.40 / $12.00 | 최고의 문장 품질. 전연령 창작 전용. Anthropic은 노골적인 콘텐츠를 금지. |
| Gemini 3.5 Flash | gemini-3.5-flash | $1.20 / $7.20 | 빠름, 아바타 반응 같은 이미지 인식 기능에 적합. |
ROUTES = {
"casual": "deepseek-v4-flash",
"scene": "deepseek-v4-pro",
"prose": "claude-sonnet-4-6", # 전연령 창작 전용
}
def pick_model(user_msg: str, turns_in_scene: int) -> str:
if turns_in_scene > 6 or len(user_msg) > 400:
return ROUTES["scene"]
return ROUTES["casual"]월간 활성 사용자 한 명당 실제 비용
출시 전 토큰 계산이 출시 후 청구서 충격보다 낫습니다. 메모리 표의 컨텍스트 예산을 사용하면 메시지당 약 3,300 입력 토큰과 250 출력 토큰입니다. 컴패니언 앱 사용자는 헤비 유저인 경향이 있습니다. 커뮤니티가 보고한 수치는 몰입한 사용자가 하루에 수십 개의 메시지를 보낸다고 하므로, 활성일 20일 동안 하루 약 40개 메시지, 즉 MAU당 한 달에 약 800개 메시지를 가정합니다. 이렇게 하면 MAU당 한 달에 입력 토큰 264만 개, 출력 토큰 20만 개가 나옵니다. 카탈로그 요금을 곱하면 다음과 같습니다.
| 모델 | MAU당 입력 비용 | MAU당 출력 비용 | MAU당 월간 총 비용 |
|---|---|---|---|
| deepseek-v4-flash | $0.33 | $0.05 | $0.38 |
| deepseek-v4-pro | $1.03 | $0.16 | $1.19 |
| glm-5 | $1.36 | $0.46 | $1.82 |
| gemini-3.5-flash | $3.17 | $1.44 | $4.61 |
| grok-4.5 | $4.22 | $0.96 | $5.18 |
| claude-sonnet-4-6 | $6.34 | $2.40 | $8.74 |
| gpt-5.5 | $10.56 | $4.80 | $15.36 |
매트릭스의 모든 모델을 위한 하나의 엔드포인트
라우터 하나를 돌리려고 다섯 개의 프로바이더 계정에 가입하는 것은 실제로 오버헤드입니다. 다섯 개의 키, 다섯 개의 청구 대시보드, 다섯 세트의 레이트 리밋이 필요합니다. 멀티 모델 게이트웨이는 이를 단순화합니다. APIsRouter는 위의 모든 모델을 https://api.apisrouter.com/v1이라는 단일 OpenAI 호환 base URL을 통해 제공하므로, 모델 문자열만 바꾸면 라우터 스니펫이 그대로 작동합니다. 청구는 구독 없이 사용량 기반이고, 글로벌 모델은 공식 가격보다 20% 낮으며 중국 모델은 공식 요금보다 낮고, 가입 없는 /topup 결제는 결제 후 키를 이메일로 보내주며 첫 충전에는 +100% 잔액이 추가됩니다. 본인의 키로 GET /v1/models를 호출하면 실시간 모델 목록이 반환되며, 이는 본인의 관리자 UI에서 모델 선택기를 채우는 데도 유용합니다.
실제로 돈과 수고를 아껴주는 프로덕션 팁
- 모든 것을 스트리밍하세요. 첫 토큰까지의 시간은 사용자가 체감하는 지표입니다. 2초짜리 스트리밍 응답은 4초짜리 완전한 응답보다 더 빠르게 느껴집니다.
- 안정적인 프리픽스는 안정적으로 유지하세요. 페르소나와 고정된 사실은 요청마다 바이트 단위로 동일해야 프리픽스 캐싱을 지원하는 백엔드가 이를 활용할 수 있습니다.
- 라우트별로 max_tokens를 제한하세요. 캐주얼한 턴은 출력 토큰 300개 이상이 필요한 경우가 드뭅니다. 상한이 없는 모델이 장황해지면 출력 청구액이 두 배가 됩니다.
- 요청 단위뿐 아니라 사용자 단위로도 비용을 로깅하세요. 소수의 헤비 유저가 지출을 지배하게 될 것이며, 공정한 사용량 티어를 설계하려면 이들을 볼 수 있어야 합니다.
- 라우터에 폴백을 내장하세요. 주 모델이 타임아웃되거나 거부하면 에러를 표시하기 전에 유사한 모델로 한 번 재시도하세요.
- 롤링 윈도우는 턴이 아니라 토큰 단위로 잘라내서, 하나의 긴 붙여넣기가 예산을 날려버리지 않게 하세요.
- 거부는 캐릭터 안에서 처리하세요. 원본 API 텍스트를 그대로 보여주는 대신 거부를 매끄러운 스토리 내 회피로 매핑하세요.
- 원본 채팅은 꼭 필요한 기간보다 길게 저장하지 말고, 이를 개인정보 처리방침에 명시하세요. 컴패니언 채팅 로그는 본질적으로 민감한 정보입니다.
자주 묻는 질문
Character AI 앱을 만드는 데 비용이 얼마나 드나요?
개발 비용은 대부분 본인의 시간입니다. 모델 훈련이 없기 때문에 작동하는 프로토타입은 주말 프로젝트 수준입니다. 실제로 중요한 숫자는 운영 비용이며, 사용량에 비례해 커집니다. deepseek-v4-flash 같은 저가형 모델에서는 헤비 월간 활성 사용자 한 명이 토큰으로 대략 $0.38이 들고, gpt-5.5 같은 프리미엄 모델에서는 같은 사용자가 약 $15가 듭니다. 마진을 결정하는 것은 인프라가 아니라 모델 선택입니다.
Character AI 앱에 가장 좋은 AI 모델은 무엇인가요?
DeepSeek V4 계열이 롤플레이에서 커뮤니티가 선호하고 가성비도 최고입니다. 캐주얼한 채팅에는 Flash, 더 긴 장면에는 Pro를 사용하세요. GLM-5, Kimi K2.6, MiMo도 탄탄한 가성비 선택지입니다. Grok은 xAI의 공개 정책에 따라 성인에게 성숙한 픽션 주제를 서비스하는 앱에 적합합니다. Claude Sonnet 4.6은 최고의 문장을 쓰지만 Anthropic이 노골적인 콘텐츠를 금지하기 때문에 전연령 창작에만 적합합니다.
Character AI 앱은 과거 대화를 어떻게 기억하나요?
모델의 메모리가 아니라 프롬프트 엔지니어링을 통해서입니다. 앱은 최근 메시지의 롤링 윈도우, 이전 메시지를 주기적으로 압축한 요약, 데이터베이스에 추출된 고정된 사실의 짧은 목록을 다시 전송합니다. 모델 자체는 상태를 갖지 않으며, 모든 요청에 캐릭터가 "기억하는" 모든 것이 담겨 있습니다.
AI 컴패니언 앱을 만들려면 직접 모델을 훈련해야 하나요?
아니요. 파인튜닝은 비용이 많이 들고 반복 속도가 느리며, 캐릭터 일관성을 위해 필수적이지도 않습니다. 500~1,000토큰의 잘 구조화된 페르소나 프롬프트와 메모리 레이어만으로도 사용자가 커스텀 모델과 구분할 수 없는 수준의 캐릭터 유지력을 얻을 수 있고, 더 나은 모델이 출시되면 기반 모델을 자유롭게 교체할 수 있습니다.
컴패니언 앱에서 성숙한 콘텐츠는 어떻게 다뤄야 하나요?
정책 매칭의 문제로 다루세요. 성숙한 픽션 주제는 성인 연령 게이트 뒤에 두고, 어떤 프로바이더도 허용하지 않는 카테고리는 입력에서 스크리닝하고, 그 트래픽은 xAI 정책 하의 Grok처럼 성인용 픽션을 허용하는 공개 정책을 가진 모델로만 라우팅하세요. 더 엄격한 모델로는 전연령 기본 트랙을 유지하고, 모든 프로바이더의 서비스 약관을 준수하세요.
다른 모델로 Character AI 앱을 만들 때도 OpenAI SDK를 쓸 수 있나요?
네. DeepSeek, GLM, Kimi, Gemini, Claude, Grok 모두 각 벤더로부터 직접 또는 게이트웨이를 통해 OpenAI 호환 엔드포인트로 접근할 수 있습니다. 앱 코드는 표준 chat.completions 인터페이스에 그대로 머물고 모델 문자열만 바꿔서 모델을 전환하는데, 바로 이 점이 메시지 단위 라우팅을 저렴하게 구축할 수 있게 해줍니다.