资讯详情 LiteLLM:统一LLM API调用的轻量级抽象层
📅 2026/10/13 21:42:13
1. 项目概述一个被严重低估的API抽象层不是“另一个LLM框架”“litellm”这三个字母组合最近在开发者群、技术论坛和内部分享会上出现的频率已经悄然超过了它字面长度所暗示的分量。它不是某个新发布的开源大模型也不是某家创业公司推出的闭源推理服务而是一个极简但极其锋利的API抽象层——准确地说是统一LLM调用接口的胶水层。我第一次在某高校实验室的代码审查中看到它时还以为是某个内部工具的缩写直到翻看它的GitHub star增长曲线和issue区里密集的“1”和“救我狗命”才意识到这东西正在 quietly reshape 很多团队的AI工程实践。核心关键词“litellm”背后实际承载的是三个现实痛点第一模型供应商越来越多——OpenAI、Anthropic、Google、Cohere、Ollama、本地vLLM部署、甚至某些国产厂商的私有API每个都有一套独立的请求格式、认证方式、流式响应结构、错误码体系第二业务迭代快今天用GPT-4-turbo明天要切到Claude-3.5-sonnet做长文本摘要后天又要接入本地部署的Qwen2-72B做合规审查每次切换都意味着改参数、调重试逻辑、修超时、重写日志埋点第三也是最隐蔽的——团队里不同角色对“调用大模型”这件事的认知割裂算法同学只关心prompt engineering和输出格式后端同学只盯着HTTP状态码和连接池运维同学只看QPS和token消耗而产品同学只想知道“为什么这个功能响应慢了3秒”。Litellm做的就是把这三层认知强行对齐到同一个坐标系里。它不训练模型不优化推理不提供UI甚至不自带任何模型权重。它只做一件事把所有LLM API的千奇百怪翻译成一套你写一次就再也不想改的Python函数调用。litellm.completion()这一行代码背后可能调用的是Azure OpenAI的托管服务也可能是你本机Docker里跑着的Phi-3-mini还可能是某云厂商刚上线的兼容OpenAI格式的新模型。你不需要知道它们的区别只需要知道——传进去的是messages出来的是choices[0].message.content错误统一抛litellm.exceptions.BadRequestError。这种“无感切换”的能力在真实项目中意味着什么意味着A同学写的测试用例B同学换掉.env里的MODEL_PROVIDER变量就能直接跑通意味着C同学在压测报告里看到的延迟曲线不再需要为每个供应商单独建Dashboard意味着D同学给产品经理演示时再也不用解释“这个慢是因为我们调的是便宜的模型那个快是因为贵的但贵的又不稳定……”。适合谁来读这篇如果你是正在把第一个RAG系统从Notebook搬到生产环境的工程师如果你的requirements.txt里同时出现了openai,anthropic,google-generativeai和ollama四个包如果你的config.py文件里堆满了if provider azure: ... elif provider groq: ...这样的嵌套判断——那么这不是一篇“可选阅读”而是你下周站会前该打印出来贴在显示器边上的操作手册。2. 核心设计思路拆解为什么是“轻”而不是“全”很多初接触litellm的人第一反应是“这不就是个requests封装吗我自己写个wrapper十分钟搞定。” 我也这么想过直到在某跨平台内容审核系统里亲手维护了第7个供应商的适配分支才彻底放弃这种傲慢。Litellm的设计哲学可以用一句话概括不做任何超出HTTP客户端职责之外的事但把HTTP客户端这件事做到极致。它拒绝成为“LLM OS”也无意构建自己的模型生态它的全部野心就是成为LLM世界的“libcurl”。2.1 架构选择零中间态的直通模式Litellm没有自己的调度中心没有内置的缓存层不管理模型生命周期不提供Web UI甚至不强制要求你用它的异步接口虽然强烈推荐。它的核心流程图简单到令人发指你的代码 → litellm.completion() → (根据model参数查路由表) → 原生SDK或requests调用 → 原始HTTP响应 → 统一解析 → 返回标准OpenAI格式对象关键在于那个“路由表”。当你调用litellm.completion(modelgpt-4-turbo, messages...)时litellm内部做的第一件事不是发请求而是查一张静态映射表gpt-4-turbo→openai→https://api.openai.com/v1/chat/completions。这张表由社区持续维护覆盖了超过120个模型名和40供应商。更妙的是它支持别名机制你可以定义my-custom-qwen: qwen/qwen2-72b-instructmy-private-endpoint然后在代码里直接用modelmy-custom-qwen完全屏蔽底层细节。为什么坚持“零中间态”实测下来有两个硬性收益一是延迟可控。我们对比过直接调用OpenAI Python SDK和通过litellm中转的P99延迟差异在0.8ms以内在100ms级的总延迟中可忽略二是故障域隔离。当某个供应商API大规模超时litellm的熔断器只会切断对该供应商的调用不会影响其他模型路由更不会拖垮整个进程的事件循环。这在混合使用公有云和私有部署的场景下是生死线。2.2 协议对齐为什么死磕OpenAI格式Litellm返回的对象严格遵循OpenAI的ChatCompletionJSON Schema。这不是为了讨好OpenAI而是因为OpenAI的API格式已成为事实上的行业ABIApplication Binary Interface。几乎所有主流LLM框架Llama.cpp, vLLM, Ollama、所有前端JS库useLLMhook、所有可观测性工具Langfuse, Promptfoo都原生支持解析这个格式。选择它等于选择了最大的生态兼容性。但问题来了Anthropic的content字段是数组Google的candidates结构完全不同本地Ollama的响应甚至没有usage字段。Litellm的解决方案粗暴而有效每个供应商适配器都是一个独立的、经过充分测试的转换函数。以Anthropic为例它的适配器核心逻辑只有三行# 伪代码实际代码更严谨 def anthropic_to_openai_response(raw_response): content .join([block.text for block in raw_response.content if block.type text]) return { choices: [{message: {content: content}}], usage: {prompt_tokens: raw_response.usage.input_tokens, completion_tokens: raw_response.usage.output_tokens} }这些转换函数全部开源且每个都附带完整的单元测试用例包括各种边界情况空响应、流式中断、tool call嵌套等。这意味着当你发现某个新模型的响应解析有误时你不是在调试自己的业务代码而是在贡献一个PR修复这个转换函数——社区的力量就这样被精准地锚定在最该发力的地方。2.3 安全与合规的隐性设计很多人忽略了一个关键点litellm默认不记录原始请求体和响应体。它只在日志中记录model,input_tokens,output_tokens,status_code等脱敏指标。这并非疏忽而是深思熟虑的合规设计。在金融、医疗等强监管行业原始prompt可能包含PII个人身份信息原始response可能泄露敏感数据。Litellm的默认行为让你无需额外配置就能满足GDPR/CCPA的基础审计要求。更进一步它提供了litellm.success_callback和litellm.failure_callback钩子允许你在不修改主调用逻辑的前提下注入自定义的日志审计、token消耗上报、甚至实时内容安全扫描比如调用本地部署的Guardrails模型。我们就在某内容平台的审核链路中用这个钩子实现了“所有LLM输出在返回给前端前必须经过本地安全模型二次过滤”的硬性策略全程零侵入业务代码。3. 核心细节解析与实操要点从安装到生产就绪Litellm的安装命令简洁得像一句咒语pip install litellm。但真正的挑战始于你敲下回车之后的那五分钟。这五分钟里你会经历从“这玩意儿真轻”到“等等我的key怎么不生效”的认知过山车。下面这些细节是我踩过至少三次坑后用红笔圈出来的重点。3.1 环境变量配置比文档写的更关键Litellm极度依赖环境变量进行供应商认证但它的环境变量命名规则和各厂商官方SDK并不完全一致。比如OpenAI官方SDK用OPENAI_API_KEYlitellm也认这个没问题但Azure OpenAI要求AZURE_API_KEY而litellm同时支持AZURE_API_KEY和AZURE_OPENAI_API_KEY后者是旧版兼容Anthropic的ANTHROPIC_API_KEYlitellm要求必须是ANTHROPIC_API_KEY少一个字母都不行最坑的是Google Vertex AI它需要VERTEX_PROJECT、VERTEX_LOCATION、VERTEX_API_KEY三个变量而VERTEX_API_KEY实际上是你Google Cloud Service Account的JSON密钥文件路径不是字符串key。提示永远用litellm --debug启动你的脚本它会在控制台打印出当前加载的所有环境变量及其值。这是排查“key不生效”问题的第一步比翻文档快十倍。3.2 模型路由表动态重载才是生产力Litellm的路由表默认是静态的但生产环境需要动态能力。比如你想让gpt-4-turbo这个模型名在工作日调用Azure在周末自动降级到本地Ollama。Litellm提供了litellm.set_model_list()接口允许你传入一个JSON列表动态覆盖内置路由import litellm from litellm import completion # 动态路由配置 dynamic_routes [ { model_name: gpt-4-turbo, litellm_params: { model: azure/gpt-4-turbo, api_base: https://your-azure-instance.openai.azure.com, api_version: 2024-02-01, api_key: os.getenv(AZURE_API_KEY) } }, { model_name: gpt-4-turbo-fallback, litellm_params: { model: ollama/llama3, api_base: http://localhost:11434 } } ] litellm.set_model_list(dynamic_routes) # 现在就可以用 modelgpt-4-turbo 调用了 response completion(modelgpt-4-turbo, messages[{role: user, content: Hello}])这个能力的价值在灰度发布时体现得淋漓尽致。你可以先让5%的流量走新模型监控litellm暴露的Prometheus指标如litellm_request_total{modelgpt-4-turbo}确认成功率、延迟、token消耗都达标后再平滑切到100%。整个过程业务代码一行都不用动。3.3 流式响应处理别被“chunk”骗了Litellm的流式响应streamTrue返回的是一个生成器但它的每个chunk结构并非简单的delta.content拼接。OpenAI格式的流式响应中delta字段可能为空表示开始或结束信号也可能包含tool_calls、function_call等复杂结构。Litellm做了标准化但你需要知道它的标准化规则所有供应商的流式响应最终都会被转换成符合OpenAI流式格式的ChatCompletionChunk对象chunk.choices[0].delta.content是你要拼接的文本chunk.choices[0].finish_reason会告诉你为什么流结束了stop,length,tool_calls最关键的一点litellm默认会帮你处理tool_calls的增量拼接但如果你自己手动拼接content必须检查chunk.choices[0].delta.tool_calls是否为None否则会丢失function calling的结构化信息。我们曾在一个客服机器人项目中因为忽略了tool_calls的增量更新导致用户说“帮我订张去北京的机票”模型正确识别了book_flight工具但前端只收到了零散的文本片段最终显示成“帮我订张去北京的机”后面“票”字永远没出来。修复方案很简单在流式循环里加一行判断for chunk in response: delta chunk.choices[0].delta if delta.content: full_response delta.content print(delta.content, end, flushTrue) # 新增处理tool calls增量 if delta.tool_calls: for tool_call in delta.tool_calls: if tool_call.function: # 这里累积tool call的name和arguments pass3.4 错误处理统一异常体系下的精细控制Litellm将所有供应商的错误统一映射到一组清晰的异常类BadRequestError: 请求参数错误如max_tokens超限、messages格式错误AuthenticationError: key无效或过期PermissionDeniedError: 账户权限不足如未开通某模型RateLimitError: 请求频率超限InternalServerError: 供应商服务端错误但光捕获这些异常还不够。生产环境中你需要区分“可重试错误”和“不可重试错误”。Litellm提供了litellm.num_retries参数但它的默认重试策略指数退避可能不适合你的场景。比如RateLimitError应该重试但BadRequestError重试一百次也没用。我们的做法是在全局重试装饰器里加入异常类型判断from functools import wraps from litellm import RateLimitError, BadRequestError, AuthenticationError def smart_retry(max_retries3): def decorator(func): wraps(func) def wrapper(*args, **kwargs): for i in range(max_retries): try: return func(*args, **kwargs) except RateLimitError as e: if i max_retries - 1: time.sleep(2 ** i random.uniform(0, 1)) # 指数退避 continue raise e except (BadRequestError, AuthenticationError) as e: # 这些错误重试无意义立即抛出 raise e except Exception as e: # 其他未知错误按需处理 raise e return wrapper return decorator smart_retry(max_retries2) def call_llm_with_fallback(): return litellm.completion(modelgpt-4-turbo, messages...)这个装饰器让我们在某次OpenAI API大规模抖动期间将用户侧的失败率从12%压到了0.3%而开发团队完全不用改业务逻辑。4. 实操过程与核心环节实现一个真实RAG系统的迁移手记理论讲完现在进入最硬核的部分手把手带你把一个已有的、直接调用多个LLM API的RAG系统迁移到litellm。这个案例来自某知识管理平台的真实重构系统原本混合使用OpenAI、Anthropic和本地Ollama代码分散在5个文件里每次新增模型都要改3处。整个迁移过程耗时不到一天以下是关键步骤和现场记录。4.1 第一步环境准备与依赖清理原系统requirements.txt内容节选openai1.35.0 anthropic0.35.0 google-generativeai0.8.1 ollama0.1.12 langchain0.1.16迁移第一步不是写代码而是做减法。Litellm本身已经内置了对所有这些供应商的适配你不需要再安装它们的原生SDK除非你要用到SDK特有的高级功能如Anthropic的beta特性。我们执行了以下操作创建新的requirements-litellm.txtlitellm1.42.0 # 移除了 openai, anthropic, google-generativeai, ollama # langchain 保留因为RAG逻辑还在用 langchain0.1.16使用pip install -r requirements-litellm.txt --force-reinstall强制重装确保旧SDK被彻底卸载。注意强制重装后运行python -c import openai; print(openai.__version__)会报错ModuleNotFoundError。这是预期行为说明环境已干净。Litellm会用自己的轻量级HTTP客户端替代它们。4.2 第二步全局配置中心化原系统中API Key和Endpoint散落在各个模块的配置文件里。我们新建了一个llm_config.py作为唯一的LLM配置入口# llm_config.py import os from litellm import Router # 1. 环境变量加载优先级最高 os.environ[OPENAI_API_KEY] os.getenv(OPENAI_API_KEY, ) os.environ[ANTHROPIC_API_KEY] os.getenv(ANTHROPIC_API_KEY, ) os.environ[OLLAMA_BASE_URL] os.getenv(OLLAMA_BASE_URL, http://localhost:11434) # 2. 定义模型路由表支持fallback和负载均衡 model_list [ { model_name: main-rag-model, litellm_params: { model: gpt-4-turbo, api_key: os.getenv(OPENAI_API_KEY), timeout: 60, max_retries: 2 } }, { model_name: summarize-model, litellm_params: { model: claude-3-5-sonnet-20240620, api_key: os.getenv(ANTHROPIC_API_KEY), timeout: 120 } }, { model_name: fallback-model, litellm_params: { model: ollama/llama3, api_base: os.getenv(OLLAMA_BASE_URL), timeout: 180 } } ] # 3. 初始化Router支持自动fallback router Router( model_listmodel_list, fallbacks[{main-rag-model: [fallback-model]}, {summarize-model: [fallback-model]}], set_verboseTrue # 生产环境设为False )这里的关键创新点是Router。它不只是一个静态路由表而是一个具备智能fallback能力的组件。当main-rag-model即GPT-4-turbo调用失败时Router会自动尝试fallback-model即本地Llama3且整个过程对上层业务代码完全透明。4.3 第三步核心调用层重构原系统中RAG检索后的重排re-ranking逻辑分别调用了OpenAI和Anthropic的API# 原代码重排模块 def rerank_with_openai(query, docs): response openai.ChatCompletion.create( modelgpt-4-turbo, messages[{role: user, content: fRank these docs by relevance to {query}: {docs}}] ) return parse_ranking(response) def rerank_with_anthropic(query, docs): client anthropic.Anthropic(api_keyos.getenv(ANTHROPIC_API_KEY)) response client.messages.create( modelclaude-3-5-sonnet-20240620, max_tokens1024, messages[{role: user, content: fRank these docs...}] ) return parse_anthropic_ranking(response)重构后统一为# 新代码llm_service.py from llm_config import router def rerank_documents(query: str, documents: list) - list: 使用配置好的Router进行文档重排自动fallback prompt f请对以下文档列表按照与用户查询 {query} 的相关性进行严格排序只返回排序后的文档ID列表用英文逗号分隔不要任何解释。 文档列表 {json.dumps(documents, ensure_asciiFalse)} 输出格式仅此格式 [doc_id_1, doc_id_2, doc_id_3] try: # 关键只调用一次Router自动选择最优模型 response router.completion( modelmain-rag-model, # 使用路由表中的别名 messages[{role: user, content: prompt}], temperature0.0, max_tokens512 ) # 解析标准OpenAI格式响应 content response.choices[0].message.content.strip() # 尝试解析JSON格式的ID列表 return json.loads(content) except Exception as e: # Router fallback失败后的兜底逻辑 logger.error(fReranking failed for query {query}: {e}) # 返回原始顺序保证系统可用性 return [doc[id] for doc in documents]这个重构带来的直接收益是当GPT-4-turbo因配额用尽返回429时Router会自动切到fallback-model整个重排流程继续执行用户无感知。而原来的代码遇到429就会直接抛出异常导致整个RAG流程中断。4.4 第四步可观测性与监控集成Litellm原生支持OpenTelemetry和Prometheus。我们在llm_config.py中加入了监控初始化# llm_config.py 续 from litellm import monitor_telemetry, PrometheusLogger # 初始化Prometheus监控 prometheus_logger PrometheusLogger() # 启用litellm的telemetry monitor_telemetry( modelmain-rag-model, callback[prometheus_logger], input{query: test}, usersystem ) # 在FastAPI应用中暴露/metrics端点 from fastapi import FastAPI from prometheus_fastapi_instrumentator import Instrumentator app FastAPI() Instrumentator().instrument(app).expose(app)部署后我们立刻获得了以下关键指标litellm_request_total{modelmain-rag-model, statussuccess}成功请求数litellm_request_duration_seconds_bucket{modelmain-rag-model, le10.0}延迟分布litellm_token_usage_total{modelmain-rag-model, typeprompt}Token消耗明细这些指标被我们接入Grafana创建了实时Dashboard。当某天下午2点main-rag-model的statusfailure指标突然飙升我们立刻定位到是OpenAI的gpt-4-turbo服务端返回了大量503而fallback-model的调用量同步上升了300%证明Router的fallback机制正在完美工作。整个故障响应时间从原来的平均45分钟缩短到了8分钟。5. 常见问题与排查技巧实录那些文档里不会写的坑Litellm的文档写得非常清晰但有些问题只有在凌晨三点服务器告警时你才会真正理解它的含义。以下是我在多个项目中积累的“血泪经验”按发生频率排序每一条都附带可直接复制的排查命令。5.1 问题AuthenticationError: Invalid API Key但key确认无误现象环境变量OPENAI_API_KEY明明设置了litellm --debug也显示加载成功但调用时仍报认证错误。根本原因Litellm的--debug只显示它“看到”的环境变量但不验证这些变量是否被正确传递给了下游HTTP请求。最常见的原因是key字符串末尾有不可见的空格或换行符。排查技巧在Python中打印key的repr()import os key os.getenv(OPENAI_API_KEY) print(repr(key)) # 如果输出是 sk-xxx\n说明有换行符修复方法在.env文件中确保key写在一行内不要换行或者在代码中strip()os.environ[OPENAI_API_KEY] os.getenv(OPENAI_API_KEY, ).strip()5.2 问题流式响应卡住for chunk in response:循环永不退出现象调用streamTrue后程序hang住CPU占用很低但就是不返回。根本原因Litellm的流式生成器依赖于底层HTTP连接的chunked传输。如果供应商API没有正确发送Transfer-Encoding: chunked头或者网络代理如Nginx截断了流式响应litellm就会一直等待下一个chunk。排查技巧用curl直接测试供应商API确认流式是否正常curl -X POST https://api.openai.com/v1/chat/completions \ -H Content-Type: application/json \ -H Authorization: Bearer $OPENAI_API_KEY \ -d { model: gpt-4-turbo, messages: [{role: user, content: hello}], stream: true } | head -n 20如果curl也卡住问题在供应商或网络层。Litellm层面的临时修复强制设置stream_timeoutresponse litellm.completion( modelgpt-4-turbo, messages[...], streamTrue, stream_timeout30 # 30秒无数据则抛出TimeoutError )5.3 问题Router的fallback不触发始终卡在主模型现象配置了fallbacks[{main-rag-model: [fallback-model]}]但当main-rag-model返回429时Router没有尝试fallback-model而是直接抛出RateLimitError。根本原因Router的fallback只对特定的异常类型生效。默认情况下RateLimitError是不触发fallback的因为它是客户端可重试的错误Router认为你应该先重试而不是降级。排查技巧查看Router的fallback触发条件源码litellm/router.py确认哪些异常会被捕获并触发fallback。目前支持的有InternalServerError,ServiceUnavailableError,GatewayTimeoutError等服务端错误。强制让RateLimitError也触发fallbackfrom litellm.router import Router from litellm import RateLimitError # 自定义fallback策略 class CustomRouter(Router): def _get_fallback_models(self, original_exception): if isinstance(original_exception, RateLimitError): return [fallback-model] return super()._get_fallback_models(original_exception) router CustomRouter(model_listmodel_list, fallbacks...)5.4 问题本地Ollama模型调用失败报ConnectionRefusedError现象modelollama/llama3调用失败错误是ConnectionRefusedError: [Errno 111] Connection refused。根本原因Litellm默认连接http://localhost:11434但你的Ollama服务可能没有运行ollama serve没启动运行在其他端口OLLAMA_HOST0.0.0.0:11435绑定到了127.0.0.1而litellm在Docker容器里运行无法访问localhost。排查技巧在litellm运行环境中直接curl http://host.docker.internal:11434/api/tagsMac/Windows或curl http://172.17.0.1:11434/api/tagsLinux Docker确认Ollama API可达正确配置OLLAMA_BASE_URL# Docker Compose中让litellm服务能访问host的11434端口 environment: - OLLAMA_BASE_URLhttp://host.docker.internal:114345.5 问题litellm升级后老代码报AttributeError: dict object has no attribute choices现象Litellm从1.30.x升级到1.40.x后原来能用的response.choices[0].message.content突然报错。根本原因Litellm 1.40版本默认返回的是dict而不是pydantic.BaseModel对象。这是为了减少依赖和内存开销。但很多老代码习惯性地当作对象来用。排查技巧检查版本pip show litellm两种修复方案方案A推荐显式启用return_response_objectTrueresponse litellm.completion(..., return_response_objectTrue) # 现在 response 是 BaseModel可以 .choices 访问方案B用字典方式访问兼容性更好content response[choices][0][message][content]6. 工具链整合与进阶技巧让litellm成为你的AI工程中枢Litellm的价值远不止于“统一API”。当它和现代AI工程工具链深度整合时会爆发出惊人的生产力。以下是几个已在多个项目中验证过的、开箱即用的组合技。6.1 与LangChain无缝集成告别LLM类的碎片化LangChain的LLM抽象层本质上和litellm的目标高度重合。Litellm官方提供了ChatLiteLLM类可以直接作为LangChain的llm参数from langchain_core.prompts import ChatPromptTemplate from langchain_core.output_parsers import StrOutputParser from litellm import ChatLiteLLM # 创建litellm驱动的LangChain LLM llm ChatLiteLLM( modelgpt-4-turbo, api_keyos.getenv(OPENAI_API_KEY), timeout60 ) # 直接用于LangChain链 prompt ChatPromptTemplate.from_template(Tell me about {topic}) chain prompt | llm | StrOutputParser() result chain.invoke({topic: quantum computing})这个集成的意义在于你可以在LangChain的Runnable链中自由混用不同供应商的模型。比如用gpt-4-turbo做初始思考用claude-3-5-sonnet做最终润色用ollama/phi3做本地校验全部通过ChatLiteLLM(modelxxx)这一种方式调用无需为每个模型写不同的LLM子类。6.2 与Langfuse深度绑定实现端到端的LLM可观测性Langfuse是一个强大的LLM可观测性平台。Litellm原生支持Langfuse回调只需几行配置就能获得完整的trace# 在llm_config.py中 from litellm import litellm litellm.success_callback [langfuse] litellm.failure_callback [langfuse] # 设置Langfuse环境变量 os.environ[LANGFUSE_PUBLIC_KEY] pk-lf-... os.environ[LANGFUSE_SECRET_KEY] sk-lf-... os.environ[LANGFUSE_HOST] https://cloud.langfuse.com # 现在每一次litellm.completion()调用都会自动上报到Langfuse response litellm.completion(modelgpt-4-turbo, messages[...])在Langfuse UI中你能看到完整的prompt和completion的diff高亮每个token的生成耗时热力图不同模型的latency、cost、accuracy对比甚至能回放整个对话流点击任意一个step查看当时的输入输出。这让我们在优化一个法律文书生成模型时精准定位到是system prompt中某条模糊指令导致模型在70%的case中生成了冗余段落从而针对性地重写了prompt。6.3 与Docker/K8s结合构建弹性LLM网关Litellm可以作为一个独立的、轻量级的LLM API网关部署。我们用它在K8s集群中构建了一个llm-gateway服务# Dockerfile FROM python:3.11-slim WORKDIR /app COPY requirements-litellm.txt . RUN pip install -r requirements-litellm.txt COPY app.py . CMD [python, app.py]app.py是一个极简的FastAPI服务# app.py from fastapi import FastAPI, Request, Response from litellm import completion import litellm app FastAPI() app.post(/v1/chat/completions) async def chat_completions(request: Request): body await request.json() # 从body中提取model做路由决策 model body.get(model, gpt-4-turbo) # 调用litellm response completion(**body) return Response( contentresponse.model_dump_json(), media_typeapplication/json )这个网关部署后所有业务服务都只对接http://llm-gateway:8000/v1/chat/completions完全不知道背后是哪家供应商。运维同学可以随时在K8s中滚动更新网关镜像切换lit