我之前落地过Coze+Ansible的智能体,大家可以看案例-->Aiops探索:基于ansible的coze运维智能体终于成功了。而最近有个同学想做基于Dify的版本来找我帮忙,于是就有了今天这篇文章!
先说整体思路: Dify智能体会把我们的自然语言通过大模型转换为Dify工作流需要的必要参数,比如对哪个服务器做什么操作。这样Dify工作流就会去调用Asible的Dify插件,然后和Ansible控制台关联起来,最后Ansible再执行对应的Playbook去落地需求。
注意,此方案有一个投机取巧的点,就是将Dify服务器和Ansible控制节点合二为一了,这样就不用远程去调用,省去了很多麻烦。当然,这样做也有弊端,就是安全性会差一些。

看下落地细节吧,最关键的点在于如何在Dify制作访问Ansible的插件?Dify 的自定义插件是一个包含 yaml 配置文件和 python 代码的 zip 包。
1. 创建插件目录结构
在你的本地电脑上创建如下目录结构:
my_ansible_tool/├── provider.yaml # 插件元信息└── tools/ └── ansible_runner.yaml # 工具定义 └── ansible_runner/ └── __init__.py # 空文件,使其成为包 └── tool.py # 核心逻辑代码
2. 编写 provider.yaml
这个文件定义了插件的作者、名称、图标等基本信息。
# my_ansible_tool/provider.yamlidentity: author: Dify User name: ansible_tool label: en_US: Ansible Tool zh_Hans: Ansible 工具 description: en_US: A tool to execute Ansible playbooks for server automation. zh_Hans: 一个用于执行 Ansible Playbook 以实现服务器自动化的工具。 icon: icon.svg tags: - api - devops
3. 编写 tools/ansible_runner.yaml
这个文件定义了工具本身,包括它的参数。这些参数将作为用户在 Dify 工作流中配置的输入项。
# my_ansible_tool/tools/ansible_runner.yamlidentity: name: ansible_runner author: Dify User label: en_US: Ansible Playbook Runner zh_Hans: Ansible Playbook 执行器 description: en_US: Executes a specified Ansible playbook against an inventory. zh_Hans: 在指定的主机清单上执行一个 Ansible Playbook。 icon: icon.svgparameters: - name: playbook_path type: string required: true label: en_US: Playbook Path zh_Hans: Playbook 路径 human_description: en_US: The absolute path to the Ansible playbook file inside the Dify container (e.g., /data/ansible/ping.yml). zh_Hans: Dify 容器内 Ansible playbook 文件的绝对路径 (例如: /data/ansible/ping.yml)。 llm_description: The absolute path to the ansible playbook file to be executed. form: llm - name: inventory_path type: string required: true label: en_US: Inventory Path zh_Hans: 主机清单路径 human_description: en_US: The absolute path to the Ansible inventory file inside the Dify container (e.g., /data/ansible/hosts.ini). zh_Hans: Dify 容器内 Ansible 主机清单文件的绝对路径 (例如: /data/ansible/hosts.ini)。 llm_description: The absolute path to the ansible inventory file. form: llm - name: extra_vars type: string required: false label: en_US: Extra Variables zh_Hans: 额外变量 human_description: en_US: Optional. A JSON string of extra variables to pass to the playbook. zh_Hans: 可选。一个 JSON 格式的字符串,用于向 Playbook 传递额外变量。 llm_description: A JSON string of extra variables for the ansible playbook. form: llm
4. 编写核心代码 tools/ansible_runner/tool.py
这是插件的核心,负责接收参数并执行 ansible-playbook 命令。
# my_ansible_tool/tools/ansible_runner/tool.pyimport jsonimport subprocessfrom typing import Any, Dict, Listfrom dify_plugin import Tool
class AnsibleRunnerTool(Tool): def _run_ansible_command(self, command: List[str]) -> Dict[str, Any]: """ Executes the ansible-playbook command and returns its output. """ try: # 使用 subprocess.run 执行命令,更安全且能捕获输出 result = subprocess.run( command, capture_output=True, text=True, check=False, # 不检查返回码,我们自己处理 encoding='utf-8', errors='replace' )
output = { "returncode": result.returncode, "stdout": result.stdout, "stderr": result.stderr, }
# 将输出格式化为 JSON 字符串,方便 Dify 解析和展示 return json.dumps(output, indent=2, ensure_ascii=False)
except FileNotFoundError: return json.dumps({"error": "ansible-playbook command not found. Is Ansible installed and in PATH?"}, ensure_ascii=False) except Exception as e: return json.dumps({"error": f"An unexpected error occurred: {str(e)}"}, ensure_ascii=False)
def invoke(self, user_id: str, tool_parameters: Dict[str, Any]) -> str: """ The main entry point for the tool invocation. """ playbook_path = tool_parameters.get('playbook_path') inventory_path = tool_parameters.get('inventory_path') extra_vars_str = tool_parameters.get('extra_vars')
if not playbook_path or not inventory_path: return self.create_text_message("Error: Playbook path and inventory path are required.")
# 构建基础命令 command = [ 'ansible-playbook', '-i', inventory_path, playbook_path ]
# 如果提供了额外变量,添加到命令中 if extra_vars_str: try: # 验证 extra_vars 是否为有效的 JSON json.loads(extra_vars_str) command.extend(['--extra-vars', extra_vars_str]) except json.JSONDecodeError: return self.create_text_message(f"Error: Invalid JSON format for extra_vars: {extra_vars_str}")
# 执行命令并获取结果 result_json = self._run_ansible_command(command)
# 将结果返回给 Dify return self.create_text_message(result_json)
将这些文件打包为zip格式压缩包,直接在Dify控制台,通过"自定义工具"导入。有了此工具,就可以设计工作流了。
1)创建工作流:在 Dify 中创建一个新的空白工作流。
2)添加开始节点:设置一个输入变量,例如 task_description,让用户描述他们想做什么。
3)添加 LLM 节点:
-
连接"开始"节点。
-
在 "系统提示词" 中,明确告诉 AI 它的角色和可用的工具。例如:
你是一个专业的运维助手。你可以使用 'Ansible_Playbook_Runner' 工具来执行服务器管理任务。
你知道以下预定义的 Playbook:1. '/data/ansible/ping.yml': 用于检查服务器连通性。2. '/data/ansible/install_nginx.yml': 用于在 webservers 组的服务器上安装 Nginx。
主机清单文件位于 '/data/ansible/hosts.ini'。
根据用户的请求,选择合适的 Playbook 和主机清单来调用工具。如果用户请求的任务没有对应的 Playbook,请告知用户。
-
在 "模型" 中选择一个合适的模型。
-
在 "工具" 中,启用你刚刚上传的 "Ansible Tool"。
4)添加结束节点:连接 LLM 节点,用于输出最终结果。
对了,忘记提醒大家,不要忘记编写你自己的playbook,放到Dify服务器也就是Ansible控制节点上。真正干活儿的是这些playbook。你想做啥,就写啥playbook吧。上面的"系统提示词"中也提到了,留给大家自由发挥吧。
注意:我目前就是提供一个落地思路,具体细节还需你好好调教调教!