feat: add OpenAI-compatible embedding provider - #187
castlenthesky wants to merge 1 commit into
Conversation
Adds `EMBEDDING_PROVIDER=openai`, which embeds through any service exposing an OpenAI-compatible `/v1/embeddings` endpoint. This covers OpenAI itself as well as locally hosted servers such as Ollama, vLLM and LM Studio. The provider is additive: FastEmbed remains the default and its behaviour is unchanged. No existing server code is refactored. - `EMBEDDING_BASE_URL` points at the endpoint, so one provider serves every OpenAI-compatible backend rather than one provider per vendor. - `EMBEDDING_API_KEY` falls back to `OPENAI_API_KEY` and then to a placeholder, because local servers do not check it but the client refuses to start without one. - `EMBEDDING_VECTOR_SIZE` is detected from the API when unset, since the dimensionality is not otherwise discoverable for arbitrary models. - `EMBEDDING_QUERY_PREFIX` / `EMBEDDING_DOCUMENT_PREFIX` support asymmetric models that expect an instruction prefix on queries but not on documents. Tests are mocked and require no network access. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01EnVZkTXryuPFcRqe8R9XAa
2ccdf6b to
66f18b3
Compare
|
Sorry for the tag list, I'll keep this brief. @anush008 @kanungle @timvisee @tbung, you've all been active here recently so you're who I landed on. @joein, pulling you in as well since this sits right next to fastembed and that's more your area than anyone's. @generall, same, if you have a minute. No pressure to read the code. What I'm really after is a steer on whether this is wanted and roughly the right shape. Any one of you saying so would unblock it. Bit of context for why I'm asking instead of just waiting. There are five open PRs doing versions of this, the oldest going back about a year, and none have had a review yet. The Ollama one (#143) was mergeable with CI passing and its author ended up closing it himself after a couple of months of not hearing anything back. I'd rather not quietly add a sixth to that pile, so if the answer is "no thanks" or "not right now", that's genuinely useful and I'll close this out. It doesn't have to be my branch, but the desire for this feature is clear, and the community is effectively begging to help add it - myself included. If it is wanted, the things I'd like a steer on:
One small practical thing: CI hasn't run here because the workflows need a maintainer to approve them for a first-time contributor. It all passes locally, 34 tests, and the provider tests are mocked so there's no network or API key involved. You just can't see any of that from here until someone clicks approve. |
|
Hi @castlenthesky, Please don't worry about "jumping the queue". I don't mind at all. Personally, my PR was born out of a specific need for a project that is still up and running, and it perfectly serves its purpose for my company. I opened my PR with the exact same spirit as your comment: to help push the development forward. I am more than happy to support any solution that brings this functionality into the main codebase, whether it's my implementation, yours, or an even better one. I completely agree with you, though: it is definitely time for this issue to move forward. |
Adds
EMBEDDING_PROVIDER=openai, so you can embed through anything that speaks the OpenAI/v1/embeddingsAPI.I've left it as a draft on purpose. There are already three open PRs doing roughly this, and I'd rather help get one of them finished than pile on a fourth. More on that below.
What it's for
Two open issues asking for exactly this:
What's been tried already
Still open, none of them reviewed:
Closed:
Why I think they stalled
Two different things going on here, and only one of them is about the code.
#55 was too big, and the maintainers said so. From @kacperlukawski in that thread:
That's a clear brief and as far as I can tell nobody has matched it since. All three of the open OpenAI PRs bundle refactors or unrelated deletions in with the feature, and all three have gone stale against master. The files they touch are the ones that keep moving.
Everything after that just looks like review bandwidth. #143 was small, mergeable and green, and the author pinged four times over two months before giving up and closing it himself. No amount of rewriting fixes that one.
There's a fragmentation problem too. OpenAI, OpenRouter, Ollama and Gemini all showed up as separate provider classes, but three of those four speak the same wire format. Reviewing them one at a time is a lot of work for not much payoff.
What I did differently
elifin the factory, six settings fields, one dependency.EMBEDDING_BASE_URLwherever you like, OpenAI, Ollama, vLLM, LM Studio and OpenRouter all become config instead of new code. That should cover feat: add OpenRouter embedding provider support #118 and both Ollama PRs.The diff
embeddings/openai.pyembeddings/types.pyembeddings/factory.pyelifbranchsettings.pypyproject.tomlopenaitests/README.mdThree bits I'd flag for whoever reviews it:
EMBEDDING_API_KEYfalls back toOPENAI_API_KEYand then to a placeholder. Local servers don't check the key, butAsyncOpenAIwon't construct without one, so a keyless endpoint would otherwise blow up with a confusing credentials error.EMBEDDING_VECTOR_SIZEgets detected by embedding a short probe string if you don't set it. There's no reliable way to read dimensionality off/v1/modelsfor arbitrary backends. Set it explicitly and the probe is skipped.EMBEDDING_QUERY_PREFIXandEMBEDDING_DOCUMENT_PREFIXare there for asymmetric models like Qwen3-Embedding, E5 and BGE, which want an instruction prefix on queries but not on documents. Both default to empty, so they're invisible if you don't need them.Testing
ruff,ruff-formatandisortare clean.mypyis clean on the new file, and the 9 pre-existing errors elsewhere are unchanged from master.What I'm actually asking
I don't want to jump the queue on four people who got here first. So, for whoever picks this up (see the comment below on who's been active lately):
Happy to mark it ready, cut it down, or close it in favour of someone else's branch.
@chaserhkj @sk7n4k3d @HosseinShahabadi @zsxh1990 @pablomichelettii, tagging you since this overlaps what you already wrote. Not trying to step on anyone, I'd just rather we combined efforts than kept filing the same PR.