news 2026/9/8 18:48:08

LiteLLM Pass-Through Endpoint Guardrail Translation 源码解析与配置实战:让任意上游 API 也走统一护栏流水线

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
LiteLLM Pass-Through Endpoint Guardrail Translation 源码解析与配置实战:让任意上游 API 也走统一护栏流水线

LiteLLM Pass-Through Endpoint Guardrail Translation 源码解析与配置实战:让任意上游 API 也走统一护栏流水线

【免费下载链接】litellmThe fastest, litest AI Gateway. Rust core with Python SDK. Call 100+ LLM APIs in OpenAI (or native) format with cost tracking, guardrails, load balancing, and logging [Bedrock, Azure, OpenAI, Anthropic, OpenAI, VertexAI, vLLM, Nvidia NIM]项目地址: https://gitcode.com/GitHub_Trending/li/litellm

LiteLLM Proxy 的「透传端点(Pass-Through Endpoint)」允许把一个自定义路径原样转发到任意上游 API(例如 Cohere/v1/rerank),此时请求不再经过 chat/completion 这类标准 LLM 路由,护栏(Guardrail)默认不会生效。本文以仓库中 guardrail_translation/README.md 为骨架,结合litellm/llms/下的翻译层实现与 litellm/proxy/pass_through_endpoints 的主流程代码,讲解 LiteLLM 如何通过「护栏翻译映射(Guardrail Translation Mapping)」机制,把透传端点的请求/响应纳入统一护栏流水线——包括 JSONPath 字段定向提取、全载荷兜底、双层 handler 分发与 YAML 配置实战。

一、这套机制要解决的问题

透传端点本质上是一个「透明代理」:客户端请求/v1/rerank,Proxy 把它 1:1 转发给目标上游并原样回传响应。与标准 LLM 请求不同,这类端点:

  • 没有messagesmodel等 OpenAI 规范字段,护栏框架无法复用「从 messages 提取文本」的通用逻辑;
  • 请求/响应结构完全由上游 API 决定,可能是{"query": "..."}{"documents": [...]}{"results": [...]}等任意形态;
  • 仍然存在内容安全、敏感信息泄露等风险,用户希望护栏在这里同样生效。

解决思路在模块 docstring 中写得很清楚(见 litellm/llms/pass_through/init.py):以配置文件里声明的字段表达式为指引,从请求/响应里定向取出需要检查的文本,再交给统一的护栏实例执行,且透传场景下护栏只做「检查(check)」而不改写请求文本。

二、模块为什么放在litellm/llms/而不是主透传代码里

README 首先解释了目录归属问题:该模块位于 litellm/llms/pass_through/guardrail_translation/,而不是与主透传实现放在一起,原因有二:

  1. 自动发现(Auto-discovery)litellm/llms/__init__.py中的load_guardrail_translation_mappings()会递归扫描litellm/llms/下所有名为guardrail_translation且含__init__.py的目录,把其中导出的guardrail_translation_mappings字典聚合注册;
  2. 一致性(Consistency):其他 provider 的护栏翻译 handler 都遵循同一目录模式(README 举例为openai/chat/guardrail_translation/anthropic/chat/guardrail_translation/),透传端点也照此办理,便于统一发现与加载。

对应源码位于 litellm/llms/init.py,其中核心是三个函数:

  • discover_guardrail_translation_mappings():遍历litellm/llms/目录树,凡os.path.basename(root) == "guardrail_translation"且有__init__.py的模块都会被导入,若模块含guardrail_translation_mappings属性则并入结果集;随后还会额外并入 MCP Server 相关映射(litellm/llms/init.py);
  • load_guardrail_translation_mappings():带缓存的入口,首次调用触发全量发现,结果存入全局endpoint_guardrail_translation_mappings
  • get_guardrail_translation_mapping(call_type):按CallTypes取映射,若不存在会抛出异常并列出可用映射清单,方便排查「为什么某个透传类型没有护栏翻译 handler」。

三、本模块导出的映射注册表

模块的init.py 是自动发现机制的直接消费对象,它向注册表声明了两个CallTypes的映射:

guardrail_translation_mappings: Final = { CallTypes.pass_through: PassThroughEndpointHandler, CallTypes.allm_passthrough_route: LlmPassthroughRouteHandler, }

