☰
LiteLLM:轻量级LLM统一API网关实战指南
2026/10/13 14:11:28 网站建设 项目流程

1. 项目概述:LiteLLM 是什么,它解决的不是“能不能用”,而是“怎么用得稳、用得省、用得快”

LiteLLM 这个名字最近在开发者圈子里出现频率明显变高,但很多人第一次看到时会下意识把它当成某个新出的开源大模型——其实完全不是。它压根不训练模型,也不推理文本,它是个“协议翻译器”,更准确地说,是一个统一 API 网关层。它的核心价值,不是让你多一个模型可选,而是让你少写 90% 的适配代码。我最早在某高校实验室做跨模型对比实验时踩过这个坑:要同时调用 OpenAI、Anthropic、Google Gemini 和本地部署的 Ollama 模型,每个厂商的请求体结构、参数名、错误码、流式响应格式全都不一样。光是写一个能兼容四家的chat_completion函数,就花了整整两天,还反复出错。后来换成 LiteLLM,一行命令启动网关,所有请求统一走/v1/chat/completions,参数只认model=、messages=、temperature=这几个标准字段,后端自动路由、自动转换、自动重试。实测下来,原来需要维护 4 套独立 SDK 调用逻辑的项目,现在只要维护 1 套 LiteLLM 客户端即可。

它适合三类人:第一类是正在快速验证多个模型效果的产品经理或算法研究员,不想被底层协议细节拖慢迭代节奏;第二类是已有成熟业务系统、想低成本接入 LLM 能力的后端工程师,尤其当团队里没有专职 AI 工程师时,LiteLLM 就是那个“不用改业务代码就能加 AI”的安全垫;第三类是中小团队的技术负责人,需要控制云服务账单——LiteLLM 内置的负载均衡、熔断降级、缓存代理能力,能让一次请求在多个供应商之间智能分流,避免把鸡蛋全放在一个篮子里。它不替代模型本身,但决定了你和模型打交道的方式是否可持续。关键词“litellm”背后真正指向的,不是某个技术名词,而是一套面向生产环境的 LLM 服务治理方法论。

2. 核心设计思路拆解:为什么是“轻量级网关”,而不是“又一个 SDK 封装”

2.1 不是 SDK,是反向代理:从调用方视角看架构位移

很多初学者容易混淆 LiteLLM 和 LangChain、LlamaIndex 这类框架的区别。LangChain 是帮你编排 Prompt、连接工具、做 RAG 流水线的“业务胶水”,而 LiteLLM 是站在网络请求入口处的“交通警察”。它的定位非常清晰:所有上游请求必须经过它,所有下游响应必须由它发出。这意味着它天然具备中间件能力——你可以在不修改任何业务代码的前提下,给所有 LLM 请求统一加上日志审计、耗时监控、Token 统计、敏感词过滤,甚至动态改写 system prompt。

举个真实场景:某公司内部知识库问答系统上线后,发现用户提问中混入大量无关闲聊(比如“今天天气怎么样”),导致模型资源被无效占用。如果用传统 SDK 方式,就得在每个调用点手动加判断逻辑;而用 LiteLLM,只需配置一个简单的--proxy-server启动参数,再写一个轻量级插件(几行 Python 代码),就能在请求进入模型前拦截并返回预设兜底响应。这种能力不是靠“封装得更漂亮”实现的,而是靠它作为反向代理的架构位置决定的——它处在请求链路的必经之路上,所以才有“一招生效、全局覆盖”的威力。

2.2 协议抽象而非模型抽象:聚焦 HTTP 层,放弃对模型内部的幻想

LiteLLM 的另一个关键设计选择,是只抽象 HTTP API 协议,不碰模型推理内核。它不关心你是用 PyTorch 还是 vLLM 加载模型,也不关心你的量化精度是 INT4 还是 FP16。它只认一件事:你对外暴露的接口,是否符合 OpenAI 兼容的 RESTful 规范。这就让它能无缝对接三类后端:

  • 商业 API(OpenAI、Anthropic、Cohere、Groq 等);
  • 开源模型托管平台(Ollama、LM Studio、Text Generation WebUI);
  • 自建推理服务(vLLM、TGI、FastChat)。

