指南 01 · 条件分支与分类路由¶
Agent 最常见的需求就是「按情况走不同分支」。本章覆盖两条路径:
- 规则判定
IfElse:写代码做条件判断(转人工?金额够不够?)。 - 模型分类
QuestionClassify:让模型把用户问题归到预定义类别,再分流。
两者都产出路由键 branch,配合 add_conditional_edge 做多路分发。
1. IfElse 条件判定¶
1.1 二分支(bool)¶
IfElse 的 condition 返回 bool,条件边按 True/False 二选一。
from agentframework import Workflow
from agentframework.nodes import Answer, ChatLLM, IfElse
wf = Workflow(name="demo_binary")
wf.add_node(ChatLLM(name="llm", chat_model=model, output=False))
# left: 把上游 llm.reply 作为「待判断值」传进来供 condition 读取
wf.add_node(
IfElse(
name="judge",
left=wf.ref("llm.reply"),
condition=lambda inputs, ctx: "转人工" in str(inputs["left"]),
)
)
wf.add_node(Answer(name="handoff", text="好的,为您转人工客服"))
wf.add_node(Answer(name="auto", text="已为您自动处理"))
wf.add_edge("llm", "judge")
wf.add_conditional_edge("judge", {True: "handoff", False: "auto"})
condition 是 (inputs, ctx) -> 分支值 的可调用对象,可读 inputs["left"],也能读 ctx.variables(如判断 ctx.variables["flag"])。
1.2 多分支(str / 任意可哈希值)¶
condition 返回 str(或任意可哈希值),条件边查表路由。
wf.add_node(
IfElse(
name="cls",
left=wf.ref("llm.reply"),
condition=lambda inputs, ctx: "投诉" if "投诉" in str(inputs["left"]) else "其他",
)
)
wf.add_conditional_edge("cls", {"投诉": "complaint", "其他": "default"})
1.3 condition 的三种形态¶
| 形态 | 说明 | 典型 |
|---|---|---|
| 可调用对象 | (inputs, ctx) -> 分支值,最灵活,可读 ctx.variables |
上面两个例子 |
| 常量 / 引用 | condition 取某输入或 wf.ref 到某节点输出 |
由上游算好的布尔/值 |
| 缺失 | 抛 ValueError |
— |
1.4 进阶:把 IfElse 当「纯计算节点」¶
IfElse 不一定要用于路由——它的 branch 输出也可被下游 wf.ref 当数据引用(读取而不路由)。例如在完整案例里,用无 LLM 的纯函数节点做「取最后 user 文本」「读变量」「解析响应」「成败判定」,作为联合路由的输入。这种用法让流程逻辑完全可测、不烧模型:
# 例:判定第三方接口调用是否成功
wf.add_node(
IfElse(
name="http_ok",
left=wf.ref("http.json"),
condition=lambda inputs, ctx: dict(inputs["left"]).get("code") == "FBASE0000",
)
)
# 例:读控制变量
wf.add_node(
IfElse(
name="flag_value",
left=None,
condition=lambda inputs, ctx: str(ctx.variables.get("flag")),
)
)
这样把「判定逻辑」沉淀为可单测的节点,是复杂状态机的推荐做法。完整源码见 withdrawal_customer_service 示例。
2. QuestionClassify 模型分类¶
给模型一组类别,让它把当前问题归到其中一类;未命中归为 "其他"。输出 branch(=命中类别名)稳定匹配条件边。
from agentframework.nodes import QuestionClassify
wf.add_node(
QuestionClassify(
name="cls",
chat_model=model, # LLM 客户端(可注入 mock)
categories=[
{"name": "退款", "description": "用户要求退款/退货"},
{"name": "物流", "description": "查询快递进度"},
],
description="判断用户意图", # 可选,默认「判断用户的意图」
query=wf.ref("input"), # 待分类问题
)
)
wf.add_conditional_edge("cls", {"退款": "refund", "物流": "logistics", "其他": "default"})
要点:
- 输入
query(必填,待分类问题)、history(可选)。 - 输出
branch/category(命中类别名)、confidence(置信度,占位1.0)。 - 框架做确定性匹配(规范化 → 精确 → 双向包含 → 兜底
"其他"),保证branch不会因模型输出抖动而对不上条件边 key。 - 必填
chat_model、categories,缺失抛ValueError。
3. 把路由接到分支工作流¶
两种节点都产出 branch,路由写法一致:
# 规则 or 分类二选一作为判据源
wf.add_node(IfElse(name="judge", ...)) # 或 QuestionClassify(name="cls", ...)
wf.add_node(Answer(name="refund", text="正在为您处理退款"))
wf.add_node(Answer(name="logistics", text="您的快递正在派送"))
wf.add_node(Answer(name="default", text="转人工"))
wf.add_conditional_edge("judge", {True: "refund", False: "logistics"}) # 示例,按需改
# 或分类版:
wf.add_conditional_edge("cls", {"退款": "refund", "物流": "logistics", "其他": "default"})
4. 完整可运行示例¶
- ifelse_demo 示例:二分支 / 多分支 / 三种 condition 形态 / left 输入 / 当计算节点用,五合一最小演示。
- withdrawal_customer_service 示例:真实模型分类 +
IfElse计算节点 + 联合路由的完整多轮状态机。