feat: add Voyage AI as embedding provider#474
feat: add Voyage AI as embedding provider#474mcinteerj wants to merge 2 commits intoAsyncFuncAI:mainfrom
Conversation
Adds VoyageEmbedderClient to support Voyage AI embeddings
(voyage-code-3) alongside existing providers (OpenAI, Google,
Ollama, Bedrock). Voyage AI's code-optimised models provide
strong retrieval quality for code repositories.
Changes:
- api/voyage_client.py: new ModelClient wrapping voyageai SDK.
Lazy client init via property + __getstate__/__setstate__ +
to_dict(exclude) to handle voyageai's non-serialisable tenacity
retry internals across pickle and adalflow's own DB serialisation.
backoff.on_exception with giveup guard for programmer errors.
acall implemented via voyageai.AsyncClient.
- api/config.py: register VoyageEmbedderClient, read
VOYAGE_AI_API_KEY env var (aliased to VOYAGE_API_KEY for SDK),
add embedder_voyage config routing, is_voyage_embedder() detection
consistent with other provider patterns.
- api/config/embedder.json: add embedder_voyage block (voyage-code-3,
batch_size 100, input_type document).
- api/tools/embedder.py: add input_type param to get_embedder() for
query vs document distinction.
- api/rag.py: query_embedder for Voyage initialised once at startup
with input_type=query (not per-call). FAISS retriever uses
query_embedder for both ollama and voyage.
- api/main.py: remove OPENAI_API_KEY from required env vars (it was
never required for non-OpenAI providers).
- api/config/generator.json: add gemini-2.0-flash-exp model params.
- docker-compose.yml: use ${HOME} for .adalflow volume path.
- README.md: document voyage embedder type, VOYAGE_AI_API_KEY env
var, and switching instructions.
Set DEEPWIKI_EMBEDDER_TYPE=voyage and VOYAGE_AI_API_KEY to use.
Summary of ChangesHello @mcinteerj, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed! This pull request significantly enhances the application's embedding capabilities by integrating Voyage AI as a new provider. This addition offers specialized models, particularly for code-related tasks, and includes robust client-side handling for proper serialization and distinct query embedding. The changes also streamline environment variable requirements and update documentation to reflect the new options, providing users with more choice and flexibility in their embedding strategies. Highlights
🧠 New Feature in Public Preview: You can now enable Memory to help Gemini Code Assist learn from your team's feedback. This makes future code reviews more consistent and personalized to your project's style. Click here to enable Memory in your admin console. Changelog
Using Gemini Code AssistThe full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips. Invoking Gemini You can request assistance from Gemini at any point by creating a comment using either
Customization To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a Limitations & Feedback Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here. You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension. Footnotes
|
- tests/unit/test_all_embedders.py: add embedder_voyage config check, VoyageEmbedderClient CLIENT_CLASSES check, is_voyage_embedder() detection test and mutual exclusivity assertion, matching the pattern from the Bedrock embedder PR (AsyncFuncAI#419) - api/data_pipeline.py: add voyage branch to count_tokens() and update docstring to include voyage type
There was a problem hiding this comment.
Code Review
This pull request adds Voyage AI as a new embedding provider, which is a great addition, especially with its code-optimized models. The implementation is thorough, with careful handling of serialization for the Voyage client and integration into the existing configuration and RAG pipeline. The changes are consistent with the existing provider patterns.
I've added a couple of suggestions to improve maintainability by refactoring some repetitive logic. These are minor points in an otherwise excellent contribution.
| elif embedder_type == 'voyage' and 'embedder_voyage' in configs: | ||
| return configs.get("embedder_voyage", {}) |
There was a problem hiding this comment.
While this addition is correct and consistent with the existing structure, the if/elif chain in get_embedder_config is becoming long and less maintainable. Each new provider requires adding another block.
Consider refactoring the entire function to be more scalable, for example:
def get_embedder_config():
"""
Get the current embedder configuration based on DEEPWIKI_EMBEDDER_TYPE.
Returns:
dict: The embedder configuration with model_client resolved
"""
embedder_type = EMBEDDER_TYPE
config_key = f"embedder_{embedder_type}"
if embedder_type != 'openai' and config_key in configs:
return configs.get(config_key, {})
# Default to 'openai' config which has the key 'embedder'
return configs.get("embedder", {})This approach avoids modifying the function for every new provider, as long as the configuration key in embedder.json follows the embedder_<type> pattern.
| api_key = self._api_key or os.getenv(self._env_api_key_name) | ||
| if not api_key: | ||
| raise ValueError( | ||
| f"Environment variable {self._env_api_key_name} must be set" | ||
| ) |
There was a problem hiding this comment.
Summary
Adds Voyage AI as an embedding provider via a new
VoyageEmbedderClient, alongside the existing OpenAI, Google, Ollama, and Bedrock providers. Voyage AI's code-optimised models (voyage-code-3) provide strong retrieval quality for code repositories.Usage
Changes
api/voyage_client.py(new):VoyageEmbedderClientwrapping thevoyageaiSDK. Handles serialisation carefully —voyageai.Clientstores tenacity retry objects internally that cannot be pickled; solved via lazy init,__getstate__/__setstate__, and ato_dict()override covering adalflow's own DB serialisation path. Retry viabackoff.on_exceptionwith agiveupguard for programmer errors.acallimplemented viavoyageai.AsyncClient.api/config.py: registerVoyageEmbedderClient, readVOYAGE_AI_API_KEY(aliased toVOYAGE_API_KEYfor the SDK), routeembedder_voyageconfig key, addis_voyage_embedder()consistent with other provider detection patterns.api/config/embedder.json: addembedder_voyageblock (voyage-code-3,batch_size: 100,input_type: document).api/tools/embedder.py: addinput_typeparam toget_embedder()for query vs document distinction.api/rag.py: Voyagequery_embedderinitialised once at startup withinput_type=query(critical — Voyage models distinguish query vs document embeddings for retrieval quality). FAISS retriever usesquery_embedderfor both Ollama and Voyage.api/main.py: removeOPENAI_API_KEYfrom required env vars (was incorrectly flagged as required for all providers).api/config/generator.json: addgemini-2.0-flash-expmodel params.docker-compose.yml: use${HOME}for.adalflowvolume path (more portable).README.md: documentvoyageembedder type,VOYAGE_AI_API_KEY, and switching instructions.Notes
voyageaiadded topyproject.toml/poetry.lockvoyage-code-3(latest Voyage code model, 1024 dimensions)