在 Dify 中,要让 Agent 高效处理复杂任务——比如“帮用户比价并预订下周北京飞上海的经济舱机票”——单靠一次 LLM 生成远远不足以应对。目标必须拆解为可验证、可中断、可工具调用的明确步骤,否则模型很容易产生价格幻觉、忽略航班时间、跳过退改规则校验。下面直接剖析实操层面的拆解方法、控制机制与收敛策略。

识别可拆解任务的三个关键信号
什么样的用户输入需要启动多步推理拆解?具备三个典型特征:含时间范围(例如“下周”“未来三天”)、含比较逻辑(例如“cheapest”“better than”)、含多实体约束(例如“北京→上海+经济舱+含行李额”)。只要命中其中一个条件,就不要指望单次 Prompt 能给出准确结果。实测数据表明,强行使用单 Prompt 让 LLM 一次性输出比价结果,错误率高达 68%——模型根本难以同时精确追踪航班号、班次时刻、航司政策、实时库存这四个维度。这一步不拆解,后续所有工具调用都将建立在错误前提之上。
使用 CotAgentRunner 强制分步执行流程
方法一:在 Agent 配置中启用思维链模式
进入 Agent 编辑页面 →「高级设置」→ 勾选【Enable Chain of Thought】→ 选择 cot_v2 模式。该模式会自动注入思考模板,强制模型输出 【Plan→Tool Call→Observation→Revise】 四段结构。简单来说,模型必须先规划、再调用工具、再观察返回结果、再决定是否需要修正。
方法二:手动注入分步指令前缀
在 System Prompt 开头插入固定引导语:“你必须严格按以下四步执行:① 明确用户需求中的全部约束条件;② 列出需调用的工具及调用顺序;③ 每次仅调用一个工具并等待返回结果;④ 根据观测结果决定是否继续下一步或合成最终答案。”请注意,“每次仅调用一个工具”这句话一定不能省略——Dify 默认允许并行调用,但多数机票类 API 并不支持并发查询,一并发就容易触发限流并返回空数据。
设计可终止的子任务边界
完成拆解和强制分步后,还需要为每个子任务设定明确的“终点线”,以防止无限循环或提前偏离正确方向。
第一步:定义每个子任务的 success_criteria 字段
在 workflow.yaml 的每个 Agent 节点下添加 output_schema。示例如下:
response_generator:
output_schema:
type: object
properties:
final_answer: {type: string}
should_terminate: {type: boolean, description: "当前轮次是否已满足用户全部需求"}
第二步:配置条件路由终止链路
在 edges 中添加显式的终止分支:
- from: response_generator
to: end
condition: "response.should_terminate == true"
第三步:设置全局最大迭代次数
进入 Workflow Settings → Execution Limits → 将 max_retries 设为 3。超过三次仍未达成 should_terminate:true,系统将自动降级为兜底响应——这能有效避免 Agent 在某个分支中陷入死循环。
工具调用顺序的物理约束校验
最后一个关键环节:确保工具调用的先后顺序不会被跳过或并行打乱。Dify 本身支持灵活编排,但一旦依赖关系配置错误,输出的结果就会完全偏离预期。
方法1:用 routing_rule 强制串行执行
在 workflow.yaml 中为工具类 Agent 添加依赖声明:
flight_searcher:
depends_on: [date_parser, city_resolver]
Dify Orchestrator 会自动检测依赖关系——如果 date_parser 未返回有效日期格式(例如不是 YYYY-MM-DD),flight_searcher 节点将直接跳过,不会触发执行。这就避免了使用错误参数去查询航班数据。
方法2:在 Tool 插件内嵌校验逻辑
在自定义工具代码中,于 execute() 函数开头加入以下校验:
if not re.match(r'^\d{4}-\d{2}-\d{2}$', inputs.get('date')):
raise ValueError("Invalid date format. Must be YYYY-MM-DD")
这个异常会被 CotAgentRunner 捕获并触发 revise 步骤,而非静默地将错误参数传入后续流程。这意味着,一旦参数格式不匹配,模型会被要求重新检查并修正,直到数据合规后再继续下一环节。
