fix: AIPlanner에서 finish_reason 처리 및 휴리스틱 폴백 로직 개선

- 응답의 finish_reason이 'length'이고 비JSON 텍스트가 포함된 경우, 즉시 상태 기반 휴리스틱 폴백으로 전환하는 로직 추가
- AIPlanner 클래스에 _last_glm_finish_reason 속성을 추가하여 이전 finish_reason을 추적
- README.md에 변경 사항 반영
This commit is contained in:
kswdev0
2026-03-26 13:08:38 +09:00
parent 9d3c7176d3
commit 084c17418a
2 changed files with 16 additions and 0 deletions

View File

@@ -177,6 +177,7 @@ class AIPlanner:
self.step = 0
self.feedback_log: list[dict] = []
self._last_glm_finish_reason: str | None = None
# GLM 전부 실패 시 explore 방향 순환 (동일 방향 탐색 루프 완화)
self._fallback_explore_turn = 0
self.long_term_goal = (
@@ -222,6 +223,17 @@ class AIPlanner:
detail = describe_glm_exception(e)
parse_no_brace = isinstance(e, ValueError) and "JSON 파싱 실패 ('{' 없음)" in str(e)
# 첫 시도에서 이미 finish_reason=length + 비JSON 텍스트면,
# repair 재시도도 같은 패턴으로 반복되는 경우가 많아 즉시 폴백한다.
if parse_no_brace and self._last_glm_finish_reason == "length":
if _glm_debug_enabled():
print("[GLM][디버그] finish_reason=length + 비JSON -> 즉시 휴리스틱 폴백")
plan = self._fallback_plan_from_summary(
state_summary,
last_error=detail,
)
break
# JSON-only repair를 이미 한 번 적용했는데도 여전히 비JSON 텍스트만 오는 경우:
# 추가 API 호출을 반복하지 말고 즉시 상태 기반 휴리스틱으로 진행한다.
if parse_no_brace and repair_applied_once:
@@ -437,6 +449,8 @@ class AIPlanner:
if _glm_debug_enabled():
finish_reason = data.get("choices", [{}])[0].get("finish_reason")
print(f"[GLM][디버그] finish_reason={finish_reason!r}")
finish_reason = data.get("choices", [{}])[0].get("finish_reason")
self._last_glm_finish_reason = str(finish_reason) if finish_reason is not None else None
content = self._extract_glm_assistant_text(data).strip()
if not content and _glm_debug_enabled():
# content가 비어있으면 아래 파서에서 원인 추적이 어려워지므로 raw 일부를 남긴다.
@@ -466,6 +480,7 @@ class AIPlanner:
)
return content
except urllib.error.HTTPError as e:
self._last_glm_finish_reason = None
body = ""
try:
body = e.read().decode("utf-8", errors="replace")