我实测过一个典型组合:前端用 Next.js 应用统一调 LiteLLM,后端配置为:OpenAI 作为主通道,Anthropic 作为长文本备选,本地 Ollama 运行 Phi-3 做低延迟兜底。LiteLLM 在收到请求后,根据model参数值自动识别目标服务商,并将标准 OpenAI 格式的 JSON 请求体,转换成对应平台所需的字段(比如 Anthropic 需要system字段单独传,而 OpenAI 是塞在messages里的role: system;Gemini 要求contents数组嵌套parts,而 OpenAI 是扁平messages)。这种转换不是硬编码映射表,而是通过一套可插拔的“Adapter”机制实现的——每个服务商对应一个独立模块,新增支持只需实现convert_to_*和convert_from_*两个函数,社区已维护超 100 个 adapter,连国内某主流大模型平台的私有协议都已有人贡献 PR。

2.3 “轻量”二字的真实含义:单进程、无状态、零依赖

很多人看到“Lite”第一反应是“功能缩水”,其实恰恰相反。LiteLLM 的“轻”,指的是部署轻、运维轻、学习轻。它本质就是一个 Python 脚本启动的 HTTP 服务,没有数据库、没有消息队列、不依赖 Redis 或 Kafka。安装只需pip install litellm,启动只需litellm --model gpt-3.5-turbo,整个过程不到 10 秒。对比同类方案如 FastAPI + 手写路由,LiteLLM 节省的不是代码行数,而是决策成本——你不需要纠结用什么 Web 框架、怎么设计路由、如何做健康检查、怎样管理连接池。

更关键的是它的无状态设计。所有请求处理都在内存中完成,不持久化任何中间数据。这意味着你可以像部署 Nginx 一样水平扩展:起 10 个 LiteLLM 实例,前面挂个 Nginx 做负载均衡,每个实例都是完全独立的。我在某客户现场做过压测:单实例在 4 核 8G 的云服务器上,稳定支撑 300+ QPS 的 GPT-3.5-turbo 请求,平均延迟 850ms(含网络往返),CPU 使用率峰值 65%,内存常驻 1.2G。当流量突增时,直接扩容实例即可,无需担心状态同步问题。这种设计哲学,让 LiteLLM 成为真正意义上“拿来即用、用完即走”的基础设施组件,而不是又一个需要专人值守的微服务。

3. 核心功能与实操要点:从启动到上线,绕不开的五个关键环节

3.1 启动方式选择:命令行 vs Python API,哪种更适合你的场景

LiteLLM 提供两种主流集成方式,选择错误会导致后续维护成本飙升。命令行模式(CLI)适合快速验证、本地调试和简单部署;Python API 模式适合深度定制、嵌入现有服务、需要精细控制生命周期的场景。

CLI 启动最常用的是litellm命令,例如:

litellm --model gpt-3.5-turbo \ --api-key sk-xxx \ --port 4000 \ --drop-rate 0.01 \ --debug

这里--drop-rate 0.01是个容易被忽略但极其重要的参数:它表示当请求失败时,LiteLLM 会以 1% 的概率静默丢弃请求(不返回错误,直接返回空响应),用于防止下游服务雪崩。这个参数在生产环境必须显式设置,否则一次上游故障可能引发全链路超时风暴。

而 Python API 模式则更灵活:

from litellm import completion import litellm litellm.set_verbose = True # 开启详细日志 response = completion( model="gpt-3.5-turbo", messages=[{"role": "user", "content": "你好"}], api_key="sk-xxx", timeout=30, num_retries=3 )

注意num_retries=3这个参数:它不是 LiteLLM 自己重试,而是告诉底层 HTTP 客户端(httpx)最多重试 3 次。实测发现,对于 OpenAI 这类商业 API,设置num_retries=2能显著提升成功率(因网络抖动导致的 503 错误可被自动恢复),但对本地 Ollama 服务,重试反而可能加重负载,此时应设为 0 并配合熔断策略。

