feat: 메모리 섹션 추가 및 상태 요약 개선
- `_append_memory_sections` 함수를 추가하여 압축 모드에서 기억된 광맥과 마지막 행동 정보를 상태 요약에 포함하도록 개선 - `main.py`에서 상태 요약 생성 시 메모리 섹션을 자동으로 추가하여 AI의 의사결정에 필요한 정보를 제공 - `README.md`에 새로운 메모리 기능 및 사용 방법에 대한 설명 추가 - `state_reader.py`에서 인벤토리 판독 로직을 개선하여 캐시 사용 조건을 명확히 하여 안정성 향상
This commit is contained in:
79
main.py
79
main.py
@@ -17,7 +17,8 @@ from state_reader import StateReader
|
||||
from context_compressor import ContextCompressor
|
||||
from ai_planner import AIPlanner
|
||||
from action_executor import ActionExecutor
|
||||
from agent_last_action_memory import save_last_action_memory
|
||||
from agent_last_action_memory import save_last_action_memory, load_last_action_memory
|
||||
from ore_patch_memory import load_ore_patch_memory, compute_distance_sq
|
||||
|
||||
RCON_HOST = os.getenv("FACTORIO_HOST", "127.0.0.1")
|
||||
RCON_PORT = int(os.getenv("FACTORIO_PORT", "25575"))
|
||||
@@ -58,6 +59,80 @@ end
|
||||
return False
|
||||
|
||||
|
||||
def _append_memory_sections(summary: str) -> str:
|
||||
"""
|
||||
압축 모드(중반/후반)에서는 context_compressor 출력만 들어가서
|
||||
state_reader의 "기억된 광맥/마지막 행동" 섹션이 사라질 수 있다.
|
||||
이 정보를 프롬프트에 다시 덧붙여 폴백/복구를 가능하게 한다.
|
||||
"""
|
||||
ore_mem = load_ore_patch_memory()
|
||||
last_action = load_last_action_memory()
|
||||
|
||||
# compressed summary에도 "위치: (x, y)"가 포함되므로, 여기서 플레이어 좌표만 뽑는다.
|
||||
m = None
|
||||
try:
|
||||
import re
|
||||
|
||||
m = re.search(r"위치:\s*\(\s*(-?\d+)\s*,\s*(-?\d+)\s*\)", summary)
|
||||
except Exception:
|
||||
m = None
|
||||
|
||||
px = py = None
|
||||
if m:
|
||||
try:
|
||||
px = int(m.group(1))
|
||||
py = int(m.group(2))
|
||||
except Exception:
|
||||
px = py = None
|
||||
|
||||
mem_lines: list[str] = []
|
||||
|
||||
mem_lines.append("### 기억된 광맥 (좌표)")
|
||||
if ore_mem:
|
||||
known: list[tuple[int, str, int, int, object]] = []
|
||||
for ore, patches in ore_mem.items():
|
||||
if not isinstance(patches, list):
|
||||
continue
|
||||
for patch in patches:
|
||||
if not isinstance(patch, dict):
|
||||
continue
|
||||
tx = patch.get("tile_x")
|
||||
ty = patch.get("tile_y")
|
||||
if isinstance(tx, int) and isinstance(ty, int):
|
||||
if px is not None and py is not None:
|
||||
dist = int(compute_distance_sq(px, py, tx, ty) ** 0.5)
|
||||
else:
|
||||
dist = 10**18
|
||||
known.append((dist, ore, tx, ty, patch.get("count", "?")))
|
||||
|
||||
known.sort(key=lambda x: x[0])
|
||||
for dist, ore, tx, ty, cnt in known[:10]:
|
||||
if dist >= 10**18:
|
||||
mem_lines.append(f"- {ore}: ({tx},{ty}) [거리: ~?타일] count={cnt}")
|
||||
else:
|
||||
mem_lines.append(f"- {ore}: ({tx},{ty}) [거리: ~{dist}타일] count={cnt}")
|
||||
else:
|
||||
mem_lines.append("- 없음")
|
||||
|
||||
mem_lines.append("")
|
||||
mem_lines.append("### 마지막 행동(기억)")
|
||||
if last_action and isinstance(last_action, dict) and last_action.get("action"):
|
||||
act = last_action.get("action", "")
|
||||
success = last_action.get("success", None)
|
||||
msg = last_action.get("message", "")
|
||||
mem_lines.append(f"- action={act} success={success} message={msg}")
|
||||
params = last_action.get("params", {})
|
||||
if params:
|
||||
try:
|
||||
mem_lines.append(f"- params={json.dumps(params, ensure_ascii=False)}")
|
||||
except Exception:
|
||||
pass
|
||||
else:
|
||||
mem_lines.append("- 없음")
|
||||
|
||||
return summary + "\n\n" + "\n".join(mem_lines)
|
||||
|
||||
|
||||
def run():
|
||||
print("=" * 60)
|
||||
print(" 팩토리오 순수 AI 에이전트 (치트 없음)")
|
||||
@@ -97,9 +172,11 @@ def run():
|
||||
elif entity_count < 200:
|
||||
print(f"[상태] 중반 모드 - 구역 압축 (건물 {entity_count}개)")
|
||||
summary = compressor.get_compressed_state(detail_level=1)
|
||||
summary = _append_memory_sections(summary)
|
||||
else:
|
||||
print(f"[상태] 후반 모드 - 글로벌 압축 (건물 {entity_count}개)")
|
||||
summary = compressor.get_compressed_state(detail_level=0)
|
||||
summary = _append_memory_sections(summary)
|
||||
|
||||
global_info = compressor._get_global_summary()
|
||||
entity_count = global_info.get("total_entities", entity_count)
|
||||
|
||||
Reference in New Issue
Block a user