You could just use cosine similarity to cluster them.
Just pick a small radius, like 0.01 or something, depending on the embedding model, and amount of embeddings you want to reduce.
Then pick a random embedding to start with and define an abstract starting label “0”. Find all embeddings, that aren’t labeled, within 0.01 of “0”, and label these “0” as well.
Then pick a random non-labeled vector, and find all vectors within 0.01 of this, and give it abstract label “1”, and mark off all these as done as well.
Keep doing this until all embeddings are abstractly labeled.
Then, when done, you have clustered embeddings.
Hopefully the algorithm makes sense. It’s a recursive for-loop, but gets faster and faster each iteration, since you skip computing the similarity for already labeled vectors.
As for the 0.01, this is a hyper parameter. Smaller means your clusters are more distinct, as you will have more clusters. Higher, and you get less clusters, and less distinction.
PS. Oh, and and because you want the categories to be “centered” in the space, you do this whole categorization multiple times, and the final label is the median or average category value. So the random seed should not be set the same for each run, it really needs to be random.