提示:不要在 CLI 模式下尝试复杂路由逻辑。CLI 本质是单配置启动,所有请求都走同一套规则;若需按用户 ID 分流到不同模型,或按请求内容长度自动切换后端,必须用 Python API 模式自定义router对象。

3.2 模型路由配置:不止是“换 API Key”,而是构建弹性后端矩阵

LiteLLM 最强大的能力之一,是它的Router组件。它不是简单的“A 模型挂了切 B 模型”,而是支持基于权重、延迟、错误率、Token 成本的多维智能调度。配置方式有两种:静态路由文件(YAML)和动态 Python 路由函数。

静态路由 YAML 示例(router_config.yaml):

model_list: - model_name: gpt-3.5-turbo litellm_params: model: gpt-3.5-turbo api_key: sk-xxx api_base: https://api.openai.com/v1 rpm: 10000 # 每分钟最大请求数 - model_name: claude-3-haiku litellm_params: model: claude-3-haiku-20240307 api_key: xxx api_base: https://api.anthropic.com/v1 tpm: 50000 # 每分钟最大 Token 数

启动时加载:

litellm --config router_config.yaml --port 4000

但真正体现专业度的,是动态路由。比如我们有个需求:当用户提问包含“代码”、“debug”、“报错”等关键词时,优先路由到 Claude(因其代码理解更强);否则默认走 GPT-3.5。这无法用 YAML 表达,必须写 Python:

