문서 AI로 Bot 만들기

LLM으로 Bot 만들기

프로그래밍을 몰라도 됩니다. 여러분은 어떻게 싸우고 싶은지 명확히 설명하고, 코드는 LLM이 씁니다. 프롬프트 템플릿을 복사해 전략을 설명하고, 실행해 본 뒤 다시 고쳐 달라고 하세요.

워크래프트는 잘 알지만 프로그래밍은 모르는 분께 적합하고, 시간을 아끼고 싶은 개발자에게도 좋습니다. 전체 과정은 하나의 대화입니다: 전략을 설명 → 모델이 코드 작성 → 한 게임 실행 → 본 현상을 모델에게 전달 → 모델이 수정.

먼저 빠른 시작을 따라 환경을 설치하고 hello_bot을 실행해 보세요(농부가 금을 캐러 가면 성공). 그래야 문제가 생겼을 때 환경 문제인지 Bot 문제인지 구분할 수 있습니다.

1. 모델에게 자료 주기

모델이 코드를 잘 쓰느냐는 대부분 올바른 자료를 읽었느냐에 달려 있습니다. 사용하는 도구에 맞춰 하나를 고르세요:

사용하는 도구자료를 주는 방법
저장소를 읽을 수 있는 Coding Agent(Claude Code, Cursor, Codex 등)저장소 디렉터리에서 실행하고, 먼저 docs/BOT_HANDBOOK_ZH.md, docs/api.json과 예제 하나(운영은 brains/examples/macro_bot.py, 전투는 micro_bot.py)를 읽게 하세요
인터넷에 접속할 수 있는 대화형 모델먼저 https://war3ai.com/llms-full.txt를 읽게 하세요. 사이트의 모든 문서가 이 파일 하나에 들어 있습니다
인터넷에 접속할 수 없는 웹 대화핸드북, api.json, 예제 파일 하나를 프롬프트 뒤에 붙여 넣으세요
로컬 모델(LM Studio, Ollama)위와 같습니다. 컨텍스트 창은 32K 토큰 이상을 권장합니다. 그보다 작으면 핸드북과 API 목록이 다 들어가지 않습니다

특정 프로 운영을 원하면 프로 운영 레시피에서 해당 항목도 함께 붙여 넣으세요.

2. 이 프롬프트를 복사하기

마지막의 “원하는 전략”을 여러분의 말로 바꾸세요. 구체적일수록 좋습니다:

워크래프트 III 1.27용 AI를 Python으로 작성해 줘. api.json에 나열된 Game 메서드만 사용하고,
존재하지 않는 메서드를 지어내지 마. 작성 방식은 rush_bot.py를 따라: openwar3.Bot을 상속하고 on_start(g)와 on_tick(g)를 구현해.

규칙:
- on_tick은 초당 약 5번 호출되니 빨라야 해(안에서 sleep하지 마).
- 읽지 못한 값은 0이 아니라 None이야. 먼저 확인하고 써.
- 명령은 회신(Receipt)을 반환해. `if r:`은 "엔진이 수락했다"는 뜻이고, 수락되지 않으면 `r.reason`에 이유가 적혀 있어
  (인구 부족, 금 부족, 대상이 안 보임, 이미 있는 영웅……). 다음 틱에 다시 시도하거나 다른 방법을 써.
- 특정 적을 공격할 때는 g.attack(유닛, 적)을 써. 적은 반드시 시야 안에 있어야 하고, 안 보이면 거부돼.
- 영웅이 죽으면 g.revive(제단)으로 부활시켜야 해. 새로 훈련할 수는 없어.
- 건물은 g.build_near(일꾼, 건물 코드, x, y)로 지어: 지을 수 있는 지점을 스스로 찾고 결과를 추적하며, 돈이 부족하면 아무것도 하지 않아.
- "방금 무슨 일이 있었는지"(누가 죽었는지, 누가 피해를 입었는지, 영웅 레벨 업, 아이템 드롭)를 알고 싶으면 on_event(g, ev)를 구현해.
- 같은 유닛에게 매 틱 같은 명령을 반복하지 마(하던 일이 끊겨). "놀고 있는" 유닛에게만 명령해.
- 채집은 idle_workers()의 일꾼에게만 맡겨. 금광 하나에 일꾼은 최대 5명.
- 훈련 대기열에는 1개만 넣어(g.queue(건물)이 비었을 때 다음 것을 넣어). 인구가 막혔는지는 g.production(건물).blocked로 확인해.
- 한 틱에 명령을 많이 내릴 때는 with g.batch(): 로 감싸(게임 스레드를 한 번만 기다려).
- 누구를 칠지는 g.time_to_kill(내 유닛 무리, 적)으로 골라(상성과 방어력 반영). 어디로 갈지는 g.path_distance로 골라(갈 수 없으면 None).
- 공정 모드에서는 시야 안의 것만 보여. 전에 봤던 적은 g.last_seen()으로 확인해.
- 유닛은 4자 코드로 나타내(휴먼 농부 hpea, 보병 hfoo, 병영 hbar……). 스킬은 오더 문자열을 써(thunderbolt 폭풍 망치,
  blizzard 눈보라, holybolt Holy Light……, 전체 목록은 data/order-ids.txt). 스킬 습득은 4자 코드를 써(AHtb, AHbz……).

원하는 전략:
<여기에 평범한 말로 쓰세요. 예:
  "휴먼, 시작하면 농부 5명은 금, 1명은 벌목. 영웅은 대마법사 먼저. 병영 두 개에서 보병과 소총병.
   12기가 모이면 영웅과 함께 상대 확장 기지를 공격. 영웅 체력이 30% 아래로 떨어지면 본진으로 후퇴.
   사냥은 본진에서 가까운 캠프부터.">

전략을 명확하게 설명하는 법

모델은 모호한 요구를 가장 어려워합니다. “좀 더 공격적으로” 같은 말보다 다음 정보가 훨씬 유용합니다:

  • 종족과 영웅: 어떤 영웅을 먼저 뽑는지, 스킬 찍는 순서(예: 대마법사는 물의 정령, 눈보라, 물의 정령……).
  • 빌드 순서: 몇 번째 농부 때 병영을 짓는지, 언제 테크 업을 하는지, 병영은 몇 개인지.
  • 병력 조합: 보병 + 소총병? 몇 기가 되면 출발하는지?
  • 진퇴 조건: 몇 기가 모이면 공격하는지, 영웅 체력이 얼마 아래면 후퇴하는지, 많이 잃으면 본진으로 돌아가 다시 모으는지.
  • 사냥: 할지 말지, 언제 할지(해가 진 뒤?), 이길 수 있는 캠프만 칠지?
  • 공정 여부: 나중에 아레나에 올릴 생각이라면 “시야 안에 보이는 적만 사용”이라고 말하세요.

3. 실행하기

모델이 준 코드를 brains/my_bot.py로 저장하고:

python tools/play.py --bot brains/my_bot.py --race 1 --difficulty 2

결과를 빨리 보고 싶으면 --speed 200(2배속)을 붙이세요.

4. 고쳐 달라고 하기

  • 오류가 났다면: 오류 메시지 전체를 그대로 모델에게 붙여 넣고 “고쳐 줘”라고 하세요.
  • 잘 못 싸운다면: 여러분이 추측한 원인이 아니라 게임에서 본 것을 설명하세요. 예: “영웅이 계속 본진에 서 있기만 한다”, “유닛이 한 기씩 따로 들어가서 죽는다”, “농부가 금광 하나에 몰려 있다”.
  • 새 전략을 추가하고 싶다면: 한 번에 하나만 추가하고, 한 게임을 돌려 망가지지 않았는지 확인한 뒤 다음 것을 추가하세요.

직접 명령을 실행할 수 있는 Coding Agent라면 3, 4단계도 맡길 수 있습니다. 한 게임을 실행하고, 로그와 회신을 읽고, 코드를 고치고, 다시 실행합니다. Agent가 충분한 정보를 보게 하는 방법은 Agent 자율 반복을 참고하세요.

5. 자주 묻는 문제

현상대개의 원인
아무것도 움직이지 않음인스턴스 번호(--inst)가 틀렸거나, 게임이 아직 시작되지 않음
농부가 금을 캐지 않음일하고 있는 농부에게 명령을 내림. idle_workers()에게만 맡기세요
건물이 계속 지어지지 않음좌표를 하드코딩하지 말고 build_near를 쓰세요. 회신 reason이 돈 부족인지 확인하세요
영웅이 나오지 않음train의 회신을 보세요. 인구 부족인가요? 아니면 영웅이 죽었나요(revive 필요)?
영웅이 스킬을 쓰지 않음배우지 않았거나(learn) 마나가 없음. 사용한 뒤 cooldown()이 쿨다운에 들어갔는지 보세요
유닛이 틱마다 움찔거림매 틱 명령을 다시 내리고 있음. 놀고 있는 유닛에게만 명령하세요
유닛이 안 나오고 돈만 쌓임인구가 막힘: g.production(병영).blocked를 확인하세요
모델이 존재하지 않는 메서드를 씀프롬프트에서 “api.json의 메서드만 사용”을 다시 강조하고, api.json 전체를 붙여 넣으세요

심화

  • 모든 API와 각 API의 내부 메커니즘: API 목록
  • 레퍼런스 브레인(brains/xwar3/strategy)은 확장, 사냥, 공격까지 하는 완전한 AI입니다. 모델에게 그 사고방식을 읽게 할 수는 있지만, 더 저수준의 API를 쓰므로 그대로 베끼는 것은 권하지 않습니다.
  • 나중에 아레나에 올리면 시야 안의 적만 볼 수 있습니다 — 지금부터 --fair로 스스로 제약을 걸어 두면 나중에 고칠 필요가 없습니다.