design-pattern
design-pattern/factory/llm-provider-factory.md
medium
factory-llm-provider
LLM provider 工厂 — provider_name → ProviderInstance。Use when 写 Python 后端代码 / 评审涉及 `llm-provider-factory` 的 PR。
factoryproviderllm工厂
paths
**/services/llm_*.py**/agents/**/*
Factory · LLM Provider 工厂
何时用 Factory
| 信号 | 用 Factory |
|---|---|
| 多个实现接口相同,需运行时选 | ✅ |
| 实现需要参数化构造(环境变量等) | ✅ |
| 单一实现 | ❌(直接 new 即可) |
| 需依赖注入 | ✅ |
LLM Provider Factory 示例
# services/llm_factory.py
from abc import ABC, abstractmethod
from typing import AsyncGenerator
from langchain_community.chat_models import ChatTongyi, ChatOpenAI
from core.config import llm_settings
class LLMProvider(ABC):
@abstractmethod
async def astream(self, prompt: str) -> AsyncGenerator[str, None]: ...
class QwenProvider(LLMProvider):
def __init__(self, model: str = "qwen-plus"):
self.llm = ChatTongyi(
model=model,
dashscope_api_key=llm_settings.dashscope_api_key,
streaming=True,
)
async def astream(self, prompt: str):
async for chunk in self.llm.astream(prompt):
yield chunk.content
class OpenAIProvider(LLMProvider):
def __init__(self, model: str = "gpt-4o-mini"):
self.llm = ChatOpenAI(
model=model,
api_key=llm_settings.openai_api_key,
base_url=llm_settings.openai_base_url,
streaming=True,
)
async def astream(self, prompt: str):
async for chunk in self.llm.astream(prompt):
yield chunk.content
# Factory
PROVIDERS: dict[str, type[LLMProvider]] = {
"qwen": QwenProvider,
"openai": OpenAIProvider,
}
def get_llm(provider: str = "qwen", **kwargs) -> LLMProvider:
if provider not in PROVIDERS:
raise ValueError(f"unknown provider: {provider}")
return PROVIDERS[provider](**kwargs)
使用
llm = get_llm("qwen")
async for chunk in llm.astream(prompt):
print(chunk)
# 降级到备用
llm = get_llm("openai")
注册新 Provider
class ClaudeProvider(LLMProvider):
...
PROVIDERS["claude"] = ClaudeProvider
调用方代码不变(开放 / 封闭原则)。
与依赖注入协同
FastAPI 风格:
# core/deps.py
def get_default_llm() -> LLMProvider:
return get_llm("qwen")
@router.post("/stream")
async def stream(
req: ...,
llm: Annotated[LLMProvider, Depends(get_default_llm)],
):
...
反例
# ❌ 在 Service 内 if/else 选 provider
async def generate(prompt: str, provider: str):
if provider == "qwen":
llm = ChatTongyi(...)
elif provider == "openai":
llm = ChatOpenAI(...)
# 新增 claude 要改这里所有 service
# ✅ 用工厂
llm = get_llm(provider)
自检
- [ ] 多个实现继承公共抽象 LLMProvider?
- [ ] 工厂函数 get_llm() 集中创建?
- [ ] 注册表 PROVIDERS 可扩展?
- [ ] 调用方不知道具体类(只用接口)?