요즘 “이제 자연어로 다 되는데 코드를 왜 써”라는 말을 가끔 듣는다.
나도 한동안 그렇게 생각했다.
나는 혼자 쓰려고 개인용 AI 시스템을 하나 만들고 있다. 메모를 모으고, 글을 정리하고, 투자 기록을 남기는 걸 도와주는 작은 시스템이다. 그걸 만들면서 자꾸 같은 경계에 부딪혔다. 어디까지는 말로 시키면 되고, 어디부터는 코드가 필요한지. 한번 정리해두고 싶었다.
만들다 보니 세 종류로 갈렸다
내가 만드는 것들이 세 종류로 갈렸다.
- Skill — 부르면 한 번 일하고 끝나는 도구. 예를 들어 회사 이름을 넣으면 한 장짜리 분석 리포트를 만들어 주는 도구를 만들어 뒀다. 부르면 결과를 내놓고, 거기서 끝난다.
- Agent — 중간에 스스로 판단해서 다음을 정하는 것. 결과를 보고 “이건 다시 해야겠다”, “여기서 멈추자”를 스스로 결정한다.
- Workflow — 미리 정해둔 흐름대로 여러 개를 엮어 조율하는 것. 도구 A를 돌리고, 다음 B, 그다음 C.
이름이 달라서가 아니라, 하는 일의 성격이 다르다.
Skill도 판단은 한다
여기서 헷갈리기 쉬운 게 있다. “그럼 Agent는 판단하고 Skill은 판단 안 하나?” 아니다. Skill도 판단한다.
예를 들어 나는 메모 몇 개를 넣으면 블로그 초안을 뽑아 주는 도구를 쓴다.
이것도 Skill인데, 그 안에서 LLM이 어떤 톤으로 쓸지, 뭘 넣고 뺄지를 다 판단한다. 판단이 잔뜩 들어간다.
차이는 판단이 있느냐 없느냐가 아니다. 판단이 무엇을 정하느냐다.
Skill의 판단은 그 한 번의 결과물 안에서 끝난다. 초안을 어떻게 쓸지는 판단하지만, 그게 끝나면 일도 끝난다. 다음에 뭘 할지는 건드리지 않는다.
Agent의 판단은 다음 차례를 정한다. 다시 할지, 더 모을지, 다른 데로 넘길지. 판단이 일의 흐름 자체를 바꾼다.
그래서 Agent는 “이거 판단해줘”보다 “이 다음에 뭘 할지를 네가 스스로 정해서 수행해”에 가깝다.
갈림길은 질문 하나
그래서 뭘 만들지는 질문 하나로 갈린다.
이 일이 미리 정해진 순서로 끝나나?
끝나면 Skill이다. 중간에 “이제 뭘 하지”를 매번 판단해야 하면 Agent가 필요하다.
여러 개를 정해진 흐름으로 엮으면 Workflow이고,
해보니 대부분의 일은 Skill로도 충분했다. 스스로 판단하는 Agent는 생각보다 자주 필요하지 않았다.
말로는 안 되는 것들
그럼 자연어로 안 되는 건 뭔가.
사실 자연어도 결국 코드 위에서 돈다. 내가 말로 시키면, 그 말을 받아 실제로 실행하는 건 코드다. 그래서 진짜 질문은 “자연어냐 코드냐”가 아니라 “이 일을 말로 시킬 수 있나”다.
말로 시키기 어려운 게 몇 개 있었다.
첫째, 사람 없이 알아서 시작하는 일. 자연어는 누군가 말을 걸어야 시작된다.
매일 아침 7시에 저절로 실행되게 하려면, 정해진 시간에 일을 깨우는 코드가 따로 있어야 한다.
둘째, 실패하면 다시 하는 일.
“이건 실패다”라고 판단하고 처음으로 되돌리는 규칙은, 매번 말로 설명하기 어렵다. 코드로 박아둬야 한다.
셋째, 끝나도 기억해야 하는 일.
대화가 끝나면 맥락은 사라진다. 어제 한 걸 오늘 이어가려면, 어딘가에 저장해두는 코드가 있어야 한다.
정리하면 이렇다.
자연어는 “뭘 할지”를 말하는 데 좋고, 코드는 “언제, 어떻게, 실패하면 어떻게”를 정하는 데 필요하다.
매번 부를까, 한 번 굳힐까
요즘 이런 얘기를 봤다. LLM한테 매번 일을 시키지 말고, 그 일을 하는 코드를 한 번 짜게 시키라는 거다.
차이가 크다.
매번 LLM을 부르면, 같은 걸 시켜도 답이 조금씩 달라진다. 느리고, 부를 때마다 비용이 들고, 왜 그렇게 나왔는지 나중에 추적하기 어렵다.
대신 코드를 한 번 짜게 시키면, 그다음부터는 그 코드가 돈다. 같은 입력에는 늘 같은 출력이 나온다. 같은 걸 넣으면 늘 같은 게 나오는 성질, 이걸 결정론적이라고 한다. 빠르고, 추적되고, 천 번을 돌려도 똑같다.
LLM이 진짜 잘하는 건 그 코드를 짜 주는 일이지, 그 코드를 매번 대신 실행하는 일이 아니었다.
그래서 코드가 덜 중요해진 게 아니다. 오히려 더 중요해졌다. 한 번 정해두고 흔들리면 안 되는 부분은, 여전히 코드로 단단히 굳혀야 한다. LLM은 그 코드를 더 빨리 쓰게 도와줄 뿐이다.
나도 작은 걸 하나 붙들고 있다. 시스템이 스스로를 조금씩 고쳐 나가는 부분, 그리고 그게 시간이 지나며 원래 의도에서 슬슬 어긋나는 걸 잡아내는 부분. 그 둘을 위한 작은 프로젝트다.
사람 없이 매일 돌고, 점수를 시간 순서로 쌓고, 어디서 어긋나는지 본다. 이 뼈대는 코드로 굳혀야 한다. 판단의 일부는 LLM한테 맡기더라도, 재는 쪽이 매번 흔들리면 어긋남을 재겠다는 것부터 같이 흔들리니까.
처음 질문으로 돌아가면, “자연어로 다 되는데 코드를 왜 써”의 답은 이렇다.
그래서 결국 코드는 사라지지 않는다.
처음 질문으로 돌아가 보자.
“자연어로 다 되는데, 코드를 왜 써?”
내가 지금까지 얻은 답은 이렇다.
자연어로 다 되는 것처럼 보일수록, 오히려 흔들리면 안 되는 부분이 더 또렷해진다.
그 부분은 코드로 작성해야 한다.
반복되어야 하는 것, 추적되어야 하는 것, 실패해도 다시 돌아와야 하는 것, 시간이 지나도 기억되어야 하는 것은 코드로 굳혀야 한다.
자연어는 의도를 전달하는 데 강하다.
코드는 실행 조건을 고정하는 데 강하다.
LLM은 코드를 없애지 않는다.
다만 코드를 더 빨리 만들게 해준다.
아직은 대부분 말로 시킨다. 코드는 꼭 필요한 데만 넣는다. 다만 만들수록 조금씩 알게 된다.
말로 충분한 일과, 코드로 굳혀야 하는 일의 경계가 어디인지.