
Discord Bot을 생성하는 자작 AI 에이전트를 컴파일러 파이프라인으로 만들었다
요약
Discord 대화만으로 봇 생성부터 배포까지 완료하는 AI 시스템 'C2B' 개발 사례를 소개합니다. 단순 채팅 에이전트가 아닌 결정론적 파일 생성을 지향하는 컴파일러 파이프라인 구조를 채택하여 안정성을 높였습니다.
핵심 포인트
- Discord를 인터페이스로 활용해 환경 구축 및 배포 과정 생략
- LLM의 불안정성을 극복하기 위해 컴파일러 파이프라인 설계 도입
- 결정론적(Deterministic) 베이스 파일 생성 방식 사용
- UX 컨트랙트 애널라이저를 통한 코드 품질 검증
- 「누구나 Discord에서 말을 거는 것만으로 Bot 생성부터 배포까지 완결된다」를 목적으로 한 AI 시스템 「C2B」를 만들고 있다.
- C2B는 채팅 에이전트가 아니라 **컴파일러 파이프라인 (Compiler Pipeline)**으로서 설계했다. LLM을 사용하는 것은 Cog 생성과 복구뿐이며, 베이스 파일은 결정론적(Deterministic)으로 생성한다.
- 「작동은 하지만 망가져 있는」 상태를 검출하는 UX 컨트랙트 애널라이저 (UX Contract Analyzer)를 만들었다.
동기
프로그래밍을 시작한 것은 2025년 7월로, 처음 5개월 동안은 PC가 없어서 스마트폰으로 AI와 대화하며 Discord Bot을 만들고 있었습니다. discord.py 에러가 발생해도 스마트폰으로는 터미널(Terminal)을 복사하기가 매우 어렵기 때문에 AI에게 「에러가 났다」고 전달할 뿐이었고, 배포는 render 등을 설정한 뒤 GitHub에 코드를 붙여넣는 방식이었습니다. (PC 없이·사전 조사 없이 하던 시절의 방식: Discord Bot을 PC 없이·서버 없이·돈 없이 만드는 방법)
그러다 보니 동세대 친구들로부터 「Bot을 만들고 싶은데 어떻게 해야 해?」라는 상담이 몇 번 들어오게 되었고, 스마트폰으로 만드는 방법을 알려주었지만 환경 구축과 배포, 코드 수정 및 배치 단계에서 막히는 사람이 많았습니다.
「Discord에서 말을 거는 것만으로 Bot이 생성·배포된다면, 환경 구축도 배포도 전부 스킵할 수 있어서 편하지 않을까???」, 그리고 동시에 「누구나 저렴한 비용으로 질 좋은 Bot을 만들 수 있게 하고 싶다」는 생각을 PC를 갖게 된 후부터 하기 시작했습니다.
이것이 C2B 발상의 원점입니다.
Discord를 입구로 삼은 이유는 「스마트폰에서 앱을 설치하거나 Web을 여는 것이 번거롭고 사용하기 불편하다」고 느꼈기 때문이며, 「실제로 대상 사용자가 그곳에 있기」 때문입니다. 실제로 앱 설치가 제한되어 있거나 Web 필터링에 걸리는 사람들도 있습니다.
C2B를 만들어 보았다
한마디로 말하면 「Discord상의 Bot에게 말을 거는 것만으로, Discord Bot이 AI에 의해 자동으로 생성·배포되는 시스템」입니다. 사용자가 하는 일은 /create로 스레드를 열어 대화하는 것뿐이며, PC·터미널·서버 지식은 필요하지 않습니다. Discord를 사용할 수 있는 환경이라면 완결됩니다.
/create → Discord에서 대화하며 사양을 확정 → Bot의 ZIP 파일이 도착 → 기동·배포
/upgrade → 기존 Bot을 Discord에서 대화하며 기능 추가·버그 수정

create 커맨드

