당신은 AI 비용을 잘못된 방식으로 최적화하고 있습니다
요약
AI 에이전트 운영 시 단순히 토큰 수를 줄이는 것이 아니라, 작업 완료당 실제 비용을 최적화하는 전략을 제시합니다. 프롬프트 캐싱 활용, 컨텍스트 제어, 모델 선택 기준의 변화 등 효율적인 비용 관리를 위한 7가지 핵심 전략을 다룹니다.
핵심 포인트
- 단순 토큰 절감이 아닌 '작업 완료당 비용'을 측정해야 함
- 프롬프트 캐싱을 위해 컨텍스트의 앞부분을 안정적으로 유지할 것
- 저렴한 모델이라도 반복 시도가 많아지면 결과적으로 더 비쌀 수 있음
- 재사용 가능한 정보와 새로운 정보를 구분하여 컨텍스트를 제어할 것
만약 당신이 프로그래밍을 위해 AI 에이전트 (AI agents)를 사용한다면, 아마도 더 저렴한 모델을 사용하거나, 프롬프트 (prompts)를 더 짧게 작성하거나, 혹은 단순히 전체 토큰 (tokens) 수를 줄이는 방식으로 비용을 절감하려고 시도해 보았을 것입니다. 이 모든 방법이 도움이 될 수는 있지만, 이러한 지표 중 그 어느 것도 단독으로는 특정 작업이 실제로 얼마만큼의 비용이 들 것인지를 말해주지 않습니다.
10만 개의 토큰을 사용하는 요청이 2만 개의 토큰을 사용하는 요청보다 비용이 적게 들 수도 있습니다. 토큰당 비용이 더 비싼 모델이 결과적으로 더 적은 돈을 쓰고 작업을 완료할 수도 있습니다. 그리고 모든 요청에 토큰을 추가하는 규칙 (Rule)이 결국에는 전체 비용을 줄여줄 수도 있습니다.
모순처럼 들리겠지만, 이유는 간단합니다: 토큰은 모두 동일한 비용을 갖지 않으며, 전체 토큰의 수는 전체 상황을 설명해주지 못하기 때문입니다.
요청의 구성이 중요합니다. 재사용할 수 있는 컨텍스트 (Context), 처리해야 하는 새로운 정보, 그리고 모델이 생성한 콘텐츠는 비용에 서로 다른 영향을 미칩니다. 그렇기 때문에 총 토큰 수가 동일한 두 번의 실행이라도 결과적인 비용은 완전히 다를 수 있습니다.
그리고 훨씬 더 중요한 또 다른 변수가 있습니다: 결과에 도달하기 위해 얼마나 많은 실행이 필요했는가 하는 점입니다.
실수를 저질러 여러 번의 시도가 필요한 저렴한 모델은, 문제를 단번에 해결하는 비싼 모델보다 더 많은 비용이 들 수 있습니다. 마찬가지로, 컨텍스트를 추가하는 것은 한 번의 호출 비용을 높일 수 있지만, 그 컨텍스트가 재작업을 방지한다면 전체 비용을 줄여줄 수 있습니다.
따라서 전략은 단순히 토큰을 적게 사용하거나, 모든 것을 캐시 (cache)에 넣거나, 항상 가장 저렴한 모델을 선택하는 것이 아닙니다.
목표는 다음과 같습니다:
안정적인 것은 저렴하게 재사용하고, 새로 들어오는 것은 제어하며, 에이전트가 해결책에 도달하는 데 도움이 되지 않는 작업을 피하는 것.
이 포스트에서 저는 이를 고민하기 위해 사용하는 일곱 가지 전략을 살펴보겠습니다:
- 재사용 가능한 것을 보호하십시오.
- 컨텍스트 (Context)에 들어가는 것을 제어하십시오.
- 정보를 검색할 때 가장 선택적인 도구를 사용하십시오.
- Rules와 Skills를 통해 필요할 때만 지식을 로드하십시오.
- 모델이 생성하는 것을 제어하십시오.
- 노력의 정도를 조절하고, 오류 비용에 따라 모델을 선택하십시오.
- 단순히 토큰 (Tokens)이 아니라, 완료된 작업당 비용을 측정하십시오.
결국, 이 모든 전략은 동일한 질문에 답하려고 노력합니다:
작업을 올바르게 완료하는 데 비용이 얼마나 들었는가?
왜냐하면 토큰을 적게 사용하면서 세 번의 시도가 필요하다면 그것은 절약이 아니기 때문입니다. 그것은 그저 보기 좋은 지표를 가진 나쁜 실행일 뿐입니다.
1. 재사용 가능한 것을 보호하십시오
프롬프트 캐싱 (Prompt caching)은 접두사 (Prefixes)를 기반으로 작동합니다. 컨텍스트의 초기 부분이 호출 간에 계속 동일하다면, 이를 새로운 콘텐츠로 다시 처리하는 대신 재사용할 수 있습니다.
Anthropic의 구현에서 접두사 계층 구조는 다음과 같습니다:
tools → system → messages
이전 부분의 변경은 이후 부분의 재사용에 영향을 미칠 수 있습니다. 규칙은 간단합니다:
앞부분은 안정적으로, 뒷부분은 가변적으로.
호출 간에 동일하게 유지되는 안정적인 부분이 클수록 재사용 가능성이 높아집니다. 작업 중에 동일하게 유지되는 시스템 지침 (System instructions), 도구 정의 (Tool definitions) 및 기타 정보를 생각하십시오.
긴 작업 중에 안정적인 지침을 수정하는 것을 피하십시오
Rules는 에이전트를 위한 지속적인 지침입니다. 모델에 전송되는 안정적인 부분의 일부인 지침을 변경하면, 재사용되고 있던 콘텐츠를 수정하게 될 수 있습니다.
Cursor의 모든 Rule이 프롬프트 내의 특정 위치를 차지한다거나, 하나를 편집하면 항상 전체 캐시가 무효화된다고 단정 지을 수는 없습니다. 내부 구현이 그렇게 문서화되어 있지 않기 때문입니다. 그럼에도 불구하고, 긴 실행 과정 동안 안정적인 지침을 적게 수정할수록 컨텍스트 재사용이 더 예측 가능해지는 경향이 있습니다.
실제로 저는 대규모 흐름이 이미 진행 중인 동안이 아니라, 작업(task)이나 세션(session) 사이에서 구조적 규칙(Rules)을 조정하는 것을 선호합니다.
콜드 세션(Cold session)은 더 비쌀 수 있지만, 무한 세션 또한 해결책은 아닙니다
Anthropic의 기본 캐시(cache)에서 TTL(Time To Live)은 5분이며, 1시간까지 연장할 수 있는 옵션이 있습니다. 기본 TTL을 사용하는 설정에서는 빈번한 상호작용을 통해 이미 캐싱된 콘텐츠를 계속 재사용할 수 있습니다. 긴 휴식 후에는 다음 호출 시 해당 컨텍스트의 일부를 다시 처리해야 할 수도 있습니다. OpenAI의 모델 또한 컨텍스트 재사용 메커니즘과 연속적인 상호작용에 유리한 내부 최적화를 사용하지만, 캐시 TTL을 동일한 방식으로 노출하지는 않습니다. Cursor의 경우, 재사용 여부는 세션의 연속성과 상호작용 전반에 걸쳐 컨텍스트가 유지되고 업데이트되는 방식에 달려 있습니다.
이것이 캐시를 보호하기 위해서만 무한한 대화를 유지해야 한다는 의미는 아닙니다. 긴 세션은 히스토리(history)를 축적하며, 그중 상당 부분이 현재 작업에 더 이상 관련이 없어지는 시점이 옵니다.
이러한 축적은 비용에만 영향을 미치는 것이 아닙니다. 에이전트(agent)의 성능에도 영향을 미칠 수 있습니다.
컨텍스트에 무관한 정보가 너무 많이 포함되면, 모델은 중요한 정보와 무시해도 되는 정보를 구분해야 합니다. 이는 처리해야 할 정보가 많아짐을 의미하며, 모호성이 증가하고 에이전트가 문제 해결에 도움이 되지 않는 세부 사항을 고려할 가능성이 높아집니다.
실제로 모델은 오래된 파일, 이미 폐기된 해석, 또는 현재 작업에 더 이상 적용되지 않는 지침을 고려하게 될 수 있습니다.
여기에는 트레이드오프(trade-off)가 존재합니다:
긴 세션: 재사용 가능성이 높지만, 더 많은 컨텍스트가 축적되어 잠재적으로 노이즈(noise)가 많아질 수 있습니다.
새 세션: 컨텍스트가 더 작고 깨끗하지만, 이전에 캐싱되었던 정보에 대해 새로운 콜드 스타트(cold start)가 발생할 수 있습니다.
완전히 독립적인 작업의 경우, 저는 별도의 세션을 선호합니다. 새 세션이 보편적으로 더 저렴하기 때문이 아니라, 관련 없는 컨텍스트 (context)를 무기한으로 로드하는 것은 비용 측면이나 에이전트 (agent)의 의사결정 품질 측면 모두에서 의미가 없기 때문입니다.
목표는 다음과 같습니다:
모델이 현재 작업을 해결하는 데 도움이 되지 않는 정보를 처리하게 하지 마세요.
2. 컨텍스트에 들어가는 내용을 제어하세요
에이전트는 코드를 검색하고, 파일을 열고, 테스트 결과를 읽고, 의존성 (dependencies)을 조사해야 합니다. 문제는 이러한 작업을 수행하는 것이 아닙니다. 문제는 방대한 양의 관련 없는 정보가 불필요하게 컨텍스트 (context)에 들어오도록 방치하는 것입니다.
이는 생각보다 자주 발생합니다. 단 몇 줄만으로도 실패 원인을 설명할 수 있는데 로그 (log) 전체를 붙여넣습니다. 변경 사항이 특정 모듈에 국한되어 있음에도 에이전트에게 프로젝트 전체를 분석하라고 요청합니다. 오류가 이미 단일 테스트를 가리키고 있음에도 파이프라인 (pipeline)의 전체 출력을 전달합니다. 또는 생성된 파일, 거대한 모크 (mocks), 작업과 직접적인 관련이 없는 문서들을 포함시키기도 합니다.
이 모든 것은 모델이 문제에 대해 추론하기 시작하기도 전에 처리해야 할 정보의 양을 증가시킵니다.
따라서 가장 간단한 최적화 방법 중 하나는 컨텍스트를 확장하기 전에 범위를 축소하는 것입니다.
만약 파이프라인이 특정 테스트에서 실패했다면, 실행 전체 로그가 아니라 해당 테스트와 관련된 오류부터 시작하세요. 작업이 사용자 생성 흐름을 변경하는 것이라면, 에이전트가 전체 리포지토리 (repository)를 탐색하게 하기 전에 해당 도메인으로 안내하세요. 도구에 의해 생성된 출력이 매우 크다면, 에이전트가 먼저 무엇이 실패했는지 조사하게 하고 필요할 때만 심층적으로 파고들 수 있도록 하세요.
아이디어는 모델로부터 정보를 숨기는 것이 아닙니다. 정보를 점진적으로 제공하는 것입니다.
문제를 조사하기에 충분한 최소한의 컨텍스트로 시작하고, 새로운 질문이 생김에 따라 확장하세요.
이는 에이전트(agent)가 직접 사용하는 도구의 결과물에도 동일하게 적용됩니다. 수천 줄을 반환하는 명령어는 반드시 더 유용한 정보를 생성하지 않으면서도 과도한 컨텍스트 (context)를 생성할 수 있습니다. 가능할 때마다 실패한 테스트만 실행하거나, 관련된 서비스의 로그를 조회하거나, 문제가 발생하는 도메인으로 검색 범위를 제한하는 것과 같이 더 정밀한 실행을 선호하는 것이 가치가 있습니다.
이득은 단순히 "더 적은 토큰 (tokens)을 보내는 것"에서 오는 것이 아닙니다. 모델이 작업을 시작하기 전에 신호 (signal)와 소음 (noise)을 분리해야 하는 상황을 방지하는 데서 옵니다.
에이전트에서 더 많은 컨텍스트가 항상 더 높은 지능을 의미하는 것은 아닙니다.
때로는 그저 무시해야 할 것이 더 많아진다는 것을 의미할 뿐입니다.
3. 정보를 찾기 위해 가장 선택적인 도구를 사용하세요
코딩 에이전트 (Coding agents)는 정보를 찾는 다양한 방법을 가지고 있으며, 각 방법은 질문의 유형에 따라 더 효과적으로 작동합니다. 예를 들어, Cursor는 리터럴 (literal) 검색, 시맨틱 (semantic) 검색을 수행하고 에이전트 방식 (agentic)으로 코드베이스 (codebase)를 탐색할 수 있습니다. 목표는 선호하는 도구를 선택하는 것이 아니라, 문제에서 요구하는 것보다 더 광범위한 검색을 피하는 것이어야 합니다.
만약 코드 내에서 UserRepository의 모든 발생 지점을 찾고 싶다면, 저는 정확한 것을 찾고 있는 것입니다. 리터럴 검색이 아마도 빠르게 해결해 줄 것입니다.
하지만 질문이 다음과 같다고 가정해 봅시다:
"쿠폰 적용 후 체크아웃 (checkout) 흐름의 어느 시점에서 배송비가 재계산되나요?"
아마 당신은 함수 이름이나 클래스 이름, 심지어 구현에 사용된 용어조차 모를 수도 있습니다. 이 경우, 검색할 단어를 추측하려고 노력하는 것보다 에이전트가 시맨틱 검색을 사용하여 동작을 찾아내도록 하는 것이 덜 비효율적일 수 있습니다.
차이점은 질문의 유형에 있습니다.
무엇을 찾고 있는지 알고 있다면, 직접 검색하세요.
동작은 알고 있지만 어디에 구현되어 있는지 모른다면, 시맨틱하게 검색하세요.
여러 부분이 어떻게 연결되는지 이해해야 한다면, 에이전트가 흐름을 탐색하게 하세요.
원칙은 다음과 같습니다:
현재 질문에 답할 수 있는 가장 좁은 범위의 검색을 사용하세요.
이는 두 가지 극단적인 상황을 방지합니다. 한쪽에서는 단순한 질문에 답하기 위해 너무 많은 파일을 여는 것이 문제라면, 다른 한쪽에서는 검색 범위를 너무 제한하여 에이전트가 실제로 중요한 것을 찾을 때까지 여러 번 시도해야 하는 상황이 문제입니다.
최적화는 특정 도구를 선택하는 데 있지 않습니다.
코드에 대한 모든 질문을 저장소(Repository) 전체에 대한 완전한 탐색으로 변질시키지 않는 데 있습니다.
탐색(Discovery) 작업을 가장 비싼 모델로부터 분리하세요
에이전트가 작업을 시작하기 전에 프로젝트를 이해해야 할 때, 또 다른 낭비가 발생할 수 있습니다. 바로 문제를 해결할 비싼 모델과 동일한 모델을 모든 탐색 작업에 사용하는 것입니다.
모든 단계가 동일한 수준의 지능을 요구하는 것은 아닙니다.
탐색의 순수하게 구조적인 부분은 결정론적(Deterministic) 방식으로 수행될 수 있습니다. 간단한 스크립트가 저장소를 훑으며 관련 디렉토리, 알려진 설정 파일, 워크스페이스(Workspaces), 모듈 및 가능한 엔트리포인트(Entrypoints)를 식별하고 구조에 대한 압축된 지도를 반환할 수 있습니다.
그 후, 이러한 정보를 여전히 해석해야 하는 경우라면, 더 저렴한 모델이 이 지도를 아키텍처 요약본으로 변환하여 메인 모델에 전달하기 전에 처리할 수 있습니다.
흐름은 대략 다음과 같습니다:
결정론적 수집 (Deterministic collection)
↓
구조적 지도 (Structural map)
...
핵심 아이디어는 수집(Collection), 합성(Synthesis), 그리고 추론(Reasoning)을 분리하는 것입니다.
스크립트는 기존 모듈, 설정 파일, 디렉토리 구조와 같이 프로젝트 구조를 직접 추출하는 데 여전히 좋은 도구입니다.
반면 "이 시스템의 아키텍처는 무엇인 것 같습니까?", "주요 도메인은 무엇입니까?", 또는 "이 모듈들은 서로 어떻게 연관되어 있습니까?"와 같은 질문은 해석을 필요로 합니다. 이를 위해 메인 모델을 개입시키기 전에 더 저렴한 모델을 사용하여 요약본을 생성하는 것이 합리적일 수 있습니다.
이 경우, 스킬(Skill)이 프로세스를 오케스트레이션할 수 있습니다:
---
name: project-discovery
description: "광범위한 컨텍스트를 요구하는 작업 전에 프로젝트 아키텍처를 매핑하고 요약합니다."
...
해당 스크립트도 컨텍스트 비용이 0인 것은 아니며, 저렴한 모델 또한 비용이 발생합니다. 핵심은 프로세스의 모든 단계를 실행하는 데 가장 비싼 능력을 사용하고 있지 않다는 점입니다.
결정론적 (deterministic)인 작업은 코드로 처리하고, 합성 (synthesis)에는 저렴한 모델을 사용하며, 오류의 비용이 큰 결정에는 가장 강력한 모델을 예약하십시오.
이는 컨텍스트에 적용된 단계별 라우팅 (routing)과 동일한 논리입니다.
메인 모델은 프로젝트가 어떻게 구성되어 있는지 처음부터 파악하는 데 실행 자원을 낭비하는 대신, 이미 해석된 지도를 전달받아 어디를 더 깊게 파고들지 결정합니다.
이는 단순히 토큰을 절약하는 차원을 넘어섭니다. 이것은 에이전트 아키텍처 (agent architecture)입니다.
비싼 모델이 코드나 더 저렴한 모델로 충분히 신뢰성 있게 수행할 수 있는 작업에 추론 (reasoning) 능력을 소모하고 있다면, 해당 단계가 정말로 그 모델의 소관이어야 하는지 자문해 볼 가치가 있습니다.
4. Rules와 Skills를 통한 온디맨드 (on-demand) 지식 로드
에이전트가 항상 알고 있어야 하는 것과 특정 상황에서만 알아야 하는 것 사이에는 중요한 차이가 있습니다.
AI 자동 생성 콘텐츠
본 콘텐츠는 Dev.to AI tag의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기