CoolFace
Modelpublic

nlpai-lab/KURE-v2

sourceHugging Faceapache-2.0updated 15d agoView on Hugging Face
20likes5.5kdownloads
Model Card

<a href="https://github.com/nlpai-lab/KURE"> <img src="kure_logo.png" width="50%"/> </a>

πŸ”Ž KURE-v2

KURE-v2 is a Korean-English bilingual late-interaction (multi-vector) retrieval model built on skt/A.X-Encoder-base. It encodes every token into a 128-dimensional vector and scores query–document pairs with MaxSim.

At 154M parameters it averages nDCG@10 0.8160 across the nine MTEB(kor, v2) retrieval tasks β€” the strongest model on that suite, above every single-vector model measured, including one 175Γ— its size.

It is trained in two stages: unsupervised contrastive pretraining on 20.7M unlabeled pairs (KURE-v2-unsupervised), then supervised fine-tuning with contrastive loss and KL distillation from a reranker.

Key Characteristics

  • β€”Late interaction: one 128-d vector per token, scored with MaxSim.
  • β€”Long documents: up to 8,192 tokens.
  • β€”Compact: 154M parameters.
  • β€”No instruction prefixes: queries and documents need no task instruction. Query expansion to 64 tokens is handled by the model.

Usage

<details> <summary><b>PyLate Usage</b></summary>

bash
pip install -U pylate

Indexing documents

python
from pylate import indexes, models, retrieve

model = models.ColBERT(model_name_or_path="nlpai-lab/KURE-v2")

index = indexes.PLAID(
    index_folder="pylate-index",
    index_name="index",
    override=True,
)

documents_ids = ["1", "2", "3"]
documents = [
    "μ„Έμ’…λŒ€μ™•μ€ 1443년에 ν›ˆλ―Όμ •μŒμ„ μ°½μ œν•˜κ³  1446년에 이λ₯Ό λ°˜ν¬ν•˜μ˜€λ‹€.",
    "κΉ€μΉ˜λŠ” λ°°μΆ”λ‚˜ 무λ₯Ό μ†ŒκΈˆμ— 절인 λ’€ 고좧가루와 μ “κ°ˆμ„ λ„£μ–΄ λ°œνš¨μ‹œν‚¨ μŒμ‹μ΄λ‹€.",
    "ν•œλΌμ‚°μ€ ν•΄λ°œ 1,947m둜 λ‚¨ν•œμ—μ„œ κ°€μž₯ 높은 산이며 μ œμ£Όλ„ 쀑앙에 μžλ¦¬ν•œλ‹€.",
]

documents_embeddings = model.encode(
    documents,
    batch_size=32,
    is_query=False,
    show_progress_bar=True,
)

index.add_documents(
    documents_ids=documents_ids,
    documents_embeddings=documents_embeddings,
)

To reuse an existing index, instantiate it without override:

python
index = indexes.PLAID(index_folder="pylate-index", index_name="index")

Retrieving top-k documents

python
retriever = retrieve.ColBERT(index=index)

queries_embeddings = model.encode(
    ["ν›ˆλ―Όμ •μŒμ€ μ–Έμ œ λ§Œλ“€μ–΄μ‘Œλ‚˜μš”?"],
    batch_size=32,
    is_query=True,
    show_progress_bar=True,
)

scores = retriever.retrieve(
    queries_embeddings=queries_embeddings,
    k=10,
)

Reranking

To rerank a first-stage candidate list without building an index:

python
from pylate import models, rank

model = models.ColBERT(model_name_or_path="nlpai-lab/KURE-v2")

