Dify 中级实验(12):Agent 深度配置——如何让智能体自主调用工具?

Dify 实验系列 · 中级 12/20 | 实验编号:DIFY-102-13
基于 Dify 1.16.1 实测(2026-08)

1. 业务场景

先讲一个我们实际遇到的场景。

一家电商公司的运营团队想做一个「业务助手」:销售问「最近订单怎么样?」,它去查数据;运营说「把促销数据算一下」,它跑分析;主管说「给王经理发个会议通知」,它真的把消息发出去。一开始他们以为这只是「把对话模型接进来」的事,结果发现完全不是——闲聊模型只会在对话框里聊天,它不会自己去查数据、不会主动调工具、更不知道什么时候该发消息。真正能干活的助手,必须能自己决定做什么、用什么工具做、按什么顺序做

我们第一次接这类需求时,第一反应也是「把模型换聪明点不就行了」。真正动手配起来才发现——「会聊」和「会干活」之间隔着的不是模型,是工具:模型再聪明,手上没有工具可调,也只会礼貌地说一句「我无法访问外部系统」。

这不是个例。任何「用户一句话、系统要动手办事」的场景都是这个模式:客服机器人要查订单状态再回复、HR 助手要查员工档案再开证明、运维助手要查服务状态再告警——「会聊」和「会干活」之间,隔着工具调用这道坎

2. 场景痛点

这个流程的痛点,在运营团队的「业务助手」项目上体现得最直接:

  • 只会聊、不会干:普通对话模型对「查一下数据」只能回复「我无法访问外部系统」,所有动手的活还得人去做,助手形同虚设。
  • 不知道该用哪个工具:就算模型能调工具,面对「查订单」「算数据」「发消息」多个工具,它经常用错——用代码解释器去查数据,用消息工具去算数,工具长期闲置或乱用。
  • 破坏性操作没有确认:助手直接按指令把消息发出去了,内容错了、接收人错了,没有挽回余地——业务上这是事故级的问题。
  • 行为边界不可控:不约束规则的话,模型想怎么干就怎么干,同样的指令两次执行行为不一致,没法上线。

本质上,「助手能不能干活」不取决于模型多聪明,而取决于给它挂了什么工具、定了什么规则——工具即能力边界

3. 方案:为什么是 Agent + 自定义工具

Dify 的 Agent 应用(agent-chat) 就是为「自主调用工具干活」设计的:模型 + Function Calling 策略 + 工具列表 + 行为规则,四件套配齐,Agent 就能自己决定何时调用什么工具。而工具从哪来?任何工作流发布后都可以变成自定义工具——这正是本实验的关键能力。

选它的理由:

  • Function Calling 策略稳定可控:相比 ReAct 的文本推理,function_call 让模型直接输出结构化的函数调用,工具选择更准、更省 Token;
  • 工具能力可自建:不用等官方插件,内部系统(查数据、发消息、跑报表)都能通过工作流发布成工具挂给 Agent;
  • 行为规则可约束:pre_prompt 里写清工具选择策略和确认规则,破坏性操作强制先确认,把 Agent 的行为边界定死。

这篇文章我们就用它搭一个「全栈业务助手」:Agent 自主决定何时调用内置时间工具、代码解释器和自定义「发送消息」工具,完成「查数据 → 分析 → 生成报告 → 发通知」的完整业务动作。

4. 整体架构

13_02(工具载体,workflow 模式):

开始:to / title / content / priority

模拟发送消息(Code:生成 MSG-xxx 消息 ID)

确认回复(LLM:一句话告知发送结果)

结束:result / message_id / status

13_01(agent-chat 模式):无画布节点,配置 = 模型 + 策略 + 工具 + 系统提示词。

链路很清晰:13_02 工作流负责「把发消息这件事做成一个工具」,13_01 Agent 负责「决定什么时候用这个工具」——工具与决策分离,Agent 只认工具的输入输出契约,工具内部怎么实现它不关心。

5. 模块设计

5.1 Agent 核心配置(agent_mode)

model_config:
  agent_mode:
    enabled: true
    max_iteration: 10            # 太少跑不完,太多浪费 Token,10-15 合理
    strategy: function_call       # function_call 更稳;ReAct 更灵活
    tools:
    - enabled: true
      provider_id: time
      provider_name: time
      provider_type: builtin
      tool_label: 获取当前时间
      tool_name: current_time
      tool_parameters: {}
  model:
    completion_params:
      max_tokens: 4000
      temperature: 0.7
      top_p: 0.9
    name: deepseek-v4-flash
    provider: deepseek
  prompt_type: simple             # agent-chat 必须 simple / advanced

5.2 系统提示词(pre_prompt)——Agent 的行为上限

pre_prompt: |
  你是一个全栈业务助手,可以帮助用户完成以下任务:
  ## 可用工具
  1. **数据查询** - 查询业务数据(订单、用户、产品)
  2. **代码解释器** - 执行 Python 代码做数据分析(数值计算、统计、趋势)
  3. **发送消息** - 发送通知消息(接收人/标题/内容/优先级)
  4. **获取当前时间** - 获取系统当前时间(内置工具)
  ## 行为规则
  1. 分步思考:确定用户需要什么 → 需要哪些工具 → 按什么顺序调用
  2. 工具传递:一个工具的输出可以作为下一个工具的输入
  3. 确认优先:对破坏性操作(如发送消息),先请用户确认
  4. 错误处理:工具返回错误则分析原因并修正参数重试;连续 3 次错误停止并告知"系统暂时不可用"
  ## 工具选择策略
  1. 优先使用专用工具(如数据查询)而非代码解释器
  2. 代码解释器只用于数值计算和数据分析
  3. 发送消息前必须请用户确认
  ## 输出格式
  - 涉及数据分析必须展示完整分析过程;最终回答结构化、清晰

5.3 自定义工具(13_02)

自定义工具的本质是 OpenAPI 规范中定义的 API,Dify 会把它转成 Function Calling 的函数定义交给 LLM。开始节点四个变量:

- data:
    type: start
    variables:
    - label: 接收人
      required: true
      type: text-input
      variable: to
    - label: 消息标题
      required: true
      type: text-input
      variable: title
    - label: 消息内容
      required: true
      type: paragraph
      variable: content
    - label: 优先级(默认 normal)
      required: false
      type: select
      variable: priority
      options: [low, normal, high]

代码节点模拟发送:

def main(to: str, title: str, content: str, priority: str) -> dict:
    import time
    pri = (priority or "normal").strip() or "normal"
    msg_id = "MSG-{}-{}".format(time.strftime("%Y%m%d%H%M%S"), abs(hash(to + title)) % 10000)
    return {
        "message_id": msg_id,
        "status": "success",
        "send_text": "已向 {} 发送消息「{}」(优先级 {}):{}".format(to, title, pri, content)
    }

发布流程:工作流 → 发布为工具 → 在 13_01 的工具列表中挂载,Agent 即可通过 send_message(to/title/content/priority)自主调用。

6. 运行验证

输入 预期 实测
你好 直接回复,不调任何工具 无工具调用,正常闲聊
现在几点了? 调用内置 current_time 工具调用并返回当前时间
给王经理发一条通知,内容:明早 9 点开会 先请求确认 → 调 send_message → 返回 MSG-xxx 三轮工具编排完整,消息 ID 正确返回
12345 × 67890 等于多少? 自动判断需要计算,调代码解释器 计算结果正确展示
连续追问「再发一次」 记忆生效,复用上轮参数 记忆窗口内参数延续,无需重述

7. 实战坑

现象 修复
agent-chat 的 prompt_type 留空 导入/保存报 '' is not a valid PromptType 必须显式填 simpleadvanced
agent-chat 用 blocking 响应模式 应用不可用/调用报错 agent-chat 只支持 streaming,必须用 streaming
工具描述写得太简略 LLM 不知道何时该用,工具长期闲置 描述写清「做什么/何时用/参数含义」(实验文档设计约束)
工作流没发布就去找工具 Agent 工具列表里找不到 send_message 先「发布为工具」再挂载;改动后需重新发布(实验文档设计约束)
破坏性操作不设确认规则 一条指令就发出真实通知 pre_prompt 里写「发送前请用户确认」(实验文档设计约束)

8. 实验文档及源码获取

文章聚焦核心配置与采坑点;实验的完整分步操作(节点搭建/参数表/调试指引)见实验文档原文。


下一篇:Dify 中级实验(13):多 Agent 协作——如何编排多个智能体分工干活?

💬 你在这个实验的场景里踩过什么坑?欢迎评论区分享你的实战经验。

更多推荐