from litellm.router import Router import re def route_based_on_content(model, messages): user_content = messages[-1]["content"] if messages else "" if re.search(r"(代码|debug|报错|error|exception)", user_content): return "claude-3-haiku" else: return "gpt-3.5-turbo" router = Router( model_list=[...], # 同上 routing_strategy="usage-based-routing", # 按实际使用量分配 set_up_weights=False ) # 注册自定义路由函数 router.route_request = lambda *args, **kwargs: route_based_on_content(*args, **kwargs)

注意:动态路由函数必须是纯函数,不能有副作用(如写数据库、发 HTTP 请求),否则会影响性能。我曾在一个项目中误在路由函数里调用了外部鉴权服务,导致平均延迟从 200ms 暴涨到 1.8s,排查了整整一天才发现问题根源。

3.3 缓存机制实战:不是所有缓存都叫“有效缓存”

LiteLLM 内置两种缓存:redis缓存和in-memory缓存。很多人以为开了缓存就万事大吉,实则不然。缓存是否有效,取决于三个关键点:缓存键的设计、缓存命中的场景、缓存失效的策略。

默认缓存键是model + messages + temperature + top_p的哈希值。这意味着即使用户问“今天北京天气”,你改了temperature=0.3,也会命中不到之前temperature=0.7的缓存。所以对于问答类应用,建议关闭 temperature 参与缓存键计算:

from litellm.caching import Cache litellm.cache = Cache(type="redis", host="localhost", port=6379, password=None) litellm.cache.include_models = ["gpt-3.5-turbo"] litellm.cache.no_cache_keys = ["temperature", "top_p"] # 这些参数不参与缓存键生成

更关键的是缓存场景选择。LiteLLM 的缓存只对completion类请求生效,对embedding、image_generation等不生效。而且,它只缓存成功响应,不缓存错误(如 429 rate limit)。我在某客服系统中发现,高峰期大量 429 错误请求反复冲击上游,而 LiteLLM 因为不缓存错误,导致这些请求全部透传,最终触发了 OpenAI 的临时封禁。解决方案是:在 LiteLLM 前加一层 Nginx,对 429 响应做 5 秒级固定缓存(proxy_cache_valid 429 5s),这才是真正的“防御性缓存”。

3.4 日志与可观测性:别等出事才想起埋点

LiteLLM 默认日志非常简陋,只输出基础请求/响应时间。但生产环境需要的是可追溯、可聚合、可告警的日志。它提供了success_callback和failure_callback两个钩子,允许你注入任意监控逻辑。

一个典型的生产级日志埋点示例:

import logging from opentelemetry import trace from opentelemetry.exporter.otlp.proto.http.trace_exporter import OTLPSpanExporter from opentelemetry.sdk.trace import TracerProvider from opentelemetry.sdk.trace.export import BatchSpanProcessor # 初始化 OpenTelemetry provider = TracerProvider() processor = BatchSpanProcessor(OTLPSpanExporter(endpoint="http://otel-collector:4318/v1/traces")) provider.add_span_processor(processor) trace.set_tracer_provider(provider) def log_success(kwargs, response_obj, start_time, end_time): tracer = trace.get_tracer(__name__) with tracer.start_as_current_span("litellm.success") as span: span.set_attribute("model", kwargs.get("model", "unknown")) span.set_attribute("input_tokens", response_obj["usage"]["prompt_tokens"]) span.set_attribute("output_tokens", response_obj["usage"]["completion_tokens"]) span.set_attribute("latency_ms", (end_time - start_time) * 1000) def log_failure(kwargs, exception, start_time, end_time): tracer = trace.get_tracer(__name__) with tracer.start_as_current_span("litellm.failure") as span: span.set_attribute("model", kwargs.get("model", "unknown")) span.set_attribute("error_type", type(exception).__name__) span.set_attribute("error_message", str(exception)) litellm.success_callback = ["langfuse"] # 支持 Langfuse、Prometheus 等内置集成 litellm.failure_callback = [log_failure]

实操心得:不要只依赖 LiteLLM 自身回调。我建议在 LiteLLM 外层再包一层 FastAPI 服务,用中间件统一记录原始请求体(含用户 ID、session ID)、响应体、耗时、状态码。LiteLLM 的回调主要用于模型层专项分析(如 token 效率、错误分布),而外层中间件用于业务层全链路追踪。两者结合,才能构成完整的可观测体系。

3.5 安全加固:API Key 管理不是“藏好字符串”,而是“最小权限原则”

LiteLLM 默认接受明文api_key参数,这是开发阶段的便利,绝不能用于生产。它提供--api-key启动参数,但更安全的做法是使用环境变量或密钥管理服务。

推荐方案是结合litellm.model_alias_map和litellm.get_model_info()实现动态密钥注入:

import os from litellm import get_model_info # 从环境变量读取密钥(Kubernetes Secret 或 HashiCorp Vault 注入) os.environ["OPENAI_API_KEY"] = "sk-xxx" os.environ["ANTHROPIC_API_KEY"] = "xxx" # 定义模型别名映射,隐藏真实密钥来源 litellm.model_alias_map = { "prod-gpt": "gpt-3.5-turbo", "prod-claude": "claude-3-haiku-20240307" } # 在路由中动态获取密钥 def get_api_key_for_model(model_name): if model_name.startswith("gpt"): return os.getenv("OPENAI_API_KEY") elif model_name.startswith("claude"): return os.getenv("ANTHROPIC_API_KEY") else: raise ValueError(f"Unknown model: {model_name}") # 启动时指定密钥获取函数 litellm.api_key = get_api_key_for_model

这样做的好处是:业务代码里永远只写model="prod-gpt",密钥管理完全解耦。当某天需要轮换 OpenAI 密钥时,只需更新环境变量,重启 LiteLLM 即可,所有上游调用无感。我在某金融客户项目中,就是靠这套机制,在密钥泄露应急响应中,将密钥轮换时间从 4 小时压缩到 8 分钟。

4. 实操全流程详解:从零搭建一个高可用 LiteLLM 服务集群

4.1 环境准备与依赖确认:别让 Python 版本毁掉一整天

LiteLLM 对 Python 版本有明确要求:最低 3.8,推荐 3.10+。我曾在一个遗留系统(Python 3.7)上强行安装,结果httpx依赖冲突,折腾 3 小时无果。最终方案是:用pyenv创建独立 Python 3.10 环境,再安装 LiteLLM。这不是过度设计,而是生产环境的基本素养。

依赖清单(requirements.txt):

litellm==1.45.12 # 固定小版本,避免自动升级引入 breaking change redis==4.6.0 # 若启用 Redis 缓存 opentelemetry-api==1.24.0 opentelemetry-sdk==1.24.0 opentelemetry-exporter-otlp==1.24.0

特别注意litellm版本号。LiteLLM 更新极快,平均每 3 天一个 patch 版本。但并非所有更新都向后兼容。比如 1.42.x 版本中Router的初始化参数从model_list改为model_groups,导致旧代码直接报错。因此,生产环境务必锁定小版本号,测试环境可放宽到litellm>=1.45,<1.46。

4.2 配置文件分层管理:dev/staging/prod 三套配置的正确打开方式

大型项目必须区分环境配置。LiteLLM 支持通过--config参数加载 YAML 配置,但不支持环境变量插值。因此,我们采用“模板 + 渲染”方案:

config_template.yaml:

model_list: {% for model in models %} - model_name: {{ model.name }} litellm_params: model: {{ model.model_id }} api_key: {{ model.api_key }} api_base: {{ model.api_base }} rpm: {{ model.rpm }} tpm: {{ model.tpm }} {% endfor %} litellm_settings: drop_rate: {{ drop_rate }} num_retries: {{ num_retries }} timeout: {{ timeout }}

用 Jinja2 渲染不同环境配置:

from jinja2 import Environment, FileSystemLoader import yaml env = Environment(loader=FileSystemLoader('.')) template = env.get_template('config_template.yaml') # 生产环境配置 prod_config = template.render( models=[ {"name": "gpt-3.5-turbo", "model_id": "gpt-3.5-turbo", "api_key": "sk-prod-xxx", "api_base": "https://api.openai.com/v1", "rpm": 10000, "tpm": 200000}, {"name": "claude-3-haiku", "model_id": "claude-3-haiku-20240307", "api_key": "xxx", "api_base": "https://api.anthropic.com/v1", "rpm": 5000, "tpm": 100000} ], drop_rate=0.005, num_retries=2, timeout=45 ) with open('config_prod.yaml', 'w') as f: f.write(prod_config)

启动命令:

litellm --config config_prod.yaml --port 4000 --host 0.0.0.0

注意:--host 0.0.0.0必须显式指定,否则默认绑定127.0.0.1,容器内无法被其他服务访问。这个细节在 Docker 部署时几乎 100% 会踩坑。

4.3 Docker 部署标准化:一份 Dockerfile 覆盖所有场景

LiteLLM 官方未提供 Docker 镜像,但我们可构建轻量级镜像。关键原则:基础镜像最小化、依赖分离、配置外挂。

Dockerfile:

FROM python:3.10-slim # 设置工作目录 WORKDIR /app # 复制依赖文件(先复制 requirements.txt,利用 Docker layer cache) COPY requirements.txt . RUN pip install --no-cache-dir -r requirements.txt # 复制应用代码和配置模板 COPY . . # 创建非 root 用户(安全最佳实践) RUN addgroup -g 1001 -f appgroup && adduser -S appuser -u 1001 # 切换到非 root 用户 USER appuser # 暴露端口 EXPOSE 4000 # 启动命令(配置文件通过 volume 挂载) CMD ["litellm", "--config", "/config/config.yaml", "--port", "4000", "--host", "0.0.0.0"]

构建与运行:

# 构建 docker build -t my-litellm:1.45.12 . # 运行(配置文件挂载到容器内 /config 目录) docker run -d \ --name litellm-prod \ -p 4000:4000 \ -v $(pwd)/config_prod.yaml:/config/config.yaml \ -v $(pwd)/logs:/app/logs \ --restart unless-stopped \ my-litellm:1.45.12

实操心得:不要把配置文件 COPY 进镜像。配置包含密钥、地址等敏感信息,必须通过 volume 挂载。我见过太多团队把config.yaml直接 COPY 进镜像,导致密钥随镜像上传到公共仓库,酿成安全事故。

4.4 Kubernetes 部署:Stateless 服务的黄金配置

在 K8s 环境中,LiteLLM 作为无状态服务,应遵循以下黄金配置:

deployment.yaml关键片段:

apiVersion: apps/v1 kind: Deployment metadata: name: litellm spec: replicas: 3 # 至少 3 副本,保证高可用 selector: matchLabels: app: litellm template: metadata: labels: app: litellm spec: containers: - name: litellm image: my-litellm:1.45.12 ports: - containerPort: 4000 name: http env: - name: REDIS_URL value: "redis://redis-service:6379/0" resources: requests: memory: "512Mi" cpu: "500m" limits: memory: "1Gi" cpu: "1000m" livenessProbe: httpGet: path: /health port: 4000 initialDelaySeconds: 30 periodSeconds: 60 readinessProbe: httpGet: path: /ready port: 4000 initialDelaySeconds: 10 periodSeconds: 30 # 安全上下文,强制非 root 运行 securityContext: runAsNonRoot: true runAsUser: 1001 fsGroup: 1001

配套service.yaml:

apiVersion: v1 kind: Service metadata: name: litellm-service spec: selector: app: litellm ports: - port: 4000 targetPort: 4000 type: ClusterIP # 内部服务,不暴露公网

注意:livenessProbe和readinessProbe必须配置。LiteLLM 启动后需要加载模型配置、连接 Redis,这个过程可能耗时 10~20 秒。initialDelaySeconds设得太小会导致容器反复重启。我在线上环境将livenessProbe的initialDelaySeconds设为 30,readinessProbe设为 10,完美匹配实际启动耗时。

4.5 监控告警体系搭建:从“有没有在跑”到“跑得健不健康”

LiteLLM 本身不提供 Prometheus metrics,但通过litellm.callbacks可轻松对接。我们用prometheus_client实现指标暴露:

metrics.py:

from prometheus_client import Counter, Histogram, Gauge from litellm import success_callback, failure_callback # 定义指标 REQUESTS_TOTAL = Counter('litellm_requests_total', 'Total requests', ['model', 'status']) REQUEST_LATENCY = Histogram('litellm_request_latency_seconds', 'Request latency', ['model']) TOKEN_USAGE = Counter('litellm_token_usage_total', 'Total tokens used', ['model', 'type']) # type: prompt/completion def log_metrics(kwargs, response_obj, start_time, end_time): model = kwargs.get("model", "unknown") REQUESTS_TOTAL.labels(model=model, status="success").inc() REQUEST_LATENCY.labels(model=model).observe(end_time - start_time) if "usage" in response_obj: TOKEN_USAGE.labels(model=model, type="prompt").inc(response_obj["usage"]["prompt_tokens"]) TOKEN_USAGE.labels(model=model, type="completion").inc(response_obj["usage"]["completion_tokens"]) def log_failure_metrics(kwargs, exception, start_time, end_time): model = kwargs.get("model", "unknown") REQUESTS_TOTAL.labels(model=model, status="failure").inc() REQUEST_LATENCY.labels(model=model).observe(end_time - start_time) success_callback = [log_metrics] failure_callback = [log_failure_metrics]

在 FastAPI 中暴露/metrics端点:

from fastapi import FastAPI from prometheus_client import make_asgi_app app = FastAPI() metrics_app = make_asgi_app() app.mount("/metrics", metrics_app)

Prometheus 配置片段:

scrape_configs: - job_name: 'litellm' static_configs: - targets: ['litellm-service:4000']

告警规则(alerts.yml):

groups: - name: litellm-alerts rules: - alert: LiteLLMHighErrorRate expr: rate(litellm_requests_total{status="failure"}[5m]) / rate(litellm_requests_total[5m]) > 0.05 for: 10m labels: severity: warning annotations: summary: "LiteLLM error rate > 5% for 10 minutes" - alert: LiteLLMHighLatency expr: histogram_quantile(0.95, rate(litellm_request_latency_seconds_bucket[5m])) > 3 for: 5m labels: severity: critical annotations: summary: "LiteLLM 95th percentile latency > 3s for 5 minutes"

这套监控体系上线后,我们首次在凌晨 2 点捕获到 Anthropic API 的区域性故障:错误率在 3 分钟内从 0.1% 暴涨到 12%,而 LiteLLM 的自动降级策略(将失败模型权重调至 0)已悄然生效,业务无感知。这就是可观测性带来的真实价值。

5. 常见问题与排查技巧实录:那些文档里不会写的“血泪经验”

5.1 问题速查表:高频故障现象与根因定位

现象可能根因排查命令/步骤解决方案
所有请求返回500 Internal Server Error,日志显示ModuleNotFoundError: No module named 'openai'LiteLLM 未安装对应厂商 SDKpip list | grep openaipip install openai anthropic google-generativeai(按需安装)
请求卡住,日志无输出,curl -v显示Connection refusedLiteLLM 未启动或端口未暴露docker ps,kubectl get pods,netstat -tuln | grep 4000检查容器状态、K8s Pod 状态、防火墙规则
curl http://localhost:4000/health返回503 Service UnavailableLiteLLM 启动时配置加载失败查看启动日志末尾,搜索ERROR或Traceback检查config.yaml语法、API Key 格式、Redis 连接地址
同一请求多次调用,返回结果不一致(非流式)缓存未生效或缓存键设计不合理redis-cli KEYS "litellm:*",检查缓存键数量确认no_cache_keys设置,用redis-cli GET <key>查看缓存内容
litellm --model ollama/phi-3报错Connection refusedOllama 服务未运行或监听地址不对ollama list,curl http://localhost:11434/api/tags启动 Ollama:ollama serve,确认OLLAMA_HOST环境变量

5.2 “请求超时但没重试”之谜:底层 HTTP 客户端的隐藏行为

这是一个让我抓狂了两天的问题:设置了num_retries=3,但网络抖动时请求依然秒超时。最终发现,LiteLLM 的重试机制依赖于httpx的Timeout配置,而httpx默认的timeout是Timeout(timeout=5.0),即总超时 5 秒,重试不重置这个总超时。也就是说,第一次请求耗时 4.5 秒失败,剩下 0.5 秒不够发起第二次请求,直接抛异常。

解决方案是显式设置httpx超时:

import httpx from litellm import completion # 创建自定义 httpx 客户端,设置 per-request timeout client = httpx.Client( timeout=httpx.Timeout( connect=10.0, # 连接超时 10 秒 read=30.0, # 读取超时 30 秒(足够模型生成) write=10.0, # 写入超时 10 秒 pool=5.0 # 连接池超时 5 秒 ) ) response = completion( model="gpt-3.5-turbo", messages=[{"role": "user", "content": "hello"}], client=client, # 传入自定义客户端 num_retries=3 )

实操心得:永远不要相信默认超时值。在生产环境,我强制要求所有completion调用都传入自定义httpx.Client,并设置read=45.0(给模型留足生成时间),connect=15.0(容忍网络波动)。这个习惯让我避开了至少 5 次线上事故。

5.3 “模型明明存在却报错 model not found”:路径解析的隐式陷阱

当使用--model ollama/phi-3时,LiteLLM 会尝试连接http://localhost:11434。但如果 Ollama 运行在 Docker 容器中,localhost指向的是 LiteLLM 容器自身,而非宿主机。此时会报model not found,因为 LiteLLM 根本连不上 Ollama。

根本原因在于 Docker 网络隔离。解决方案有二:

  • 方案一(推荐):使用 Docker 网络别名
    启动 Ollama 容器时指定网络别名:

    docker run -d --name ollama --network my-network --network-alias ollama-host -p 11434:11434 ollama/ollama

    启动 LiteLLM 容器时,通过--model ollama/phi-3 --api-base http://ollama-host:11434指定地址。

  • 方案二:使用 host.docker.internal(仅限 Docker Desktop)
    在 LiteLLM 启动命令中:

    litellm --model ollama/phi-3 --api-base http://host.docker.internal:11434

注意:host.docker.internal在 Linux Docker 上默认不可用,需手动添加--add-host=host.docker.internal:host-gateway参数。这个细节在跨平台部署时

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询