아무도 다시 쓰고 싶어하지 않는 코드가, 기후 정책을 만든다
ICML 2026. 레거시 과학 코드를 미분 가능 프레임워크로 이식하는 체계적 LLM 번역.
이 글은 ICML 2026에서 들은 발표 “Systematic LLM Translation of Legacy Scientific Code to Differentiable Frameworks”를 발표자 1인칭 시점으로 재구성한 것입니다.
500만 줄짜리 코드를 물려받았다고 상상해보자. 그것도 40년에 걸쳐 여러 세대의 과학자들이 손을 대며 쌓아온 코드를, 지금은 그 코드를 처음 짠 사람들 대부분이 은퇴하거나 떠난 상태에서 물려받았다고 말이다. 이 코드가 하는 일은 사소하지 않다. 국제 기후 정책에 반영되는 예측치를 만들어낸다. 그런데 정작 이 코드를 고칠 수 있는 사람은 해마다 줄고 있다. 나는 이 상황을 마주하면서 이상한 위화감을 느꼈다. 우리가 세상에서 가장 중요하다고 말하는 과학적 판단 중 일부가, 가장 적게 현대화된 소프트웨어 위에서 돌아가고 있다는 사실 말이다.
이게 바로 지구 시스템 모델(Earth system model) 이야기다. 대략 50만 줄에서 300만 줄에 이르는 포트란(Fortran) 코드로, 개발자 풀은 계속 줄어드는데 이 모델들을 현대화해야 한다는 공감대는 이미 오래전부터 있었다. 이유는 명확하다. 지금 우리가 답하지 못하는 과학적 질문들, 특히 새로운 방법론을 필요로 하는 질문들에 이 모델들을 쓰고 싶기 때문이다. 그런데 아키텍처와 호환성 문제 때문에, 정작 우리가 배우고 싶은 새로운 도구들과 이 모델들을 함께 쓸 방법이 없었다. 나는 콜로라도의 국립대기연구센터(NCAR)에서 개발되는 더 큰 지구 시스템 모델, CLM(Community Land Model)의 일부인 육상 표면 모델을 구체적인 사례로 삼았다.
문제를 더 들여다보면 왜 이게 단순한 코드 마이그레이션이 아닌지 알 수 있다. 지구 시스템 모델링 같은 레거시 과학 코드를 리팩터링하려면 그 도메인 커뮤니티가 수십 년에 걸쳐 쌓아온 물리적 가정과 파라미터화를 그대로 보존해야 한다. 그러니 사람이 손으로 다시 짜는 건 이 규모에서 애초에 불가능하고, 그렇다고 대형 언어 모델에게 한 번에 통째로 번역시키는 것도 답이 아니었다. 그래서 질문은 이렇게 좁혀졌다. 이렇게 거대한 지구 시스템 모델을, 빠르면서도 확장 가능하고, 게다가 미분 가능한 형태로 옮기려면 어떻게 해야 하는가.
지도부터 그리고, 에이전트에게 기억을 쥐어줬다
가장 먼저 한 일은 이 모델을 제대로 이해하는 것이었다. 40년 가까이 여러 사람의 손을 거친 코드는 종종 그 누구도 전체 그림을 갖고 있지 않다. 그래서 정적 의존성 분석부터 시작해 모델 전체를 DAG(방향성 비순환 그래프)로 그렸다. 이 그래프를 보면 본격적인 번역에 들어가기 전에 어디를 먼저 모듈화하고 정리해야 하는지가 보인다. 그리고 이 정보를 바탕으로 위상 정렬(topological sort)된 순서로 번역을 진행했다. 항상 의존하는 대상부터 먼저 번역하니 언어 모델이 아직 존재하지 않는 코드를 참조하는 일이 없고, 이미 번역된 코드가 계속 맥락으로 쌓이면서 환각(hallucination)을 최대 33%까지 줄여준다는 걸 확인했다.
그 다음으로 마주한 건 언어 모델의 근본적인 약점, 기억이었다. 우리는 외부 에이전트 메모리를 문서 형태로 따로 두기로 했다. 첫 번째 문서는 claude.md였다. 여기에 이 과학 코드베이스에 특화된 컨벤션과 요구사항을 정리해두었는데, 다른 지구 시스템 모델에도 그대로 쓸 수 있는 템플릿 형태로 만들었다. 에이전트가 프로젝트 도구를 쓰고 아키텍처를 이해하려 할 때 어떤 방향을 잡아야 하는지, 어디서부터 시작해야 하는지, 그리고 이 애플리케이션에 특화된 문서화 요구사항은 무엇인지를 담았다. 두 번째는 체인지로그였다. 이건 프로젝트의 외부 기억으로서, 컨텍스트 윈도우와 세션의 경계를 넘어 프로젝트 상태를 보존하고, 이전 대화 기록에 의존하지 않고도 작업을 재개할 수 있게 해준다. 장기적으로 토큰도 아낄 수 있고, 무엇보다 사람이 검증하기에도 좋다. 모델이 어디서 헤매고 있는지를 이 문서들만 봐도 알 수 있기 때문이다.
이 준비가 끝난 뒤, 실제 멀티 에이전트 파이프라인의 첫 단계는 검증 스위트를 만드는 일이었다. 이 모델에는 애초에 테스트가 거의 없었다. 그래서 포트란 코드를 스캔하고 이해하는 데 특화된 에이전트와, 그 이해를 바탕으로 기능 테스트를 생성하는 에이전트를 각각 두었다. 테스트가 만들어지면 실제로 한 번 실행해서 시뮬레이션 결과를 레퍼런스로 저장해두는데, 이게 이후 단계에서 점진적으로 검증할 수 있는 기준점이 된다.
숫자가 같다고, 끝난 게 아니었다
두 번째 단계가 실제 번역과 점진적 기능 검증이다. 여기엔 번역가, 테스터, 리페어 에이전트, 이렇게 세 에이전트가 붙는다. 각자 상태 문서를 먼저 확인하고, 앞서 정해둔 위상 순서에서 아직 번역되지 않은 다음 모듈을 집어온다. 번역된 코드는 테스터 에이전트로 넘어가는데, 기능 테스트가 있으면 곧바로 원본 포트란과 비교하고, 없으면 테스트 모범 사례나 프로퍼티 기반 테스트에 따라 그 자리에서 테스트를 새로 만든다. 테스터가 실패를 감지하면 리페어 에이전트가 반복적으로 고치는 루프에 들어가고, 통과할 때까지 다음 모듈로 넘어가지 않는다. 실제로 두세 번의 반복 이후 성공률은 대략 80에서 92% 사이였다.
여기서 끝이 아니라는 게 이 작업의 진짜 핵심이다. 모든 모듈이 개별적으로 번역되고 나면, 통합에 특화된 에이전트가 이 모듈들을 하나로 묶는다. 그렇게 만든 전체 컬럼(full column) 시뮬레이션을 돌려서 포트란 레퍼런스와 비교하는데, 이 단계에서는 어김없이 차이가 많이 발견된다. 그러면 전체 모델 단위에서 다시 반복적인 리페어 루프를 돈다. 이 루프가 끝나고 수치적 동등성(numerical parity)을 달성했다고 해서, 그걸로 다 끝났다고 생각하면 안 된다. 다음 단계는 미분 가능성 검증이다. 여기서 확인해야 하는 건 이 모델이 실제로 미분 가능한 방식으로 돌아가는가이고, 더 나아가 동료 연구자 Jack Stitt와 이야기를 나누며 확인했듯, 변수들 사이의 그래디언트가 물리적으로 말이 되는가이다. 이건 그래디언트가 특정 변수들 사이에서 물리적으로 어떤 모습이어야 하는지에 대한 도메인 지식이 필요한 지점이라, 미분 가능성 에이전트가 이 테스트들을 돌리고, 실패하거나 발산하는 경우를 다시 고쳐나간다.
이 마지막 단계의 실패들을 따로 분석해봤는데, 첫 번째 시도만으로 해결되는 버그가 약 88%였다. 나머지는 훨씬 덜 기계적인 문제라 사람의 개입이 필요했는데, 대표적으로 반복 솔버(iterative solver)가 관여하는 그래디언트가 해석적 보정 없이는 그냥 발산해버리는 경우가 그랬다.
이렇게 완성된 모델은 원래의 물리와 정확한 그래디언트, 수치적 동등성을 그대로 유지한다. 그리고 이 효율성 덕분에 파라미터 캘리브레이션 비용이 원래 모델보다 몇 자릿수는 저렴해진다. 파라미터 섭동(perturbation)을 샘플링하는 속도도 원래 포트란 모델보다 4.7배 빨라졌다. 이건 단순히 속도 문제가 아니라, 지금까지는 물어볼 수 없었던 완전히 새로운 종류의 과학적 질문들을 이 모델로 물어볼 수 있게 됐다는 뜻이다.
논문을 낸 뒤로 이 파이프라인을 다른 대기 모델에도 적용해봤는데, 원래보다 10배 큰 규모였다. 다음 목표는 CLM의 나머지 모든 컴포넌트에 이 방법을 적용해서, 전체를 끝에서 끝까지 미분 가능하게 만들고 이미 미분 가능해진 다른 컴포넌트들과 결합하는 것이다. 그렇게 되면 지금은 상상만 하고 있는 질문들을 실제로 던져볼 수 있는 날이 온다.
40년 된 코드 앞에서 나는 처음에 막막함을 느꼈다. 하지만 지금은 그 막막함이 오히려 출발점이었다는 생각이 든다. 코드를 이해하는 것부터, 기억을 남기는 것, 그리고 숫자가 같아 보여도 그래디언트가 물리적으로 맞는지 한 번 더 확인하는 것까지. 결국 이 모든 단계는 하나의 질문으로 수렴한다. 우리가 다음 세대에게 물려줄 코드는, 이번엔 그들이 계속 물어볼 수 있는 코드였으면 좋겠다는 것.