KURE is a family of Korean-English retrieval embedding models developed by the NLP & AI Lab and the HIAI Institute at Korea University.
- 2026.10.20: π€ KURE-v3 released with API.
- 2026.10.12: π€ KURE-Sparse-base and π€ KURE-Sparse-nano released.
- 2026.10.01: π€ KURE-Reranker-base and π€ KURE-Reranker-nano released.
- 2026.08.29: π€ KURE-v2 released.
- 2024.12.21: π€ KURE-v1 released with the MTEB-ko-retrieval leaderboard.
- 2024.10.02: π€ KoE5 and π€ ko-triplet-v1.0 released.
| Model | Type | Params | Base model |
|---|---|---|---|
| KURE-v3 | Dense (single-vector) | 1.1B | nvidia/Nemotron-3-Embed-1B-BF16 |
| KURE-Sparse-base | Learned Sparse Retrieval (LSR) | 593M | omai-research/milco-650m |
| KURE-Sparse-nano | Learned Sparse Retrieval (LSR) | 149M | nlpai-lab/KURE-v2-unsupervised |
| KURE-Reranker-base | Reranker (cross-encoder) | 1.7B | Qwen/Qwen3-1.7B |
| KURE-Reranker-nano | Reranker (cross-encoder) | 149M | skt/A.X-Encoder-base |
| KURE-v2 | Late-interaction (multi-vector) | 154M | skt/A.X-Encoder-base |
| KURE-v1 | Dense (single-vector) | 568M | BAAI/bge-m3 |
| KoE5 | Dense (single-vector) | 560M | intfloat/multilingual-e5-large |
We use uv to manage the environment.
uv sync # dense, sparse and cross-encoder models
uv sync --extra late-interaction --no-default-groups # KURE-v2 with PyLateKURE-v3, KURE-Sparse-{base, nano} and KURE-Reranker-nano are served at kure.kullm.ai. Sign in with GitHub there to get an API key. Each request takes up to 8 texts (100 documents for reranking).
| Endpoint | Models |
|---|---|
/embeddings |
kure-v3 |
/sparse-embeddings |
kure-sparse-base, kure-sparse-nano |
/rerank |
kure-reranker-nano |
import os
import requests
from openai import OpenAI
BASE_URL = "https://kure.kullm.ai/api/v1"
API_KEY = os.environ["KURE_API_KEY"]
query = "νλ―Όμ μμ μΈμ λ§λ€μ΄μ‘λμ?"
documents = [
"μΈμ’
λμμ 1443λ
μ νλ―Όμ μμ μ°½μ νκ³ 1446λ
μ μ΄λ₯Ό λ°ν¬νμλ€.",
"κΉμΉλ λ°°μΆλ 무λ₯Ό μκΈμ μ μΈ λ€ κ³ μΆ§κ°λ£¨μ μ κ°μ λ£μ΄ λ°ν¨μν¨ μμμ΄λ€.",
"νλΌμ°μ ν΄λ° 1,947mλ‘ λ¨νμμ κ°μ₯ λμ μ°μ΄λ©° μ μ£Όλ μ€μμ μ리νλ€.",
]
# KURE-v3 (OpenAI-compatible). input_type adds the query or document prompt. Vectors are 2048-d, pass dimensions=(256 to 2048) for a smaller Matryoshka size
client = OpenAI(base_url=BASE_URL, api_key=API_KEY)
query_embedding = client.embeddings.create(
model="kure-v3", input=query, extra_body={"input_type": "query"}
)
document_embeddings = client.embeddings.create(
model="kure-v3", input=documents, extra_body={"input_type": "document"}
)
headers = {"Authorization": f"Bearer {API_KEY}"}
# KURE-Sparse returns vocabulary ids (indices) and their weights (values)
sparse = requests.post(
f"{BASE_URL}/sparse-embeddings",
headers=headers,
json={"model": "kure-sparse-nano", "input": documents, "input_type": "document"},
).json()
# KURE-Reranker returns the documents sorted by relevance_score (0 to 1, higher is more relevant)
ranked = requests.post(
f"{BASE_URL}/rerank",
headers=headers,
json={"model": "kure-reranker-nano", "query": query, "documents": documents},
).json()from sentence_transformers import SentenceTransformer
model = SentenceTransformer("nlpai-lab/KURE-v3", model_kwargs={"attn_implementation": "flash_attention_2"})
# model = SentenceTransformer("nlpai-lab/KURE-v3", model_kwargs={"attn_implementation": "flash_attention_2"}, truncate_dim=1024) # smaller Matryoshka vectors
# KURE-v2 is late-interaction and needs sentence-transformers>=6.0:
# from sentence_transformers import MultiVectorEncoder
# model = MultiVectorEncoder("nlpai-lab/KURE-v2")
# model = SentenceTransformer("nlpai-lab/KURE-v1")
# model = SentenceTransformer("nlpai-lab/KoE5", prompts={"query": "query: ", "document": "passage: "})
query = "νλ―Όμ μμ μΈμ λ§λ€μ΄μ‘λμ?"
documents = [
"μΈμ’
λμμ 1443λ
μ νλ―Όμ μμ μ°½μ νκ³ 1446λ
μ μ΄λ₯Ό λ°ν¬νμλ€.",
"κΉμΉλ λ°°μΆλ 무λ₯Ό μκΈμ μ μΈ λ€ κ³ μΆ§κ°λ£¨μ μ κ°μ λ£μ΄ λ°ν¨μν¨ μμμ΄λ€.",
"νλΌμ°μ ν΄λ° 1,947mλ‘ λ¨νμμ κ°μ₯ λμ μ°μ΄λ©° μ μ£Όλ μ€μμ μ리νλ€.",
]
# encode_query / encode_document add each model's query and document prompts
query_embeddings = model.encode_query(query)
document_embeddings = model.encode_document(documents)
# Higher is more relevant (cosine, or MaxSim for KURE-v2)
scores = model.similarity(query_embeddings, document_embeddings)from sentence_transformers import SparseEncoder
model = SparseEncoder("nlpai-lab/KURE-Sparse-nano", trust_remote_code=True)
# model = SparseEncoder("nlpai-lab/KURE-Sparse-base", trust_remote_code=True)
query = "νλ―Όμ μμ μΈμ λ§λ€μ΄μ‘λμ?"
documents = [
"μΈμ’
λμμ 1443λ
μ νλ―Όμ μμ μ°½μ νκ³ 1446λ
μ μ΄λ₯Ό λ°ν¬νμλ€.",
"κΉμΉλ λ°°μΆλ 무λ₯Ό μκΈμ μ μΈ λ€ κ³ μΆ§κ°λ£¨μ μ κ°μ λ£μ΄ λ°ν¨μν¨ μμμ΄λ€.",
"νλΌμ°μ ν΄λ° 1,947mλ‘ λ¨νμμ κ°μ₯ λμ μ°μ΄λ©° μ μ£Όλ μ€μμ μ리νλ€.",
]
# encode_query / encode_document add the query and document markers KURE-Sparse-nano expects
query_embeddings = model.encode_query(query)
document_embeddings = model.encode_document(documents)
# Dot-product scores (higher is more relevant)
scores = model.similarity(query_embeddings, document_embeddings)from sentence_transformers import CrossEncoder
model = CrossEncoder("nlpai-lab/KURE-Reranker-nano", max_length=8192)
# model = CrossEncoder("nlpai-lab/KURE-Reranker-base", max_length=8192)
query = "νλ―Όμ μμ μΈμ λ§λ€μ΄μ‘λμ?"
documents = [
"μΈμ’
λμμ 1443λ
μ νλ―Όμ μμ μ°½μ νκ³ 1446λ
μ μ΄λ₯Ό λ°ν¬νμλ€.",
"κΉμΉλ λ°°μΆλ 무λ₯Ό μκΈμ μ μΈ λ€ κ³ μΆ§κ°λ£¨μ μ κ°μ λ£μ΄ λ°ν¨μν¨ μμμ΄λ€.",
"νλΌμ°μ ν΄λ° 1,947mλ‘ λ¨νμμ κ°μ₯ λμ μ°μ΄λ©° μ μ£Όλ μ€μμ μ리νλ€.",
]
# Higher is more relevant
results = model.rank(query, documents, return_documents=True)We evaluate on the nine MTEB(kor, v2) Retrieval tasks with the latest mteb (v2), using the Korean subsets only (Belebele: kor_Hang-kor_Hang; MLDR is the mean of its dev/test splits):
- Ko-StrategyQA: Korean ODQA multi-hop retrieval (translated StrategyQA)
- AutoRAGRetrieval: document retrieval over parsed PDFs in finance, public sector, healthcare, law, and commerce
- MIRACLRetrieval: Wikipedia-based retrieval, ~1.5M documents
- PublicHealthQA: medical / public-health domain retrieval
- BelebeleRetrieval: FLORES-200-based retrieval
- MrTidyRetrieval: Wikipedia-based retrieval, ~1.5M documents
- MultiLongDocRetrieval: long-document retrieval across domains
- LawIRKo: Korean statute / case-law retrieval
- SQuADKorV1Retrieval: KorQuAD v1 passage retrieval
Dense models are evaluated with mteb, and late-interaction models with mteb + PLAID (4-bit) retrieval. Models with results in the official MTEB results repository use those scores, and the others are run with eval/dense/evaluate.py. To evaluate a model, pass its name and paradigm:
uv run python eval/dense/evaluate.py nlpai-lab/KURE-v3 single-vector
uv run --extra late-interaction --no-default-groups python eval/dense/evaluate.py nlpai-lab/KURE-v2 multi-vectorAverage over the nine tasks. Per-task scores are in eval/dense/results/README.md and on the official MTEB Leaderboard.
| Model | Type | Params | Avg nDCG@10 | Avg Recall@10 |
|---|---|---|---|---|
| nlpai-lab/KURE-v2 | Late-interaction | 154M | 0.8160 | 0.8921 |
| nvidia/Nemotron-3-Embed-8B-BF16 | Dense | 8.0B | 0.8127 | 0.8934 |
| yjoonjang/colbert-ko-en-v2 | Late-interaction | 149M | 0.8063 | 0.8827 |
| nlpai-lab/KURE-v3 | Dense | 1.1B | 0.8027 | 0.8857 |
| sionic-ai/comsat-embed-ko-8b-preview | Dense | 7.6B | 0.7927 | 0.8876 |
| lightonai/mLateOn | Late-interaction | 307M | 0.7906 | 0.8740 |
| Qwen/Qwen3-Embedding-8B | Dense | 7.6B | 0.7826 | 0.8815 |
| nvidia/Nemotron-3-Embed-1B-BF16 | Dense | 1.1B | 0.7817 | 0.8690 |
| Qwen/Qwen3-Embedding-4B | Dense | 4.0B | 0.7737 | 0.8753 |
| perplexity-ai/pplx-embed-v1-4b | Dense | 4.0B | 0.7705 | 0.8699 |
| microsoft/harrier-oss-v1-27b | Dense | 27.0B | 0.7667 | 0.8624 |
| dragonkue/snowflake-arctic-embed-l-v2.0-ko | Dense | 568M | 0.7653 | 0.8609 |
| codefuse-ai/F2LLM-v2-8B | Dense | 7.6B | 0.7638 | 0.8593 |
| telepix/PIXIE-Rune-v1.5 | Dense | 568M | 0.7618 | 0.8596 |
| nlpai-lab/KURE-v1 | Dense | 568M | 0.7616 | 0.8629 |
| kakaocorp/kanana-2-3b-embedding | Dense | 3.2B | 0.7584 | 0.8569 |
| nvidia/llama-nemotron-embed-1b-v2 | Dense | 1.2B | 0.7564 | 0.8560 |
| dragonkue/BGE-m3-ko | Dense | 568M | 0.7547 | 0.8513 |
| BAAI/bge-m3 | Dense | 568M | 0.7509 | 0.8588 |
| jinaai/jina-embeddings-v5-text-small-retrieval | Dense | 596M | 0.7419 | 0.8434 |
| perplexity-ai/pplx-embed-v1-0.6b | Dense | 596M | 0.7390 | 0.8377 |
| perplexity-ai/pplx-embed-v1-late-0.6b | Late-interaction | 596M | 0.7381 | 0.8328 |
| nlpai-lab/KoE5 | Dense | 560M | 0.7337 | 0.8300 |
| nlpai-lab/KURE-v2-unsupervised | Late-interaction | 154M | 0.7283 | 0.8268 |
| google/embeddinggemma-300m | Dense | 308M | 0.7254 | 0.8383 |
| kakaocorp/kanana-2-1.3b-embedding | Dense | 1.3B | 0.7172 | 0.8204 |
| Qwen/Qwen3-Embedding-0.6B | Dense | 596M | 0.7140 | 0.8222 |
| dragonkue/colbert-ko-0.1b | Late-interaction | 149M | 0.6776 | 0.7723 |
| yjoonjang/colbert-ko-v1 | Late-interaction | 149M | 0.6282 | 0.7212 |
Truncated to 1,024 dimensions, KURE-v3 keeps 99% of its full-size score and still outperforms comsat-embed-ko-8b-preview and Qwen3-Embedding-8B (4,096 dimensions). Per-dimension scores are in eval/dense/results/README.md.
Dense and late-interaction models are also evaluated on RTEB, an English retrieval benchmark, using its eight public tasks outside the code domain. The average differs from the RTEB leaderboard score, which also covers private and code tasks. Per-task scores are in eval/dense/results/README.md.
uv run python eval/dense/evaluate.py nlpai-lab/KURE-v3 single-vector --suite rteb_engLearned sparse models are evaluated on the same nine tasks under the same conventions, with mteb's SparseEncoder wrapper in bf16 at up to 8,192 tokens and without pruning the vectors. Next to nDCG@10, we report the average number of active dimensions per query and per document, and FLOPs. To evaluate a sparse model:
uv run python eval/sparse/evaluate.py nlpai-lab/KURE-Sparse-nanoResults are averaged over the nine Korean retrieval tasks. The dashed lines mark dense models for reference. Per-task scores, along with English BEIR and RTEB results, are in eval/sparse/results/README.md.
| Model | Params | Avg nDCG@10 | Query dims | Document dims | FLOPs |
|---|---|---|---|---|---|
| nlpai-lab/KURE-Sparse-base | 593M | 0.7984 | 100 | 1,897 | 36.5 |
| omai-research/milco-650m | 593M | 0.7824 | 105 | 1,167 | 32.3 |
| nlpai-lab/KURE-Sparse-nano | 149M | 0.7716 | 147 | 843 | 23.0 |
| telepix/PIXIE-Splade-v1.5 | 149M | 0.7608 | 117 | 1,541 | 37.3 |
| yjoonjang/splade-ko-v1 | 149M | 0.7526 | 109 | 742 | 29.1 |
| telepix/PIXIE-Splade-v1.0 | 149M | 0.6636 | 121 | 625 | 22.4 |
| opensearch-project/opensearch-neural-sparse-encoding-multilingual-v1 | 167M | 0.5444 | 29 | 176 | 6.8 |
Sparse models are also evaluated on two English benchmarks with nDCG@10: the 13 BEIR tasks (BEIR-13), and the eight public English tasks of RTEB outside the code domain. SparseUp runs at its own length limits (128 query and 512 document tokens), and the other models at up to 8,192 tokens. The RTEB average differs from the RTEB leaderboard score, which also covers private and code tasks.
uv run python eval/sparse/evaluate.py nlpai-lab/KURE-Sparse-base --suite beir_eng --max-seq-length 8192
uv run python eval/sparse/evaluate.py nlpai-lab/KURE-Sparse-base --suite rteb_eng --max-seq-length 8192Per-task scores are in eval/sparse/results/README.md.
Rerankers are evaluated on the same nine tasks with the protocol of reranker-simple-benchmark: each query's candidates are its gold documents plus, as negatives, the BM25 top-50 minus the golds, every model runs in bf16 at up to 8,192 tokens, and we report nDCG@10 with throughput in pairs per second (PPS), measured on one NVIDIA RTX A6000 48GB. To evaluate a reranker:
bash eval/cross-encoder/fetch_eval_assets.sh # once: the BM25 candidate pools
uv run python eval/cross-encoder/evaluate.py nlpai-lab/KURE-Reranker-nano --speedResults are averaged over the nine Korean retrieval tasks. Per-task nDCG@10 and PPS are in eval/cross-encoder/results/README.md.
Training code in train/dense.
- Fine-tuned from nvidia/Nemotron-3-Embed-1B-BF16 by distilling a teacher's scores over each query's candidates on the KURE-v2 SFT data (min-max normalized KL), up to 8,192 tokens, 1 epoch.
- Matryoshka training at 2,048, 1,024, 512 and 256 dimensions.
Training code in train/sparse.
- Distilled from Qwen3-Reranker teacher on the KURE-v2 SFT data with an in-batch contrastive term plus a KL term over each query's candidates, an L1 sparsity regularization on queries and documents, up to 8,192 tokens, 1 epoch.
- KURE-Sparse-base: fine-tuned from omai-research/milco-650m, scoring over 30,522 English pivot terms plus 250,002 source-language tokens.
- KURE-Sparse-nano: the A.X-Encoder-base MLM head grafted onto KURE-v2-unsupervised, pre-finetuned on 20.7M pairs, then fine-tuned. Resulting in 36,282 vocabulary terms.
Training code in train/cross-encoder.
- Distilled from a Qwen3-Reranker teacher with pointwise MSE on the KURE-v2 SFT data flattened to 33.3M query-document pairs, 1 epoch.
- KURE-Reranker-base: Qwen/Qwen3-1.7B scored as logit("yes") β logit("no") over the Qwen3-Reranker template, up to 8,192 tokens.
- KURE-Reranker-nano: skt/A.X-Encoder-base with a single-logit head, up to 8,192 tokens.
The full two-stage training code is in train/late-interaction.
- Built on skt/A.X-Encoder-base with a multi-layer projection head (128-d per token).
- Stage 1 (PFT): large in-batch contrastive learning on 20.7M weakly related Korean/English pairs, released as KURE-v2-unsupervised.
- Stage 2 (SFT): contrastive learning + KL distillation from a reranker teacher on 3.03M triplets with hard negatives and false-negative filtering.
- Fine-tuned from BAAI/bge-m3 on ~2M Korean query-document-hard-negative(5) pairs.
- CachedGISTEmbedLoss, batch size 4,096, lr 2e-5, 1 epoch.
- Fine-tuned from intfloat/multilingual-e5-large on ko-triplet-v1.0 (~700K+ examples).
- CachedMultipleNegativesRankingLoss, batch size 512, lr 1e-5, 1 epoch. Requires
query:/passage:prefixes.
Index-size and latency benchmarks of KURE-v2 across ANN backends, token pooling and binary quantization, with runnable configurations, are in deploy/late-interaction.
MIT
If you find our models helpful, please consider citing:
@misc{kure-v3,
title = {KURE-v3: a Korean-English bilingual dense retriever},
author = {Jang, Youngjoon and Son, Junyoung and Lee, Taemin and Hong, Seongtae and Lee, Jungseob and Lim, Heuiseok},
year = {2026},
url = {https://huggingface.co/nlpai-lab/KURE-v3},
}@misc{kure-reranker,
title = {KURE-Reranker: Korean-English bilingual reranking models},
author = {Jang, Youngjoon and Hong, Seongtae and Son, Junyoung and Lee, Taemin and Lim, Heuiseok},
year = {2026},
url = {https://huggingface.co/nlpai-lab/KURE-Reranker-base},
}@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},
}@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}
}@inproceedings{jang2024koe5,
title={KoE5: A New Dataset and Model for Improving Korean Embedding Performance},
author={Jang, Youngjoon and Son, Junyoung and Park, Chanjun and Choi, Soonwoo and Lee, Byeonggoo and Lee, Taemin and Lim, Heuiseok},
booktitle={Annual Conference on Human and Language Technology},
pages={239--244},
year={2024},
organization={Human and Language Technology}
}





