Skip to content

planner inference timeout과 출력 예산을 모델 프로필 설정으로 이동 - #57

Merged
Createyouracccount merged 1 commit into
mainfrom
feat/model-profile-inference-limits-20260905
Sep 6, 2026
Merged

planner inference timeout과 출력 예산을 모델 프로필 설정으로 이동#57
Createyouracccount merged 1 commit into
mainfrom
feat/model-profile-inference-limits-20260905

Conversation

@Createyouracccount

Copy link
Copy Markdown
Member

배경

Production 기준과 같은 계열인 Qwen3.8 27B(Q4_K_M)를 Ollama로 로컬 실행해 실사용하다가, 읽기 Run은
경계선에서 통과하고 쓰기 Run은 항상 model_call_unknown으로 닫히는 것을 확인했습니다. 원인은
xgeny-cli 상수 MODEL_TIMEOUT = 60s였습니다. 같은 조건에서 model의 제안은 올바릅니다(파일을 먼저
읽는 step을 계획하고 관찰한 digest로 apply-patch를 씁니다).

측정 (27B, 같은 machine)
동일 planner 요청 재전송 (prompt cache hit) 28.8s / 30.5s
run_id 한 글자만 바꾼 요청 (prefix 깨짐) 64.3s
저널: 1차 호출 → plan 수락 59s (60s 직전)
2차 호출 (tool output 포함) 60s에서 model_call_unknown

Planner 호출 하나는 prefill 약 34초(planning context 3.1k token)와 생성 약 29초입니다. Planning
context는 매 호출 고유한 run/call 식별자와 digest를 앞머리에 두므로 provider prefix cache가 적용되지
않아 이 비용이 매 호출 반복됩니다. Probe는 planning context 없는 작은 prompt라 12초에 통과하며 이
지연을 예측하지 못합니다. Timeout은 model 크기·quantization·hardware에 따라 달라 상수 하나로 모든
환경을 만족시킬 수 없습니다.

변경 사항 (ADR-0035)

  • ModelProfile에 비밀이 아닌 inferenceTimeoutSeconds·maxOutputTokens를 추가합니다. 기본값은 300초·1024 token입니다.
  • xgeny model setup --inference-timeout <초> --max-output-tokens <토큰>, 환경변수 XGENY_OPENAI_INFERENCE_TIMEOUT/XGENY_OPENAI_MAX_OUTPUT_TOKENS, 프로필 순서로 해석합니다(ADR-0032와 동일). 범위 밖 값은 inference_limits_invalid(exit 64)입니다. model list와 setup 결과가 두 값을 표시합니다.
  • planner_configcompatibility_probe_config가 같은 프로필 값을 받아 PR #54의 "probe와 production planner의 request_profile_digest가 같다" 불변식을 유지합니다. 상수 MODEL_TIMEOUT/MAX_OUTPUT_TOKENS는 제거합니다.
  • 저장 형식은 format version 1을 유지하고 새 필드는 serde(default)로 읽습니다. 기존 model-profiles.json은 그대로 로드됩니다.
  • Onboarding·run/resume 문서와 문제 해결 표를 갱신합니다.

의도된 결과: digest

두 값은 ADR-0017의 request_profile_digest 입력입니다. Run manifest는 digest만 기록하고 resume은
프로필에서 config를 다시 조립하므로, 이 PR 이전에 시작해 아직 완료되지 않은 Run은 기본값 변경
(60→300초) 때문에 resume 시 configuration_mismatch로 닫힙니다.
Run 시작과 resume 사이에 프로필의
두 값을 편집해도 같습니다. Developer Preview 단계의 의도된 결과이며 ADR-0035 §4에 명시했습니다.
Manifest schema·journal·receipt는 바뀌지 않습니다.

실제로 동작하게 된 것

같은 machine, 같은 goal, 같은 GGUF입니다.

