-
-
Notifications
You must be signed in to change notification settings - Fork 304
Description
Thanks for the PRs adding new providers – it's great to see Ruby LLM expanding! As we add support for meta-providers like Bedrock (#50) and OpenRouter (#29), which resell access to models from OpenAI, Anthropic, etc., we need a consistent approach to model names.
The Problem
Right now, we're at risk of inconsistent naming like:
claude-3-5-sonnet-20241022(direct from Anthropic)anthropic.claude-3-5-sonnet-20241022-v2:0:200k(via Bedrock)anthropic/claude-3.5-sonnet(via OpenRouter)
This creates an unnecessary cognitive burden and makes switching providers harder than it needs to be.
The Ruby LLM Way
We'll implement a cleaner approach separating what (model) from where (provider):
# Default way (from the native provider)
chat = RubyLLM.chat(model: "claude-3-5-sonnet")
# Same model via different provider
chat = RubyLLM.chat(model: "claude-3-5-sonnet", provider: :bedrock)This has several benefits:
- Clean API - Model names stay simple and consistent
- Provider flexibility - Switch providers without changing model references
- Future-proof - New providers can be added without disrupting existing code
Managing models.json
For all providers, including those with large model catalogs like OpenRouter, Ollama, and HuggingFace:
- Comprehensive models.json - We'll maintain a comprehensive models.json file that includes models from all supported providers
- Easy refreshing - Users can update their local models catalog with
RubyLLM.models.refresh!when needed - Regular updates - We'll keep the distributed models.json up-to-date through automated processes
This approach provides the best balance of simplicity, usability, and maintainability.
Model Aliases
To handle provider-specific model identifiers and versions, we'll implement a global model alias system:
- Global aliases.json - We'll maintain a central
aliases.jsonfile mapping friendly model names to provider-specific identifiers - Provider mapping - Each provider implementation will use these aliases to map standard names to their specific format
Example aliases.json structure:
{
"claude-3-5-sonnet": {
"anthropic": "claude-3-5-sonnet-20241022",
"bedrock": "anthropic.claude-3-5-sonnet-20241022-v2:0:200k",
"openrouter": "anthropic/claude-3.5-sonnet"
},
"gpt-4o": {
"openai": "gpt-4o-2024-05-13",
"bedrock": "anthropic.gpt-4o-2024-05-13",
"openrouter": "openai/gpt-4o"
}
}This allows users to use consistent model names regardless of provider:
# These all use the same logical model through different providers
chat1 = RubyLLM.chat(model: "claude-3-5-sonnet") # Uses Anthropic directly
chat2 = RubyLLM.chat(model: "claude-3-5-sonnet", provider: :bedrock) # Uses via AWS Bedrock
chat3 = RubyLLM.chat(model: "claude-3-5-sonnet", provider: :openrouter) # Uses via OpenRouterIf a model can't be found with the provided ID and provider, a ModelNotFoundError will be raised with an informative message. Your implementation should make this error helpful by suggesting available alternatives.
When the same model has multiple versions and context windows e.g.
anthropic.claude-3-5-sonnet-20240620-v1:0
anthropic.claude-3-5-sonnet-20240620-v1:0:18k
anthropic.claude-3-5-sonnet-20240620-v1:0:200k
anthropic.claude-3-5-sonnet-20240620-v1:0:51k
anthropic.claude-3-5-sonnet-20241022-v2:0
anthropic.claude-3-5-sonnet-20241022-v2:0:18k
anthropic.claude-3-5-sonnet-20241022-v2:0:200k
anthropic.claude-3-5-sonnet-20241022-v2:0:51k
We default all aliases to the biggest context window, and the main alias (without date) to the latest version:
"claude-3-5-sonnet": {
"anthropic": "claude-3-5-sonnet-20241022",
"bedrock": "anthropic.claude-3-5-sonnet-20241022-v2:0:200k",
"openrouter": "anthropic/claude-3.5-sonnet"
},
"claude-3-5-sonnet-20241022": {
"anthropic": "claude-3-5-sonnet-20241022",
"bedrock": "anthropic.claude-3-5-sonnet-20241022-v2:0:200k",
"openrouter": "anthropic/claude-3.5-sonnet"
},
"claude-3-5-sonnet-20240620": {
"anthropic": "claude-3-5-sonnet-20240620",
"bedrock": "anthropic.claude-3-5-sonnet-20240620-v1:0:200k"
},Implementation Guidelines for Contributors
If you're adding a new provider:
- Use normalized model IDs - Don't include provider prefixes in the model ID itself
- Add provider mapping - Map the normalized IDs to your provider's specific format internally
- Preserve capabilities - Ensure models accessed through your provider report the same capabilities as their native counterparts
- Update models.json - Include your provider's models in models.json
- Update aliases.json - Add entries to aliases.json for models accessible through your provider
- Implement refresh mechanism - Ensure your provider supports the
list_modelsmethod for refreshing
For meta-providers (like Bedrock) that access models from existing providers:
- Models should share the same fundamental ID as their native versions
- Your provider implementation should handle any required translation
This keeps Ruby LLM's API clean and intuitive while giving users the flexibility to choose how they access their models.