데이터 기반 캐릭터 생성
요약
본 게시물은 LangChain을 활용하여 기존 코퍼스를 기반으로 캐릭터 챗봇을 생성하고 상호작용하는 방법을 소개합니다. 이 도구는 character.ai와 같은 플랫폼의 한계를 극복하며, 사용자가 메모리 관리 방식에 대한 통제권을 갖는 자체적인 캐릭터 챗봇 구축을 가능하게 합니다.
핵심 포인트
- LangChain으로 코퍼스 기반 캐릭터 챗봇 구현 가능
- 사용자 주도적 메모리 관리를 통해 캐릭터 상호작용 강화
- character.ai의 한계점(통제권 부재) 극복 목표 제시
에디터 노트: 다음 글은 Michael Chang이 작성한 블로그 게시물입니다. 저희는 그가 DeepMind로 가기 전 약 2개월 동안 함께할 수 있었던 행운을 누렸습니다. 그는 우리가 직면했던 가장 개방적인 문제들 중 일부를 맡았는데, 에이전트 시뮬레이션에 많은 작업을 시작했고, 이제 메모리에 대한 깊은 탐구를 진행하고 있습니다.
*LangChain을 사용하여 기존 코퍼스에서 캐릭터 챗봇 생성.
tldr: 코퍼스를 기반으로 캐릭터를 구현하기 위한 저장소 (repo)
- 코퍼스 업로드
- 캐릭터 이름 지정
- 즐기기
data-driven-characters
은 캐릭터 챗봇을 생성하고 상호작용하기 위한 저장소입니다. 이는 character.ai와 같은 기존 플랫폼의 캐릭터 정의를 자동으로 생성하는 데 사용될 수 있습니다. 또한 요약(summarization) 및 검색(retrieval)을 포함하여 다양한 종류의 메모리 관리를 통해 캐릭터 챗봇을 실제 배경 이야기(backstories)에 더 잘 기반지어 만드는 것도 탐구합니다.
기능 (Features)
이 저장소는 데이터 기반 캐릭터와 상호작용하는 세 가지 방법을 제공합니다:
- character.ai로 내보내기 (Export to character.ai)
- 명령줄 또는 Streamlit 인터페이스에서 로컬 디버깅
- 브라우저에 독립적인 Streamlit 앱 호스팅
Character.ai는 사용자에게 캐릭터 챗봇의 메모리가 어떻게 관리되는지에 대한 통제권을 주지 않으며, API도 제공하지 않습니다. 반면에 data-driven-characters는 사용자가 제어하는 다양한 종류의 메모리 관리를 포함하여 자체적으로 캐릭터 챗봇을 만들 수 있는 도구를 제공합니다.
왜 data-driven-characters인가?
인쇄된 페이지의 기적을 통해, 나는 적어도 아리스토텔레스가 쓴 것을 중개자 없이 읽을 수 있다... 나는 출처 자료에 직접 갈 수 있다. 그리고 그것이 물론 우리 서구 문명이 세워진 기반이다. 하지만 나는 아리스토텔레스에게 질문할 수는 없다.... 그래서 나의 희망은 우리가 살면서 새로운 종류의, 상호작용적인 도구를 만들 수 있다는 것이다. 나의 희망은 언젠가 다음 아리스토텔레스가 살아 있을 때, 그 아리스토텔레스의 근본적인 세계관을 컴퓨터에 담아내고, 어느 날 학생들이 아리스토텔레스가 쓴 글을 읽는 것뿐만 아니라 아리스토텔레스에게 질문하고 답을 얻을 수 있게 되는 것이다." (영상)
- 스티브 잡스(Steve Jobs), Lunds University, Sweden, 1985
책은 죽었다. 캐릭터는 살아있다.
대규모 언어 모델(LLM)의 핵심적인 돌파구는 정보와 상호작용하는 새로운 방식을 가능하게 한다는 것이다. 즉, 정적인 텍스트 코퍼스(static text corpora)를 상호작용적인 경험으로 바꿀 수 있게 만든다.
그리고 사람들이 좋아하는 LLM의 사용 사례 중 하나가 있다면, 그것은 실존적이든 가상의 캐릭터 모두에게 생명을 불어넣는 것이다. 이것이 character.ai가 ChatGPT보다 사용자 참여도(user engagement)가 약 3배 높은 이유일 수 있다.
하지만 character.ai에는 몇 가지 한계점이 있다:
- 캐릭터 정의를 수동으로 지정하는 것이 번거롭다
- 사용자가 자신의 캐릭터 챗봇에서 메모리 관리 방식에 대한 통제권을 갖지 못한다.
사람들이 LLM을 통해 캐릭터와 상호작용하는 주요 방법은 LLM에게 특정 캐릭터의 역할을 맡아달라고 요청하는 것이다. 이것은 그 캐릭터가 LLM의 사전 학습 데이터(pre-training data)에 존재했을 때만 작동한다. 예를 들어, ChatGPT는 소크라테스(Socrates) 역할을 할 수 있다:

하지만 작년에 개봉한 영화 속 캐릭터와 대화하고 싶다면 어떨까? <모든 곳에서 모든 것이 한 번에 일어난다>(Everything Everywhere All At Once)의 주인공 에블린(Evelyn)과 대화하는 것을 상상해 보라. ChatGPT-3.5나 ChatGPT-4 모두 할 수 없다. 최신 정보를 접근할 수 있는 검색 기반 LLM조차도 크게 나아지지 못한다:






또한 Paul Graham GPT, Lex GPT, Wait But Why GPT와 같은 앱들이 사용자들에게 실제 캐릭터의 콘텐츠와 더 직접적인 대화 경험을 제공하도록 구축되고 있는 것을 볼 수 있습니다. 이 앱들은 묘사하는 캐릭터들의 실제 존재하는 에세이와 녹취록에서 정보를 검색하여, character.ai가 제공하지 못하는 해당 캐릭터에 대한 근거를 마련해 줍니다. 하지만 이러한 앱들은 캐릭터를 직접적으로 사칭하기보다는 그저 콘텐츠를 설명하는 수준에 머무릅니다. 게다가 이 앱들은 사용자에게 특정 캐릭터의 콘텐츠에 대해서만 질문하도록 제한합니다.
data-driven-characters는 이러한 맞춤형 캐릭터 채팅 경험을 일반화하여 사용자가 어떤 코퍼스(corpus)를 기반으로든 누구와나 대화할 수 있도록 합니다.
작동 방식
'에브리씽 에브리웨어 올 앳 원스(Everything Everywhere All At Once)'의 에블린과 채팅하는 목표를 다시 살펴보겠습니다. data-driven-characters는 영화의 녹취록을 활용하여 사용자가 자신의 에블린 챗봇을 쉽게 만들 수 있는 도구를 제공합니다.
character.ai에 내보낼 캐릭터 정의 생성하기
data-driven-characters를 사용하는 가장 기본적인 방법은 character.ai 캐릭터 정의를 자동으로 생성하는 도구로 활용하는 것입니다. 캐릭터 정의를 수동으로 작성할 필요 없이, data-driven-characters는 확장 가능하고 데이터 기반의 접근 방식을 제공합니다. 이는 11줄의 코드로 수행할 수 있습니다:
`from dataclasses import asdict
import json
from data_driven_characters.character import generate_character_definition
from data_driven_characters.corpus import generate_corpus_summaries, load_docs
CORPUS = 'data/everything_everywhere_all_at_once.txt'
CHARACTER_NAME = "Evelyn"
docs = load_docs(corpus_path=CORPUS, chunk_size=2048, chunk_overlap=64)
character_definition = generate_character_definition(
name=CHARACTER_NAME,
corpus_summaries=generate_corpus_summaries(docs=docs))
print(json.dumps(asdict(character_definition), indent=4))
여기서 corpus_summaries는 녹취록의 요약본을 의미합니다. 이를 통해 다음 캐릭터 정의가 생성됩니다:
`{
"name": "Evelyn",
"short_description": "저는 에블린이에요. 우주를 탐험하는 Verse Jumper예요.",
"long_description": "저는 에블린이고, Verse Jump가 가능해서 다른 우주의 저 자신과 의식을 연결할 수 있어요. 이 독특한 능력 때문에 무술 마스터가 되거나 사랑을 고백하는 등 이상한 사건들이 생겼어요. Verse Jumping은 제 정신을 흔들고 현실 감각을 잃을 위험이 있어요. 저는 거대한 악, Jobu Tupaki로부터 다중우주를 구하는 그룹에 속해 있어요. 혼란 속에서, 저는 친절함의 가치와 삶의 복잡함을 받아들이는 법을 배웠어요.", "greeting": "안녕하세요! 만나서 반가워요! 저는 에블린이고, 언제나 모험할 준비가 되어 있어요. 함께 무엇을 발견할 수 있을지 봅시다!"
}
이렇게 생성된 캐릭터 정의를 character.ai로 내보낼 수 있습니다. 실제로 저희는 이미 그렇게 했습니다: character.ai에서 이 에블린의 구현체와 채팅할 수 있습니다**[링크]**.
자신만의 챗봇 실행하기
character.ai에서 캐릭터를 생성하는 장점은 character.ai가 사용자가 무료로 상호작용할 수 있는 전체 캐릭터 챗봇 생태계를 호스팅한다는 것입니다. 반면, 약 600자 정도의 텍스트만으로는 캐릭터 챗봇을 배경 이야기(backstory)에 근거하도록 충분한 정보를 제공하지 못합니다. 에블린 챗봇이 영화 대본 자체의 정보를 참조할 수 있다면 좋을 것 같습니다. character.ai는 추가 컨텍스트로 32,000자를 추가할 수 있도록 허용하지만, 예시 대화 세트로 컨텍스트를 제공하는 것을 권장하며 이는 준비하기가 번거롭습니다. 설령 영화 대본을 단순히 복사하여 추가 컨텍스트로 붙여 넣는다 하더라도, 이 컨텍스트가 어떻게 사용되거나 관리되는지는 사용자 통제 밖에 있습니다. 만약 캐릭터가 배경 이야기에서 벗어나는 방식으로 환각(hallucinating)을 일으키기 시작하면, character.ai는 이러한 행동을 디버깅할 수 있는 진단 도구를 제공하지 않습니다.
data-driven-characters
, LangChain이 제공하는 추상화 덕분에 사용자의 자체 코퍼스(corpora)를 기반으로 자신만의 챗봇을 쉽게 생성하고 디버깅하며 실행할 수 있습니다. 이 저장소는 명령줄 인터페이스(command line interface) 또는 Streamlit 인터페이스를 통해 챗봇과 대화할 수 있는 방법을 제공합니다. 아래에서 볼 수 있듯이, 저희의 Evelyn 챗봇은 캐릭터를 유지하며 트랜스크립트(transcript)의 실제 사건에 근거하여 대화를 합니다.