upgrade 커맨드
실제로 만들었더니 문제가 발생했다
「AI에게 코드를 쓰게 하면 되겠지!!!」라고 당시 아무것도 몰랐던 저는 생각했지만, 실제로 해보니 결과가 처참했습니다.
다음은 실제 흐름을 정리한 것입니다.
- 사용자의 프롬프트 (Prompt)를 받음
- LLM이 대략적인 계획을 세움
- 파일을 생성하거나 코드를 출력함
- 사용자에게 반환함
여기서 발생한 문제는 결과물이 안정적이지 않다는 것이었습니다.
- 커맨드 이름이 계획 단계와 구현 단계에서 어긋남 (예를 들어,
/memo_add와/add_memo가 혼재함) - 요청하지 않은 커맨드가 생겨버림
- 두 커맨드가 서로를 모르는 상태에서 별개의 JSON 경로를 결정함 → 한쪽이 쓴 것을 다른 쪽이 읽지 못함
- 「Python으로서 작동은 하지만(Bot은 구동되지만), Discord 사용자에게는 아무것도 보이지 않는」 코드가 정적 체크 (Static Check)를 통과함
실제 로그는 이렇습니다. 3개의 커맨드를 가진 이벤트 Bot을 생성했을 때의 실패 기록입니다.
command function must be a coroutine function
View EventConfirmView is missing on_timeout
View EventListView is missing on_timeout
...
async def를 쓰는 것을 잊음, on_timeout의 결여가 2곳, 요청하지 않은 커맨드가 3개, 이 모든 것이 동시에 일어나 디버깅을 4번 해도 고쳐지지 않았습니다. 「AI에게 코드를 쓰게 하면 되겠지!!!」의 실체는 이것이었습니다.
그래서 C2B는 이렇게 했다
여기서 「Discord Bot만 만든다」라는 전제가 효과를 발휘합니다. 임의의 소프트웨어를 생성하는 에이전트(예를 들어 v0나 Manus 등)와 달리, Bot의 파일 구성(Cog·커맨드·setup 함수·main.py)은 처음부터 정해져 있습니다. 정해져 있다면, 그 부분만큼은 결정론적으로 만들 수 있습니다.
따라서, /create 단계만큼은 채팅 에이전트가 아니라 컴파일러(Compiler)에 가까운 설계를 하고 있습니다.
대화 → 스펙 (사용자의 요구사항을 구조화한 데이터)
스펙 → 매니페스트 (Manifest, 커맨드 이름·데이터 경로·제약 사항을 확정한 사양서)
매니페스트 → 베이스 파일 (Base file, 결정론적으로 생성, LLM 미사용)
...
인계는 "모델이 완성되었다고 판단했다"가 아니라 "구체적인 체크를 모두 통과했다"를 기준으로 이루어집니다. 자유로운 에이전트가 "리포지토리를 돌아다니며 마음대로 다시 쓰는" 것과는 정반대되는 방식이죠.
또한, 대화 단계에서는 LLM에게 다음 질문뿐만 아니라 understanding_score (이해도 점수, 0~100)도 JSON으로 반환하게 하고 있습니다. 점수가 90을 넘는 시점에 사양 확인 Embed를 사용자에게 보냅니다. LLM이 "ready"라고 자기 선언을 하더라도 점수가 90 미만이면 되돌리며, 최대 8턴의 안전 상한선(Safety limit)을 두었습니다.
이해도 점수의 메커니즘
- 0~69: 아직 요구사항이 부족함, 히어링(Hearing) 지속
- 70~89: 대략 파악했으나 불안 요소가 있음, 확인 질문 추가
- 90~100: 사양 확인 단계로 진행 가능
Discord Bot의 파일 구성에 대하여 (discord.py 미경험자용)
discord.py로 Bot을 만들 때, 커맨드는 기본적으로 **Cog (코그)**라는 단위로 나누어 관리합니다. Cog는 "커맨드를 모아둔 클래스"이며, 1파일 1Cog가 기본입니다.
# cogs/memo.py 예시
class MemoCog(commands.Cog):
@app_commands.command(name="memo_add")
...
전체 파일 구성은 거의 다음과 같이 정해져 있습니다.
bot/
├── main.py # Bot 기동 및 모든 Cog 로드
├── config.py # 토큰 등의 설정값
...
main.py, config.py, requirements.txt, setup.sh는 어떤 Bot이든 거의 동일한 내용입니다. LLM이 관여해야 하는 부분은 cogs/ 내부뿐이며, 이 전제가 있기 때문에 베이스 파일을 결정론적으로 생성할 수 있습니다.
CreateContextCache로 Cog 간 일관성 유지하기
앞서 언급한 "JSON 경로 불일치" 문제의 상세 내용입니다. 여러 커맨드가 있는 Bot의 경우, Cog는 커맨드마다 별도로 생성되기 때문에 서로 "다른 Cog가 어떤 파일에 무엇을 쓰고 있는지" 알지 못합니다.
# /memo_add와 /memo_list를 모두 가진 Bot을 생성했을 경우
/memo_add → data/memo_add.json 에 저장 (본인이 결정)
/memo_list → data/memo_list.json 에서 읽음 (본인이 결정)
...
C2B에서는 첫 번째 Cog를 생성한 시점에 "어떤 파일에 어떤 키로 무엇을 썼는지"를 CreateContextCache에 기록하고, 다음 Cog 생성 시에 주입합니다. "다음 Cog가 호환성을 유지하기 위해 필요한 최소한의 정보"만 전달함으로써 토큰 비용(Token cost)을 낮추고 있습니다.
왜 Cog 코드를 전부 컨텍스트(Context)에 넣지 않나요?
"모든 Cog를 프롬프트에 넣으면 해결되잖아"라고 생각할 수도 있지만, 두 가지 문제가 있습니다.
1. 커맨드가 늘어날수록 비용이 폭증함
10개의 커맨드를 가진 Bot을 만드는 경우, 10번째 Cog를 생성할 때 이전 9개의 코드를 전부 프롬프트에 실어야 합니다. 각 Cog가 100200행 정도라면 매번 9001800행 분량의 코드가 포함됩니다. 커맨드가 늘어날수록 비용이 불어나기 때문에 "저렴하게 만들 수 있다"는 장점이 사라집니다.
2. 대부분 불필요한 정보이기 때문
호환성을 위해 필요한 것은 "어떤 파일에·어떤 키로·어떤 타입의 데이터를 썼는가"뿐입니다. 에러 핸들링(Error handling) 구현이나 입력 유효성 검사(Validation)의 상세 내용은 다음 Cog와 관계가 없으므로, "작동하는 Bot을 만드는" 관점에서는 일단 전달할 필요가 없습니다.
파이널 게이트(Final Gate)는 구체적인 조건으로 차단한다
처음에는 모델에게 "완성되었다고 생각하는가?"라고 물었지만, 완성되지 않았음에도 아무 생각 없이 "예"라고 대답하기 때문에 버렸습니다. 구체적인 조건을 모두 나열하고, 이를 모두 통과했을 때만 배포하는 형식을 취하고 있습니다.
-
Sandbox 실패
-
요청한 커맨드가 존재하지 않음
-
요청하지 않은 커맨드가 존재함
-
중복 커맨드 정의
-
async def setup(bot) -
없음 - 여러 커맨드가 서로 다른 JSON 경로를 가지고 있음
-
사용자용 텍스트에 존재하지 않는 커맨드에 대한 언급이 있음
-
UX 컨트랙트 (UX Contract) 에러
UX 컨트랙트 분석기 (UX Contract Analyzer)
"작동은 하지만 망가져 있는" 상태를 검출하는 모듈입니다.
제가 진행하고 있는 C2B 테스트 플로우는 대략 다음과 같습니다.
AI가 VS Code상의 web tool로 Discord를 조작한다
→ 테스트 및 VPS로의 배포까지 전부 AI에게 맡긴다
→ IDE 상에서 Discord를 열어 Bot을 조작하게 한다 (여기서 Bot이 제대로 작동하지 않으면 원인을 특정하게 한다)
...
애초에 저는 코드를 읽을 줄 모르기 때문에, 생성된 코드를 정밀 조사해 봤자 의미가 없다는 생각이 들었습니다... 안타깝게도 실제로 실행해 보고 망가진 부분을 찾아내는 방법 외에는 대안이 없습니다.
하지만 이렇게 문제를 계속 해결해도 어떻게든 누락되는 문제가 있는데, 그것이 바로 discord.py 고유의 런타임 (Runtime) 동작입니다. "Python으로서 작동하고, 테스트에서도 기동을 확인할 수 있다. 하지만 Discord 상에서는 세세한 부분에서 무언가 망가져 있다"라는 케이스는, 사용자가 실제로 Bot을 상세히 사용하기 전까지는 알아차릴 수 없습니다. 그래서 사용자가 코드를 실행하기 전에 정적으로 검출할 수 있는 메커니즘이 필요했고, 그것이 바로 UX 컨트랙트 분석기 (UX Contract Analyzer)의 정체입니다.
일반적인 Python 검증기 (Validator)는 discord.py의 런타임 동작을 알지 못하기 때문에, 다음과 같은 경우를 통과시켜 버립니다:
- 커맨드를 실행했을 때 사용자에게 아무것도 보이지 않음 (
interaction.response= 사용자에게 응답을 보내는 함수. 이를 호출하지 않으면 Bot이 무언의 상태가 됨) View.on_timeout(버튼 등의 UI가 타임아웃되었을 때의 처리)이 없어서 에러가 발생함interaction.response.defer()("처리 중입니다"라는 가응답을 먼저 보내는 함수)를 두 번 호출함- 버튼의 라벨이 "확인", "전송"뿐이고 상태나 다음 액션이 적혀 있지 않음
- Discord가 지원하지 않는 모달 (Modal) 컴포넌트를 사용함
이러한 사항들을 AST 분석과 정적 체크를 통해 검출하여, 오토픽스 (Autofix) 또는 BuildAgent 루프로 피드백을 보냅니다.
/upgrade는 설계를 분리했다
/create : 요구사항 → 사양 확정 → 설계 → 모든 파일 신규 생성 → sandbox → ZIP
/upgrade : 기존 코드 → 조사 → 차분 편집 (Diff Edit) → sandbox → 저장
/upgrade는 /create와 아키텍처 및 커맨드를 분리하고 있습니다. 중심은 AutonomousAgent라고 부르는 ReAct 루프로, 매 스텝 "다음에 무엇을 할지"를 스스로 결정합니다.
/upgrade
↓
저장된 프로젝트 목록에서 대상 Bot을 선택
...
/create는 "아무것도 없는 상태에서 사양을 확정하고 전부 구축"하는 것이므로 결정론적인 (Deterministic) 파이프라인이 적합합니다. 반면 /upgrade는 "이미 작동 중인 코드의 어딘가를 변경"하는 것이므로, 매번 어떤 파일을 읽어야 할지가 다릅니다. 동일한 설계에 억지로 끼워 맞추려 하면 어느 한쪽에는 무리가 가기 때문에 별도의 커맨드로 만들었습니다.
장기 운용을 위해 필요했던 것
discord.py는 v2.x 버전만으로도 사양 변경이 22번 있었으며, RAG의 지식 베이스("이렇게 작성하면 된다"라는 규칙 모음)가 사양 변경이 일어날 때마다 거짓 정보가 됩니다. 거짓 규칙은 규칙이 없는 것보다 더 나쁜 영향을 미치며, 오래된 규칙을 계속 사용했을 경우 정답률이 실험에서 **1%**까지 떨어지는 것을 확인했습니다. (오래된 규칙을 계속 믿고 잘못된 코드를 출력하기 때문입니다.)
하지만 저는 제약 사항으로 인해 주당 11시간밖에 PC를 사용할 수 없으므로, 규칙 유지보수에 시간을 쓰면 개발이 중단됩니다.
"인간이 고칠 수 없다면, 시스템 스스로가 고치면 된다"
이것이 Darwin RAG의 발상입니다. Sandbox 실패로부터 LLM이 새로운 규칙을 생성(변이)하고, Thompson Sampling을 통해 성적이 좋은 규칙을 우선시하며, 규칙이 너무 많아지면 성적이 나쁜 것을 자동으로 삭제(도태)합니다. 1,900회 이상의 실험을 통해 진화가 없는 경우와 비교하여 +11~18포인트의 정답률 향상을 확인했습니다.
현황
코드베이스는 8만 행 이상입니다. 지인 몇 명이 실제로 Bot을 생성할 수 있는 상태가 되었습니다. 일반 공개는 VPS 비용 문제, 품질 문제, UI의 미흡함 등이 아직 해결되지 않았기에 조금 더 나중에 진행할 예정입니다.
코드는 Mixin 패턴을 사용하여 관심사(Concern)별로 파일을 나누어 관리하고 있습니다. "나중에 파일 하나가 수천 줄이 되어 개발이 돌아가지 않을 수도 있습니다"라는 말을 AI에게 들었기에, 일찍이 "그럼 그렇게 바꿔줘"라고 한마디만 하고 도입했습니다.
갈라파고스화된 개발 방식
코드를 읽을 수 없고, 시간도 없고, 돈도 없기 때문에 개발 방식이 조금 바뀌었습니다.
① 의사(?) 직관 주도 개발
제멋대로 이름을 붙여보았습니다만, "왠지 흐름이 죽어 있는 것 같다", "직감인데 이거 좀 이상하지 않아?"와 같이 언어화할 수 없는 감각을 그대로 AI에게 던지면, AI가 가설을 제시해 줍니다.
빗나가더라도 하나만 맞으면 OK입니다. 코드를 읽지 못해도 직관은 작동하므로, 그것을 입력값으로 삼아 분석은 AI에게 맡기는 수법입니다.
직관이 작동하지 않을 때라도, "직감인데 이상한 것 같아 (으스대며)"라고 입력해도 전혀 문제없다고 생각합니다.
프롬프트의 거칠음이 이 수법의 묘미이기에
② 일단 자동화

