fix: AIPlanner JSON-only repair 및 빈 actions 처리 개선
- JSON-only repair를 한 번 적용했음에도 비JSON 텍스트가 계속 오는 경우, 즉시 상태 기반 휴리스틱 폴백으로 전환하는 로직 추가 - LLM이 빈 actions를 반환할 경우에도 즉시 휴리스틱 플랜으로 대체하여 진행을 유지하도록 개선 - README.md에 변경 사항 반영
This commit is contained in:
@@ -204,6 +204,7 @@ class AIPlanner:
|
||||
|
||||
# JSON 스키마를 위반한 경우(예: 분석 텍스트만 반환)에는 재시도 프롬프트를 강화한다.
|
||||
repair_suffix = ""
|
||||
repair_applied_once = False
|
||||
|
||||
for attempt in range(3):
|
||||
try:
|
||||
@@ -219,6 +220,19 @@ class AIPlanner:
|
||||
OSError,
|
||||
) as e:
|
||||
detail = describe_glm_exception(e)
|
||||
parse_no_brace = isinstance(e, ValueError) and "JSON 파싱 실패 ('{' 없음)" in str(e)
|
||||
|
||||
# JSON-only repair를 이미 한 번 적용했는데도 여전히 비JSON 텍스트만 오는 경우:
|
||||
# 추가 API 호출을 반복하지 말고 즉시 상태 기반 휴리스틱으로 진행한다.
|
||||
if parse_no_brace and repair_applied_once:
|
||||
if _glm_debug_enabled():
|
||||
print("[GLM][디버그] repair 후에도 비JSON 응답 -> 즉시 휴리스틱 폴백")
|
||||
plan = self._fallback_plan_from_summary(
|
||||
state_summary,
|
||||
last_error=detail,
|
||||
)
|
||||
break
|
||||
|
||||
if attempt < 2:
|
||||
if isinstance(e, ValueError) and (
|
||||
str(e).startswith("JSON 파싱 실패")
|
||||
@@ -231,6 +245,7 @@ class AIPlanner:
|
||||
"아래 JSON 스키마를 그대로(키/구조 동일) 반환하세요:\n"
|
||||
"{\"thinking\":\"\",\"current_goal\":\"\",\"actions\":[{\"action\":\"wait\",\"params\":{\"seconds\":1},\"reason\":\"repair\"}],\"after_this\":\"재시도\"}"
|
||||
)
|
||||
repair_applied_once = True
|
||||
if _glm_debug_enabled():
|
||||
print("[GLM][디버그] JSON-only repair 프롬프트 적용")
|
||||
# 429 Rate limit이면 prompt 길이를 늘리면 안 되므로 repair_suffix를 끈다.
|
||||
@@ -275,10 +290,24 @@ class AIPlanner:
|
||||
if thinking:
|
||||
print(f"\n[AI] 판단:\n{thinking}\n")
|
||||
|
||||
actions = plan.get("actions", [])
|
||||
if not isinstance(actions, list):
|
||||
actions = []
|
||||
if not actions:
|
||||
# 모델이 형식은 맞췄지만 actions가 비어 있으면 main 루프가 10초 대기 재시도만 반복한다.
|
||||
# 이런 경우도 즉시 휴리스틱 플랜으로 전환해 진행을 유지한다.
|
||||
plan = self._fallback_plan_from_summary(
|
||||
state_summary,
|
||||
last_error="LLM returned empty actions",
|
||||
)
|
||||
thinking = plan.get("thinking", "")
|
||||
if thinking:
|
||||
print(f"\n[AI] 판단:\n{thinking}\n")
|
||||
actions = plan.get("actions", [])
|
||||
|
||||
print(f"[AI] 현재 목표: {plan.get('current_goal', '')}")
|
||||
print(f"[AI] 완료 후: {plan.get('after_this', '')}")
|
||||
|
||||
actions = plan.get("actions", [])
|
||||
actions = self._ensure_move_before_build_actions(actions)
|
||||
print(f"[AI] {len(actions)}개 행동 계획됨")
|
||||
return actions
|
||||
|
||||
Reference in New Issue
Block a user