KURE

Rerank API

질의와 후보 문서들을 받아 관련도 순으로 다시 정렬합니다. 모델은 질의와 문서를 함께 읽고 점수를 내는 cross-encoder(KURE-Reranker-nano)라, 임베딩 유사도보다 정답과 비슷한 함정 문서를 더 잘 구분합니다. 보통 1차 검색(KURE-v3, KURE-Sparse, BM25 등)으로 찾은 상위 수십 개를 다시 정렬하는 데 씁니다.

인증과 한도는 Embeddings API와 같습니다.

재정렬하기

POST https://kure.kullm.ai/api/v1/rerank

요청 본문

파라미터타입구분설명
modelstring필수kure-reranker-nano 또는 스냅샷 kure-reranker-nano-20261016 (모델 ID와 버전)
querystring필수검색 질의. 빈 문자열은 안 됩니다.
documentsstring[]필수정렬할 문서. 최대 100개이며 빈 문자열은 안 됩니다.
top_ninteger선택상위 N개만 돌려줍니다. 기본값은 문서 전체입니다.
return_documentsboolean선택결과에 문서 원문을 넣습니다. 기본값 false.

질의와 문서 한 쌍은 합쳐서 최대 8,192 토큰입니다. 넘으면 에러 없이 긴 쪽부터 잘라서 채점합니다.

응답

{
  "id": "rerank-59b5073b…",
  "model": "kure-reranker-nano-20261016",
  "results": [
    { "index": 1, "relevance_score": 0.9996, "document": { "text": "고려대학교는 서울특별시 성북구 안암로 145에 있다." } },
    { "index": 2, "relevance_score": 0.0073, "document": { "text": "연세대학교는 서울특별시 서대문구 연세로 50에 있다." } }
  ],
  "usage": { "total_tokens": 73 }
}
  • results는 relevance_score가 높은 순입니다. index는 documents에서의 위치입니다.
  • relevance_score는 0~1 사이의 관련 확률입니다(모델 점수의 sigmoid). 질의가 달라도 같은 기준이라, 예를 들어 0.5 미만을 버리는 식으로 임계값을 둘 수 있습니다.
  • document는 return_documents가 true일 때만 들어갑니다.
  • usage.total_tokens는 질의·문서 쌍마다 센 토큰의 합입니다. 질의는 문서 수만큼 반복해서 셉니다(질의 20토큰, 문서 100개면 질의 몫만 2,000토큰). 이 값이 rate limit에서 차감됩니다.

예시

# pip install requests
import os
 
import requests
 
res = requests.post(
    "https://kure.kullm.ai/api/v1/rerank",
    headers={"Authorization": f"Bearer {os.environ['KURE_API_KEY']}"},
    json={
        "model": "kure-reranker-nano",
        "query": "고려대학교는 어디에 있나요?",
        "documents": [
            "김치찌개는 김치와 돼지고기를 넣어 끓인다.",
            "고려대학교는 서울특별시 성북구 안암로 145에 있다.",
            "연세대학교는 서울특별시 서대문구 연세로 50에 있다.",
        ],
        "top_n": 2,
        "return_documents": True,
    },
)
res.raise_for_status()
for r in res.json()["results"]:
    print(f"{r['relevance_score']:.4f}  {r['document']['text']}")

검색 파이프라인에 넣기

1차 검색으로 넓게 찾고(상위 20~100개), 리랭커로 다시 정렬해 상위 몇 개만 씁니다. 1차 검색은 KURE-v3 임베딩, KURE-Sparse, 또는 둘을 합친 하이브리드 검색이면 됩니다.

import os
 
import numpy as np
import requests
from openai import OpenAI
 
API = "https://kure.kullm.ai/api/v1"
KEY = os.environ["KURE_API_KEY"]
client = OpenAI(base_url=API, api_key=KEY)
 
 
def embed(texts, input_type):
    vecs = []
    for i in range(0, len(texts), 8):  # 한 요청에 최대 8개
        res = client.embeddings.create(
            model="kure-v3", input=texts[i : i + 8], dimensions=1024, extra_body={"input_type": input_type}
        )
        vecs += [d.embedding for d in res.data]
    return np.array(vecs)
 
 
docs = [...]  # 검색 대상 문서
doc_vecs = embed(docs, "document")  # 미리 계산해 벡터 DB에 저장해 두는 부분
 
 
def search(query, k=50, n=5):
    scores = doc_vecs @ embed([query], "query")[0]
    candidates = [docs[i] for i in np.argsort(-scores)[:k]]  # 1차 검색 상위 k개
    res = requests.post(
        f"{API}/rerank",
        headers={"Authorization": f"Bearer {KEY}"},
        json={"model": "kure-reranker-nano", "query": query, "documents": candidates, "top_n": n},
    )
    res.raise_for_status()
    return [(r["relevance_score"], candidates[r["index"]]) for r in res.json()["results"]]
  • 후보가 많을수록 정답을 놓칠 가능성은 줄지만 토큰과 시간이 늘어납니다. 20~50개로 시작해 조정하세요.
  • 후보가 100개를 넘으면 여러 요청으로 나눠 보낸 뒤 relevance_score로 합쳐 정렬하면 됩니다. 점수는 요청이 달라도 같은 기준입니다.
  • 결과를 플레이그라운드에서 KURE-v3 유사도와 나란히 비교해 볼 수 있습니다.