시간이 없기 때문에, 무엇이든 전부 자동화, 즉 AI에게 맡길 수 있다는 전제로 만들고 있습니다.
스스로 전부 읽고, 전부 이해하고, 전부 수동으로 수정하는 것은 보통 불가능하며, 아니, 할 수 없습니다.
그래서 IDE에서 열 수 있는 것은 대부분 AI에게 맡기고 있습니다.
상당히 거칠긴 하지만, 결국 자신의 제약 조건 안에서는 이것이 가장 진척이 빠릅니다.
③ AI에게 AI용 레일을 쓰게 하기
코드뿐만 아니라 개발 규칙이나 방침 메모도 거의 대부분 AI에게 쓰게 하고 있습니다.
예를 들어, AI에게 작업을 시키고 있을 때 "여기는 작업하기 편한가?"라고 묻는다
↓
개선안을 제시받는다
↓
AI가 알아서 바꾸게 한다
이를 통해 탄생한 것이 앞서 언급한 Mixin 패턴입니다.
그 외에도 MD(Markdown) 파일에도,
AI 사용: 횡단적 방침 판단에 사용해도 좋다. Agent 간의 전달 정의는 본 MD를 우선한다
와 같이, AI가 읽는 것을 전제로 한 지시를 쓰게 하고 있습니다. 이제는 인간을 위한 설계서라기보다, 다음에 올 AI에게 남기는 인수인계 같은 느낌입니다.
요컨대, AI에게 코드를 쓰게 할 뿐만 아니라, AI가 작업하기 쉬운 환경 그 자체를 AI가 정돈하게 만드는 느낌입니다.
AI에게 레일을 깔게 하고, 그 레일 위를 다시 AI가 달리게 하는 방법입니다.
꽤나 완성된 개발 풍경이네요.
요약
동기는 단순했습니다. "환경 구축에서 막히는 사람이 Discord에서 말을 거는 것만으로 Bot을 만들 수 있게 하고 싶다"는 것이었습니다. 실제로 LLM에게 통째로 맡겼더니 품질이 형편없어서, 컴파일러(Compiler)적인 설계로 만들었고, 그런데도 여러 Cog 간에 데이터가 어긋나고, UX가 정적 체크(Static Check)를 빠져나가고, discord.py는 사양 변경을 계속하고…… 생각보다 이것저것 만들게 되었습니다.
아직 미흡하지만, VPS나 품질 등 여러 문제가 해결되면 일반 공개할 예정입니다.
만약 이 글이 재미있다고 느껴지신다면, 응원해 주시면 기쁘겠습니다!
Discussion

AI 자동 생성 콘텐츠
본 콘텐츠는 Zenn AI의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기