Microsoft AI-103

Microsoft AI-103 시험 노트개념 정리20 MIN

시맨틱·하이브리드·벡터 검색 구성

AI-103 정보 추출 도메인의 둘째 노트입니다. 벡터 필드와 근사 최근접 이웃, 순위 융합 계산, 시맨틱 랭커, 필터와 쿼리 문법, 그리고 검색 결과가 답의 근거로 쓸 만한지 재는 법을 정리합니다.

앞 노트에서 색인을 세우고 문서를 들여왔습니다. 이제 그 색인을 어떻게 찾느냐입니다. 둘째 노트 「검색·인덱싱 방식과 에이전트 지식 통합 선택」에서 키워드·벡터·하이브리드의 세 갈래를 고르는 기준을 봤다면, 이 노트는 고른 뒤에 실제로 무엇을 구성하는지를 다룹니다. 시험은 여기서 구성 값과 질의 매개변수를 묻습니다 — 같은 하이브리드 검색이라도 후보 수·필터 적용 시점·재순위 여부에 따라 결과가 달라지기 때문입니다.

벡터 필드

필드 정의와 프로필

벡터 검색을 하려면 색인에 벡터 필드가 있어야 합니다. 타입은 Collection(Edm.Single)이고, 차원 수와 벡터 검색 프로필을 함께 적습니다. 프로필은 「이 필드를 어떤 알고리즘으로 찾고, 질의 문장은 무엇으로 벡터로 바꾸는가」를 묶어 둔 이름입니다. 필드는 프로필 이름만 가리키고, 알고리즘과 벡터 변환기는 프로필이 가리킵니다 — 세 층이 이름으로 이어져 있어서 한 칸만 틀려도 색인 생성이 실패합니다.

{
  "vectorSearch": {
    "algorithms": [
      { "name": "hnsw-1", "kind": "hnsw",
        "hnswParameters": { "m": 4, "efConstruction": 400, "efSearch": 500, "metric": "cosine" } }
    ],
    "vectorizers": [
      { "name": "aoai", "kind": "azureOpenAI",
        "azureOpenAIParameters": { "resourceUri": "https://my-foundry.openai.azure.com",
          "deploymentId": "embed-small", "modelName": "text-embedding-3-small" } }
    ],
    "profiles": [
      { "name": "default", "algorithm": "hnsw-1", "vectorizer": "aoai" }
    ]
  }
}

임베딩 생성

벡터는 두 번 만들어집니다. 문서를 넣을 때 한 번, 질의가 들어올 때 한 번입니다. 문서 쪽은 수집 파이프라인의 임베딩 단계가 만들거나 우리 코드가 미리 계산해 밀어 넣고, 질의 쪽은 프로필에 붙은 벡터 변환기(vectorizer)가 질의 문장을 받아 그 자리에서 바꿉니다. 변환기가 없으면 앱이 직접 임베딩을 계산해 숫자 배열로 보내야 합니다.

두 번의 변환은 반드시 같은 임베딩 모델이어야 합니다. 모델이 다르면 두 벡터가 서로 다른 공간에 있어 거리가 아무 뜻이 없고, 오류도 안 나서 결과만 조용히 엉뚱해집니다. 「검색 결과가 갑자기 무관한 문서로 채워졌다, 최근에 질의 쪽 임베딩 배포를 바꿨다」가 이 자리를 묻는 문항입니다.

근사 최근접 이웃

HNSW

벡터 검색은 질의 벡터에 가장 가까운 문서 벡터 k개를 찾는 일입니다. 문서가 수백만 개면 하나하나 거리를 재는 것이 너무 느리므로, 정확도를 조금 내주고 속도를 얻는 근사 최근접 이웃(ANN) 탐색을 씁니다. Azure AI Search의 기본 알고리즘이 HNSW로, 벡터들을 여러 층의 그래프로 이어 두고 위층에서 크게 건너뛰다 아래층에서 좁혀 가는 방식입니다.

매개변수 올리면
m 노드마다 잇는 이웃 수가 늘어 정확도가 오르고 메모리를 더 쓴다
efConstruction 색인을 만들 때 더 넓게 살펴 그래프 품질이 오르고 색인 시간이 늘어난다
efSearch 질의 때 더 넓게 살펴 재현율이 오르고 지연이 늘어난다

전수 탐색

전수 탐색(exhaustive KNN)은 모든 벡터와 거리를 재는 방식입니다. 결과가 정확한 대신 문서 수에 비례해 느려집니다. 그래서 운영 질의에 쓰기보다는 작은 색인이나, HNSW 결과가 얼마나 정확한지 재는 기준선으로 씁니다 — HNSW 필드에 대해서도 질의 하나만 exhaustive: true로 돌려 두 결과를 견줄 수 있습니다.

유사도 지표

거리를 무엇으로 잴지도 알고리즘 구성에 들어갑니다. 코사인 유사도가 기본이고, 내적·유클리드 거리도 고를 수 있습니다. 원칙은 임베딩 모델이 학습된 지표를 따른다는 것입니다. 길이가 1로 맞춰진 벡터라면 코사인과 내적이 같은 순서를 내므로, 그런 모델에서 둘 중 무엇을 골라도 결과 순서는 안 바뀝니다.

하이브리드 검색

순위 융합

하이브리드 검색은 텍스트 질의와 벡터 질의를 한 요청에 함께 보내 두 결과 목록을 합칩니다. 합치는 방법이 RRF이고 등수만 씁니다. 상수를 60으로 두고 두 목록에서 문서 넷의 등수가 아래와 같다고 해 봅니다.

문서 키워드 등수 벡터 등수 RRF 점수
A 1 3 1/61 + 1/63 ≈ 0.03227
B 2 1 1/62 + 1/61 ≈ 0.03252
C — 2 1/62 ≈ 0.01613
D 3 — 1/63 ≈ 0.01587

RRF(d)=∑r160+rankr(d)\mathrm{RRF}(d) = \sum_{r} \frac{1}{60 + \mathrm{rank}_r(d)}

키워드 1등인 A가 아니라 두 목록에서 고루 앞선 B가 1등이 됩니다. 한쪽에만 걸린 C·D는 한 항만 더해져 둘 다 걸린 문서를 넘지 못합니다. 그래서 하이브리드에서는 한 목록에서 압도적인 문서보다 양쪽에서 무난한 문서가 올라온다는 성질을 기억해 두면 결과 순서를 묻는 문항이 풀립니다.

후보 수와 가중치

벡터 질의의 k는 벡터 쪽이 융합에 넘길 후보 수이고, 응답의 top은 융합을 마친 뒤 돌려줄 개수입니다. 여기에 벡터 질의마다 가중치를 줄 수 있어, 벡터 쪽 등수의 몫을 키우거나 줄입니다. 식별자 검색이 많은 서비스라면 벡터 쪽 가중치를 낮추는 식입니다.

시맨틱 랭커

시맨틱 구성

시맨틱 랭커는 1차 검색이 낸 상위 결과를 언어 모델이 다시 읽어 순서를 바꾸는 재순위 단계입니다. 모델이 무엇을 읽을지 알려 주는 것이 시맨틱 구성으로, 제목 필드 하나·본문 필드 여럿·키워드 필드 여럿을 우선순위대로 지정합니다. 본문 필드를 안 넣으면 재순위 모델이 읽을 것이 거의 없어 순서가 1차 결과와 다르지 않게 됩니다.

시맨틱 랭커는 1차 검색을 대신하지 않습니다. 키워드든 벡터든 하이브리드든 먼저 후보를 뽑고, 그 위에 얹히는 층입니다. 1차 검색이 좋은 문서를 상위에 못 올리면 재순위는 그 문서를 되살릴 수 없습니다.

캡션과 답변

재순위와 함께 두 가지를 더 받을 수 있습니다. 캡션은 문서마다 질의와 가장 맞는 구절을 뽑아 강조한 것이고, 답변은 질의가 질문 꼴일 때 상위 문서들에서 답이 되는 문장을 뽑아 결과 맨 위에 따로 싣는 것입니다. 둘 다 원문에서 그대로 뽑는 추출이지 모델이 새로 쓴 문장이 아닙니다.

재순위 점수

재순위 결과에는 1차 점수와 별도로 0~4 범위의 재순위 점수가 붙습니다. 1차 점수는 질의마다 눈금이 달라 문턱값으로 쓰기 어렵지만 재순위 점수는 범위가 고정돼 있어, 「점수가 낮은 결과는 근거로 쓰지 않는다」 같은 거르기를 걸기 좋습니다.

{
  "search": "해외 배송 반품 기한",
  "vectorQueries": [
    { "kind": "text", "text": "해외 배송 반품 기한", "fields": "contentVector", "k": 50 }
  ],
  "queryType": "semantic",
  "semanticConfiguration": "policy-semantic",
  "captions": "extractive",
  "answers": "extractive|count-3",
  "filter": "region eq 'KR' and updated ge 2026-01-01T00:00:00Z",
  "vectorFilterMode": "preFilter",
  "select": "title,content",
  "top": 5
}

쿼리 문법

단순 문법과 전체 문법

텍스트 질의의 문법은 둘입니다. 단순 문법이 기본이고 +·-·따옴표 구문·접두사 별표 정도를 받습니다. 전체 문법(queryType: full)은 Lucene 문법으로, 철자 오류를 허용하는 퍼지 검색(환불~1), 낱말 사이 거리를 정하는 근접 검색, 특정 필드만 찾는 필드 지정, 낱말별 가중치(반품^3), 정규식을 더 받습니다. 「오타가 있어도 제품명이 걸려야 한다」면 전체 문법의 퍼지 검색이 답입니다.

searchMode도 결과를 크게 바꿉니다. any는 낱말 하나만 맞아도 걸고, all은 전부 맞아야 겁니다. 결과가 너무 많고 엉성하면 all로, 너무 적으면 any로 옮깁니다.

필터와 정렬

필터는 OData 식으로 적고, 점수와 무관하게 조건에 안 맞는 문서를 결과에서 아예 뺍니다. eq·ne·gt·ge·lt·le와 and·or·not, 여러 값 중 하나를 고르는 search.in, 컬렉션 필드에 쓰는 any·all이 기본 도구입니다. 정렬은 orderby이고 sortable 필드에만 걸립니다. 정렬을 걸면 관련도 점수 순서가 정렬 순서로 바뀌므로, RAG에서 근거를 고를 때는 대개 정렬을 걸지 않습니다.

벡터 질의와 필터가 함께 오면 언제 거르느냐가 갈립니다. 사전 필터(preFilter, 기본)는 거른 문서 안에서 k개를 찾으므로 결과가 k개를 채웁니다. 사후 필터(postFilter)는 k개를 먼저 찾고 거르므로, 조건이 까다로우면 k개 중 대부분이 걸러져 결과가 비거나 몇 개만 남습니다. 「필터를 걸었더니 벡터 결과가 2건밖에 안 나온다」면 필터 적용 시점을 의심합니다.

검색 품질 평가

관련성 지표

검색이 잘 되는지는 질의마다 「정답 문서」를 정해 둔 평가 세트로 잽니다. 정밀도@k는 상위 k개 중 정답의 비율이고, 재현율@k는 정답 전체 중 상위 k개에 들어온 비율입니다. 정답이 4개인 질의에서 상위 5개 안에 3개가 들어왔다면 정밀도@5는 3/5 = 0.6, 재현율@5는 3/4 = 0.75입니다. 등수까지 반영하려면 정답이 위에 있을수록 점수를 더 주는 NDCG를 씁니다.

그라운딩

RAG에서는 검색 품질과 답의 품질을 갈라 재야 합니다. 그라운딩은 모델의 답이 넣어 준 근거 문서에 실제로 기대고 있는지이고, 관련성은 그 답이 질문에 맞는지입니다. 둘을 가르면 실패의 자리가 보입니다.

증상 실패한 자리 손볼 곳
근거에 답이 없는데 모델이 지어냈다 검색과 생성 둘 다 재현율을 올리고 「근거에 없으면 모른다고 답하라」를 지시
근거에 답이 있는데 엉뚱하게 답했다 생성 프롬프트·모델
근거가 질문과 무관하다 검색 질의 구성·하이브리드·재순위

Foundry의 평가 도구는 그라운딩·관련성 평가자와 검색 결과 자체를 매기는 평가자를 따로 둡니다. 시험은 증상 문장을 주고 어느 평가자의 점수가 낮을지, 또는 어느 쪽을 고쳐야 할지를 묻습니다. 구성 값 하나를 바꾸면 평가 세트를 다시 돌려 숫자로 견주는 것이 이 절의 마지막 단계입니다.

연습 문제

  1. 질의 쪽 벡터 변환기의 임베딩 배포를 다른 모델로 바꾼 뒤 벡터 검색 결과가 무관한 문서로 채워졌습니다. 오류 로그는 없습니다. 원인은?
    ① HNSW의 efSearch가 너무 작다
    ② 문서 벡터와 질의 벡터를 서로 다른 모델이 만들었다
    ③ 시맨틱 구성에 본문 필드가 없다
    ④ 필터가 사후 필터로 걸려 있다
    ②. 두 벡터가 다른 공간에 있어 거리가 뜻을 잃었습니다. 차원이 같으면 오류 없이 결과만 틀어집니다. 문서 쪽을 새 모델로 다시 만들거나 질의 쪽을 원래 모델로 되돌립니다.
  2. 하이브리드 검색에서 문서 X는 키워드 1등·벡터 10등, 문서 Y는 키워드 4등·벡터 4등입니다. 상수 60의 RRF로 어느 쪽이 위에 섭니까?
    ① X
    ② Y
    ③ 같다
    ④ 점수를 알아야 정할 수 있다
    ②. X는 1/61 + 1/70 ≈ 0.016393 + 0.014286 = 0.030679, Y는 1/64 + 1/64 = 0.03125입니다. RRF는 등수만 쓰므로 원래 점수는 필요 없습니다.
  3. 벡터 질의에 k=10과 까다로운 필터를 함께 걸었더니 결과가 2건만 나옵니다. 가장 먼저 바꿀 것은?
    ① vectorFilterMode를 사전 필터로 둔다
    ② searchMode를 any로 바꾼다
    ③ 시맨틱 랭커를 켠다
    ④ efConstruction을 올린다
    ①. 사후 필터는 10개를 먼저 찾고 거르므로 조건에 맞는 것이 적으면 결과가 줄어듭니다. 사전 필터는 거른 집합 안에서 10개를 찾습니다.
  4. 정답 문서가 5개인 질의에서 상위 10개 결과 중 정답이 4개입니다. 정밀도@10과 재현율@10은?
    ① 0.4와 0.8
    ② 0.8과 0.4
    ③ 0.5와 0.8
    ④ 0.4와 0.5
    ①. 정밀도는 4/10 = 0.4, 재현율은 4/5 = 0.8입니다. 분모가 각각 결과 수와 정답 수라는 점만 붙잡으면 됩니다.
  5. 사용자가 「Surfase 노트북 반품」처럼 제품명을 틀리게 적어도 찾아야 합니다. 알맞은 구성은?
    ① 단순 문법에 searchMode: all
    ② 전체 문법에서 퍼지 검색
    ③ 필드에 sortable을 켠다
    ④ 시맨틱 캡션을 켠다
    ②. 철자 거리를 허용하는 퍼지 검색은 전체(Lucene) 문법에서 씁니다. 벡터 검색을 섞는 것도 도움이 되지만 보기 중에서는 ②입니다.
  6. 시맨틱 랭커를 켰는데 결과 순서가 1차 검색과 거의 같습니다. 가장 의심스러운 곳은?
    ① 시맨틱 구성에 본문 필드가 지정되지 않았다
    ② HNSW 대신 전수 탐색을 쓴다
    ③ 필터가 사전 필터다
    ④ 벡터 질의의 가중치가 1이다
    ①. 재순위 모델은 시맨틱 구성이 지정한 필드를 읽습니다. 본문이 빠지면 읽을 것이 제목뿐이라 순서를 바꿀 근거가 없습니다.
  7. RAG 앱의 평가에서 근거 문서는 질문과 잘 맞는데 그라운딩 점수만 낮습니다. 고칠 곳은?
    ① 검색 질의 구성
    ② 생성 단계의 지시문과 모델
    ③ 임베딩 모델
    ④ 색인의 필드 속성
    ②. 근거가 맞는데 답이 근거를 벗어났으니 검색이 아니라 생성 쪽 실패입니다. 근거만 써서 답하라는 지시를 세우고 모델을 견줘 봅니다.

이 노트의 문항은 대부분 어느 단계에서 갈렸는가를 묻습니다. 후보를 뽑는 1차 검색, 거르는 필터, 합치는 융합, 다시 읽는 재순위, 그리고 답을 쓰는 생성을 순서대로 놓고 증상을 그 위에 얹으면 보기가 빠르게 줄어듭니다.

Microsoft AI-103 시험 노트 전체 보기