Agents에는 더 많은 프롬프트가 아니라 제어 흐름이 필요하다
(bsuh.bearblog.dev)- 복잡한 작업을 안정적으로 처리하는 에이전트에는 더 정교한 프롬프트 체인이 아니라, 소프트웨어에 인코딩된 결정적 제어 흐름이 필요함
- 프롬프트에서 MANDATORY나 DO NOT SKIP 같은 표현에 의존한다면 프롬프팅의 한계에 도달한 상태임
- 문장이 제안처럼 동작하고 함수가 환각하면서 “Success”를 반환하는 프로그래밍 언어를 상상하면, 복잡도가 커질수록 추론이 불가능해지고 신뢰성이 무너짐
- 소프트웨어는 라이브러리, 모듈, 함수로 구성되는 재귀적 조합성을 통해 확장되며, 예측 가능한 동작을 제공하기 때문에 국소적 추론이 가능함
- 프롬프트 체인은 좁은 작업에는 유용하지만, 비결정적이고 명세가 약하며 검증하기 어려워 같은 성질을 갖지 못함
에이전트 신뢰성에 필요한 구조
- 신뢰성을 확보하려면 논리를 자연어 설명에서 꺼내 런타임으로 옮겨야 함
- 필요한 구조는 LLM을 전체 시스템이 아니라 하나의 구성요소로 다루는 결정적 스캐폴드임
- 이 스캐폴드는 명시적 상태 전이와 검증 체크포인트를 포함해야 함
- 결정적 오케스트레이션만으로는 충분하지 않으며, 조용히 실패할 수 있는 시스템에는 공격적인 오류 감지가 필요함
- 프로그램적 검증이 없으면 선택지는 세 가지로 줄어듦
-
감시자(Babysitter)
- 사람이 루프 안에 남아 오류가 전파되기 전에 잡아야 함
-
감사자(Auditor)
- 실행이 끝난 뒤 전체 결과를 철저히 검증해야 함
-
기도(Prayer)
- 결과를 분위기상 받아들이는 방식에 의존하게 됨
-
Hacker News 의견들
-
1000% 동의함. Anthropic이 계속 말하는 “미래 모델의 성능을 기준으로 만들라, 곧 더 좋아진다”는 북소리를 점점 믿기 어려워짐
브라우저 세션에서 요구사항 Markdown 파일 200개를 훑는 QA 에이전트를 만들었고, 팀 효율을 크게 올려준 좋은 시스템이었음. 하지만 “이 디렉터리의 요구사항 파일을 보고, 각 파일마다 앱이 그 요구사항을 만족하는지 확인할 할 일 항목을 만들어라”처럼 고수준 제어 흐름을 모델에게 맡기면 30개쯤부터 무너졌음
파일을 빠뜨리거나, 일부 파일 묶음을 세 번씩 테스트해서 3분 걸릴 일을 10분 걸리게 하거나, 한 파일의 오류 때문에 이전 파일 4개를 이유 없이 다시 테스트하기도 했음. Opus 4.6과 GPT 5.4, 가볍게 본 Opus 4.7과 GPT 5.5에서도 워크플로 오케스트레이션 능력은 일관성이 없었음
결국 모델 주변에 아주 단순한 결정적 하네스를 만들었고, 각 테스트 케이스마다 모델을 호출해 테스트하고 결과를 배열에 저장한 뒤 파일로 쓰게 했더니 시스템 신뢰성이 압도적으로 좋아짐. 하지만 Cursor Cloud Agents나 Anthropic 같은 관리형 에이전트 플랫폼은 “에이전트가 전부 실행해야 한다”에 너무 꽂혀 있어서, 적절한 지점에 약간의 결정성을 넣는 가치가 보이지 않는 듯함- 예전에는 그들이 프롬프트만 쓰는 워크플로로 사람들을 밀어 넣는 이유가 토큰 비용은 받지만 사용자가 만든 스캐폴딩에는 돈을 못 받기 때문이라고 생각했음. 지금은 오히려 그런 스캐폴딩을 누군가 설계하고 구현해야 한다는 점을 두려워하는 것 같음
이 기술이 전체 사람이나 전체 워크플로, 프로젝트를 대체한다는 주장에 찬물을 끼얹기 때문임. 생산성을 크게 올려 개발자 채용시장과 임금에는 재앙적 영향을 줄 수 있다고 보지만, 이 특정 기술의 현재 버전이 그들이 말하는 수준까지 갈 것 같지는 않음. “인간 개발팀의 잡무 상당 부분을 줄여주는 매우 유용한 도구”라고 포지셔닝했다면 개발자들은 원하지만 임원들은 덜 원할 것이고, 투자자들도 가만두지 않았을 듯함
또한 세밀하고 강하게 통제되는 단계는 테스트 자동화나 CSI 팬픽 5권을 순식간에 쓰는 거대한 모델보다, 더 작고 싸고 전문화된 모델을 붙이기에 훨씬 친화적임 - 이건 모델을 평가하는 벤치마크 방식 자체에서 비롯됐을 수도 있음
일부 벤치마크는 문제 하나에 여러 번 시도하게 한 뒤, 실패율은 무시하고 성공한 결과가 한 번이라도 나오면 그 결과만 채택하지 않나? - 동의함. 이런 시스템을 신뢰성 있게 만드는 유일한 방법은 문제를 작은 덩어리로 쪼개는 것임. 내부 일관성 검사도 결국 LLM이 기대보다 훨씬 덜 일관적이라는 사실을 보여줄 뿐임
apply_patch같은 도구에check_compilation과run_unit_tests를 결합한 뒤 성능이 크게 좋아졌음. 도구 이름은 여전히apply_patch지만, 이제 패치가 성공하면 빌드와 테스트에 대한 추가 정보도 반환함
에이전트 성공률이 약 80%에서 지금까지는 거의 결정적으로 보이는 수준까지 올라감. 이제 프롬프트에 컴파일과 단위 테스트 과정을 굳이 설명하지 않고, 어떤 의존 조건으로 실행되면 그 결과만 반환하면 됨
요즘 유행에서 멀어지는 느낌도 듦. 오래전부터 선불 토큰과 커스텀 하네스를 써왔고, 그냥 잘 작동함. 대부분의 뉴스는 무시해도 됨. 명시적으로 겨냥한 문제들에서는 Copilot류 도구가 더 이상 쓸모없고, 어떤 코드베이스에서는 같은 GPT 5.4 기반 모델을 쓰는데도 성능 차원이 아예 다름- 비밀은 그 오케스트레이션 프롬프트를 “컴파일”하는 것임. 프롬프트를 코드로 바꾸면, 그 코드가 다시 에이전트를 실행하거나 코드를 실행하거나 둘 다 할 수 있어 결정성 문제가 풀림
모두가 스킬에서 이 패턴을 놓침.SKILL.md옆에 코드를 같이 두면 특정 동작을 보장할 수 있는데, 다들 이상하게 프롬프트 작성에 중독돼 있음. CLI를 만들 필요도 없고, 작업이 들어 있는 단순한skill.py면 충분함.claude -p를 호출하는 헬퍼도 둘 수 있음
- 예전에는 그들이 프롬프트만 쓰는 워크플로로 사람들을 밀어 넣는 이유가 토큰 비용은 받지만 사용자가 만든 스캐폴딩에는 돈을 못 받기 때문이라고 생각했음. 지금은 오히려 그런 스캐폴딩을 누군가 설계하고 구현해야 한다는 점을 두려워하는 것 같음
-
몇 년 뒤에도 사람들이 LLM을 쓰긴 하지만, 결국 배워야 하는 통제된 어휘와 문법을 통해서만 쓰게 되면 웃길 것 같음. 15년 전 모두가 NoSQL로 옮겨가더니 곧바로 JSON 안에 스키마를 다시 만든 것과 같음
-
문제의 일부는 애초에 LLM을 잘못 적용한 데 있지 않을까 싶음. 다른 곳에서도 나온 것처럼, 에이전트의 프롬프트는 가능한 한 반복 가능하고 검증 가능하며 결정적인 방식으로 작업을 수행하는 코드를 작성하라가 되어야 할 수도 있음
에이전트 출력 검증도 포함되어야 함. 전체 목표는 프로그램으로 더 효율적이고 자주 더 정확하게 처리할 수 있는 작업에서 LLM을 빼는 것임- 100% 동의함. 90% 맞는 비결정적 도구를 사용해 100% 맞는 결정적 도구를 만들게 해야 함. 내가 프롬프트에 꼭 넣는 핵심 문장 중 하나는 “모호한 경계 사례를 만나면 나에게 문의해 달라”임
AI를 프로덕션에 붙여 API 호출로 직접 무언가를 하게 하는 건 나쁨. 앱에서 AI가 해야 할 유일한 용도는 읽기, 분류 같은 것이라고 봄. 예전 CRUD 앱의 “R”을 대체하는 정도임
같은 AI 기반 “R” 엔드포인트로 프롬프트에 따라 “C”, “U”, “D” 폼을 자동 채우는 건 괜찮지만, 사람이 검토하기 전에 고객을 위해 무언가를 변경해서는 안 됨. CRUD 앱은 여전히 CRUD 앱이고 앞으로도 그럴 것이며, 다만 고객이나 내부 도구, Jenkins 파이프라인 등에 폼 자동완성이나 행동 제안을 해주는 매우 똑똑한 “R” 엔드포인트가 생긴 것뿐임. 행동을 제안할 수는 있어도 직접 실행해서는 안 됨 - 대부분 조직에서 흐름은
llm -> prompt -> result,llm -> prompt + prompt encoded as skill -> result,llm -> prompt + deterministic code encoded as skill -> result로 가는 듯함
초기에 코드 생성을 프롬프트로 시키면 결정적 코드로 가는 길을 단축할 수는 있지만, 여전히 비결정적 래퍼 안에 결정적 코드를 넣는 셈임. 장기 과제를 성공시키려면 많은 경우 빠져 있는 결정성 계층이 필요함
에이전트 루프나 프레임워크를 통해 비결정적 경계 밖에 결정적 코드를 둬야 함. 그러면결정적 에이전트 흐름 -> 비결정적 의사결정 -> 결정적 도구처럼 비결정적 판단이 결정성 계층 사이에 끼게 됨. 실험에서 매우 강력한 패턴이었고, auto-researcher 같은 도구로 에이전트가 스스로 결정성을 만들면 더 강해짐 - 우리도 같은 경험을 했음. 처음에는 에이전트가 데이터 구조를 특정 방식으로 조작할 수 있는 도구 목록을 줬는데, 이 방식은 꽤 취약했음
지금은 작은 도메인 특화 언어와 단일 도구를 쓰고, 에이전트가 그 언어로 작성한 스크립트를 입력하게 함. 더 동적인 사용 사례를 처리할 수 있고, 잘못된 문법은 파서가 쉽게 잡아 에이전트에 되돌려줄 수 있음 - 문제는 프로그램이 해석이 필요한 경계 사례를 자주 만나고, 그 순간 LLM에게 그 경계 사례를 처리하게 하고 싶어지며, 그러다 보면 전체 반복문과 도구 호출까지 LLM에게 맡기고 싶어진다는 것임
- 마지막 프로젝트에서 하드웨어를 제어하는 서버와 모바일 앱 사이의 인터페이스 라이브러리 생성을 자동화할 때 정확히 이렇게 했음
하드웨어 제어팀은 문서와 스프레드시트로 명세를 전달했고, 모바일팀은 그것을 보고 인터페이스 라이브러리를 코딩한 뒤 서버와 맞춰 검증했음. 나는 문서를 TSV로 바꾸고 일부를 Claude에 보내, 사람이 쓴 명세의 미묘한 부분을 유지하는 TSV 파서를 작성하게 했음
모든 경계 사례를 처리하고 중간 결과를 JSON으로 생성하기까지 150회 넘는 반복이 필요했음. 이후 Claude가 Apollo 위에 커스텀 접착 코드를 얹어 모바일 앱이 소비하는 코드를 생성하는 코드 생성기를 작성하는 데 도움을 줌
이 전체 파이프라인은 Github Actions의 일부로 돌고, 라이브러리 검증기가 실패할 때만 Claude를 호출함. 실패 시 무엇이 잘못됐는지 파악하고 해결책을 제안하고 PR을 만들도록 요청에 포함되는 md 파일이 있음. 그 뒤 사람이 검토, 수정, 병합함. 여기까지 든 총 크레딧은 350달러 미만임
- 100% 동의함. 90% 맞는 비결정적 도구를 사용해 100% 맞는 결정적 도구를 만들게 해야 함. 내가 프롬프트에 꼭 넣는 핵심 문장 중 하나는 “모호한 경계 사례를 만나면 나에게 문의해 달라”임
-
취지에는 동의하지만 결론은 바뀌어야 한다고 봄. 프롬프트의 한계에 부딪히면, 실행 시점에 LLM으로 작업을 수행하려 하기보다 작업을 수행할 소프트웨어를 LLM으로 작성하게 해야 함
실행 시점의 LLM 역할은 보통 사용자가 엄격한 비즈니스 규칙을 내장한 소프트웨어 시스템에 맞는 입력을 고르도록 돕는 정도로 줄어들 것임- 회사에서 몇 주 여유가 생겨서 노트 작성, 작업 추적, 문서 관리 같은 업무 프로세스에 에이전트를 넣어보기로 했는데, 이 말이 내 경험과 정확히 일치함
첫 주는 프롬프트가 계속 커지고 성능은 떨어졌음. 둘째 주에는 노트, 작업, 프로젝트, 사람 같은 객체를 정확히 정의하고, 그 객체들에 대해 잘 정의된 작업을 수행하는 메서드를 정의하는 데 집중했음. 지적한 대로 에이전트 표면은 자연어를 입력 검증기를 통과하는 명령과 인자로 바꾸는 번역 계층으로 줄어듦 - 완전히 한 바퀴 도는 시스템 프롬프트라면 “자신을 실직시키기 위해 자동화할 수 있는 모든 기회를 찾아라. 코드가 답할 수 있는 질문을 받으면 코드를 작성하고 실행해서 결과를 얻어 답하라”가 될 것임
이런 LLM이라면 strawberry 테스트에서 더 잘했을 수도 있음 - 이 포럼에서도 소프트웨어의 미래가 생성형 AI를 사용해 실행 시점에 생성되고 적응되는 프로그램에 있다고 보는 견해가 있었음. 거기까지 얼마나 남았는지는 모르겠음
- 모델이 특정 문제 해결 방식에 갇히고, 다른 방식으로 전환하라는 넛지가 필요했던 사례를 봤음. 예를 들어 오디오 스트림의 핫플러그/언플러그를 처리하려고 시스템 서비스 설정을 잔뜩 만지는 대신, 실제로 필요했던 건 Python 수십 줄을 쓰는 것이었음
Claude가 내 워크플로에서 테스트 실행 같은 흔한 경우를 처리하는 셸 스크립트 몇 개를 스스로 쓰게 했음. 이제는 30분 동안 빙빙 돌지 않고 그 도구들을 실행해 설정을 마침
무언가를 하려고 일회성으로 기괴한 셸이나 Python 한 줄짜리 실행 허가를 물을 때마다, 자동 승인할 수 있는 도구를 쓰게 해야 하는지 생각하게 됨
- 회사에서 몇 주 여유가 생겨서 노트 작성, 작업 추적, 문서 관리 같은 업무 프로세스에 에이전트를 넣어보기로 했는데, 이 말이 내 경험과 정확히 일치함
-
그래서 “다음 세대 AI”라는 표현을 자주 씀. 단순히 LLM만 뜻하는 게 아님. LLM은 꽤 멋지고, 기초적인 발전이 더 없더라도 더 흥미로운 방식으로 활용되고 최적화되면서 계속 가치가 나올 것이라고 봄
하지만 어떤 부분은 어떤 형태로든 근본적인 다음 세대 개선이 필요해 보임. LLM이 “절대 X 하지 마라”를 흐릿하게 만들어버리고, 많은 작업 끝에도 “제발 X 해라”처럼 받아들이는 현상은 작동 방식의 근본에 가까워 보임. 우리가 아직 무엇을 할 수 있는지 알아내는 초기 흥분 속에 있어서 잊기 쉽지만, LLM이 AI에서 우리가 찾는 모든 것은 아님
“절대 X 하지 마라”를 인간처럼 다루는 구조가 있어야 함. “문맥 창” 대신 인간과 비슷한 기억 계층을 갖는 구조도 있어야 함. 처음에는 같은 AI였더라도 두 사람이 충분히 긴 대화를 나누면, 결과적으로 두 AI가 단지 문맥 창만 다른 게 아니라 실제로 서로 다른 개체가 되는 식임
물론 그 모습이 어떨지는 누구도 모름. 다만 LLM이 AI의 최종 답이라고 생각할 이유도 없음- 내 생각에는 실제 기억이 필요함. 지금의 기억은 넓게 보면 AI가 스스로 써두고 매번 확인하는 포스트잇 체계에 가깝지, 학습을 가능하게 하고 더 유연하게 발동되는 통합 시스템은 아님
- 재미있는 예시가 있음 https://www.youtube.com/watch?v=kYkIdXwW2AE&t=315s
-
프롬프트 강제 → 결정적 흐름 → 프롬프트 강제로 한 바퀴 돌아온 입장에서 동의하지 않음
“건너뛰지 마라”가 실패하는 이유는 에이전트가 너무 많은 일을 맡고 있고, 문맥 안의 다른 내용들이 이 지침에서 주의를 빼앗기 때문임
하지만 강제를 담당하는 에이전트가 꼭 만드는 에이전트와 같아야 한다고 한 사람은 없음. 결정적 제어 흐름에 똑똑한 의사결정 로직을 어느 정도 인코딩할 수는 있지만, 너무 경직되게 만들면 잘 작동하지 않고, 너무 복잡하게 만들면 차라리 에이전트를 쓰는 편이 설정과 유지보수 비용이 더 쌈
기본적으로 필요한 건 세 종류의 에이전트임. 루프를 관리하고 문제가 생기면 적절한 것을 가동하는 감독자, 적절한 에이전트에 위임하고 필요한 곳에서 가드레일을 강제하는 오케스트레이터, 작업 단위를 실행하는 작업자임- 맞음, 그냥 에이전트를 더 추가하면 됨
-
내가 보기엔 모든 하네스가 이 측면에서 잘못되어 있고, 어떤 것은 심하게 잘못되어 있음
예를 들어 슬래시 명령은 잘못된 기능임. 문맥 창 상태나 이번 세션에서 쓴 돈을 확인하려고 챗봇이 한 턴을 끝낼 때까지 기다릴 필요가 없어야 함. 제어는 채팅 루프와 직교해야 함
텍스트 생성기의 입력과 출력을 제어하는 것과 아무 상관 없는 것들까지 “채팅이니까 IRC 봇처럼 굴려보자”는 이유만으로 채팅 동작에 얽혀 있음
요즘 LLM 에이전트는 엄청 많지만, 제어와 에이전트 루프와 표현 계층을 제대로 분리한 것은 거의 없음. 몇몇은 최소한 헤드리스 모드가 있어서 그건 좋음- 무슨 말을 하려는지는 알겠지만, 실제로 제안한 아키텍처를 만드는 건 훨씬 어려움. 직접 만들어서 대기업에 채용을 노려보는 건 어떰?
- codex CLI에서는 턴 도중에도
/status가 잘 작동함
다른 것들은 그렇지 않지만 - Codex 데스크톱 앱을 씀. GUI에서 문맥 표시기와 사용량 통계를 볼 수 있음
대화 사이를 오가고 업데이트를 보기에도 더 편함. 가끔 터미널에서 Claude Code나 opencode를 쓰는데, Codex 데스크톱 앱에 비해 경험이 훨씬 나쁨
-
“문장이 제안이고 함수가 환각하면서 ‘Success’를 반환하는 프로그래밍 언어를 상상해보라. 추론은 불가능해지고, 복잡도가 커질수록 신뢰성은 무너진다”는 말은 본질적으로 선언형 프로그래밍에 가까움
대부분의 전통적 프로그래밍은 개발자에게 익숙한 명령형임. 정확한 지시 집합을 주고, 내가 쓴 대로 따르길 기대함. 에이전트는 명령형보다 훨씬 선언형에 가까워서, 결과를 주면 그 결과를 얻기 위해 작업함
물론 SQL 같은 선언형에서는 결과가 꽤 일관적이고 잘 정의되어 있지만, 그래도 어떻게 처리할지는 내부 엔진을 신뢰하는 것임. 에이전트를 선언형으로 생각하니 루브 골드버그식 “제어” 시스템을 설계하려 할 때보다 도움이 많이 됐음. 맞지 않으면 검증해서 틀렸다고 보고 다시 시도하거나 다른 접근을 택하면 됨
정말 명령형이 필요하면 명령형으로 쓰면 됨. 또는 에이전트에게 그렇게 쓰게 하면 됨. 이건 작업에 맞지 않는 도구를 쓰려는 것처럼 읽힘- 선언형보다 한 단계 더 추상적인 것 같음. “서사형 프로그래밍”이라고 부를 수 있지 않을까? 물론 “프로그래밍”이라는 단어가 여전히 맞는지도 논쟁할 수 있음
선언형처럼 보일 수는 있지만, 그건 환상 안에서의 일임. 우리는 실제로 AI에게 목표를 설명하고 해석시키는 게 아니라, 인간 대역 캐릭터가 컴퓨터 캐릭터와 대화하는 이야기 문서가 있고, 현실의 우리는 LLM이 그 뒤에 더 응집력 있는 이야기를 이어 붙여 그 안에서 유용한 것을 캐낼 수 있기를 바라는 것임
단순한 학술적 구분이 아님. 이야기가 있다는 걸 알면 입력과 출력의 관계를 이해하고 전략을 세우는 모델이 더 좋아짐. 예를 들어 프롬프트 주입 같은 위험을 이해하는 데 도움이 되고, 어떤 학습 데이터를 넣거나 빼야 하는지에도 지침을 줌 - 선언형을 떠올리긴 했지만 SQL보다는 PROLOG를 생각했음. 실제 제어 흐름과 추론 능력이 있는 쪽임
그러면 LLM과 비슷한 문제, 즉 아주 조심하지 않으면 조용한 실패, 반복, 모순에 부딪힘. 본질은 같은 폐쇄 세계 가정 문제일 수도 있음. LLM에서는 이것이 모른다고 인정하기보다 환각으로 나타남 - 동의함. 하지만 에이전트에게 명령형으로 말할 수도 있음. “여기 구체적 단계가 있으니 따르라”고 해도 여전히 망칠 수 있음. 찾는 것은 명령형성이 아니라 결정성임
그리고 말한 대로 비결정적 LLM에 선언형으로 “이 최종 상태로 데려가라”고 지시하면 궤도를 벗어날 가능성이 더 커짐 - SQL의 선언성은 관계 대수라는 수학에 기반하므로 매번 같은 결과를 반환함. 매 쿼리마다 같은 시간 안에 반환하느냐는 인덱스와 데이터베이스 크기에 달려 있음
하지만 쿼리 자체가 LLM처럼 바뀌지는 않음
- 선언형보다 한 단계 더 추상적인 것 같음. “서사형 프로그래밍”이라고 부를 수 있지 않을까? 물론 “프로그래밍”이라는 단어가 여전히 맞는지도 논쟁할 수 있음
-
이 문제를 꽤 많이 생각해왔음. 전문화에 대한 이야기와도 연결될 수 있음. 모델이 더 전문화될수록 기초 수준의 능력은 오히려 줄어드는 것처럼 보이고, 아주 약간의 추상화를 목표로 하면 양쪽의 장점을 얻을 수도 있음
꽤 구체적인 예지만 생각거리로 볼 만함
Podcast 20분 요약: https://pub-6333550e348d4a5abe6f40ae47d2925c.r2.dev/EP008.ht...
논문: https://arxiv.org/abs/2605.00225 -
2023년 Auto-GPT 때도 이미 보였음. 사람들은 GPT가 “운전”하게 했지만, 대부분의 경우 실제로 필요했던 건 Python 열 줄과 아마
llm()함수 호출 몇 번이었음
대안은 그 열 줄짜리 Python을 가능한 한 가장 비싸고, 느리고, 덜 신뢰할 수 있는 방식으로 실행하는 것임. 물론 인기는 많았음
예를 들어 대부분은 에이전트를 인터넷 조사에 썼음. 몇 시간씩 돌다가 산만해지거나 원래 하던 일을 잊어버렸음
반면import duckduckgo와import llm으로 20초 만에 같은 일을 하는 열 줄짜리 코드를 쓸 수 있고, 실제로 결정적으로 실행되며 비용은 50배 덜 듦
현재 모델은 훨씬 좋아졌고, Auto-GPT가 이제는 현실이 될 만큼 충분히 좋아졌음. 하지만 부실하게 명세된 제어 흐름을 가능한 가장 비싼 방식으로 실행하는 건 여전히 나쁜 생각임