BEFORE (60s 상수)
  27B c. write natural   XGENY_RECOVERY_REQUIRED reason=model_call_unknown (60s)
  27B d. write 2-turn    XGENY_RECOVERY_REQUIRED reason=model_call_unknown (60s)

AFTER (프로필 기본 300s; 기존 프로필 파일이 default로 로드됨)
  27B c. write natural   XGENY_COMPLETED (271s)  config.toml workers 4→8
  27B d. write 2-turn    XGENY_COMPLETED (287s)  config.toml workers 4→8
  27B a. read            XGENY_COMPLETED (117s)
  8B  a. read            XGENY_COMPLETED (50s)
  27B probe              PASS (21.1s)
  model list             timeout=300s max_output_tokens=1024 (legacy 프로필 두 개 모두)

c 시나리오의 저널: 호출별 68s(read-text plan) → 96s(apply-patch plan) → 107s(completion). 세 호출
모두 옛 60초를 넘기고 300초 안에 들어옵니다.

검증

  • cargo fmt --all -- --check
  • cargo clippy --workspace --all-targets --locked -- -D warnings
  • cargo test --workspace --locked --no-fail-fast (565 passed / 0 failed, 45 binaries)
  • cargo build --workspace --release --locked
  • xgeny protocol check
  • sh scripts/check-rc3-public-docs.sh
  • sh scripts/check-third-party-licenses.sh --check
  • 실제 로컬 endpoint(Ollama, Qwen3.8 27B·Qwen3 8B)에서 위 before/after

실패 테스트를 먼저 추가해 red를 확인한 뒤 구현했습니다: InferenceLimits 기본값과 provider 경계,
probe/planner가 프로필 값을 쓰고 digest가 같다(다른 timeout이면 다르다), 프로필 round-trip, 필드 없는
기존 파일이 기본값으로 로드, 범위 밖 저장값 fail-closed.

범위 밖

Planning context의 가변 식별자를 prompt 끝으로 옮겨 prefix cache를 살리는 변경(호출당 30초 이상
절감 가능)은 request envelope profile 변경이라 별도 ADR로 다룹니다. proposal 스키마 maxLength·
pattern--allow-file scope 제약도 별도입니다. 이 PR은 게시나 태그 생성을 수행하지 않습니다.

Public CLI는 planner 호출의 wall-clock 예산 60초와 출력 예산 1024 token을 상수로
고정했다. Production 계열인 Qwen3.8 27B(Q4_K_M)를 Ollama로 실행하면 planner 호출
하나가 prefill 약 34초(planning context 3.1k token, 매 호출 고유 id라 prefix cache
미적중)와 생성 약 29초로 60초 안팎이 걸려, 읽기 Run은 경계에 있고 쓰기 Run은 tool
output이 더해진 두 번째 호출이 model_call_unknown으로 닫혔다. 같은 조건에서 model의
제안 자체는 올바르다.

ADR-0035에 따라 두 값을 비밀이 아닌 프로필 필드 inferenceTimeoutSeconds와
maxOutputTokens로 옮긴다. 기본값은 300초와 1024 token이며 model setup의
--inference-timeout/--max-output-tokens, XGENY_OPENAI_INFERENCE_TIMEOUT/
XGENY_OPENAI_MAX_OUTPUT_TOKENS, 프로필 순서로 해석한다. 기존 model-profiles.json은
serde default로 그대로 로드된다. Probe와 production planner는 같은 값을 받아 request
profile digest 동일성 불변식을 유지한다. 두 값은 digest 입력이므로 기본값 변경으로
진행 중이던 Run의 resume은 configuration_mismatch가 되며 ADR에 명시했다.

실측: 27B 쓰기 시나리오 두 건이 XGENY_COMPLETED(호출당 68/96/107초), 읽기와 8B 회귀 없음.
@Createyouracccount
Createyouracccount merged commit 64c5cd4 into main Sep 6, 2026
6 checks passed
@Createyouracccount
Createyouracccount deleted the feat/model-profile-inference-limits-20260905 branch September 6, 2026 05:48
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant