Metadata
Context Engineering: 프롬프트에 엔지니어링 규율을 도입하기--3부
다음 글은 애디 오스마니(Addy Osmani)의 원문 「 Context Engineering: Bringing Engineering Discipline to Parts」 3부 중 마지막 글이다. 1부는 여기 에서, 2부는 여기에서 볼 수 있다.
컨텍스트 엔지니어링(context engineering)은 매우 중요하다. 하지만 완전한 LLM 애플리케이션을 구축하려면 더 큰 스택(stack)이 필요하며, 여기에는 제어 흐름(control flow), 모델 오케스트레이션(model orchestration), 도구 통합(tool integration), 가드레일(guardrails) 같은 요소도 함께 들어간다.
안드레이 카파시(Andrej Karpathy)의 표현을 빌리면, 컨텍스트 엔지니어링은 실제 LLM 앱을 구동하는 “ 새롭게 형성되고 있는 두터운 비정형 소프트웨어 계층의 작은 한 조각(one small piece of an emerging thick layer of non-trivial software) ”이다. 즉, 지금까지는 좋은 컨텍스트를 어떻게 구성할지에 초점을 맞췄지만, 그것이 전체 아키텍처에서 어디에 들어맞는지도 함께 봐야 한다.
프로덕션급 LLM 시스템은 보통 프롬프트만으로는 해결되지 않는 여러 문제를 다뤄야 한다. 예를 들면 다음과 같다.
- 문제 분해(problem decomposition)와 제어 흐름(control flow): 사용자 질의를 하나의 거대한 프롬프트로 처리하는 대신, 견고한 시스템은 문제를 여러 하위 작업이나 다단계 워크플로로 나누는 경우가 많다. 예를 들어 AI 에이전트(agent)는 먼저 계획을 개요로 정리하라는 프롬프트를 받고, 그다음 단계들에서 각 단계를 실행하라는 프롬프트를 받을 수 있다. 이런 흐름을 설계하는 일, 즉 어떤 프롬프트를 어떤 순서로 호출할지, 분기나 반복은 어떻게 결정할지는 전형적인 프로그래밍 작업이다. 다만 여기서의 “함수(function)”는 컨텍스트를 포함한 LLM 호출이라는 점이 다르다. 컨텍스트 엔지니어링은 각 단계의 프롬프트에 필요한 정보가 빠짐없이 들어가도록 해 준다. 하지만 애초에 단계를 둘지 말지를 결정하는 일은 그보다 상위 수준의 설계 문제다. 여러 LLM 호출과 도구 사용을 조율하는 스크립트를 사실상 작성하게 되는 프레임워크가 많은 이유도 여기에 있다.
- 모델 선택(model selection)과 라우팅(routing): 작업에 따라 서로 다른 AI 모델을 이용할 수 있다. 간단한 작업이나 초안 응답에는 경량 모델을, 최종 해답에는 대형 모델을 쓸 수 있다. 또는 코딩 작업에는 코드 특화 모델을, 대화형 작업에는 범용 모델을 쓸 수도 있다. 그러려면 시스템에 요청을 적절한 모델로 보내는 로직이 필요하다. 각 모델은 컨텍스트 길이 제한이나 포맷 요구 사항이 서로 다를 수 있으므로, 컨텍스트 엔지니어링도 이를 고려해야 한다. 예를 들어 작은 모델에는 컨텍스트를 더 과감히 잘라야 할 수 있다. 이 부분은 프롬프팅보다 엔지니어링에 가깝다. 적합한 도구를 적합한 작업에 연결하는 문제라고 보면 된다.
- 도구 통합(tool integrations)과 외부 동작(external actions): AI가 API 호출, 데이터베이스 질의, 웹페이지 열기, 코드 실행 같은 동작을 할 수 있다면, 소프트웨어는 그런 기능을 관리해야 한다. 여기에는 사용 가능한 도구 목록과 사용 지침을 AI에 제공하는 일, 실제로 도구 호출을 실행하는 일, 그리고 결과를 수집하는 일이 포함된다. 앞서 살펴봤듯이, 그 결과는 이후 모델 호출을 위한 새로운 컨텍스트가 된다. 아키텍처 관점에서 보면 앱은 흔히 다음과 같은 루프를 가진다. 프롬프트로 모델 호출 → 모델 출력이 사용할 도구를 가리키면 → 도구 실행 → 결과 반영 → 다시 모델 호출. 이 루프를 신뢰성 있게 설계하는 일은 쉽지 않다.
- 사용자 상호작용(user interaction)과 UX 흐름(flows): 많은 LLM 애플리케이션은 사용자를 루프 안에 포함한다. 예를 들어 코딩 보조 도구는 변경안을 제안한 뒤 실제 적용 전에 사용자에게 확인을 요청할 수 있다. 글쓰기 보조 도구는 사용자가 고를 수 있도록 초안 몇 가지를 제시할 수 있다. 이런 UX 결정도 컨텍스트에 영향을 준다. 사용자가 “2번 옵션이 괜찮은데 좀 더 짧게 해 줘”라고 말하면, 그 피드백을 다음 프롬프트에 반영해야 한다. 예를 들면 “사용자가 초안 2를 선택했고 더 짧게 해 달라고 요청했다” 같은 식이다. 사람과 AI 사이의 매끄러운 상호작용 흐름을 설계하는 것은 애플리케이션의 일부이며, 프롬프트 자체의 문제만은 아니다. 그래도 컨텍스트 엔지니어링은 각 턴의 프롬프트가 상호작용 상태를 정확히 반영하도록 뒷받침한다. 예를 들어 어떤 옵션이 선택됐는지, 사용자가 무엇을 수동으로 고쳤는지 기억하게 해 준다.
- 가드레일(guardrails)과 안전성(safety): 프로덕션 환경에서는 오용과 오류를 고려해야 한다. 여기에는 유해하거나 민감한 출력을 막기 위한 콘텐츠 필터, 도구 사용에 대한 인증 및 권한 검사, 그리고 출력 검증이 포함될 수 있다. 가령 지시사항에 그런 내용이 있다고 해서 AI가 데이터베이스를 삭제해 버리면 안 된다. 어떤 구성은 첫 번째 모델의 출력을 두 번째 모델이나 규칙 기반 시스템으로 다시 검증한다. 예를 들어 메인 모델이 답변을 생성한 뒤, “이 답변에 민감한 정보가 포함되어 있는가? 그렇다면 가려라” 같은 추가 점검을 돌릴 수 있다. 이런 점검은 프롬프트로도, 코드로도 구현할 수 있다. 어느 쪽이든 추가 지시사항이 컨텍스트에 들어가는 경우가 많다. “사용자가 허용되지 않는 콘텐츠를 요청하면 거절하라” 같은 시스템 메시지는 실제 배포 프롬프트에 흔히 포함된다. 따라서 컨텍스트에는 늘 일정한 안전성 보일러플레이트(boilerplate)가 들어갈 수 있다. 이 균형을 맞추는 일, 즉 모델이 정책은 따르되 유용성은 해치지 않도록 만드는 일도 또 하나의 과제다.
- 평가(evaluation)와 모니터링(monitoring): 두말할 필요 없이 AI가 어떻게 동작하는지 지속적으로 모니터링해야 한다. 모든 요청과 응답을 기록하면 사용자 동의와 프라이버시를 전제로 실패 사례와 이상값을 분석할 수 있다. 실시간 평가를 넣을 수도 있다. 예를 들어 특정 기준으로 모델의 답변을 점수화하고, 점수가 낮으면 자동으로 다시 시도하게 하거나 사람에게 넘기도록 라우팅할 수 있다. 평가는 개별 프롬프트의 내용을 생성하는 일 자체는 아니지만, 시간이 지나면서 프롬프트와 컨텍스트 전략을 개선하는 데 다시 반영된다. 결국 프롬프트와 컨텍스트 조립 과정 전체를, 프로덕션 데이터로 디버깅(debugged) 하고 최적화할 수 있는 대상으로 다루는 셈이다.
우리가 실제로 말하고 있는 것은 새로운 종류의 애플리케이션 아키텍처(application architecture) 다. 여기서는 결정론적 함수를 단순히 실행하는 것이 아니라, 정보인 컨텍스트를 관리하고 그것을 일련의 AI 상호작용을 통해 조정하는 일이 핵심 로직이 된다. 카파시는 컨텍스트 채우기 위에 제어 흐름, 모델 디스패치(dispatch), 메모리 관리, 도구 사용, 검증 단계 같은 요소가 얹힌다고 설명했다. 이 모든 것이 합쳐져 그가 농담처럼 말한 “새롭게 형성되는 두터운 계층”을 이룬다. “두텁다”고 한 이유는 그만큼 처리하는 일이 많기 때문이다. 이런 시스템을 만들 때 우리는 사실상 메타프로그램(metaprogram)을 쓰고 있다. 다시 말해, 어떤 작업을 해결하기 위해 또 다른 “프로그램”, 즉 AI의 출력을 지휘하는 프로그램을 작성하는 것이다.
소프트웨어 엔지니어에게 이는 흥미로우면서도 도전적인 변화다. 흥미로운 이유는 이전에는 없던 능력을 열어 주기 때문이다. 예를 들면 자연어, 코드, 외부 동작을 매끄럽게 다루는 보조 도구를 만들 수 있다. 어려운 이유는 많은 기법이 아직 새롭고 계속 변하고 있기 때문이다. 이제는 프롬프트 버전 관리, AI 신뢰성, 윤리적 출력 필터링 같은 문제를 고민해야 한다. 이런 문제는 과거의 앱 개발에서는 표준적인 요소가 아니었다. 이런 맥락에서 컨텍스트 엔지니어링은 시스템의 중심부에 놓여 있다. 적절한 시점에 올바른 정보를 모델에 넣지 못하면, 다른 무엇도 앱을 구해 주지 못한다. 하지만 앞서 봤듯이, 컨텍스트가 완벽하다고 해서 그것만으로 충분한 것도 아니다. 그 주위를 받쳐 주는 구조 전체가 필요하다.
핵심은 우리가 프롬프트 설계(prompt design)에서 시스템 설계(system design)로 이동하고 있다는 점 이다. 컨텍스트 엔지니어링은 그 시스템 설계의 핵심 요소이지만, 동시에 다른 많은 구성 요소와 나란히 존재한다.
결론
핵심 요점: 완전한 컨텍스트를 조립하는 방법을 익히고, 여기에 탄탄한 테스트를 결합하면, AI 모델에서 최선의 출력을 얻을 가능성을 높일 수 있다.
경험 많은 엔지니어라면 이 패러다임의 핵심이 낯설지 않을 것이다. 본질적으로는 좋은 소프트웨어 관행을 새로운 영역에 적용하는 일이기 때문이다. 생각해 보자.
- 우리는 늘 쓰레기를 넣으면 쓰레기가 나온다(garbage in, garbage out) 는 원칙을 알고 있었다. 이제 그 원칙은 “나쁜 컨텍스트가 들어가면 나쁜 답이 나온다”는 형태로 드러난다. 그래서 모델이 알아서 해 주기를 기대하는 대신, 품질 높은 입력인 컨텍스트를 보장하는 데 더 많은 공을 들이게 된다.
- 우리는 코드에서 모듈성(modularity)과 추상화(abstraction) 를 중시한다. 이제는 작업을 더 높은 수준으로 추상화하고 있다. 즉, 작업을 설명하고, 예시를 주고, AI가 구현하게 한다. 동시에 AI와 도구를 결합한 모듈형 파이프라인을 구축한다. 모든 로직을 직접 쓰는 대신, 여러 구성 요소 중 일부는 결정론적이고 일부는 AI인 시스템을 오케스트레이션하고 있다.
- 전통적인 개발에서는 테스트(testing)와 반복(iteration) 을 실천해 왔다. 이제는 그와 같은 엄격함을 AI 동작에도 적용한다. 평가 체계를 만들고, 프로파일링 후 코드를 다듬듯 프롬프트를 정교하게 다듬는다.
컨텍스트 엔지니어링을 받아들인다는 것은 사실상 이렇게 말하는 것이다. “개발자인 내가 AI가 하는 일에 책임을 진다.” AI는 신비한 신탁이 아니다. 내가 적절한 데이터와 규칙으로 설정하고 구동해야 하는 하나의 구성 요소다.
이런 사고방식의 전환은 힘을 실어 준다. 이제 우리는 AI를 예측 불가능한 마법처럼 대할 필요가 없다. 탄탄한 엔지니어링 기법과 약간의 창의적인 프롬프트 감각만 있다면 충분히 길들일 수 있다.
그렇다면 실무에서 이런 컨텍스트 중심 접근법을 어떻게 도입할 수 있을까?
- 데이터와 지식 파이프라인에 투자하라. 컨텍스트 엔지니어링의 큰 부분은 주입할 데이터를 확보하는 일이다. 그러니 문서용 벡터 검색 인덱스를 구축하고, 에이전트가 사용할 데이터베이스 질의를 마련하라. 지식 소스를 개발의 핵심 기능으로 취급해야 한다. 예를 들어 코딩용 AI 보조 도구라면 저장소의 코드를 끌어오거나 스타일 가이드를 참조할 수 있어야 한다. AI에서 얻는 가치의 상당 부분은 AI에 제공하는 외부 지식(external knowledge) 에서 나온다.
- 프롬프트 템플릿(prompt templates)과 라이브러리를 개발하라. 필요할 때마다 즉흥적으로 프롬프트를 쓰기보다, 목적에 맞는 구조화된 템플릿을 만들기 시작하라. 예를 들어 “출처를 포함해 답하라” 또는 “오류가 주어졌을 때 코드 diff를 생성하라” 같은 템플릿이 있을 수 있다. 이런 템플릿은 재사용 가능한 함수처럼 동작한다. 버전 관리에 넣고, 기대 동작을 문서화하라. 이렇게 해야 검증된 컨텍스트 구성 방식의 도구 상자를 쌓아 갈 수 있다. 시간이 지나면 팀은 공유 코드 라이브러리를 다루듯 이를 함께 공유하고 개선하게 된다.
- 제어권을 제공하는 도구와 프레임워크를 활용하라. 신뢰성이 필요하다면 “프롬프트만 주면 나머지는 우리가 알아서 해 준다”는 식의 솔루션은 피하는 편이 좋다. 내부를 들여다보고 세부를 조정할 수 있는 프레임워크를 선택하라. 랭체인(LangChain) 같은 저수준 라이브러리일 수도 있고, 직접 구축한 오케스트레이션일 수도 있다. 컨텍스트 조립 과정을 더 잘 보고 더 많이 통제할수록, 문제가 생겼을 때 디버깅이 쉬워진다.
- 모든 것을 모니터링하고 계측하라. 프로덕션에서는 프라이버시 한도 안에서 입력과 출력을 기록해 두고 나중에 분석하라. 랭스미스(LangSmith) 같은 관측 가능성(observability) 도구를 활용해 각 요청에서 컨텍스트가 어떻게 구성됐는지 추적하라. 출력이 나쁘다면 거슬러 올라가 모델이 실제로 무엇을 봤는지 확인하라. 무엇인가 빠졌는가? 형식이 좋지 않았는가? 이런 질문이 수정 방향을 알려 준다. 결국 AI 시스템을 어느 정도 예측 불가능한 서비스로 보고, 다른 서비스와 마찬가지로 모니터링해야 한다. 프롬프트 사용량, 성공률 등을 보여 주는 대시보드도 필요하다.
- 사용자를 루프 안에 두라. 컨텍스트 엔지니어링은 기계와 기계 사이의 정보만 다루는 일이 아니다. 궁극적으로는 사용자의 문제를 해결하는 일이다. 적절히 묻기만 하면 사용자가 직접 컨텍스트를 제공할 때도 많다. AI가 명확화 질문을 하거나, 사용자가 컨텍스트를 보완할 추가 정보를 제공할 수 있는 UX를 고민하라. 예를 들어 파일을 첨부하게 하거나, 어느 코드베이스 구간이 관련 있는지 사용자가 고르게 할 수 있다. “AI 보조(AI-assisted)”라는 말은 양방향이다. AI가 사용자를 돕기도 하지만, 사용자가 컨텍스트를 제공해 AI를 도울 수도 있다. 잘 설계된 시스템은 이를 자연스럽게 지원한다. 예를 들어 AI의 답이 틀렸다면, 사용자가 바로잡을 수 있게 하고 그 수정 내용을 다음번 컨텍스트에 다시 반영하라.
- 팀과 자신을 훈련하라. 컨텍스트 엔지니어링을 팀의 공동 규율로 만들어라. 코드 리뷰에서 프롬프트와 컨텍스트 로직도 함께 검토하기 시작하라. “이 검색이 정말 적절한 문서를 가져오는가? 이 프롬프트 구간은 명확하고 모호하지 않은가?” 기술 리더라면 팀원들이 AI 출력 문제를 드러내고, 컨텍스트를 어떻게 조정하면 해결될지 함께 논의하도록 장려하라. 이 분야는 아직 새롭기 때문에 지식 공유가 특히 중요하다. 누군가 발견한 영리한 프롬프트 기법이나 포맷 통찰은 다른 사람에게도 그대로 도움이 될 가능성이 크다. 나 역시 다른 사람들의 프롬프트 예시와 AI 실패 회고를 읽으며 정말 많은 것을 배웠다.
앞으로는 컨텍스트 엔지니어링이 제2의 천성이 될 것 이라고 본다. 오늘날 API 호출이나 SQL 질의를 작성하는 일이 자연스러운 것처럼 말이다. 이는 소프트웨어 개발의 표준 역량 목록에 포함될 것이다. 이미 많은 사람이 질문에 필요한 컨텍스트를 가져오려고 빠르게 벡터 유사도 검색을 수행하는 일을 별다른 의식 없이 한다. 그냥 흐름의 일부가 된 것이다. 몇 년 뒤에는 “컨텍스트를 제대로 설정했나요?”가 “그 API 응답은 제대로 처리했나요?”만큼 흔한 코드 리뷰 질문이 될 것이다.
이 새로운 패러다임을 받아들인다고 해서 기존의 엔지니어링 원칙을 버리는 것은 아니다. 우리는 그것을 새로운 방식으로 다시 적용할 뿐이다. 수년간 소프트웨어 기술을 갈고닦아 왔다면, 그 경험은 지금 엄청난 가치가 있다. 그 경험이 있어야 합리적인 흐름을 설계하고, 경계 사례를 찾아내고, 정확성을 보장할 수 있다. AI는 그런 역량을 쓸모없게 만든 것이 아니라, AI를 올바르게 이끌기 위해 오히려 더 중요하게 만들었다. 소프트웨어 엔지니어의 역할은 줄어드는 것이 아니라 진화하고 있다. 우리는 이제 단지 코드를 쓰는 사람이 아니라 AI의 연출자(directors) 이자 편집자(editors) 가 되어 간다. 그리고 AI를 효과적으로 지휘하게 해 주는 기술이 바로 컨텍스트 엔지니어링이다.
무슨 질문을 하느냐만이 아니라, 모델에 어떤 정보를 제공하느냐의 관점에서 생각하라. 직접 실험하고, 반복해서 다듬고, 발견한 내용을 공유하라. 그렇게 하면 오늘날의 AI에서 더 나은 결과를 얻을 뿐 아니라, 앞으로 등장할 훨씬 더 강력한 AI 시스템에도 대비할 수 있다. AI에 무엇을 먹여야 하는지 아는 사람이 늘 유리하다.
즐거운 컨텍스트 코딩을!
오라일리(O'Reilly)와 함께 새로 쓴 AI 보조 엔지니어링 도서 를 소개하게 되어 기쁘다. 여기의 글을 재미있게 읽었다면 이 책도 관심 있게 살펴볼 만하다.
게시물 주제: AI & ML
게시물 태그: