当前位置:首页 > 文章列表 > 科技周边 > 人工智能 > LangChain RunnableBranch 怎样路由输入

LangChain RunnableBranch 怎样路由输入

来源:17golang原创 2026-11-06 17:15:37 0浏览 收藏

我第一次把一个问答入口拆成“技术问题”和“账单问题”时,最容易写成一串 if/else。这样能跑,但路由判断、处理逻辑和后续模型链很快搅在一起。LangChain 的 RunnableBranch 更适合这个场景:把“条件 + Runnable”组成有顺序的分支,输入到来后按顺序判断,执行第一个匹配的处理 Runnable;全部不匹配时交给最后的默认 Runnable。

RunnableBranch 的关键不是“自动理解输入”,而是把已经得到的判断条件组合成可继续串接的 Runnable。条件顺序要从窄到宽,所有分支最好返回同一结构,并始终准备一个明确的默认分支。

官方地址:https://reference.langchain.com/python/langchain-core/runnables/branch/RunnableBranch

先约定输入和输出契约

我现在会先把路由输入定成一个小字典,而不是让每个条件函数自行猜测字符串。下面的示例约定 route 表示已经确定的路由标签,text 保存用户原话;每个分支最终都返回 route、answer 和 source_text,这样后面接格式化器、日志或模型链时不需要再判断分支类型。

RunnableBranch 输入对象、route 条件和统一结果字段的静态关系说明图
图1:RunnableBranch 输入契约说明图,展示输入字段、条件节点和统一结果字段的静态关系。

如果输入来自上游解析器,建议让解析器负责补齐 route,让 RunnableBranch 只负责选择。这样做的好处是:路由选择可以单独记录,条件函数也不会偷偷触发网络请求或模型调用。

用条件与处理 Runnable 组成分支

RunnableBranch 的构造参数由若干个二元组和最后一个默认 Runnable 组成。二元组左侧是条件,右侧是处理逻辑;普通 Python 可调用对象会被 LangChain 转成 Runnable。示例里我使用确定性字段,方便把“路由器是否选对”与模型输出质量分开。

from typing import Any

from langchain_core.runnables import RunnableBranch


def is_technical(payload: dict[str, Any]) -> bool:
    # 条件只读取稳定字段,不在判断阶段调用外部服务。
    return payload.get("route") == "technical"


def is_billing(payload: dict[str, Any]) -> bool:
    # 账单分支与技术分支使用同一份输入契约。
    return payload.get("route") == "billing"


def handle_technical(payload: dict[str, Any]) -> dict[str, str]:
    # 分支只负责产生统一结构,后续链可以继续消费 answer。
    return {
        "route": "technical",
        "answer": f"技术队列已接收:{payload['text']}",
        "source_text": payload["text"],
    }


def handle_billing(payload: dict[str, Any]) -> dict[str, str]:
    # 账单结果保持与技术结果相同的字段,便于统一格式化。
    return {
        "route": "billing",
        "answer": f"账单队列已接收:{payload['text']}",
        "source_text": payload["text"],
    }


def handle_default(payload: dict[str, Any]) -> dict[str, str]:
    # 未识别的 route 不抛出含糊结果,而是明确交给人工或通用队列。
    return {
        "route": "default",
        "answer": "暂时无法识别路由,请补充问题类型。",
        "source_text": payload.get("text", ""),
    }


router = RunnableBranch(
    # 条件按这里的顺序依次判断。
    (is_technical, handle_technical),
    (is_billing, handle_billing),
    handle_default,  # 最后一个参数是默认分支,不是条件二元组。
)

result = router.invoke({"route": "technical", "text": "接口返回 429 怎么处理"})
print(result["route"], result["answer"])

这里的要点有三个:第一,构造器至少需要一个条件分支和一个默认分支;第二,默认处理函数放在最后,不能写成带条件的二元组;第三,invoke 的输入会传给被选中的 Runnable,而不会自动改造成另一种数据结构。

利用从上到下的首次匹配

我第一次把多个“包含关键词”的条件放在一起时,踩过一个很隐蔽的坑:宽条件写在前面,后面的精确条件永远到不了。RunnableBranch 的语义是从前往后求值,哪个条件第一次返回真,就执行对应分支并停止继续选择;没有条件返回真,才进入 default。

RunnableBranch 首个匹配分支与 default 兜底关系结构图
图2:RunnableBranch 分支选择结构图,突出首个匹配分支和 default 兜底的边界。

因此,条件排序可以按“最具体的规则在前、最宽泛的规则在后”来安排。例如同一个输入既带有 technical 标签,又满足“文本非空”的通用条件时,技术条件必须先出现。更稳妥的写法是让条件只看一个已经规范化的 route 字段,减少重叠。

from langchain_core.runnables import RunnableBranch


def has_route(payload: dict[str, str]) -> bool:
    # 只把存在明确路由的输入交给专用分支。
    return bool(payload.get("route"))


def handle_known(payload: dict[str, str]) -> dict[str, str]:
    # 保留原始 route,方便审计实际选择。
    return {"route": payload["route"], "answer": "进入专用处理链"}


def handle_any_text(payload: dict[str, str]) -> dict[str, str]:
    # 这是较宽的兜底规则,应放在专用规则之后。
    return {"route": "text", "answer": "进入通用文本处理链"}


ordered_router = RunnableBranch(
    (has_route, handle_known),
    handle_any_text,
)

这段代码并不负责判断“哪个 route 合法”,它只演示顺序。生产环境里可以在上游做枚举校验;如果未知标签仍然允许进入系统,就把它显式标记为 unknown,不要让空值静默落到一个看起来成功的分支。

把路由器接入后续链

RunnableBranch 的价值在于它仍然是 Runnable,所以可以使用管道操作符继续组合。实际项目里我通常把分支输出规范成字典,再接一个统一的格式化函数。无论前面命中哪个分支,后面的链都只处理相同字段。

from langchain_core.runnables import RunnableLambda


def format_result(result: dict[str, str]) -> str:
    # 统一出口只依赖契约字段,不需要知道前面命中了哪条分支。
    return f"[{result['route']}] {result['answer']}"


final_chain = router | RunnableLambda(format_result)
print(final_chain.invoke({"route": "billing", "text": "发票抬头怎么修改"}))

如果某个分支后面要接提示模板或聊天模型,也建议先在分支内部把输入映射成模板需要的字段,再让每个分支返回一致的结果类型。不要让一个分支返回字符串、另一个分支返回字典,除非后续链明确处理这两种类型。

处理默认分支与工程边界

默认分支不是可有可无的装饰。它决定了输入不满足任何条件时的行为,也给日志和人工接管留下稳定入口。我的做法是让默认分支返回可识别的 route=default,并在外层记录原始文本,而不是直接返回空字符串。

还要注意三个边界:

  • 条件应尽量轻:条件里做纯字段判断最容易复现;如果必须异步判断,官方 API 支持异步条件,但仍应把超时、错误和成本放在路由设计中考虑。
  • 不要把 RunnableBranch 当成状态机:它负责一次输入的分支选择,不负责保存跨请求状态、重试策略或人工审批。
  • 统一输出比省几行代码更重要:多个分支共用下游链时,先定义输出字段,能显著降低后续拼接和排错成本。

最后可以用下面这张表快速检查设计:

检查项建议
条件顺序精确规则在前,宽泛规则在后
默认分支始终给未知输入一个可识别结果
输入契约让所有条件和 Runnable 读取同一组字段
输出契约分支返回相同的字段形状
后续组合用 | 接统一格式化、模型或解析步骤

相关问题

RunnableBranch 会执行多个匹配分支吗?

不会。条件按顺序判断,首个返回真的条件对应的 Runnable 被选中;后面的条件不会继续参与这次选择。

最后一个参数为什么不是二元组?

最后一个参数就是默认 Runnable。它接收原始输入,在前面的所有条件都不匹配时执行。

多个分支可以返回不同类型吗?

可以,但接统一下游链时会增加类型判断。更实用的做法是让分支返回统一字段,或者在分支末尾统一转换。

什么时候应该改用更完整的编排方案?

当需求包含跨多步状态、循环、人工介入、持久化或复杂重试时,RunnableBranch 只适合其中的局部路由,应该把状态和流程交给更合适的编排层。

对我来说,RunnableBranch 最有价值的地方不是替代所有条件逻辑,而是把“选择哪条 Runnable 链”变成一个可以继续组合、记录和复用的组件。先固定输入输出契约,再按具体到宽泛排列条件,最后用默认分支兜底,路由代码就会比散落的 if/else 更容易维护。

版本声明
本文转载于:17golang原创 如有侵犯,请联系study_golang@163.com删除
vLLM 怎样配置连续批处理最大 tokenvLLM 怎样配置连续批处理最大 token
上一篇
vLLM 怎样配置连续批处理最大 token
LlamaIndex CitationQueryEngine 怎样返回引用节点
下一篇
LlamaIndex CitationQueryEngine 怎样返回引用节点
查看更多
最新文章
查看更多
课程推荐
  • 前端进阶之JavaScript设计模式
    前端进阶之JavaScript设计模式
    设计模式是开发人员在软件开发过程中面临一般问题时的解决方案,代表了最佳的实践。本课程的主打内容包括JS常见设计模式以及具体应用场景,打造一站式知识长龙服务,适合有JS基础的同学学习。
    543次学习
  • GO语言核心编程课程
    GO语言核心编程课程
    本课程采用真实案例,全面具体可落地,从理论到实践,一步一步将GO核心编程技术、编程思想、底层实现融会贯通,使学习者贴近时代脉搏,做IT互联网时代的弄潮儿。
    516次学习
  • 简单聊聊mysql8与网络通信
    简单聊聊mysql8与网络通信
    如有问题加微信:Le-studyg;在课程中,我们将首先介绍MySQL8的新特性,包括性能优化、安全增强、新数据类型等,帮助学生快速熟悉MySQL8的最新功能。接着,我们将深入解析MySQL的网络通信机制,包括协议、连接管理、数据传输等,让
    500次学习
  • JavaScript正则表达式基础与实战
    JavaScript正则表达式基础与实战
    在任何一门编程语言中,正则表达式,都是一项重要的知识,它提供了高效的字符串匹配与捕获机制,可以极大的简化程序设计。
    487次学习
  • 从零制作响应式网站—Grid布局
    从零制作响应式网站—Grid布局
    本系列教程将展示从零制作一个假想的网络科技公司官网,分为导航,轮播,关于我们,成功案例,服务流程,团队介绍,数据部分,公司动态,底部信息等内容区块。网站整体采用CSSGrid布局,支持响应式,有流畅过渡和展现动画。
    485次学习
查看更多
AI推荐
  • PubMedQA数据集详解:生物医学问答基准、功能与应用指南
    PubMedQA
    深入了解PubMedQA生物医学问答数据集,涵盖其核心功能、使用方法及在临床决策、药物研发等场景的应用,助力提升NLP模型性能。
    912次使用
  • H2O EvalGPT:开源LLM大模型评估与排行榜工具
    H2O EvalGPT
    H2O EvalGPT是H2O.ai推出的开源LLM评估平台,提供详细的大模型性能排行榜、行业特定基准测试及A/B测试功能,助您快速选择最适合项目的高性能大语言模型。
    919次使用
  • LMArena是什么?伯克利AI模型评估平台使用指南与功能解析
    LMArena
    LMArena是加州大学伯克利分校推出的AI模型匿名评测平台。通过盲测投票机制,用户可对比不同大模型回答并生成实时排行榜,助力开发者优化模型及用户选择最佳AI工具。
    999次使用
  • 斯坦福HELM:大语言模型Holistic Evaluation整体评估框架详解
    HELM
    深入了解斯坦福推出的HELM(Holistic Evaluation of Language Models)大模型评测体系。本文解析其核心功能、安装配置步骤及应用场景,涵盖准确性、公平性、鲁棒性等多维度指标,助力开发者全面优化语言模型性能。
    995次使用
  • MMBench详解:多模态大模型基准测试、功能特点与使用指南
    MMBench
    MMBench是由上海人工智能实验室等机构联合推出的多模态基准测试平台,提供细粒度能力评估、大规模数据集及VLMEvalKit工具。本文详细介绍其核心功能、安装使用方法及应用场景,助力开发者全面评估多模态模型性能。
    815次使用
微信登录更方便
  • 密码登录
  • 注册账号
登录即同意 用户协议 和 隐私政策
返回登录
  • 重置密码