긴 대화가 코드를 바꿀 때: 컨텍스트 드리프트와 숨겨진 오류

발행: (2025년 12월 30일 오후 06:58 GMT+9)
9 min read
원문: Dev.to

I’m happy to translate the article for you, but I’ll need the text you’d like translated. Could you please paste the content you want converted to Korean (excluding the source line you already provided)? Once I have the full text, I’ll keep the source link unchanged and translate the rest while preserving the original formatting.

채팅이 모델을 조용히 재구성하는 데 걸리는 시간

I keep a live assistant thread open during tricky debugging sessions.
복잡한 디버깅 세션 동안 라이브 어시스턴트 스레드를 열어 둡니다.

At first I seed the conversation with stack details: Python 3.11, FastAPI, Postgres 14, specific environment names.
처음에는 대화에 스택 세부 정보를 제공하는데, 예를 들어 Python 3.11, FastAPI, Postgres 14, 특정 환경 이름 등을 입력합니다.

Hours later the model starts suggesting snippets that match what it saw in the latest few messages, not the initial constraints. Recent tokens dominate.
몇 시간 후 모델은 초기 제약조건이 아니라 최근 몇 개의 메시지에서 본 내용과 일치하는 코드 조각을 제안하기 시작합니다. 최신 토큰이 우세합니다.

One time the assistant began returning examples for aiohttp while my project was FastAPI. The code compiled superficially in a REPL snippet but failed in integration tests because the session‑level middleware I relied on wasn’t present.
한 번은 어시스턴트가 내 프로젝트가 FastAPI임에도 불구하고 aiohttp 예제를 반환하기 시작했습니다. 코드는 REPL 조각에서는 겉보기에 컴파일되었지만, 세션 수준 미들웨어가 없어서 통합 테스트에서는 실패했습니다.

숨겨진 가정이 코드 제안에 스며들다

이것은 극적인 환상이 아닙니다. 우리 인프라와 맞지 않는 작고 그럴듯한 기본값들일 뿐입니다. 모델은 기본 AWS 리전, 일반적인 패키지 버전, 혹은 데이터베이스 URL이 DATABASE_URL이라고 가정합니다.

제가 병합한 패치에서는 생성된 Dockerfile이 다음과 같이 사용되었습니다:

RUN pip install --user .

루트 빌드 단계 안에서 말이죠. 로컬에서는 정상적으로 빌드되었지만 CI에서는 site‑packages가 누락된 비루트 런타임 이미지가 생성되어 서비스가 시작 시점에 충돌했습니다. 어시스턴스는 우리가 어떤 베이스 이미지를 사용하는지 묻지 않고 전형적인 패턴으로 빈틈을 메꿨습니다.

다른 예시: 채팅에서 보기 좋게 제시된 kubectl 명령입니다. 이 명령은 kubectl rollout restart--record 옵션을 사용했는데, 우리 클러스터에서는 해당 옵션이 더 이상 지원되지 않습니다. 테스트 클러스터에서는 명령이 성공했지만 정책 에이전트 하에서는 실패했고, 모호한 롤아웃 상태를 만들었습니다. 모델은 훈련 중에 가장 흔히 본 플래그를 우리 환경에 맞는 것으로 간주했습니다.

도구 실패가 환각을 증폭시킨다

I wire models to search and code indexers to ground answers. But the connectors are brittle. A search timeout returned an empty payload and the model synthesized a function name that appeared in no file. I treated the reply as authoritative and copied the name into a refactor. The build failed.

From the outside it looked like a hallucination, but the root cause was an unhandled error in the tool layer. The model then kept “fixing” the non‑existent function with more invented helpers because it had no real evidence to stop.

파이프라인에서 작은 오류가 누적됩니다

이러한 실수는 곱해집니다. 생성된 CI 작업에서 하나의 잘못된 설정—환경 주입 누락—이 마이그레이션 실행을 손상시켰습니다. 마이그레이션은 일시적인 DB에서는 로컬에서 성공했지만, 스테이징에서는 중간에 멈추고 외래 키가 깨졌습니다. 로그는 도움이 되었지만, 실행 후 데이터베이스 상태를 확인하지 않고 작업의 상태 문자열만 신뢰했기 때문에 알림이 발생하지 않았습니다. 모델이 제안한 상태 확인 추가에는 펜스포스트 버그가 있었습니다. 이는 롤백이 수동적이고 번거로워질 때까지 사소해 보였습니다.

또 다른 복합 예시: 어시스턴트가 대량 삽입 주변에 try/except를 권고하고 IntegrityError를 조용히 무시하여 일반적인 성공 메시지를 반환했습니다. 하위 서비스는 오래된 캐시를 가지고 있었고, 소비자들은 끝없이 재시도했습니다. 작은 오류 처리 선택 버퍼가 눈에 보이는 장애로 이어졌습니다. 우리는 스키마와 린팅에 대한 테스트는 있었지만, 생성된 코드가 도입한 정확한 실패 처리 의미론에 대한 테스트는 없었습니다.

실제로 사용하는 실용적인 해결책

  • 긴 대화를 안정적인 사양으로 취급하는 것을 중단했습니다. 이제 제약 조건을 하나의 메시지에 고정하고 주기적으로 다시 보냅니다.
  • 스레드가 오래 지속되면 간결한 시스템 메시지로 어시스턴트를 재설정하고, 레포에 버전, 환경 이름, 배포 정책을 나열한 짧은 매니페스트 파일을 유지합니다.
  • 모든 AI‑생성 스니펫을 로그에 기록하고, 엄격한 리소스 예산이 적용된 격리된 샌드박스에서 실행합니다.
  • 도구가 결과를 반환하지 않을 때는 어시스턴트가 도구 신뢰도를 명시적으로 선언하도록 하고, 그 후에 변경을 수락합니다.

제가 문제를 잡아낸 구체적인 방어책:

  • 생성된 인프라 변경을 기능 플래그 뒤에 두기.
  • 환경 및 버전 검사를 위한 런타임 어설션 추가.
  • CI가 모델이 수정한 정확한 실패 경로를 실행하는 통합 테스트를 실행하도록 설정.

교차 검증이 필요할 때는 공유 워크스페이스에서 병렬 프롬프트를 열어 모델 간 답변을 비교하고, 단일 스레드만 신뢰하지 않습니다. 이 비교 습관은 사실 및 문서 출처를 검증하는 구조화된 흐름과 함께 존재하므로, API에 대한 모델의 제안을 최종 답으로 여기지 않습니다. 공유 채팅 워크스페이스를 사용해 비교하고, 검증을 위한 더 깊은 연구 워크플로를 활용하면 이러한 관행을 덜 즉흥적으로 만들 수 있습니다.

Back to Blog

관련 글

더 보기 »

Logger 모듈을 사용한 FastAPI 기본 로깅

Application이 Production에서 충돌할 때 Production에서 애플리케이션이 충돌했으며 사용자는 다음에 무엇을 해야 할지 확신하지 못했습니다. 나는 작년에 이와 같은 상황을 프로젝트에서 경험했습니다.

🔥 PHPS 최악 디버그 악몽… 폐위! 🔥

PHP 개발자 여러분: 현실을 직시합시다 — 디버깅이 정말 힘들었습니다. Xdebug의 불안정함, IDE 리스너 설정, Docker 네트워킹, 그리고 끝없는 dd 호출 사이에서 우리는 많은 시간을 보냈습니다. ...