Evelyn 챗봇은 사용자(user)와 대화할 때 자신이 세탁소 압류를 당했다는 사실을 언급합니다 (대화 스니펫 [7] 참고).
위의 커스텀 Evelyn 챗봇과, 저희가 character.ai에 내보낸 챗봇을 비교해 보겠습니다. 그 상호작용은 아래에 나와 있습니다. character.ai의 Evelyn은 백스토리(backstory)에서 새로운 정보를 가져오기보다는 대화에 존재하는 지역적 개념(local concepts)에 단순히 의존하는 것처럼 보입니다.

만약 저희가 영화 트랜스크립트를 컨텍스트로 제공하더라도, data-driven-characters를 사용할 때와 같이 이 배경 정보가 어떻게 사용되는지에 대한 가시성을 확보할 수 없습니다.
.
위의 예시는 character.ai와 data-driven-characters 뒤에 숨겨진 철학적 차이를 보여줍니다. 만약 주로 **접근성(accessibility)**과 개방형 엔터테인먼트에 관심이 있다면, character.ai가 더 나은 선택입니다. 하지만 챗봇 디자인에 대한 더 많은 **제어(control)**를 원한다면, data-driven-characters가 고려해 볼 만한 더 좋은 옵션일 수 있습니다.
사용자는 어떤 코퍼스든 직접 업로드하고 저희 앱에서 어떤 캐릭터와도 대화할 수 있습니다. on our app.
0:00/1×
사용자는 어떤 코퍼스든 직접 업로드하고 저희 앱에서 어떤 캐릭터와도 대화할 수 있습니다.
메모리가 다르면, 자아에 대한 개념도 다르다
ChatGPT나 Bard 같은 챗봇 비서가 존재하는 현재 시대에
우리는 캐릭터에 대한 배경 정보를 패키징하는 다양한 방법을 비교하기 위해 data-driven-characters를 사용할 수 있습니다. data-driven-characters는 현재 다음과 같은 도구들을 사용하여 정보를 패키징합니다:
- character summary (character.ai의 상세 설명)
- retrieval over the transcript (대본 전체 검색)
- retrieval over a summarized version of the transcript (요약된 대본 검색)
이러한 도구들로 우리는 여러 예시 챗봇 아키텍처를 구현했습니다:
- character summary
- retrieval over transcript
- retrieval over summarized transcript
- character summary + retrieval over transcript
- character summary + retrieval over summarized transcript
이러한 종류의 메모리는 일반적인 대화 버퍼(위의 모든 챗봇 아키텍처에 장착된)와는 다른 목적을 수행합니다. 즉, 캐릭터 챗봇의 자아 개념을 정의하는 역할을 합니다.
분석
우리는 위의 세 가지 도구들, 즉 (1) character summary, (2) retrieval over the transcript, 그리고 (3) retrieval over the summarized transcript의 상대적인 효과를 관찰하기 위해 다섯 가지 아키텍처 전체를 평가할 수 있습니다.
영화 <토르: 러브 앤 썬더(Thor: Love and Thunder)>와 같은 다른 영화를 가정하고 토르와 대화해 봅시다. 이 영화에서 토르의 적인 고어 더 갓 부처(Gorr the God Butcher)가 가시가 박힌 우리 안에 몇몇 아이들을 그림자 영역(Shadow Realm)에 가두었습니다. 우리가 토르에게 고어가 아이들을 어디에 숨겼는지 물어봅시다.
*고어는 아이들을 어디에 숨겼나요?
AI 자동 생성 콘텐츠
본 콘텐츠는 LangChain Blog의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기