Skip to content

fix: 일정 생성 LLM 보정 병렬화 - #22

Merged
Heyaaz merged 4 commits into
mainfrom
fix/schedule-generation-version-lock
May 20, 2026
Merged

fix: 일정 생성 LLM 보정 병렬화#22
Heyaaz merged 4 commits into
mainfrom
fix/schedule-generation-version-lock

Conversation

@Heyaaz

@Heyaaz Heyaaz commented May 20, 2026

Copy link
Copy Markdown
Owner

Summary

  • 일정 생성 타임아웃 및 추천 옵션 중복 방지

Changes

  • OpenAI 일정 보정 호출 10초 timeout 적용
  • 3개 추천 옵션 LLM 보정 병렬 실행
  • LLM 지연/실패 시 옵션별 deterministic fallback 유지
  • LLM 보정 후 order별 옵션 간 장소 중복 후처리 추가
  • 병렬 보정, timeout fallback, LLM 보정 후 중복 방지 회귀 테스트 추가

Verification

  • Not run
  • Build
  • Test
    • ./gradlew test --tests 'com.tripsync.infrastructure.llm.OpenAiClientTest' --tests 'com.tripsync.application.consensus.ConsensusServiceTest' --tests 'com.tripsync.application.schedule.ScheduleServiceTest' --no-daemon --max-workers=1
  • Manual
    • docker compose up -d --build server
    • tripsync-server health=healthy

Notes

Heyaaz added 3 commits May 20, 2026 23:03
OpenAI 보정은 일정 생성의 보조 단계라서 옵션별 호출을 순차 대기하면 클라이언트 타임아웃을 유발할 수 있다. 기본 일정 후보 생성은 기존 순서를 유지하고, LLM 보정만 병렬 실행해 응답 대기 시간을 단일 호출 상한에 가깝게 제한한다.

Constraint: 일정 생성 HTTP 요청이 약 30초 부근에서 클라이언트에 의해 중단됨\nRejected: OpenAI timeout만 15초로 확대 | 순차 호출 구조에서는 다시 30초 이상 지연 가능\nConfidence: high\nScope-risk: moderate\nDirective: deterministic 후보 생성 순서는 중복 회피에 영향을 주므로 병렬화하지 말고 LLM 보정 단계만 병렬화할 것\nTested: ./gradlew test --tests 'com.tripsync.infrastructure.llm.OpenAiClientTest' --tests 'com.tripsync.application.consensus.ConsensusServiceTest' --tests 'com.tripsync.application.schedule.ScheduleServiceTest' --no-daemon --max-workers=1\nTested: docker compose up -d --build server; tripsync-server health=healthy\nNot-tested: 실제 OpenAI 네트워크 성공 응답의 운영 latency 분포

@Heyaaz Heyaaz left a comment

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nogada PR Review

Verdict

❌ Blocking 이슈 1개 있습니다. 병합은 보류가 맞아 보입니다.

Blocking

  1. LLM 보정 결과 기준의 옵션 간 장소 중복 방지가 깨질 수 있습니다.

ConsensusService.buildScheduleOptions에서 balanced, individualprepareOption(...) 직후 deterministic slot 기준으로 rememberUsedPlacesByOrder(...)를 호출하고, 실제 LLM 보정은 이후 async { refinePreparedOption(...) }로 병렬 실행됩니다. 그래서 LLM이 balanced의 특정 order를 deterministic 선택지 A에서 shortlist 후보 B로 바꾸면, individual/discovery 준비 단계는 B를 이미 사용된 장소로 알 수 없습니다. 결과적으로 같은 order에서 여러 추천 옵션이 같은 장소 B를 고를 수 있습니다.

이전 순차 구조에서는 보정까지 끝난 최종 slot을 기준으로 다음 옵션의 avoid set을 만들었는데, 지금 구조는 병렬화를 위해 그 정보가 사라진 상태입니다. saveGeneratedOptions.ensureUniqueSlots(...)도 한 option 내부 중복만 보정하므로, 옵션 간 중복은 막지 못합니다.

권장 수정 방향:

  • 병렬 LLM 보정 후 최종 slot들을 기준으로 옵션 간 중복을 한 번 더 조정하거나,
  • 각 옵션의 LLM 후보 shortlist를 만들 때 이전 옵션의 전체 shortlist/후보까지 soft avoid로 넣거나,
  • 병렬화 대상은 유지하되, 최종 결과 post-process에서 order별 option 간 중복을 검증/대체하는 테스트를 추가하는 쪽이 안전합니다.

검증

  • /tmp/tripsync_server_pr22_verify fresh detached worktree에서 ./gradlew clean test --no-daemon --no-build-cache 성공
  • 테스트 XML 기준: 64 tests / 0 failures / 0 errors / 0 skipped
  • git diff --check origin/main...HEAD 통과

참고

  • 테스트 종료 시 Testcontainers/Hikari/PostgreSQL shutdown warning이 출력됐지만, Gradle 결과와 XML 요약은 정상 성공이라 별도 blocking으로 보지 않았습니다.

[Heyaaz의 Nogada]

병렬 LLM 보정은 deterministic 준비 단계의 avoid set 이후에 최종 장소를 바꿀 수 있어 같은 순번의 추천 옵션이 같은 장소로 수렴할 수 있다. 병렬화는 유지하되 최종 보정 결과를 order별로 한 번 더 검사하고 대체 후보로 조정한다.

Constraint: LLM 보정은 옵션별 병렬 실행되어 이전 옵션의 최종 LLM 선택을 다음 옵션 준비 단계에서 알 수 없음\nRejected: 다시 전체 옵션 생성을 순차화 | 타임아웃 개선 효과 상실\nConfidence: high\nScope-risk: moderate\nDirective: 옵션 간 중복 회피는 deterministic 준비 단계와 최종 LLM 후처리 양쪽에서 유지할 것\nTested: ./gradlew test --tests 'com.tripsync.infrastructure.llm.OpenAiClientTest' --tests 'com.tripsync.application.consensus.ConsensusServiceTest' --tests 'com.tripsync.application.schedule.ScheduleServiceTest' --no-daemon --max-workers=1\nTested: docker compose up -d --build server; tripsync-server health=healthy\nNot-tested: 실제 운영 OpenAI 응답 분포에서의 대체 빈도

@Heyaaz Heyaaz left a comment

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nogada PR Review

Verdict

✅ 승인 가능 — 이전 blocking 이슈는 해결된 것으로 봤습니다.

확인한 내용

  • LLM 보정 병렬화 후 resolveCrossOptionPlaceCollisions로 최종 보정된 슬롯 기준의 옵션 간 장소 중복을 다시 정리합니다.
  • 이전에 막았던 케이스(LLM이 여러 옵션에서 같은 orderIndex의 같은 후보 장소를 선택하는 경우)를 테스트가 직접 재현합니다.
  • OpenAI timeout 설정과 병렬 fallback 동작도 테스트로 확인됩니다.

검증

  • git diff --check origin/main...HEAD 통과
  • ./gradlew clean test --no-daemon --no-build-cache 성공
  • 테스트 XML: 65 tests / 0 failures / 0 errors / 0 skipped

비고: 테스트 종료 시 Testcontainers/Hikari shutdown 경고가 있었지만, Gradle exit code와 XML 결과가 모두 정상이라 비차단으로 봤습니다.

[Heyaaz의 Nogada]

@Heyaaz
Heyaaz merged commit a2fd91f into main May 20, 2026
1 check passed
@Heyaaz
Heyaaz deleted the fix/schedule-generation-version-lock branch May 20, 2026 19:21
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