queries = [
    "μ „κΈ°μ°¨ νλ°°ν„°λ¦¬λŠ” μ–΄λ–»κ²Œ μž¬ν™œμš©ν•˜λ‚˜μš”?",
    "κ²¨μšΈμ— ν•œλΌμ‚°μ„ 였λ₯Ό λ•Œ ν•„μš”ν•œ μž₯λΉ„λŠ”?",
]
documents = [
    [
        "νλ°°ν„°λ¦¬μ—μ„œ 리튬과 μ½”λ°œνŠΈλ₯Ό νšŒμˆ˜ν•˜λŠ” μŠ΅μ‹ 제련 곡정이 μƒμš©ν™”λ˜κ³  μžˆλ‹€.",
        "급속 μΆ©μ „κΈ°λŠ” 30λΆ„ λ‚΄μ™Έλ‘œ 배터리λ₯Ό 80%κΉŒμ§€ μΆ©μ „ν•  수 μžˆλ‹€.",
    ],
    [
        "겨울 ν•œλΌμ‚° μ‚°ν–‰μ—λŠ” 아이젠과 λ°©ν•œ μž₯갑이 ν•„μˆ˜μ΄λ©° μž…μ‚° μ‹œκ°„μ΄ μ œν•œλœλ‹€.",
        "제주 μ˜¬λ ˆκΈΈμ€ ν•΄μ•ˆμ„ 따라 μ΄μ–΄μ§€λŠ” 27개 μ½”μŠ€λ‘œ κ΅¬μ„±λ˜μ–΄ μžˆλ‹€.",
        "μ μ„€κΈ°μ—λŠ” 등산화에 슀패츠λ₯Ό μ°©μš©ν•΄ 눈이 λ“€μ–΄κ°€λŠ” 것을 λ§‰λŠ” 것이 μ’‹λ‹€.",
    ],
]
documents_ids = [[1, 2], [1, 3, 2]]

queries_embeddings = model.encode(queries, is_query=True)
documents_embeddings = model.encode(documents, is_query=False)

reranked_documents = rank.rerank(
    documents_ids=documents_ids,
    queries_embeddings=queries_embeddings,
    documents_embeddings=documents_embeddings,
)

</details>

<details> <summary><b>Sentence-Transformers Usage</b></summary>

bash
pip install -U sentence-transformers
python
from sentence_transformers import MultiVectorEncoder

model = MultiVectorEncoder("nlpai-lab/KURE-v2")

query = "ν›ˆλ―Όμ •μŒμ€ μ–Έμ œ λ§Œλ“€μ–΄μ‘Œλ‚˜μš”?"
documents = [
    "μ„Έμ’…λŒ€μ™•μ€ 1443년에 ν›ˆλ―Όμ •μŒμ„ μ°½μ œν•˜κ³  1446년에 이λ₯Ό λ°˜ν¬ν•˜μ˜€λ‹€.",
    "κΉ€μΉ˜λŠ” λ°°μΆ”λ‚˜ 무λ₯Ό μ†ŒκΈˆμ— 절인 λ’€ 고좧가루와 μ “κ°ˆμ„ λ„£μ–΄ λ°œνš¨μ‹œν‚¨ μŒμ‹μ΄λ‹€.",
    "ν•œλΌμ‚°μ€ ν•΄λ°œ 1,947m둜 λ‚¨ν•œμ—μ„œ κ°€μž₯ 높은 산이며 μ œμ£Όλ„ 쀑앙에 μžλ¦¬ν•œλ‹€.",
]

query_embeddings = model.encode_query(query)
document_embeddings = model.encode_document(documents)
print(query_embeddings.shape, document_embeddings[0].shape)
# (64, 128) (29, 128)

# MaxSim late-interaction scoring (higher is more relevant)
scores = model.similarity(query_embeddings, document_embeddings)
print(scores)

</details>

Evaluation

KURE-v2 is evaluated on the nine MTEB(kor, v2) Retrieval tasks. We report nDCG@10. The results are also shown in the official MTEB Leaderboard?types=Retrieval&s.summary=meanTask&d.summary=desc)