其中:

  • CallTypes.pass_through→ 通用透传端点场景,由PassThroughEndpointHandler负责;
  • CallTypes.allm_passthrough_route→ LLM 透传路由场景,由LlmPassthroughRouteHandler负责。allm_passthrough_route是比通用透传更接近「LLM 调用」的一种透传形态,请求体里带custom_llm_provider字段,因此需要按 provider 再分发。

两个 handler 都继承自 litellm/llms/base_llm/guardrail_translation/base_translation.py 中的抽象基类BaseTranslation,后者用@abstractmethod规定了两个必须实现的方法(base_translation.py):

  • process_input_messages(data, guardrail_to_apply, litellm_logging_obj):护栏处理请求入站内容;
  • process_output_response(response, guardrail_to_apply, litellm_logging_obj, user_api_key_dict, request_data):护栏处理响应出站内容。

换句话说,任何希望接入护栏体系的端点类型,本质都是实现一个「把任意结构翻译成护栏可检查的GenericGuardrailAPIInputs」的翻译器。

四、PassThroughEndpointHandler:核心处理逻辑

该 handler 的实现集中在 handler.py,模块 docstring 明确它「使用 litellm_logging_obj 上的字段定向配置,提取指定字段交给护栏处理」。整体分三步:

1. 读取护栏设置(_get_guardrail_settings

def _get_guardrail_settings(self, litellm_logging_obj, guardrail_name): passthrough_config = getattr(litellm_logging_obj, "passthrough_guardrails_config", None) if not passthrough_config or not guardrail_name: return None return PassthroughGuardrailHandler.get_settings(passthrough_config, guardrail_name)

关键点:透传护栏的字段定向配置并不是临时从 YAML 现取的,而是由透传主流程在请求进入时把它存到litellm_logging_obj.passthrough_guardrails_config属性上(见后文数据流),handler 侧通过getattr取回,再按护栏名查设置。这就把「配置解析」与「护栏执行」解耦成两个阶段。

2. 字段定向或全载荷兜底(_extract_text_for_guardrail

def _extract_text_for_guardrail(self, data, field_expressions): if field_expressions: text = JsonPathExtractor.extract_fields( data=data, jsonpath_expressions=field_expressions, ) return text # 未配置字段表达式 → 整包检查(剔除内部字段) payload_to_check = { k: v for k, v in data.items() if not k.startswith("_") and k not in ("metadata", "litellm_logging_obj") } return safe_dumps(payload_to_check)

这里体现了 README 强调的两条设计:

  • 字段定向(Field Targeting):若配置了request_fields/response_fields(JSONPath 表达式列表),仅提取命中的字段拼成检查文本,降低护栏扫描成本与误报率;
  • 全载荷兜底(Full Payload Fallback):若未配置,就把整包 JSON 作为检查文本,但会剔除三类内部字段——下划线开头的键、metadatalitellm_logging_obj,避免把代理自身的审计元数据塞给护栏(序列化走 safe_json_dumps,保证异常值不会炸掉序列化)。

3. 组装输入并执行护栏(仅检查、不改写)

process_input_messagesprocess_output_response的落点一致:把提取出的文本包装为GenericGuardrailAPIInputs(texts=[text_to_check]),若载荷含model字段则一并带上,然后调用guardrail_to_apply.apply_guardrail(inputs=..., input_type="request"/"response", ...)(handler.py)。

三个值得注意的实现细节:

  • 纯检查语义:透传 handler 拿到_guardrailed_inputs后并不用它回填/改写原始data,而是原样return data/return response——护栏在这里负责「拦截放行」,文本改写由各 provider 自己的翻译器完成;
  • 响应必须可解析process_output_response开头就检查isinstance(response, dict),非字典响应(如流式 chunk、二进制)直接跳过(handler.py);
  • 空文本短路:提取结果为空时直接跳过护栏(No text to check, skipping guardrail),避免护栏空跑。

响应处理还额外做了上下文补全:当request_data为空(SDK / 直接调用路径)时自建{"response": ...}字典,并把user_api_key_dict通过基类transform_user_api_key_dict_to_metadata转成user_api_key_前缀键写入litellm_metadata,让护栏回调里能拿到密钥/团队身份信息。

五、主透传实现:litellm/proxy/pass_through_endpoints/

README 指出主透传端点实现并不在本模块,而在:

litellm/proxy/pass_through_endpoints/ ├── pass_through_endpoints.py # 核心透传路由逻辑 ├── passthrough_guardrails.py # 护栏收集与字段定向 ├── jsonpath_extractor.py # JSONPath 字段提取工具 └── ...

目录下还有streaming_handler.pysuccess_handler.pypassthrough_endpoint_router.py等,共同构成透传子系统。三个与护栏翻译层关系最密切的文件如下。

1.passthrough_guardrails.py:护栏收集与执行助手

PassthroughGuardrailHandler是透传护栏的「总调度」,负责四件事(passthrough_guardrails.py):

  • normalize_config:把配置归一为字典。支持两种写法——简单列表["g1", "g2"]会被转成{"g1": None, "g2": None};带设置的字典原样保留;
  • is_enabled/get_guardrail_names:判空、取名单。模块 docstring 强调透传是opt-in 模型——只有显式配置至少一个护栏才执行,绝不隐式启用;
  • collect_guardrails:在透传启用后,合并「端点自己声明的护栏」与「继承自 org/team/key 元数据的护栏」。后者通过_add_guardrails_from_key_or_team_metadatauser_api_key_dict.metadata/team_metadata中提取并去重合并,实现「组织/团队/密钥级护栏自动继承」;
  • execute:主入口,把护栏名写成request_data["metadata"]["guardrails"] = {name: True},并通过set_passthrough_guardrails_config写入请求级上下文,供后续阶段查询(上下文读写由 litellm/proxy/pass_through_endpoints/passthrough_context.py 提供)。

2.jsonpath_extractor.py:轻量 JSONPath 引擎

字段定向依赖JsonPathExtractor,它不引入外部 JSONPath 依赖,而是实现了一个极简、够用的子集(jsonpath_extractor.py):

  • 简单键:"query"data["query"]
  • 嵌套键:"foo.bar"data["foo"]["bar"](点号逐层取);
  • 数组通配:"documents[*].text"/"items[*]"→ 遍历数组每项递归求值,结果扁平合并;
  • 多点路径:表达式列表逐一求值,最终所有命中值用换行\n连接成一个字符串。

解析实现先把[*]归一为.[*]再按.切分,遇到[*]段时判断当前节点是 list,取出剩余路径对每个元素递归evaluate(jsonpath_extractor.py)。单字段求值失败只打 debug 日志、不影响其余字段,因此对上游形态变化有不错的容错性。

3.pass_through_endpoints.py:把护栏挂进透传请求生命周期

主路由文件中可看到护栏配置从入参到执行的全过程:

  • 端点配置里guardrails字段与pathtargetheaders并列(PassThroughGenericEndpoint模型见 litellm/proxy/_types.py),forward_request接收guardrails_config: dict | None
  • 进入请求处理时调用PassthroughGuardrailHandler.collect_guardrails(...),把guardrails_to_run写入_parsed_body["metadata"]["guardrails"]
  • 随即「初始化 LOGGING OBJECT」,并把logging_obj.passthrough_guardrails_config = guardrails_config存到日志对象上——这正是第四节PassThroughEndpointHandler._get_guardrail_settings反查配置的数据来源;
  • 响应侧在response.status_code < 400且响应体可 JSON 解析、且存在待运行护栏时重新挂载guardrails(见 pass_through_endpoints.py),保证 post-call 护栏能看到它们,随后才把响应交还客户端。

于是整条调用链闭合为:

请求进入 → collect_guardrails(合并端点+org/team/key护栏) → metadata.guardrails 写入 + set_passthrough_guardrails_config → logging_obj.passthrough_guardrails_config 缓存 → PassThroughEndpointHandler.process_input_messages → _get_guardrail_settings 反查 request_fields/response_fields → JsonPathExtractor 定向提取 / 全载荷兜底 → apply_guardrail(检查+拦截) → 原样放行或抛 HTTPException 阻断

六、YAML 配置实战与参数详解

README 给出了最小可运行配置,这里原样保留并做必要标注:

passthrough_endpoints: - path: "/v1/rerank" target: "https://api.cohere.com/v1/rerank" guardrails: bedrock-pre-guard: request_fields: ["query", "documents[*].text"] response_fields: ["results[*].text"]

逐项拆解:

  • path:注册到 LiteLLM Proxy 上的对外路由;
  • target:实际转发目标(这里是 Cohere rerank 服务);
  • guardrails:opt-in 的护栏声明。名字(如bedrock-pre-guard)必须在 Proxy 的护栏注册表里存在(即配置文件中guardrails:顶层节里定义的预护栏实例),透传端点本身不定义护栏,只引用;
  • request_fieldsPassThroughGuardrailSettings的入站字段定向(见 litellm/proxy/_types.py)。接收 JSONPath 表达式列表,典型值:querydocuments[*].textmessages[*].content;不填则护栏跑整个请求载荷;
  • response_fields:出站字段定向,典型值:results[*].textoutput;不填则护栏跑整个响应载荷。

guardrails还支持两种等价写法PassthroughGuardrailHandler.normalize_config会把列表格式归一为字典格式:

# 写法 A:简单列表(无字段定向,整包检查) guardrails: ["bedrock-pre-guard"] # 写法 B:字典 + 每个护栏各自的 request_fields / response_fields guardrails: bedrock-pre-guard: request_fields: ["query", "documents[*].text"] response_fields: ["results[*].text"]

使用建议:

  • 字段定向能显著降低护栏扫描成本并减少误报,凡是明确知道敏感/待审内容落在哪个字段的场景都应优先配置;
  • 数组通配[*]语法只支持到单层数组递归,若上游返回嵌套更深的结构(数组套数组),需要评估该轻量引擎的覆盖范围(jsonpath_extractor.py 的实现即唯一事实依据);
  • 护栏名与字段设置一一对应意味着同一端点可为不同护栏配置不同的扫描面——例如入站文本安全护栏只扫query,出站合规护栏只扫results[*].text

七、LlmPassthroughRouteHandler:按 provider 二次分发

通用透传之外,同文件还定义了一个面向 LLM 透传路由的翻译器LlmPassthroughRouteHandler(handler.py)。它本身不做字段提取,而是充当分发器

  • 内部维护_PROVIDER_HANDLERS注册表,目前仅注册{"bedrock": BedrockPassthroughGuardrailHandler}(provider 专属翻译器位于 litellm/llms/bedrock/passthrough/guardrail_translation/handler.py);
  • process_input_messages/process_output_response依据data["custom_llm_provider"](响应侧从request_data取)选择 provider handler,找不到对应 provider 时只打 debug 日志并原样放行,保证「未知 provider 不阻塞透传」;
  • 额外暴露一批事件流(SSE)辅助静态方法is_event_stream_responseevent_stream_media_typesupports_event_stream_de_anonymizationde_anonymize_event_stream等。这些方法委托给 provider handler 的对应实现,用于识别并「去匿名化」事件流内容——因为流式响应需要反序列化成可检查形态后才能跑护栏,检查完再还原给客户端(handler.py)。

这从源码结构上印证了 README 提到的设计一致性:每个端点/provider 形态各写一个guardrail_translationhandler,统一通过CallTypes映射注册,由统一框架发现和调用。

八、与其他 Provider 翻译层的关系

透传护栏翻译并不是孤例。README 明确指出所有护栏翻译 handler 遵循同一模式(openai/chat/guardrail_translation/anthropic/chat/guardrail_translation/等),它们都:

  1. 继承同一个BaseTranslation抽象基类,保证process_input_messages/process_output_response(以及可选的流式处理钩子)接口一致;
  2. 在各自目录的__init__.py导出guardrail_translation_mappings字典;
  3. litellm/llms/__init__.py的自动发现机制统一加载,按CallTypes检索。

因此,接入新形态(新 provider 透传、新端点类型)时最需要做的是补一个翻译器并注册CallTypes映射,而无需改动护栏执行框架本身——这也解释了本模块目录位置的选择是出于框架可扩展性的刻意安排(参见 litellm/llms/init.py 的扫描与聚合逻辑)。

九、小结

围绕透传端点护栏这条链路,LiteLLM 实际上建立了三层清晰的分工:

层次位置职责
配置层passthrough_endpoints[*].guardrails(YAML)与 PassThroughGuardrailSettings声明护栏名、request_fields/response_fieldsJSONPath 定向
执行层passthrough_guardrails.py + jsonpath_extractor.pyopt-in 收集(含 org/team/key 继承)、字段提取、写请求元数据
翻译层litellm/llms/pass_through/guardrail_translation/handler.py把透传载荷翻译成护栏输入,CallTypes→ handler 注册与自动发现

透传端点的护栏执行是opt-in、字段可定向、默认全载荷兜底的行为模型:不配置就完全不干预转发;配置了就在 pre-call 与 post-call 两处对目标字段做纯检查式拦截,拦截失败可抛异常阻断,通过则 1:1 放行上游响应。对需要「透明转发 Cohere、Bedrock 等非标准 API 又不想失去内容安全能力」的网关部署场景,这套翻译机制是值得直接照搬的最小实现范式。

【免费下载链接】litellmThe fastest, litest AI Gateway. Rust core with Python SDK. Call 100+ LLM APIs in OpenAI (or native) format with cost tracking, guardrails, load balancing, and logging [Bedrock, Azure, OpenAI, Anthropic, OpenAI, VertexAI, vLLM, Nvidia NIM]项目地址: https://gitcode.com/GitHub_Trending/li/litellm

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/8 18:46:42

Flink基础之Flink on Yarn原理详解:三种模式与提交流程

摘要 讲透 Flink 跑在 YARN 上的完整原理&#xff1a;YARN 核心概念与 Flink 角色映射、Session/Per-Job/Application 三种运行模式的差异与选型、Application 模式下从上传 JAR 到 TaskManager 启动的完整提交流程、Container 与 Slot 的两层资源模型&#xff0c;并给出容错机…

作者头像 李华
网站建设 2026/9/8 18:46:39

TBOX信息安全系列3需求篇-车企信息安全需求对比

做TBOX项目&#xff0c;你第一个拿到的不是原理图&#xff0c;而是一份客户的网络安全需求规范。很多工程师看到几十页的"应/应该/可能"就头大&#xff0c;不知道从哪下手。这篇用两份真实的OEM需求规范做对标——某自主品牌&#xff08;33页&#xff09;和某合资品牌…

作者头像 李华
网站建设 2026/9/8 18:45:44

WorkBuddy实操指南:AI智能体如何自动化周报汇总与多维表同步

上周五下午&#xff0c;我差点又被钉钉群里的“周报接龙”给淹没了。十几个同事把各自的周报往群里一甩&#xff0c;我整理汇总&#xff0c;照着以往的速度&#xff0c;这一趴怎么也得花上四十分钟。但那天我用了不到十分钟就收拾完了——不是手下多了人&#xff0c;也不是手速…

作者头像 李华
网站建设 2026/9/8 18:45:20

MoneyPrinterTurbo:开源AI短视频自动化生产全攻略

简介&#xff1a;这是一份面向短视频创作与AI应用开发者的视频生成器源码包&#xff0c;基于MoneyPrinterTurbo实现&#xff0c;只需输入主题或关键词&#xff0c;即可自动完成文案、素材、字幕、背景音乐并合成高清短视频。压缩包共80个文件&#xff0c;约111MB&#xff0c;以…

作者头像 李华
网站建设 2026/9/8 18:44:34

昇思大模型推理服务生命周期管理:从状态机到优雅下线实践

刚开始做昇思大模型推理服务的时候&#xff0c;我栽得最狠的一次就是在“升级模型版本”。当时想法很简单&#xff1a;新模型推理代码写好&#xff0c;直接把服务停了&#xff0c;换权重&#xff0c;再启动。结果呢&#xff1f;服务中断了将近十分钟&#xff0c;线上积压的推理…

作者头像 李华
网站建设 2026/9/8 18:43:13

深入解析Telegram for macOS:终极加密通讯客户端的完整指南

深入解析Telegram for macOS&#xff1a;终极加密通讯客户端的完整指南 Telegram for macOS是一款备受欢迎的加密通讯客户端&#xff0c;为Mac用户提供了安全、便捷的即时通讯体验。尽管这是基于Objective-C的macOS客户端版本&#xff0c;目前已不再官方支持&#xff0c;但其核…

作者头像 李华