Conversation
Propose a provider-agnostic GenericLlmConfig component that uses a string-based provider.type discriminator and flexible ProviderConfig, replacing the need for per-provider LlmConfig subclasses.
|
Hi @spichen, thank you for the great work. This is a very good starting point, we have been discussing this design internally, and we agreed on a few points. Here's what we thought could be a possible solution: Instead of having a new GenericLlmConfig, we make the LlmConfig not abstract anymore. # Not abstract anymore
class LlmConfig(Component):
"""A generic, provider-agnostic LLM configuration."""
model_id: str
"""Primary model identifier"""
provider: Optional[str] = None
"""Model provider (e.g., meta, openai, anthropic, ...)"""
api_provider: Optional[str] = None
"""APIs provider (e.g., oci, openai, vertex_ai, aws_bedrock, ...)"""
api_type: Optional[str] = None
"""API protocol to use (e.g., chat_completions, responses, ...)"""Existing classes will fix the value of these attributes where needed, and they should be excluded from the serialization for brevity. class OciGenAiConfig(GenericLlmConfig):
# Don't know the (model) provider a priori
api_provider: str = "oci" # Freeze the value
...
class OpenAiConfig(GenericLlmConfig):
# We know both provider and api_provider, we fix them
provider: str = "openai" # Freeze the value
api_provider: str = "openai" # Freeze the value
...
class OpenAiCompatibleConfig(GenericLlmConfig):
# This limits only the api_type to chat_completions or responses
# We don't know what is the model, nor the api provider
...The name of the attributes are chosen to fit what is already present in some LlmConfig classes (you can give a look at the OCI ones for example). The main reason for this choice is that all the attributes are quite independent from each other, and collecting them in a Provider class would require to fix one of the attributes, but in an unclear manner, and the number of subclasses could explode. For example: meta model exposed by AWS bedrock behind responses APIs, cohere model exposed by OCI behind chat_completions, ... Let us know what you think about it. |
|
Hi @cesarebernardis , thanks for the thoughtful feedback and for discussing this internally. I agree with the direction here. Making Totally on board with deferring Auth as well. Better to land the provider/API fields as a focused change and layer authentication on top later. I'll rework the PR to follow this approach. Let me know if there's anything else you'd like adjusted. |
Strong support for this RFC — concrete use case: OpenRouter + reasoning tokensI want to share a concrete problem that this RFC would unblock. The problem todayWhen using OpenRouter (or similar routing proxies like LiteLLM) with Agent Spec + the LangGraph adapter, the only viable config types are The issue is that
This is a known and tracked problem on the LangChain side:
LangChain's solution is provider-specific packages. For example, But the current Agent Spec type hierarchy has no way to reach these provider-specific LangChain classes. The How this RFC solves itThe component_type: LlmConfig
model_id: "anthropic/claude-sonnet-4"
api_provider: openrouter
api_type: chat_completions
default_generation_parameters:
temperature: 0.7And on the adapter side: # In _llm_convert_to_langgraph, string-based dispatch for bare LlmConfig:
elif llm_config.api_provider == "openrouter":
from langchain_openrouter import ChatOpenRouter
return ChatOpenRouter(model=llm_config.model_id, ...)Without this RFC, the only alternative is adding a full Suggestions
Overall, this is a well-designed proposal. The three-axis separation ( |
Propose a provider-agnostic GenericLlmConfig component that uses a string-based provider.type discriminator and flexible ProviderConfig, replacing the need for per-provider LlmConfig subclasses.