ModelParamsAvgAutoRAGPubHealthQAKo-StrategyQALawIRKoSQuADKorV1Belebele (ko-ko)MrTidyMLDRMIRACL
Our Models
[nlpai-lab/KURE-v2](https://huggingface.co/nlpai-lab/KURE-v2)154M0.81600.97180.82290.80700.75500.98460.96600.59740.71590.7237
[nlpai-lab/KURE-v2-unsupervised](https://huggingface.co/nlpai-lab/KURE-v2-unsupervised)154M0.72830.88220.82400.78180.76800.94270.95250.34960.61300.4411
Late-Interaction (Multi-Vector) Models
yjoonjang/colbert-ko-en-v2149M0.80630.96860.82220.79400.71810.98460.96870.57830.69920.7230
lightonai/mLateOn307M0.79060.93920.80610.79050.64310.98030.96080.58170.70050.7135
perplexity-ai/pplx-embed-v1-late-0.6b596M0.73810.85570.80890.79730.72850.96960.95480.54000.28160.7064
dragonkue/colbert-ko-0.1b149M0.67760.97000.74820.73640.44750.97940.96440.39660.28720.5685
yjoonjang/colbert-ko-v1149M0.62820.95570.67830.65600.48230.95940.91540.32790.22140.4575
Dense (Single-Vector) Models
sionic-ai/comsat-embed-ko-8b-preview7.6B0.79270.85180.88710.83940.81640.91680.98530.62530.51570.6964
Qwen/Qwen3-Embedding-8B7.6B0.78260.82760.87210.83630.81710.90630.98240.61870.50460.6783
Qwen/Qwen3-Embedding-4B4.0B0.77370.84310.86930.82700.77690.90440.95220.60760.50220.6803
microsoft/harrier-oss-v1-27b27.0B0.76670.81760.89710.83610.87370.92040.95460.53060.40460.6653
dragonkue/snowflake-arctic-embed-l-v2.0-ko568M0.76530.90930.83370.80500.77350.94470.95180.57120.43040.6685
codefuse-ai/F2LLM-v2-8B7.6B0.76380.76780.93800.83710.84050.88740.95130.61620.40470.6313
telepix/PIXIE-Rune-v1.5568M0.76180.89270.84260.80640.77050.94570.96170.54920.44820.6393
nlpai-lab/KURE-v1568M0.76160.87080.81930.79990.74260.93570.95020.59090.46370.6816
dragonkue/BGE-m3-ko568M0.75470.87380.81550.79590.73220.94140.95030.60990.38990.6833
BAAI/bge-m3568M0.75090.83010.80410.79410.71740.90380.93160.64710.42870.7015
nlpai-lab/KoE5560M0.73370.84340.83510.80010.77560.89800.94250.58410.30150.6235

Late-interaction rows were measured with mteb 2.18.16 and PLAID retrieval. Single-vector rows are taken from the official MTEB results repository, except for Belebele, where only the Korean-query / Korean-corpus subset is used. The original version also includes cross-lingual subsets (Korean query – English corpus, English query – Korean corpus).

Serving

KURE-v2 is a late-interaction model: each document is stored as a set of token vectors, so the practical questions for deployment are index size and search cost. We benchmarked KURE-v2 across ANN backends and compression schemes on the 9 Korean MTEB retrieval tasks, against five single-vector baselines served with faiss HNSW. All numbers are end-to-end: batch-1 query encoding + index search, measured serially on one A100 80GB.

<p align="center"> <img src="assets/deploy_overview.png" width="100%" alt="Average nDCG@10 vs. index storage (left) and vs. end-to-end QPS (right)"> </p>

Two things the figures show:

  • β€”Hierarchical token pooling (x2) halves the index for a 0.04 nDCG drop. Asymmetric binary quantization (1-bit document tokens, bf16 queries) shrinks it 9.4x for 1.05. Stacking the two (pooling x3 + binary), the entire 9-corpus index fits in 1.7 GB, smaller than every single-vector HNSW index (13.1-50.0 GB), while still outscoring the best single-vector model (79.57 vs 79.07).
  • β€”A live query arrives as text: 4B-8B single-vector models spend 38-40 ms encoding it, capping them at ~25 QPS no matter how fast HNSW is. KURE-v2 encodes in 13.8 ms (154M params), so every configuration except MUVERA serves 43-55 QPS, roughly 2x the 8B single-vector models, at higher quality.

Large corpora: tail latency

<p align="center"> <img src="assets/bigcorpus_miracl.png" width="70%" alt="MIRACL (1.5M docs): quality, e2e p95 latency, index size"> </p>

On the largest corpus (MIRACL, ~1.5M documents) an exhaustive 1-bit scan costs O(corpus): p95 climbs to 156 ms, and pooling the tokens 3x only brings it to 74 ms. Generating candidates with faiss BinaryIVF (Hamming search over the same 1-bit index) and re-scoring them with exact asymmetric MaxSim cuts p95 to 38 ms on the same 2.2 GB index, lower tail latency than the 4B-8B single-vector baselines (43 ms) at higher nDCG. For large collections, use a candidate-generating index (PLAID or BinaryIVF), not an exhaustive scan.

<details> <summary><b>Measurement details</b></summary>

  • β€”Hardware: 1x NVIDIA A100 80GB, 2x AMD EPYC 7513 (64 cores), 1.2 TB RAM.
  • β€”Software: faiss-cpu 1.15.0, fast-plaid 1.6.0, sentence-transformers 6.0.0, PyTorch 2.8.0.
  • β€”Protocol: batch-1, serial. Index-search latency: 10 warmup queries, then every query of the task measured once (QPS = 1/mean). Query-encoding latency: 5 warmup, 50 measured. End-to-end = encoding + search.
  • β€”Precision: encoding in bf16; each index stores its own format (HNSW fp32, PLAID 4-bit residuals, binary 1-bit).
  • β€”Index size: the full serialized index on disk (vectors, graph, codebooks; external doc-id mapping excluded).
  • β€”Tasks: the 9 Korean MTEB retrieval tasks; MLDR is the mean of its dev/test splits; nDCG@10 x100.
  • β€”HNSW: IndexHNSWFlat (inner product on L2-normalized embeddings), M=32, efConstruction=200, efSearch=64.
  • β€”PLAID: nbits=4, all other settings fast-plaid defaults (kmeansniters=4, nivfprobe=8, nfull_scores=4096). nbits=2/1 give 27.0/17.0 GB at 81.25/81.09 nDCG.
  • β€”MUVERA: numrepetitions=10, numsimhashprojections=6, finalprojection_dimension=8192, exact-MaxSim rerank of the top 1,000.
  • β€”BinaryIVF: nlist=floor(sqrt(total tokens)) capped at 65,536, nprobe=32, top-128 Hamming tokens per query token, exact asymmetric-MaxSim rerank of the top 1,000 documents.
  • β€”Token pooling: hierarchical (Ward linkage), pool_factor 2-3, documents only. </details>

Citation

bibtex
@misc{kure-v2,
  title  = {KURE-v2: a Korean-English bilingual late-interaction retriever},
  author = {Jang, Youngjoon and Son, Junyoung and Lee, Taemin and Hong, Seongtae and Lim, Heuiseok},
  year   = {2026},
  url    = {https://huggingface.co/nlpai-lab/KURE-v2},
}
bibtex
@inproceedings{jang2025kure,
  title={KURE: Embedding Model for Korean-Specific Retrieval},
  author={Jang, Youngjoon and Son, Junyoung and Lee, Taemin and Hong, Seongtae and Park, JeongBae and Lim, Heuiseok},
  booktitle={Annual Conference on Human and Language Technology},
  pages={129--134},
  year={2025},
  organization={Human and Language Technology}
}
bibtex
@inproceedings{santhanam-etal-2022-colbertv2,
  title     = {ColBERTv2: Effective and Efficient Retrieval via Lightweight Late Interaction},
  author    = {Santhanam, Keshav and Khattab, Omar and Saad-Falcon, Jon and Potts, Christopher and Zaharia, Matei},
  booktitle = {Proceedings of the 2022 Conference of the North American Chapter of the Association for Computational Linguistics: Human Language Technologies},
  year      = {2022},
  pages     = {3715--3734},
}
bibtex
@misc{PyLate,
  title  = {PyLate: Flexible Training and Retrieval for Late Interaction Models},
  author = {Chaffin, Antoine and Sourty, RaphaΓ«l},
  year   = {2024},
  url    = {https://github.com/lightonai/pylate},
}