File size: 5,186 Bytes
906fe66
 
 
c61e59c
906fe66
 
c61e59c
906fe66
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
c61e59c
 
 
906fe66
810ea8e
906fe66
 
 
 
 
 
 
 
c61e59c
 
 
906fe66
 
e773f61
 
 
 
 
906fe66
 
 
 
 
 
 
 
 
 
e773f61
 
 
 
 
 
 
 
 
906fe66
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
c61e59c
906fe66
 
c61e59c
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
906fe66
 
 
c61e59c
 
906fe66
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
---
license: apache-2.0
base_model: Qwen/Qwen3-Embedding-0.6B
library_name: sentence-transformers
pipeline_tag: feature-extraction
tags:
  - transformers
  - sentence-similarity
  - retrieval
  - agent-skills
  - skill-routing
  - skillcorpus
  - contrastive-learning
  - text-embeddings-inference
language:
  - en
---

# skillcorpus-embedding-0.6b

A bi-encoder for **agent-skill retrieval**: given a task description, embed it and
the skill documents into one space so the relevant skills come back by nearest
neighbour. Fine-tuned from
[Qwen/Qwen3-Embedding-0.6B](https://huggingface.co/Qwen/Qwen3-Embedding-0.6B).

Paired with [skillcorpus-reranker-0.6b](https://huggingface.co/EverMind-AI/skillcorpus-reranker-0.6b),
which reranks this model's top candidates. The skill documents it was built to
index have the schema of
[skillcorpus-demo-1k](https://huggingface.co/datasets/EverMind-AI/skillcorpus-demo-1k).

| Property | Value |
|---|---|
| Parameters | 596M |
| Hidden size | 1024 (embedding dimension) |
| Layers | 28 |
| Precision | bfloat16 |
| Pooling | last token |
| Normalization | L2 |

Requires `transformers>=4.56` (the `dtype=` argument was named `torch_dtype=`
before that) or `sentence-transformers>=3.0`.

## Usage

The two sides are encoded asymmetrically — a task description carries an
instruction prefix, a skill is the bare `name | description | body`
concatenation. Encode them the way the model was trained or retrieval quality
drops. Embeddings come back L2-normalized, so cosine similarity is a plain dot
product.

```python
import torch
import torch.nn.functional as F
from transformers import AutoModel, AutoTokenizer

MODEL = "EverMind-AI/skillcorpus-embedding-0.6b"
tok = AutoTokenizer.from_pretrained(MODEL, padding_side="left")
model = AutoModel.from_pretrained(MODEL, dtype=torch.bfloat16).cuda().eval()

QUERY_INSTRUCTION = (
    "Instruct: Given a task description, retrieve the most relevant "
    "skill document that would help an agent complete the task\nQuery:"
)


def doc(name, description, body):
    return f"{name} | {description} | {body}"


def last_token_pool(hidden, attention_mask):
    if attention_mask[:, -1].sum() == attention_mask.shape[0]:   # left padding
        return hidden[:, -1]
    idx = attention_mask.sum(dim=1) - 1
    return hidden[torch.arange(hidden.shape[0], device=hidden.device), idx]


def embed(texts, max_length=2048):
    enc = tok(texts, padding=True, truncation=True,
              max_length=max_length, return_tensors="pt").to(model.device)
    with torch.no_grad():
        out = model(**enc).last_hidden_state
    return F.normalize(last_token_pool(out, enc["attention_mask"]), p=2, dim=1)


query = embed([QUERY_INSTRUCTION + "resolve conflicts after a git merge"])
docs = embed([doc("resolve-conflicts", "Resolve git merge conflicts.", "..."),
              doc("sourdough", "Bake sourdough bread.", "...")])
print((query @ docs.T).tolist())
# -> [[0.75, 0.07]]
```

Exact scores shift in the last decimal with dtype and hardware; the ordering is
what matters.

### With sentence-transformers

The repo ships a sentence-transformers configuration (last-token pooling + L2
normalization, and the query instruction registered as the `query` prompt), so
this path is equivalent to the code above, up to bf16 noise:

```python
from sentence_transformers import SentenceTransformer

st = SentenceTransformer("EverMind-AI/skillcorpus-embedding-0.6b")
q = st.encode(["resolve conflicts after a git merge"], prompt_name="query")
d = st.encode(["resolve-conflicts | Resolve git merge conflicts. | ...",
               "sourdough | Bake sourdough bread. | ..."])
print(st.similarity(q, d))
```

Pass `prompt_name="query"` for tasks and nothing for skill documents — that is
the asymmetry above, applied for you.

### Truncation used in training

Beyond the token-level `max_length`, each field was cut to a fixed number of
**characters** before the strings were assembled. Matching this keeps inference
inputs on the same distribution as training:

| field | limit |
|---|---|
| task description (after the instruction prefix) | 1,500 chars |
| skill `description` | 500 chars |
| skill `body` | 8,000 chars |

## Intended use

First-stage retrieval over a large skill registry: encode the registry offline,
encode each incoming task online, take the top K by cosine similarity (K in the
20–50 range is typical), then rerank that shortlist with
[skillcorpus-reranker-0.6b](https://huggingface.co/EverMind-AI/skillcorpus-reranker-0.6b).
Not a generative model — it produces embeddings, not answers.

## Citation

```bibtex
@article{wang2026skillcorpus,
  title         = {SkillCorpus: Consolidating and Evaluating the Open Skill Ecosystem for Real-World LLM Agents},
  author        = {Wang, Yanze and Yao, Pengfei and Sun, Tianyi and Hu, Chuanrui and Xiao, Yan and Luo, Xiaotian and Han, Yunyun and Chen, Yifan and Sun, Jun and Deng, Yafeng},
  year          = {2026},
  eprint        = {2607.15557},
  archivePrefix = {arXiv},
  url           = {https://arxiv.org/abs/2607.15557}
}
```

## License

Apache-2.0, inherited from the base model. Skills in the corpus keep their own
upstream licenses.