춘식이는 Minecraft 채팅 명령을 받아서 GPT-4o로 판단하고, Mineflayer 봇이 실제 게임 안에서 움직이고 행동하는 마인크래프트 AI 에이전트입니다.
현재 버전은 기존 v1/ 기록을 사용하지 않는 새 구조입니다. 루트의 src/ 코드가 현재 실행되는 춘식이입니다.
플레이어가 채팅으로 자연어 명령을 내리면 춘식이가 그 목표를 계속 기억하면서 행동합니다.
예시:
춘식아 나무 캐줘
춘식아 돌 캐줘
춘식아 다이아몬드 캐줘
춘식아 네더 가줘
춘식아 엔더드래곤 잡아줘
choonsik follow me
춘식이는 단순히 한 번 GPT에게 물어보고 끝나는 구조가 아닙니다. 목표가 끝날 때까지 계속 현재 상태를 관찰하고, GPT에게 다음 행동을 다시 물어보고, 실패하면 바로 다음 계획으로 바꾸는 방식으로 작동합니다.
처음 설치:
npm install빌드 후 실행:
npm run build
npm start개발 모드:
npm run dev테스트:
npm test.env 파일에 설정합니다. .env.example을 참고하면 됩니다.
OPENAI_API_KEY=
OPENAI_MODEL=gpt-4o
MINECRAFT_HOST=121.131.126.66
MINECRAFT_PORT=25565
MINECRAFT_VERSION=1.16.5
MINECRAFT_USERNAME=choonsik
MINECRAFT_AUTH=offline
COMMAND_PREFIXES=춘식아,choonsik
COMMAND_ALLOW_ALL=true
OWNER_USERNAME=
AGENT_MAX_CYCLES=300
AGENT_TICK_DELAY_MS=1000
LOG_LEVEL=info중요한 값:
OPENAI_API_KEY: OpenAI API 키입니다.OPENAI_MODEL: 기본값은gpt-4o입니다.MINECRAFT_HOST,MINECRAFT_PORT: 접속할 서버 주소입니다.MINECRAFT_AUTH: 서버가online-mode=false이면 보통offline을 씁니다. 정품 Microsoft 인증 서버면microsoft를 씁니다.COMMAND_PREFIXES: 춘식이가 명령으로 인식할 접두어입니다.AGENT_MAX_CYCLES: 한 목표를 위해 최대 몇 번까지 GPT 판단 사이클을 돌릴지 정합니다.AGENT_TICK_DELAY_MS: 한 사이클이 끝난 뒤 다음 GPT 판단까지 기다리는 시간입니다. 실패가 있으면 보통 기다리지 않고 바로 다음 사이클로 넘어갑니다.
Minecraft 채팅
-> "춘식아" 또는 "choonsik" 명령 감지
-> 현재 목표 시작 또는 기존 목표 교체
-> Mineflayer가 현재 상태 관찰
-> GPT-4o에게 목표, 기억, 최근 사건, 현재 상태 전달
-> GPT가 다음 행동 JSON 생성
-> Zod 스키마로 JSON 검증
-> 허용된 Mineflayer skill만 실행
-> 성공/실패/상태를 터미널과 채팅에 출력
-> 목표가 끝날 때까지 다시 관찰하고 재계획
사이클은 춘식이가 한 번 “보고, 생각하고, 행동하는” 단위입니다.
한 사이클은 대략 이렇게 진행됩니다.
1. 현재 상태 관찰
2. 최근 사건과 실패 기록 정리
3. GPT에게 현재 목표와 상황 전달
4. GPT가 다음 행동 1~5개를 JSON으로 결정
5. JSON 검증
6. skill 실행
7. 실행 결과 기록
8. 목표가 안 끝났으면 다음 사이클로 이동
즉, 목표 하나가 사이클 하나라는 뜻이 아닙니다. 목표 하나를 이루기 위해 여러 사이클이 반복됩니다.
예를 들어 춘식아 네더 가줘라고 하면 한 사이클에 네더까지 가는 것이 아니라, 여러 사이클에 걸쳐 다음처럼 진행될 수 있습니다.
사이클 1: 현재 인벤토리 확인, 나무가 없으니 나무 캐기
사이클 2: 나무가 생겼으니 판자와 작업대 만들기
사이클 3: 나무 곡괭이 만들기
사이클 4: 돌 캐기
사이클 5: 돌 곡괭이 만들기
사이클 6: 철과 석탄 찾기
사이클 7: 화로로 철 굽기
사이클 8: 철 곡괭이 만들기
...
각 사이클마다 GPT를 다시 부르기 때문에, 중간에 좀비를 만나거나, 음식이 부족하거나, 아이템을 잃거나, 길이 막히면 다음 사이클에서 계획이 바뀔 수 있습니다.
한 사이클은 보통 다음 중 하나로 끝납니다.
- GPT가 고른 행동들을 모두 실행함
- 어떤 행동이 실패해서 바로 재계획이 필요함
- 목표가 완료됨
- 목표가 막혔다고 판단됨
- 플레이어가
멈춰또는stop명령을 내림 - 봇이 죽거나 연결이 끊김
실패가 발생하면 AGENT_TICK_DELAY_MS를 기다리지 않고 다음 사이클로 바로 넘어가도록 되어 있습니다. 예를 들어 제작대에서 막대기 제작이 실패했는데도 3분을 기다리는 일을 줄이기 위해, 제작 skill 자체에도 짧은 no-progress 제한이 들어 있습니다.
스킬은 GPT가 직접 마인크래프트를 조작하지 못하게 막기 위한 실행 함수입니다.
GPT는 “무엇을 해야 할지”를 JSON으로 말하고, 실제 마인크래프트 조작은 src/skills.ts에 있는 skill 함수들이 합니다.
예시:
{
"type": "dig_block",
"block": "stone",
"radius": 32,
"count": 16,
"timeoutMs": 1200000
}GPT가 위 JSON을 만들면, 실행기는 검증 후 dig_block skill을 호출합니다. 이 skill은 실제로 Mineflayer API를 사용해서 이동하고, 필요한 곡괭이를 확인하고, 블록을 캐고, 드롭 아이템을 주웠는지 확인합니다.
스킬을 둔 이유는 안전성과 현실성 때문입니다.
- GPT가 임의 코드를 실행하지 못하게 합니다.
- GPT가 존재하지 않는 행동을 만들면 거절합니다.
- 블록을 캘 때 필요한 도구를 확인합니다.
- 실제로 닿을 수 없는 벽 뒤 블록을 캐지 않게 합니다.
- 화로에 곡괭이 같은 중요한 아이템을 연료로 넣지 않게 합니다.
- 제작이 멈추면 긴 timeout을 다 기다리지 않고 실패로 돌립니다.
- 행동 성공 후 실제 아이템을 얻었는지 확인합니다.
즉, GPT는 두뇌이고 skill은 몸입니다. GPT가 계획을 세워도 skill이 위험하거나 불가능하다고 판단하면 실행하지 않습니다.
춘식이는 매 사이클마다 GPT에게 현재 상황을 요약해서 보냅니다.
포함되는 정보:
- 현재 목표
- 몇 번째 판단 사이클인지
- 최근 성공/실패 사건
- 체력, 배고픔, 음식 보유 여부
- 현재 위치와 차원
- 손에 든 아이템
- 인벤토리
- 주변 플레이어
- 주변 적
- 주변 동물
- 주변 블록
- 낙하 위험
- 현재 도구로 캘 수 있는 블록 수준
GPT는 이 정보를 보고 “지금 당장 해야 할 1~5개의 행동”만 JSON으로 반환합니다.
GPT는 마인크래프트를 직접 조작하지 않습니다.
GPT가 하는 일:
- 목표를 해석합니다.
- 현재 상황에서 다음 행동을 고릅니다.
- 실패한 행동을 보고 다른 방법을 생각합니다.
- 장기 목표를 작은 단계로 나눕니다.
GPT가 못 하는 일:
- 임의 코드를 실행하지 못합니다.
- 허용되지 않은 Mineflayer API를 직접 호출하지 못합니다.
- whitelist 밖의 행동을 만들 수 없습니다.
- 실제로 가능한지 검증되지 않은 행동을 강제로 실행할 수 없습니다.
GPT는 아래 행동만 JSON으로 요청할 수 있습니다.
say: 채팅 말하기wait: 잠깐 기다리기move_to_player: 플레이어에게 이동explore: 주변 탐색explore_for_block: 특정 블록을 찾으면서 이동find_block: 근처 블록 위치 확인dig_block: 블록 캐기mine_tunnel: 터널 또는 계단식 광질place_block: 블록 설치craft_item: 아이템 제작equip_item: 아이템 장착eat_food: 음식 먹기attack_entity: 엔티티 공격use_item: 아이템 사용smelt_item: 화로 제련stop: 현재 작업 중단
이 목록 밖의 행동은 검증 단계에서 거절됩니다.
네더 가줘, 다이아몬드 캐줘, 엔더드래곤 잡아줘 같은 목표는 한 번에 끝낼 수 없습니다.
춘식이는 이런 목표를 받으면 매 사이클마다 다음 질문을 합니다.
지금 목표를 위해 가장 먼저 빠진 준비물이 무엇인가?
예를 들어 네더에 가려면 보통 이런 순서가 필요합니다.
나무
-> 판자와 막대기
-> 작업대
-> 나무 곡괭이
-> 돌
-> 돌 곡괭이
-> 철광석과 석탄
-> 화로
-> 철괴
-> 철 곡괭이
-> 다이아몬드
-> 다이아몬드 곡괭이
-> 흑요석
-> 네더 포털
README에 고정된 목표표를 넣어 춘식이를 묶어두지는 않습니다. 실제 판단은 매번 GPT가 현재 상황을 보고 합니다. 다만 GPT 프롬프트에는 “정석 생존 루트와 선행 조건을 지켜라”는 규칙이 들어 있습니다.
행동이 실패하면 춘식이는 오래 기다리지 않고 다음 GPT 사이클로 넘어갑니다.
예시:
- 돌을 캐려 했는데 곡괭이가 없으면 곡괭이 제작으로 돌아갑니다.
- 철을 캐려 했는데 돌 곡괭이가 없으면 돌 곡괭이를 먼저 만듭니다.
- 석탄이 없어서 화로가 멈추면 석탄을 캐러 갑니다.
- 낙하 위험이 있으면 무작정 앞으로 가지 않습니다.
- 죽거나 아이템을 잃었다는 사건이 기록되면 인벤토리를 다시 확인하고 기본 도구부터 복구합니다.
실패도 터미널에 기록되기 때문에, 지금 춘식이가 왜 멈췄는지 확인할 수 있습니다.
춘식이는 서바이벌 모드에서 행동한다고 가정합니다.
기본 규칙:
- 배고픔이 위험하면 위험한 작업보다 음식을 우선합니다.
- 체력이 낮거나 주변 적이 있으면 목표보다 생존을 우선합니다.
- 근처 동물이 있고 음식이 필요하면 사냥을 고려합니다.
- 네더, 엔드, 긴 광질 전에는 음식 여유분을 챙기려 합니다.
- 낙하 위험이 큰 방향으로 무작정 이동하지 않습니다.
춘식이는 블록마다 필요한 도구 단계를 확인합니다.
예시:
- 돌, 석탄: 나무 곡괭이 이상
- 철광석: 돌 곡괭이 이상
- 다이아몬드, 금, 레드스톤, 에메랄드: 철 곡괭이 이상
- 흑요석: 다이아몬드 곡괭이 이상
도구가 없으면 잘못된 도구로 계속 캐려고 하지 않고, 필요한 도구 제작 단계로 돌아가게 되어 있습니다.
탐색은 단순히 현재 위치 주변만 계속 훑는 방식이 아닙니다.
explore_for_block은 한 방향으로 이동하면서 계속 주변을 스캔합니다.- 목표 블록이 범위 안에 들어오면 탐색을 끝내고 바로 행동으로 옮깁니다.
- 지하 자원이 필요하면
mine_tunnel이나explore_for_block(searchMode="underground")로 내려가며 찾습니다. - 네더 자원은 네더에 간 뒤 찾고, 엔드 자원은 엔드에 간 뒤 찾는 식으로 차원을 구분합니다.
화로 작업은 별도로 안전장치가 들어 있습니다.
- 석탄이 있으면 석탄을 우선 사용합니다.
- 석탄이 없고 목탄이 있으면 목탄을 사용합니다.
- 석탄/목탄이 없으면 먼저 석탄을 넉넉히 캐러 갑니다.
- 그래도 실패했을 때만 여분의 나무, 판자, 막대기 같은 안전 연료를 마지막 수단으로 봅니다.
- 곡괭이, 도구, 무기, 방어구, 버킷, 작업대, 화로, 광물, 음식은 연료로 쓰지 않습니다.
- 화로의 연료가 꺼졌는지 계속 확인합니다.
- 연료가 부족하면 다시 채웁니다.
- 출력물이 완성되면 타임아웃까지 기다리지 않고 바로 챙깁니다.
- 작업대와 화로는 사용 후 가능하면 다시 회수해서 들고 다닙니다.
제작은 craft_item skill이 담당합니다.
- 제작 전에 레시피가 있는지 확인합니다.
- 작업대가 필요한 레시피면 근처 작업대를 찾거나 인벤토리의 작업대를 설치합니다.
- 작업대가 있으면 접근 가능한지 확인합니다.
- 제작 호출이 멈추면 긴 timeout을 끝까지 기다리지 않고 짧게 실패 처리합니다.
- 제작 후 실제 결과물이 인벤토리에 늘었는지 확인합니다.
- 임시로 설치한 작업대는 가능하면 다시 회수합니다.
실행 중에는 터미널에서 춘식이의 상태를 볼 수 있습니다.
예시:
[choonsik] spawned
[choonsik] listening prefixes=춘식아,choonsik
[choonsik] command from makeroni0810: 네더 가줘
[choonsik] goal started #1: 네더 가줘
[choonsik-cycle] cycle=3 goal="네더 가줘" ...
[choonsik] thought=철 곡괭이가 없으므로 철 준비 전에 돌 곡괭이가 필요하다.
[choonsik] actions=craft_item,dig_block
[choonsik] action started ...
[choonsik] action result ...
[choonsik-status] goal="네더 가줘" hp=18 food=14 pos=-10.3,66.0,-17.6 held=stone_pickaxe
로그에서 볼 수 있는 것:
- 현재 목표
- GPT의 생각 요약
- 이번 사이클의 행동 목록
- 각 행동의 성공/실패
- 체력, 배고픔, 위치, 손에 든 아이템
- 실패 후 다음 사이클까지 대기 시간
마인크래프트 채팅에서 다음처럼 말하면 현재 목표와 행동을 멈춥니다.
춘식아 멈춰
choonsik stop
stop은 현재 행동과 이동, 공격, 채굴 작업을 중단합니다.
skin/chskin.png는 64x64 마인크래프트 스킨 이미지입니다. 다만 Java 서버에서 플레이어 스킨은 Mineflayer 클라이언트가 PNG를 직접 서버로 보내서 정하는 방식이 아닙니다. 다른 플레이어에게 보이는 스킨은 서버가 보내는 player profile texture로 결정됩니다.
따라서 로컬 파일 skin/chskin.png를 코드에서 바로 씌우는 것은 불가능하고, 아래 방법 중 하나가 필요합니다.
- 서버에 SkinsRestorer 같은 스킨 플러그인을 설치하고, 봇이 접속 후
/skin ...명령어를 실행하게 하기 - 실제 Java Edition 계정의 스킨을
chskin.png로 바꾸고, 해당 계정으로 접속하기 - 서버/프록시에서 직접 봇의 skin texture property를 넣어주는 플러그인을 만들기
이 프로젝트에는 서버 스킨 플러그인을 쓸 때를 위한 자동 명령어 옵션이 있습니다.
BOT_SKIN_COMMAND=/skin set {username}또는 플러그인이 URL 스킨을 지원한다면:
BOT_SKIN_COMMAND=/skin url https://example.com/chskin.png{username}은 실행 시 MINECRAFT_USERNAME 값으로 바뀝니다. 서버 플러그인이 로컬 PC 파일을 읽을 수는 없으므로, URL 방식은 chskin.png를 서버가 접근 가능한 공개 주소에 올려야 합니다.
이 프로젝트의 방향은 “정해진 스크립트 봇”이 아니라, 관찰하고 생각하고 행동하고 다시 생각하는 Minecraft AI 에이전트입니다.