근래에 claude code 와 같은 AI 에이전트를 이것저것 만지다 보면, 기존 소프트웨어를 사용할 때와는 다른 종류의 감각을 만나게 된다는 생각이 든다. 이전의 소프트웨어들은 대개 개발자가 미리 설계해놓은 버튼과 메뉴, 폼과 API 의 흐름 안에서만 움직였다. 사용자는 허용된 경로를 따라 입력을 넣고, 소프트웨어는 그에 대응하는 정해진 출력을 내놓는다. 말하자면 이미 굳어진 길 위를 걷는 식이다.

하지만 AI 에이전트는 다르다. 사용자가 던지는 것은 종종 “무엇을 하라"는 목표 수준의 요청이고, 에이전트는 그 요청을 수행하기 위해 어떤 순서로 사고하고 어떤 tool 을 꺼내들지를 그때그때 판단한다. 판단 자체는 결국 LLM 엔진에 기대고 있지만, 중요한 것은 동작의 세부 로직이 사전에 빼곡하게 고정되어 있지 않다는 점이다. 이 지점이 내게는 이전의 소프트웨어들과 확연히 다른 결로 느껴진다.

비교하자면 이전의 소프트웨어가 정적 로직에 가까웠다면, AI 에이전트는 동적 로직에 가까운 성질을 가진다. 물론 완전히 무질서한 것은 아니다. 시스템 프롬프트와 권한, tool 목록과 실행 환경 같은 울타리 안에서 움직인다. 다만 그 울타리 안에서 어떤 길을 실제로 택할지는 런타임의 판단에 의해 결정된다. 개발자가 모든 분기문을 손으로 써넣는 대신, 판단의 주체 일부를 모델에게 넘긴 셈이다.

제어의 주체 변화

이 현상을 바라보면서 Spring 프레임워크를 공부할 때 자주 듣던 IoC 를 떠올렸다. 물론 정확히 같은 개념은 아니다. 그럼에도 제어의 중심이 이동한다는 점에서는 묘하게 닮아 있다. 기존 소프트웨어에서는 제어의 주체가 거의 전적으로 개발자였다. 반면 AI 에이전트에서는 그 제어의 일부가 런타임의 LLM 모델에게 넘어간다. 어쩌면 우리는 소프트웨어 패러다임의 전환 초입을 보고 있는 것인지도 모르겠다.

기존 소프트웨어는 결정론적 기계에 가깝다. 개발자가 if-else 구문과 상태 전이를 통해 분기점을 사전에 설계해놓고, 입력값 A 에 대해 결과 B 가 나오지 않으면 버그라고 판단한다. 논리가 고정되어 있으니 빠르고 예측 가능하다. 개발자의 입장에서도 무엇이 잘못되었는지를 역추적하기가 상대적으로 쉽다.

그에 반해 AI 에이전트는 추론 루프를 통해 사용자의 의도를 해석하고 가용한 tool 목록을 살핀 뒤, “지금 이 상황에서는 이 tool 을 쓰는 편이 가장 적절하다” 는 판단을 내린다. 인상적인 것은 그 판단 로직이 소스 코드 안에 고정된 채로 들어있는 것이 아니라 매 요청마다 동적으로 조립된다는 점이다. 말하자면 이전의 소프트웨어가 정해진 배선을 따라 전류가 흐르는 회로였다면, AI 에이전트는 실행 순간마다 회로 일부를 다시 짜는 시스템에 가깝다.

개발자의 역할 변화

이러한 에이전트들의 성능이 점차 개선되면 개발자들은 코딩과 디버깅 같은 작업에서 완전히 해방되지는 못하더라도, 적어도 그것만으로 변별력을 만들기는 어려워질 것 같다는 생각을 한다. 이렇게 말하는 것이 다소 씁쓸하긴 하지만, 코드를 직접 짜는 행위는 점점 구현 수단으로 밀려나고 무엇을 왜 만들어야 하는지를 정의하는 일이 더 앞단으로 올라올 가능성이 크다.

예를 들어 프로그래밍 언어의 문법을 익히고 프레임워크의 베스트 프랙티스를 체득하는 것만으로는 더이상 충분한 차별점을 만들기 어려울 수 있다. 그 자리를 문제 정의 능력, 의사 결정 능력, 맥락을 읽는 감각이 채우게 되지 않을까 싶다. 무엇이 진짜 문제인지 식별하고, 그것을 비즈니스 요구사항으로 번역하고, 다시 모호하지 않은 스펙으로 구조화하는 능력이 더욱 중요해질 것이다.

사실 개발이라는 일은 애초에 코드를 많이 쓰는 사람을 가리는 게임이라기보다는 문제를 정확히 구조화하는 사람을 가리는 일에 더 가까웠는지도 모르겠다. 다만 그동안은 구현 난이도가 높았기 때문에 그 사실이 덜 도드라졌을 뿐이다. 에이전트가 구현의 마찰을 낮추기 시작하면, 그 밑에 깔려 있던 본질이 더 선명하게 드러날 것이다.

