AI 에이전트와 컨텍스트 엔지니어링에서 검색 속도가 중요한 이유
문서 코퍼스 2,000만 개에 대한 벤치마크에서 Elasticsearch는 필터링된 벡터 검색에서 OpenSearch 대비 최대 8배 높은 처리량을 제공하는 동시에, 테스트한 모든 구성에서 더 높은 Recall@100을 달성했습니다. 컨텍스트 엔지니어링에는 빠른 벡터 검색 이상이 필요합니다. 워크플로우가 반복되면서 하이브리드 검색 및 필터링과 같은 강력한 관련성 제어, 운영 간소화, 예측 가능한 성능이 필요합니다. 그러나 에이전트가 요청당 검색, 추론, 검색 루프를 여러 번 실행하는 경우가 많기 때문에 검색 지연 시간이 배가되므로, 이 문제를 개선하면 엔드투엔드 응답성 향상과 비용 절감 효과를 누릴 수 있습니다.

그래프 1: 처리량.
컨텍스트 엔지니어링에서 검색은 일회성 단계가 아닙니다. 에이전트와 애플리케이션은 검색 → 추론 → 검색과 같은 루프를 반복적으로 실행해 쿼리를 정제하고, 사실을 검증하며, 근거 있는 컨텍스트를 조립하고, 작업을 완료합니다. 이 패턴은 에이전트 워크플로우와 반복 Retrieval-Augmented Generation(RAG)에서 흔히 볼 수 있습니다. 사용자 요청당 검색이 여러 번 호출될 수 있으므로 응답 시간이 지연되거나 인프라 비용이 증가할 수 있습니다.

그림 1: 컨텍스트 엔지니어링은 반복적인 검색과 선별을 통해 대규모 컨텍스트 풀(문서, 메모리, 도구, 채팅 기록)을 제한된 대형 언어 모델(LLM) 컨텍스트 창으로 변환합니다.
컨텍스트 엔지니어링의 최적 구현은 새로 각광받는 기술입니다. 반복 횟수는 워크플로우에 따라 크게 다릅니다. 이 벤치마크 결과의 가장 근본적인 핵심 개념은 컨텍스트 엔지니어링이 방향성을 가진다는 것입니다. 이는 반복적인 검색은 지연 시간을 배가시킨다는 의미입니다.
벡터 검색 성능이 중요한 이유
쇼핑 어시스턴트가 '15인치 노트북이 들어가고, 방수 기능이 있으며, 금요일까지 배송 가능한 6만원 이하의 기내용 백팩을 찾는다'는 질문에 답하는 경우를 생각해 보겠습니다.
실제 환경에서 어시스턴트가 벡터 쿼리를 한 번만 실행하고 멈추는 경우가 거의 없습니다. 올바른 컨텍스트를 구축하기 위해 검색 루프를 실행하는데, 각 단계는 일반적으로 가용성, 지역, 배송 예정일, 브랜드 규칙 및 정책 적합성과 같은 필터에 의해 제한을 받습니다.
1단계: 의도를 해석해 제약 조건으로 변환
에이전트는 요청을 다음과 같은 구조화된 필터와 의미론적 쿼리로 변환합니다.
- 필터: 재고 있음, 사용자의 우편번호로 배송 가능, 금요일까지 배송, 가격 6만원 미만, 유효한 상품 목록
- 벡터 쿼리: '기내 반입 가능한 백팩, 15인치 노트북, 방수'
2단계: 후보를 검색한 후 정제
우수한 일치 항목을 놓치지 않기 위해 종종 변형된 검색을 반복합니다.
- '노트북 슬리브가 포함된 기내용 백팩'
- '통근용 방수 백팩 15인치'
- '기내용 경량 백팩'
관련성이 없거나 사용할 수 없는 항목을 검색하는 것은 컨텍스트 낭비이므로 각 쿼리는 동일한 자격 필터를 사용합니다.
3단계: 위험을 줄이기 위해 확장하여 세부 정보 확인
그런 다음 에이전트는 최종 답변에 영향을 미치는 주요 속성을 확인하기 위해 데이터를 다시 검색합니다.
- 재질 및 방수 기능 관련 문구
- 치수 및 노트북 수납 공간 크기
- 반품 정책 또는 보증 제약 조건
- 재고가 부족한 경우 대체 옵션
이것이 검색, 추론, 검색, 조립을 거치는 다단계 컨텍스트 엔지니어링입니다.
컨텍스트 엔지니어링에서 지연 시간과 재현율이 중요한 이유
이러한 상호작용은 사용자 세션당 수십 건의 필터링된 검색 호출을 포함할 수 있습니다. 따라서 통화당 지연 시간이 엔드투엔드 응답 시간에 직접적인 영향을 미치며, 재현율이 낮으면 에이전트가 추가 재시도를 하거나 적격 항목을 놓치게 되어 응답 품질이 저하됩니다.
요점: 컨텍스트 엔지니어링 시스템에서 필터링된 근사 이웃(ANN)은 일회성 조회로 끝나지 않습니다. 이는 제약 조건 하에서 반복되는 작업이므로, 대형 언어 모델(LLM)이 가장 중요한 구성 요소인 경우에도 벡터 검색 성능이 지연 시간, 처리량, 비용에 즉각적으로 영향을 미칩니다.
벤치마킹
결과
그래프 2에서 각 점은 하나의 테스트 구성을 나타냅니다. 지연 시간이 짧고 재현율이 높은 최상의 결과는 왼쪽 상단에 표시됩니다. Elasticsearch의 결과가 OpenSearch보다 지속적으로 왼쪽 상단에 가깝게 위치한다는 점에서 동일한 워크로드 설정에서 더 나은 속도와 정확도를 확인할 수 있습니다.

그래프 2: 재현율 대비 평균 지연 시간, 재채점 1.
주요 인사이트
s_n_r_value:size_numCandidates_rescoreOversample의 약어(k 및 numCandidates는 이러한 테스트에서 numCandidates와 동일하게 설정됨), 예를 들어100_500_1은 size=100, numCandidates=500 및 k=500, rescore oversample=1을 의미합니다.- 재현율: 해당 구성에 대한 측정된 Recall@100
- 평균 지연 시간(ms): 쿼리당 평균 엔드투엔드 지연 시간
- 처리량: 초당 쿼리 수
- 재현율 %: Elasticsearch와 OpenSearch의 상대적 재현율 상승(Elasticsearch-OpenSearch)/OpenSearch
- 지연 시간 Xs: OpenSearch의 평균 지연 시간을 Elasticsearch의 평균 지연 시간으로 나눈 값
- 처리량 Xs: Elasticsearch 처리량을 OpenSearch 처리량으로 나눈 값
| 엔진 | `s_n_r_value` | 재현율 | 평균 지연 시간(ms) | 처리량 | 재현율 % | 지연 시간 Xs | 처리량 Xs |
|---|---|---|---|---|---|---|---|
| Elasticsearch | 100_250_1 | 0.7704 | 25 | 534.75 | 9.70% | 2.28 | 1.91 |
| OpenSearch | 100_250_1 | 0.7023 | 57.08 | 279.58 | |||
| Elasticsearch | 100_500_1 | 0.8577 | 25.42 | 524.14 | 7.20% | 2.4 | 2 |
| OpenSearch | 100_500_1 | 0.8001 | 60.9 | 262.12 | |||
| Elasticsearch | 100_750_1 | 0.8947 | 29.67 | 528.09 | 5.72% | 2.25 | 2.21 |
| OpenSearch | 100_750_1 | 0.8463 | 66.76 | 239.11 | |||
| Elasticsearch | 100_1000_1 | 0.9156 | 29.65 | 534.5 | 4.66% | 2.46 | 2.44 |
| OpenSearch | 100_1000_1 | 0.8748 | 72.88 | 219.01 | |||
| Elasticsearch | 100_1500_1 | 0.9386 | 31.84 | 497.3 | 3.38% | 2.71 | 2.68 |
| OpenSearch | 100_1500_1 | 0.9079 | 86.16 | 185.4 | |||
| Elasticsearch | 100_2000_1 | 0.9507 | 34.69 | 457.2 | 2.57% | 2.98 | 2.96 |
| OpenSearch | 100_2000_1 | 0.9269 | 103.36 | 154.55 | |||
| Elasticsearch | 100_2500_1 | 0.9582 | 37.9 | 418.43 | 1.99% | 3.28 | 3.26 |
| OpenSearch | 100_2500_1 | 0.9395 | 124.29 | 128.53 | |||
| Elasticsearch | 100_3000_1 | 0.9636 | 41.86 | 379.4 | 1.62% | 3.46 | 3.44 |
| OpenSearch | 100_3000_1 | 0.9482 | 144.67 | 110.34 | |||
| Elasticsearch | 100_4000_1 | 0.9705 | 50.28 | 316.21 | 1.06% | 3.87 | 3.85 |
| OpenSearch | 100_4000_1 | 0.9603 | 194.36 | 82.22 | |||
| Elasticsearch | 100_5000_1 | 0.9749 | 58.77 | 270.91 | 0.73% | 4.43 | 4.41 |
| OpenSearch | 100_5000_1 | 0.9678 | 260.33 | 61.38 | |||
| Elasticsearch | 100_6000_1 | 0.9781 | 66.75 | 238.59 | 0.52% | 4.91 | 4.89 |
| OpenSearch | 100_6000_1 | 0.973 | 327.44 | 48.81 | |||
| Elasticsearch | 100_7000_1 | 0.9804 | 74.64 | 213.49 | 0.38% | 5.28 | 5.27 |
| OpenSearch | 100_7000_1 | 0.9767 | 394.24 | 40.53 | |||
| Elasticsearch | 100_8000_1 | 0.9823 | 82.28 | 193.59 | 0.27% | 6.86 | 6.83 |
| OpenSearch | 100_8000_1 | 0.9797 | 564.14 | 28.33 | |||
| Elasticsearch | 100_9000_1 | 0.9837 | 90.08 | 176.96 | 0.16% | 7.63 | 7.61 |
| OpenSearch | 100_9000_1 | 0.9821 | 687.25 | 23.25 | |||
| Elasticsearch | 100_10000_1 | 0.9848 | 97.64 | 163.31 | 0.08% | 8.38 | 8.36 |
| OpenSearch | 100_10000_1 | 0.984 | 818.64 | 19.53 |
예를 들어, 100_9000_1에서 OpenSearch는 검색당 평균 687밀리초를 기록하는 반면, Elasticsearch에서는 90밀리초이며, 10단계 검색 루프에서는 약 10x(687-90)=6초의 추가 대기 시간이 발생합니다.
전체 결과 보기.
방법론
Python을 사용하여 쿼리를 전송하고 응답 시간 및 기타 통계를 추적하기 위해 다음 쿼리를 각 엔진에 전송했습니다. 벡터 검색 엔진의 성능은 고려할 후보 수, 재채점의 적극성, 반환할 컨텍스트의 양 등 핵심 매개변수를 어떻게 조정하느냐에 따라 달라진다는 점을 유의하시기 바랍니다. 이러한 설정은 재현율(올바른 답변을 찾을 가능성)과 대기 시간(결과를 얻는 속도)에 직접적인 영향을 미칩니다.
벤치마크 테스트에서는 에이전틱 검색 루프에서 일반적으로 조정하는 것과 동일한 후보, 재채점, 결과 크기 설정을 사용하여 해당 워크로드에서 Elasticsearch의 성능을 측정했습니다. 그런 다음 참조를 위해 동일한 설정으로 OpenSearch를 실행했습니다.
OpenSearch
"size": <RESULT_SIZE>: 클라이언트에 반환된 결과 수입니다. 이 벤치마크에서는 Recall@100을 계산하기 위해 결과 크기가 100입니다."k": <NUMBER_OF_CANDIDATES>: 최근접 이웃 후보의 수입니다."ef_search": <NUMBER_OF_CANDIDATES>: 검사할 벡터의 개수."oversample_factor": <OVERSAMPLE>: 재채점 전에 검색되는 후보 벡터의 수입니다.
Elasticsearch
"size": <RESULT_SIZE>: 클라이언트에 반환된 결과 수입니다. 이 벤치마크에서는 Recall@100을 계산하기 위해 결과 크기가 100입니다."k": <NUMBER_OF_CANDIDATES>각 샤드에서 반환할 가장 가까운 이웃의 수입니다."num_candidates": <NUMBER_OF_CANDIDATES>:knn검색 수행 시 샤드별로 고려할 최근접 이웃 후보 수."oversample": <OVERSAMPLE>: 재채점 전에 검색되는 후보 벡터의 수입니다.
예
Knn 쿼리(100_500_1)는 다음과 같습니다.
OpenSearch
Elasticsearch
전체 구성, Terraform 스크립트, Kubernetes 매니페스트 및 벤치마킹 코드는 이 저장소의 es-9.3-vs-os-3.5-vector-search 폴더에서 확인할 수 있습니다.
클러스터 설정
테스트는 각각 16개의 vCPU와 64GB RAM을 갖춘 6개의 e2-standard-16 클라우드 서버에서 실행되었습니다. 각 서버에서 검색 엔진 노드를 실행하는 각 Kubernetes 포드에 15개의 vCPU와 56GB RAM을 할당하였으며, 그 중 28GB는 JVM 힙을 위해 예약했습니다.
클러스터는 Elasticsearch 9.3.0과 OpenSearch 3.5.0 (Lucene 10.3.2)을 실행합니다. 이 벤치마크에서 두 시스템 모두 동일한 Lucene 버전을 사용하기 때문에, 관찰된 처리량과 지연 시간 차이는 Lucene에만 기인하는 것이 아니라 각 엔진이 필터링된 kNN(k-최근 이웃) 검색 및 재채점을 통합하고 실행하는 방식의 차이를 반영합니다. 3개의 기본 샤드와 1개의 복제본이 있는 단일 인덱스를 사용했습니다(따라서 노드당 1개씩 총 6개의 샤드).
또한 같은 지역 내 별도의 서버를 사용해 벤치마크 클라이언트를 실행하고 타이밍 통계를 수집했습니다.

그림 2: 클러스터링 구성도.
데이터 세트
이 벤치마크에서는 대규모 실제 환경에서의 필터링된 벡터 검색을 반영하도록 설계된 대규모 이커머스 스타일의 카탈로그 임베딩 데이터 세트(2,000만 개 문서)을 사용했습니다.
각 문서는 카탈로그 항목을 나타내며 다음을 포함합니다.
- 128차원 고밀도 벡터 임베딩으로, 대략적인 kNN 검색에 사용됩니다.
- 필터링에 사용되는 구조화된 메타데이터 필드(예: 항목 유효성 및 가용성, 기타 카탈로그 제약 조건)는 적합한 하위 집합 내에서만 가장 가까운 이웃을 검색하는 일반적인 제작 패턴을 지원합니다.
이 데이터 세트를 선택한 이유는 선택한 이유는 프로덕션 환경의 에이전틱 및 RAG 스타일 시스템에서 나타나는 핵심 성능 과제를 잘 반영하기 때문입니다. 벡터 유사도만으로는 충분하지 않고, 검색은 필터에 의해 제한을 받는 경우가 많고, 시스템은 해당 제약 조건 하에서 지연 시간을 낮게 유지하면서 높은 재현율을 달성해야 합니다. 소규모 QA 스타일 데이터 세트와 비교했을 때, 2,000만 개 문서 코퍼스는 실제 환경에서 필터링된 ANN 시스템이 직면하는 규모와 후보 압력을 더 잘 반영합니다.
결론
현대 AI 아키텍처, 특히 컨텍스트 엔지니어링을 중심으로 구축된 아키텍처에서 벡터 검색 속도는 사소한 구현 세부 사항으로 치부할 수 없습니다. 이는 효과를 배가시킵니다. 에이전트와 워크플로가 검색 → 추론 → 검색 과정을 반복할 때, 검색 성능은 엔드투엔드 지연 시간, 처리량, 모델에 입력되는 컨텍스트 품질에 직접적인 영향을 미칩니다.
벤치마크 테스트 결과, Elasticsearch는 정확한 문서 검색 여부가 중요한 시나리오(단순히 유사한 벡터를 검색하는 것이 아닌)에서 OpenSearch보다 지속적으로 더 높은 재현율과 더 낮은 지연 시간을 제공했습니다. 제어된 데이터 세트에서 차이는 분명하며, 실제 환경에서는 대규모 검색 호출 전반에 걸쳐 이러한 이점이 누적되어 응답성을 향상시키고, 용량 여유를 확대하며, 인프라 비용을 절감합니다.




