- `_append_memory_sections` 함수를 추가하여 압축 모드에서 기억된 광맥과 마지막 행동 정보를 상태 요약에 포함하도록 개선 - `main.py`에서 상태 요약 생성 시 메모리 섹션을 자동으로 추가하여 AI의 의사결정에 필요한 정보를 제공 - `README.md`에 새로운 메모리 기능 및 사용 방법에 대한 설명 추가 - `state_reader.py`에서 인벤토리 판독 로직을 개선하여 캐시 사용 조건을 명확히 하여 안정성 향상
13 KiB
13 KiB
채굴 시 mining_state 반복 설정 제거 (우클릭 유지)
문제
mine_resource내부에서 약 0.1초마다update_selected_entity+mining_state = { mining = true, ... }를 RCON으로 재전송하고 있었음.- 플레이어는 보통 우클릭을 누른 채 유지하는데, 스크립트는 매번 상태를 다시 써서 뗐다 누르는(re-trigger) 것에 가까운 동작이 됨.
변경
- 이동·근처 광물 확인 후, 채굴 루프 진입 직전에 한 번만
mining_state설정. - 루프에서는
sleep과 인벤토리/채굴 진행률 읽기만 수행. 종료·목표 달성 시에만mining = false.
범위
action_executor.py—mine_resourceREADME.md— 동작 설명 한 줄 보강
채굴 실패 시 제외 좌표 반복 버그 수정 계획
문제 재현/관찰
mine_resource에서 실패한 타일을failed_positions에 추가한 뒤 Lua에exclude테이블로 전달하지만, 다음 시도에서도 동일 좌표(예:388,2)로 다시 이동하는 로그가 발생합니다.
원인 후보
- Lua에서 제외 판정에 쓰는 좌표 키가
string.format("%.0f,%.0f", ...)기반인 반면, Python에서exclude["{fx:.0f},{fy:.0f}"]를 만들 때 반올림/절삭 방식이 Lua와 1:1로 일치하지 않는 케이스가 있을 수 있습니다. - 이 경우
exclude[key]가 항상 false가 되어, Lua가 “가장 가까운 광석”을 계속 같은 엔티티로 반환할 수 있습니다.
변경 목표
failed_positions를 “Lua 키 생성과 동일한 정수 타일 좌표(tx, ty)”로만 저장합니다.- Lua에서 후보 광석 엔티티를 검사할 때도 정수 타일 좌표를 계산해 키/반환/마이닝 좌표에 일관되게 사용합니다.
- 그 결과, 제외한 좌표는 다음 루프에서 절대로 다시 선택되지 않도록 보장합니다.
구현 범위
action_executor.pymine_resource내부에서 좌표 처리 로직을 정수 타일 기반으로 통일- Lua 반환값을
tx,ty정수 문자열로 변경하고 Python 파싱을 이에 맞춤
README 업데이트 계획
- 채굴 제외(exclude) 로직이 “정수 타일 키 기반으로 통일”되도록 README의 기술/동작 설명(또는 체크리스트)을 업데이트합니다.
자원 패치 중심 오차로 인한 채굴 실패 완화 계획
문제 관찰
scan_resources()가 패치의 평균 중심(center_x/y)을 추천 좌표로 사용하면서, 플레이어가 해당 좌표로 이동한 직후mine_resource의 엔티티 탐색 반경 안에서 실제 자원 엔티티를 찾지 못해 실패하는 케이스가 발생할 수 있음.
근거(팩토리오 Lua API)
LuaInventory.get_contents()는dictionary[string -> uint]를 반환하므로, 인벤토리 판독은name -> count형태로 처리하는 것이 맞다.- 자원 엔티티의
e.position은 부동소수(MapPosition) 좌표이므로, 타일 중심/평균 중심과 실제 엔티티 좌표 간 오차가 생길 수 있다.
변경 목표
scan_resources()결과에 패치 대표 좌표를 평균 중심뿐 아니라 플레이어 기준 가장 가까운 실제 엔티티 좌표(앵커anchor_x/y및anchor_tile_x/y)로 함께 제공summarize_for_ai()에서는 평균 중심 대신 앵커 좌표 기반으로 거리/추천을 계산mine_resource후보 엔티티 탐색 반경을 더 크게 잡아(행동 레벨) 이동 직후 실패를 흡수
구현 범위
state_reader.pyscan_resources()에anchor_x/y및anchor_tile_x/y추가summarize_for_ai()거리 계산을 앵커 우선으로 변경
action_executor.pymine_resource에서 후보 엔티티 탐색 반경을80→250으로 확장
GLM 응답 지연 원인 계측/완화 계획
문제 관찰
ai_planner.py에서 GLM 호출이[GLM] 생각 중...이후 30초~1분 이상 지연되는 현상 발생- JSON 파싱 실패로 인한 재시도는 가끔 발생(하지만 느림의 주 원인이 아닐 가능성도 있음)
1단계(증거 수집)
ai_planner.py의_call_glm()에 타이밍 로그 추가total: 요청 시작~콘텐츠 반환까지 전체 소요http_read: HTTP 응답 본문 수신까지 소요json_parse: 응답 JSON 파싱 시간prompt_chars/system_chars/max_tokens: 입력 크기 동시 기록
2단계(완화: 로그 확인 후)
json_parse가 아니라http_read/total이 큰 경우:max_tokens를 우선 크게 줄여 생성 길이 상한 조정SYSTEM_PROMPT/state_summary길이를 더 강하게 제한
json_parse가 큰 경우:- JSON 파싱/복구 로직 비용 또는 응답 형식 편차 원인 재점검
README 업데이트
README.md의주의사항/실행섹션에 GLM 지연 계측 로그 출력 방식 및 파라미터 조정 힌트를 반영
Cursor Hooks - Windows sessionStart 앱 선택창 원인/해결 계획
문제 재현/관찰
- Cursor
@cursor.hooks로그에서sessionStart훅 실행 중./hooks/session-start가 stdout JSON을 내지 못하거나, Windows에서 앱 선택창이 뜨는 현상이 관찰됨
원인 후보
- Windows에서 확장자 없는
./hooks/session-start를 실행할 때bash로 해석되지 않아, OS가 실행 대신 “어떤 앱으로 열지”를 요청할 수 있음
변경 목표
- 프로젝트 훅은
powershell로 stdout에 JSON을 출력하도록 고정 - superpowers 플러그인의 Cursor 훅은
bash로 감싸 실행되도록 구성 변경
구현/검증 범위
E:/develop/factorio-ai-agent/.cursor/hooks.jsonE:/develop/factorio-ai-agent/.cursor/session-start-hook.ps1.../superpowers/.../hooks/hooks-cursor.json- 검증: Cursor 재시작 후
View -> Output -> Hooks에서 sessionStart 훅이 정상 파싱되어OUTPUT에 JSON이 나타나는지 확인
인벤토리 캐시(메모리) 추가 계획
목표
- 파이썬 에이전트만 종료/재실행할 때
RCON으로 인벤토리를 읽지 못하거나({}반환) 빈 값이 나오면, 직전에 성공적으로 읽은 인벤토리를 기억해서 프롬프트에 반영한다.
정책(캐시 fallback 조건 변경)
get_inventory()에서 JSON 파싱/출력 추출이 성공(parsed_ok=True) 했으면, 결과가{}라도 캐시로 덮지 않는다.- 캐시를 덮어쓰면 실제 진행이 반영되지 않아 같은 행동을 반복하는 루프가 생길 수 있다.
get_inventory()에서 파싱이 실패(parsed_ok=False) 하거나 예외가 발생한 경우에만inventory_memory.json캐시를 로드한다.
구현 범위
state_reader.pyinventory_memory.json로드/저장 유틸 추가get_inventory()반환값을 캐시 fallback으로 교체
README.md- 인벤토리 캐시 동작과 파일명(
inventory_memory.json)을 설명
- 인벤토리 캐시 동작과 파일명(
발견된 광맥 좌표 기억(메모리) 추가 계획
문제 관찰
explore로 광맥을 발견해도, 재실행/재계획/초기화 상황에서 동일 좌표를 다시 추천받지 못해 불필요한 탐색이 반복될 수 있음.
변경 목표
- 자원 엔티티(광맥)의 좌표를
ore_patch_memory.json에 ore 종류별로 여러 패치 좌표로 저장 - 다음 상태 요약에서 “기억된 광맥” 섹션으로 AI에게 제공
- LLM이 가능하면 기억된 좌표로 먼저 이동해
move -> mine_resource를 수행하도록 유도
구현 범위
action_executor.pyexplore성공 시 발견한 광맥 좌표를 파일에 갱신
state_reader.pyscan_resources()결과로도 광맥 좌표를ore_patch_memory.json에 갱신summarize_for_ai()에 “기억된 광맥” 출력 추가
ai_planner.py- SYSTEM_PROMPT에 기억된 광맥 우선 이동 가이드 추가
README 업데이트
ore_patch_memory.json파일과 동작 방식 설명 추가
에이전트 재시작 시 마지막 행동 기억(메모리) 추가 계획
문제 관찰
- 코드를 수정하면 보통 에이전트를 재시작해야 하고,
이때
ai_planner.py의feedback_log/직전 실패 정보가 초기화되어 같은 시행착오가 반복될 수 있음.
변경 목표
- 재시작 시에도 “직전에 실행했던 action”과 결과(success/message)를 파일에 저장
- 다음 실행의 상태 요약(
state_reader.summarize_for_ai())에 “기억된 마지막 행동” 섹션을 포함 - LLM이 마지막 행동이 실패였다면 같은 행동을 즉시 반복하지 않도록 유도
저장 기준(확정)
- 성공/실패 상관없이 가장 마지막으로 실행을 시도한 action 1개만 저장한다.
구현 범위
main.py- 행동 실행 직후 action/result를
agent_last_action_memory.json에 저장
- 행동 실행 직후 action/result를
state_reader.py- 재시작 시 파일을 로드해 상태 요약에 포함
ai_planner.py- SYSTEM_PROMPT에 “마지막 행동 실패 재시도 금지/원인 해결 우선” 가이드 추가
README 업데이트
agent_last_action_memory.json존재/동작 설명 추가
place_entity BLOCKED 완화 계획 (인접 타일 탐색)
문제 관찰
- 로그에서
stone-furnace배치가FAIL 배치 불가(내부적으로BLOCKED)로 반복됨 - 또한
stone-furnace가 이미 맵에 설치돼 있어도, executor가 먼저NO_ITEM으로 종료해 재사용 탐색이 실행되지 않는 케이스가 관찰됨 mine_resource가 자원 엔티티 근처(종종 자원 패치 타일)로 이동한 뒤, 같은 좌표에 건물을 배치하려고 하면 Factorio의can_place_entity조건에 걸려 막힐 수 있음
변경 목표
action_executor.py의place_entity에서 배치 아이템 유무(NO_ITEM) 확인 전에, 먼저surface.find_entities_filtered로 기존 엔티티(같은name)가 있는지 탐색- (기존) 요청 좌표 주변
±1 타일(9칸)후보에서 기존 엔티티가 있으면REUSED로 성공 처리 - (추가) 요청 좌표 중심으로 반경
3타일 내에 같은 엔티티가 있으면 가장 가까운 것을REUSED로 성공 처리 - 기존 엔티티가 없을 때만 인벤토리에
name아이템이 있는지 확인하고,surface.can_place_entity+±1 타일후보로 실제 배치를 시도 - 실제로 배치된/재사용된 좌표를 결과 메시지에 포함해 이후
stone-furnace자동 부트스트랩이 좌표를 정확히 파싱하도록 보장
구현 범위
action_executor.py- 기존 엔티티 탐색을
NO_ITEM체크보다 먼저 수행 - 재사용(
REUSED) 성공 케이스의 메시지/좌표 포맷 확정 - 반경 3 타일의 넓은 재사용 탐색 추가
- 기존 엔티티 탐색을
README 업데이트
place_entity가BLOCKED/NO_ITEM상황에서도 기존 엔티티를 찾아REUSED로 재사용하고,stone-furnace는 재사용이어도 자동 부트스트랩이 동작하도록 설명 반영
GLM HTTP read timeout 대응 계획 (예외 포함 재시도)
문제 관찰
- 로그에
TimeoutError: The read operation timed out가 발생 - 현재
ai_planner.py는 JSON 파싱 실패만 재시도하고, 네트워크 타임아웃/연결 오류는 별도 재시도 경로가 약함
변경 목표
AIPlanner.decide()의 재시도 예외 범위를TimeoutError,ConnectionError,urllib.error.URLError까지 확장- 해당 오류가 발생하면 동일한 “plan 응답 받기” 재시도로 복구 시도
- 3회 연속 실패 시에는 상태 요약 기반 휴리스틱(광맥 있으면 채굴/이동, 없으면 explore 방향 순환)으로 폴백
구현 범위
ai_planner.pydecide()의except절 범위 확장 및 경고 로그 보강
README 업데이트
- GLM read timeout/연결 오류 발생 시 재시도 동작을
주의사항에 추가
GLM 전부 실패 시 explore 무한 루프 완화 (상태 기반 폴백)
문제 관찰
- GLM API가
TimeoutError/ConnectionError로 연속 실패하면 폴백이 항상explore(고정 east)만 선택됨 - 이미
주변 자원 패치·기억된 광맥에 철/석탄 좌표가 있는데도 탐색만 반복되어 진행이 멈춤
변경 목표
state_reader.summarize_for_ai()텍스트에서 플레이어 위치·앵커/기억 광맥 좌표를 정규식으로 추출- 광맥이 있으면
mine_resource우선(거리가 크면move선행), 없을 때만explore방향 순환 - 기본 HTTP 타임아웃 90초→120초, 재시도 간격 소폭 완화
구현 범위
ai_planner.py:_fallback_plan_from_summary,_parse_player_position,_parse_ore_anchors, 환경변수GLM_HTTP_TIMEOUT_SECONDS,GLM_FALLBACK_MOVE_THRESHOLD
README 업데이트
- 폴백 동작 및 환경변수 설명 반영
GLM 예외 상세 로그 + 연결 검사 스크립트
목표
TimeoutError/ConnectionError한 줄만으로는 DNS·SSL·프록시·HTTP 본문 오류를 구분하기 어려움URLError.reason·체인 예외·errno를 항상 출력하고,GLM_DEBUG=1에서 스택까지 확보scripts/glm_connection_check.py로 최소 POST만 수행해 네트워크/API 키를 분리 진단
구현
ai_planner.describe_glm_exception(),_glm_debug_enabled()scripts/glm_connection_check.py
README
GLM API 연결 문제 디버깅절 추가