액체 같은 소프트웨어

여기서 한발 더 나아가면 어떻게 될까 하는 생각도 해본다. 여기서부터는 정말 순수하게 망상에 가까운 이야기다. 하지만 요즘 돌아가는 속도를 보고 있으면 마냥 허황된 이야기처럼만 들리지는 않는다. 추론 루프 상의 지연이 지금보다 훨씬 줄어들고, 런타임에서 스스로 동작을 바꿔나가는 비용이 충분히 낮아진다면 지금과는 상당히 다른 형태의 소프트웨어가 등장할 수도 있겠다.

이 아이디어를 설명하기 위해 굳이 비유를 가져오자면, 지금까지의 소프트웨어는 대체로 ‘고체’에 가까웠다. 한 번 빌드되어 배포되면 누군가 코드를 수정하고 다시 배포하기 전까지는 그 형태가 유지된다. 물론 설정값과 feature flag 로 어느 정도 유연성을 만들 수는 있었지만, 그 유연성의 범위 역시 개발자가 미리 설계해놓은 틀 안에 있었다.

하지만 앞으로의 소프트웨어는 액체에 가까운 성질을 가질 수도 있다. 필요한 로직이 JIT (Just-In-Time) 으로 생성될 수도 있고, 사용자의 요청이 들어오는 순간 그 요청에 최적화된 일회성 실행 로직을 즉석에서 조립하고 실행한 뒤 폐기할 수도 있을 것이다. 그리고 그 로직이 반복적으로 유효하다고 판단되면 캐싱되거나 정식 경로로 승격될 수도 있겠다. 지금 우리가 함수나 클래스를 미리 만들어두고 호출하던 자리에, 순간적으로 생성되고 사라지는 실행 조각들이 들어오는 셈이다.

조금 더 과감하게 상상해보면 시스템이 스스로의 부하를 모니터링하다가 특정 구간에 병목이 생겼을 때, 단순히 autoscaling 을 거는 수준을 넘어 구조 자체를 재구성하는 일도 가능할 수 있다. 어떤 요청 패턴이 몰리는지, 어느 레이어의 비용이 비정상적으로 큰지, 어떤 캐시 전략이 더 유효한지를 시스템이 스스로 판단해 임시 구조를 조립해내는 식이다. 개발자 입장에서는 꽤 피곤한 미래일 수도 있겠다.

재현성의 상실과 책임 문제

물론 기존 소프트웨어를 다루던 관점에서 보면 이는 문제 덩어리다. 소프트웨어의 상태나 학습된 문맥에 따라 동일한 요청이 어제는 이렇게 처리되고 오늘은 저렇게 처리되는 일이 자연스러워질 수도 있다. 즉, 우리가 오랫동안 소프트웨어의 핵심 속성처럼 여겨왔던 재현성이 약해지는 것이다. 장애 분석, 감사 로그, 테스트 전략, 책임 추적 같은 문제들이 한꺼번에 더 어려워진다.

또한 동적으로 생성되는 로직을 누가 어디까지 관리 감독할 것인가에 대한 책임 문제도 남는다. 시스템이 요청을 처리하는 과정에서 개인 정보가 다른 경로로 새어나가거나, 특정 사용자군에게만 편향된 의사 결정을 내리거나, 설명할 수 없는 방식으로 우회 동작을 만들어냈을 때 그 책임은 누구에게 귀속될까. “모델이 그렇게 판단했다” 는 말은 법적 책임도, 운영 책임도 대신 져주지 못한다.

그럼에도 이러한 소프트웨어의 등장이 마냥 비현실적으로만 느껴지지 않는 이유는, 앞서 이야기한 문제점들마저 비즈니스 논리로 덮어버릴 가능성이 충분히 있기 때문이다. 비용 대비 효용이 압도적으로 좋아지는 순간 산업은 종종 기존의 원칙을 다시 정의해왔다. LLM 모델은 점차 경량화되고 있고, 온디바이스 AI 와 추론 최적화가 뒷받침된다면 단위 요청 당 추론 비용은 지금보다 상당한 정도로 더 낮아질 수 있다.

비용 문제가 해결되는 순간, 우리가 기존에 소프트웨어의 필수 속성으로 여겼던 것들, 이를 테면 재현성, 고정된 로직, 개발자의 명시적 제어 같은 것들은 더이상 절대 조건이 아니라 트레이드 오프의 대상으로 밀려날 수도 있다. 물론 이 상상이 과장일 수도 있다. 하지만 요즘의 변화를 보고 있으면 소프트웨어의 액체화라는 방향 자체는 생각보다 빠르게 현실의 언어가 될지도 모르겠다는 생각이 든다.