Dify_专题七_Agent_shell_provider修复_cursor.md
这是基于原文生成的 Cursor 版文档。
原文件未改动;本版只做三件事:统一阅读入口、修正已审出的明显问题、补充更适合快速排障的提示。
Cursor 版修订说明
- 增加边界提示:本文处理的是配置侧与运行时连通性问题,不覆盖插件源码语法错误。
阅读提示
- 若正文中的容器名、目录名、IP 与你的环境不一致,请以实际
docker ps、docker compose ps、目录结构为准。 - 若正文属于“本次实战记录”,应理解为环境实录,不等同于所有环境的唯一正确默认值。
运行环境:业务脚本均在 207 固定目录
/opt/workbuddy执行,Python 为/usr/bin/python3。 Windows 开发机仅保留_probe_*调试脚本;同步命令:python scripts_cursor/完整代码约定/00_部署_workbuddy到207.py。
原文主体(已纳入 Cursor 版纠错)
专题七:Agent 应用 Shell Provider 修复(DifyShellLayer)
阅读导航(何时打开 · 报错往哪查)
本文是单点修复/排障专题,配合《安装配置手册》使用;下文实战步骤与代码全部保留,此处只做索引。
| 现象 | 本文 | 还可能是 |
|---|---|---|
| Agent 开了 Shell 但执行失败 | §2 三步确认 | sandbox/ssrf_proxy 未起 |
| 工作区看不到 Shell provider | §2.1 安装 | plugin_daemon |
本专题从原《Dify_专题九_其它配置问题解决.md》的第五节独立出来,专门讲:
在 Dify 里创建带 Shell / 代码执行能力的 Agent 应用时,shell 类工具报错或不可用 这一配置问题的解决。
所有涉及的配置、命令、检查手法均详细列出。本文是 Agent 应用侧配置,不是插件代码改动。
0. 背景:Dify 里的 Shell 执行是怎么跑起来的
Dify 的 Agent 应用要执行 Shell 命令 / 运行代码,依赖一个「Shell / 代码执行」provider。 本环境安装并启用的 provider 名为 DifyShellLayer(出现在 Agent 应用「工具」面板里的 provider 条目)。
它底层由 Dify 的沙箱体系承接,相关容器在 docker-compose.yml 里是几组独立服务:
| 容器 | 职责 |
|---|---|
sandbox | 真正在隔离环境里跑代码的沙箱(gVisor / seccomp 隔离) |
ssrf_proxy | 出站代理;Shell 工具里若要访问外网,请求走它 |
plugin_daemon | 插件 / provider 运行时;DifyShellLayer 这类 provider 由它加载与注册 |
所以「Shell 工具不可用」通常是下面三层任意一层没就绪:
- provider 没在 Agent 应用里启用;
- sandbox 服务没起来;
- plugin_daemon 没加载 / 注册该 provider。
排查与修复就按这三层逐层确认即可。
1. 现象(本次部署遇到的)
创建带「代码执行 / Shell」能力的 Agent 应用时:
- 在 Agent 的「工具」面板里,Shell / 代码执行类工具显示为 不可用 / 添加失败;
- 或添加成功但运行时报错:
provider not ready/no available node/ 工具调用直接失败; docker logs docker-plugin_daemon-1里能看到该 provider 初始化相关报错(如有)。
2. 解决步骤(按顺序来)
2.1 确认底层沙箱服务在跑
完整脚本:scripts_bash_cursor/Dify_专题七_Agent_shell_provider修复/专题七_内联_01.sh
运行/引用:bash /opt/workbuddy/scripts_bash_cursor/Dify_专题七_Agent_shell_provider修复/专题七_内联_01.sh
#!/usr/bin/env bash
set -euo pipefail
cd /dify/dify-main/docker
docker compose ps | grep -E "sandbox|ssrf_proxy|plugin_daemon"正常应看到 sandbox、ssrf_proxy、plugin_daemon 状态都是 Up。
若 sandbox / ssrf_proxy 没起来,先把它们拉起:
完整脚本:scripts_bash_cursor/Dify_专题七_Agent_shell_provider修复/专题七_内联_02.sh
运行/引用:bash /opt/workbuddy/scripts_bash_cursor/Dify_专题七_Agent_shell_provider修复/专题七_内联_02.sh
#!/usr/bin/env bash
set -euo pipefail
docker compose up -d sandbox ssrf_proxy
docker compose ps | grep -E "sandbox|ssrf_proxy"2.2 确认 plugin_daemon 加载了 DifyShellLayer
完整脚本:scripts_bash_cursor/Dify_专题七_Agent_shell_provider修复/专题七_内联_03.sh
运行/引用:bash /opt/workbuddy/scripts_bash_cursor/Dify_专题七_Agent_shell_provider修复/专题七_内联_03.sh
#!/usr/bin/env bash
set -euo pipefail
docker logs docker-plugin_daemon-1 --tail 80 | grep -iE "shell|DifyShellLayer|provider"- 看到该 provider 的
load/register日志 → 已加载; - 看到报错(常见是 sandbox 地址连不上)→ 按 2.3 核对端点后重启 plugin_daemon:
docker compose restart plugin_daemon2.3 核对 sandbox 端点环境变量(以实际 .env 为准)
Dify 服务通过环境变量找到 sandbox 与 ssrf 代理。在 docker/.env(或 docker-compose.yml 的 environment 段)里应有类似:
完整 .env 片段:patches_cursor/Dify_专题七_Agent_shell_provider修复/专题七_内联_01.env
运行/引用:patches_cursor/Dify_专题七_Agent_shell_provider修复/专题七_内联_01.env
# ---- docker/.env(Dify 服务侧)----
SANDBOX_API_KEY=dify-sandbox-not-secret
SANDBOX_URL=http://sandbox:8194
SSRF_PROXY_HTTP_URL=http://ssrf_proxy:3128
SSRF_PROXY_HTTPS_URL=http://ssrf_proxy:3128⚠️ 关键点:
SANDBOX_URL/SSRF_PROXY_HTTP_URL必须指向 compose 服务名(sandbox、ssrf_proxy),不要写成
localhost或127.0.0.1。因为 Dify 的api/worker容器与 sandbox 不在同一网络命名空间,写
localhost在 Dify 容器里解析到的是容器自己,连不到 sandbox,Shell 工具就会no available node。
改完 .env 后需重建相关服务让环境变量生效:
docker compose up -d2.4 在 Agent 应用里启用 DifyShellLayer(控制台侧)
以下是控制台操作的文字版(对应截图步骤):
- 打开
http://192.168.110.207/console,进入目标 Agent 应用; - 进入「工具 / Tools」配置页;
- 在「已安装 Provider / 自定义工具」列表里找到 DifyShellLayer;
- 点击「添加 / 启用」,确认其状态变为「可用 / Enabled」;
- 回到 Agent 编排界面,把该 Shell / 代码执行工具挂到 Agent 的 tool 列表;
- 点「保存 / 发布」。
这一步是 Agent 应用侧配置,不是插件代码改动。只要 provider 已被
plugin_daemon加载、sandbox 已起,这里启用后即可用。无需改任何插件源码。
新 Agent 工作室经常对不上上面的截图路径。 找不到「工具 / 已安装 Provider」时,用控制台 API 确认插件已加载,再看快照里有没有挂上该工具:
完整程序:/opt/workbuddy/scripts_cursor/Dify_专题七_Agent_shell_provider修复/专题七_内联_01.py
运行/引用:/usr/bin/python3 /opt/workbuddy/scripts_cursor/Dify_专题七_Agent_shell_provider修复/专题七_内联_01.py
from dify_api import Dify, pp
import json
d = Dify("38205036@qq.com", "Difyai123456")
d.login()
# 1) 工作区已安装的工具 provider(DifyShellLayer 应出现在列表里)
for path in (
"/workspaces/current/tools/builtin",
"/workspaces/current/tool-providers",
"/workspaces/current/tools",
):
r = d.get(path)
print("GET", path, "HTTP", r["code"], (r["text"] or "")[:300])
# 2) 新 Agent 真正生效的是快照,不是旧版 model_config
out, err = d.sh(
"docker exec docker-db_postgres-1 psql -U postgres -d dify -t -A -c "
"\"SELECT config_snapshot::json -> 'tools' "
"FROM agent_config_snapshots "
"WHERE id='01a0135c-320e-79dc-97a0-94da9b904c13'\""
)
print("snapshot.tools", out or err)
d.close()哪个 GET 是 200,就以哪个为准(Dify 小版本路径会变)。snapshot.tools 里应能看到 Shell 相关项。改快照后 不要点发布(专题十一)。
2.5 验证
在 Agent 对话里发一条会触发 Shell 的指令(如「用 python 算一下 1+1」),观察:
- 工具被正常调用、返回结果正确 → 修复成功;
- 仍报
provider not ready/no available node→ 回到 2.2 看 plugin_daemon 日志,多半是 sandbox 没起或SANDBOX_URL指错。
3. 排错清单
- [ ]
docker compose ps中sandbox/ssrf_proxy/plugin_daemon均为Up; - [ ]
docker logs docker-plugin_daemon-1无 DifyShellLayer 加载报错; - [ ]
SANDBOX_URL/SSRF_PROXY_HTTP_URL指向 compose 服务名,不是localhost; - [ ] Agent 应用「工具」里 DifyShellLayer 状态为「可用」,并已挂到 Agent;
- [ ] 实跑一条 Shell 指令验证通过。
4. 本次实战(真实遇到的情况)
本次部署中,创建带 Shell 能力的 Agent 时该工具一度不可用。按统一维度拆解。
现象:Agent 的「工具」面板里 Shell / 代码执行类工具显示为不可用 / 添加失败;或添加成功但运行时报 provider not ready / no available node。
定位(逐层排查):
docker compose ps确认 sandbox / ssrf_proxy / plugin_daemon 状态;docker logs docker-plugin_daemon-1 --tail 80 | grep -iE "shell|DifyShellLayer|provider"看是否加载;- 核对
.env里SANDBOX_URL。
改了什么(逐条):
- 确认 sandbox / ssrf_proxy 已起:
完整脚本:scripts_bash_cursor/Dify_专题七_Agent_shell_provider修复/专题七_内联_04.sh
运行/引用:bash /opt/workbuddy/scripts_bash_cursor/Dify_专题七_Agent_shell_provider修复/专题七_内联_04.sh
#!/usr/bin/env bash
set -euo pipefail
cd /dify/dify-main/docker && docker compose up -d sandbox ssrf_proxy
- 修正
.env:SANDBOX_URL=http://sandbox:8194(早期误写localhost导致 Dify 容器内解析不到)、SSRF_PROXY_HTTP_URL=http://ssrf_proxy:3128;改完docker compose up -d生效。 - 控制台 Agent 应用「工具」页把 DifyShellLayer 启用并挂到 Agent,点保存/发布。
怎么重启服务: 完整脚本:scripts_bash_cursor/Dify_专题七_Agent_shell_provider修复/专题七_内联_05.sh
运行/引用:bash /opt/workbuddy/scripts_bash_cursor/Dify_专题七_Agent_shell_provider修复/专题七_内联_05.sh
#!/usr/bin/env bash
set -euo pipefail
cd /dify/dify-main/docker
docker compose up -d sandbox ssrf_proxy # 拉起沙箱
docker compose restart plugin_daemon # 重新注册 provider
docker compose up -d # 让 .env 改动生效怎么看日志: 完整脚本:scripts_bash_cursor/Dify_专题七_Agent_shell_provider修复/专题七_内联_06.sh
运行/引用:bash /opt/workbuddy/scripts_bash_cursor/Dify_专题七_Agent_shell_provider修复/专题七_内联_06.sh
#!/usr/bin/env bash
set -euo pipefail
docker logs docker-plugin_daemon-1 --tail 80 | grep -iE "shell|DifyShellLayer|provider"
# 看到 load/register 日志、无报错 → provider 就绪怎么判断正常:在 Agent 对话里发一条会触发 Shell 的指令(如「用 python 算一下 1+1」),工具被正常调用、返回结果正确;仍报 no available node 则回到 plugin_daemon 日志看 sandbox 是否真起、SANDBOX_URL 是否指对。
一句话:Shell 工具不可用 = provider 启用 + sandbox 服务 + SANDBOX_URL 指向 compose 服务名,三层都齐才行。
关联文档:
- 原收录于《Dify_专题九_其它配置问题解决.md》(专题九),现已独立成此专题;
- 插件代码级修复见《Dify_专题八_插件patch_future顺序子坑.md》(专题八);
- 知识库 / 向量库相关见《Dify_专题六_weaviate中继.md》(专题六)。
本专题 Python 程序一览
| 文件 | 用途 | |---|---|| 专题七_01_检查沙箱服务.py | 专题七 · 步骤 1:检查 sandbox / ssrf_proxy / plugin_daemon 服务状态。 | | 专题七_02_查ShellProvider与快照.py | 专题七 · 步骤 2:查工作区 Shell Provider 与新 Agent 快照 tools 配置。 |
专题七_01_检查沙箱服务.py
运行:/usr/bin/python3 /opt/workbuddy/scripts_cursor/Dify_专题七_Agent_shell_provider修复/专题七_01_检查沙箱服务.py
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""专题七 · 步骤 1:检查 sandbox / ssrf_proxy / plugin_daemon 服务状态。"""
from __future__ import annotations
import sys
import _bootstrap # noqa: F401
import _config as C
from dify_api import Dify
def main() -> int:
d = Dify(C.DIFY_EMAIL, C.DIFY_PASSWORD)
try:
d.login()
out, err = d.sh(
"cd %s && docker compose ps | grep -E 'sandbox|ssrf_proxy|plugin_daemon'" % C.DIFY_DOCKER_DIR
)
print(out or err)
out2, _ = d.sh(
"docker logs %s --tail 80 2>&1 | grep -iE 'shell|DifyShellLayer|provider'" % C.PLUGIN_CONTAINER
)
print("\n=== DifyShellLayer 相关日志 ===")
print(out2.strip() or "(无匹配)")
return 0
finally:
d.close()
if __name__ == "__main__":
sys.exit(main())专题七_02_查ShellProvider与快照.py
运行:/usr/bin/python3 /opt/workbuddy/scripts_cursor/Dify_专题七_Agent_shell_provider修复/专题七_02_查ShellProvider与快照.py
完整补丁:patches_cursor/Dify_专题七_Agent_shell_provider修复/专题七_内联_01.py
运行/引用:见 patches_cursor/Dify_专题七_Agent_shell_provider修复/专题七_内联_01.py
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""专题七 · 步骤 2:查工作区 Shell Provider 与新 Agent 快照 tools 配置。"""
from __future__ import annotations
import sys
import _bootstrap # noqa: F401
import _config as C
from dify_api import Dify
def main() -> int:
d = Dify(C.DIFY_EMAIL, C.DIFY_PASSWORD)
try:
d.login()
for path in (
"/workspaces/current/tools/builtin",
"/workspaces/current/tool-providers",
"/workspaces/current/tools",
):
r = d.get(path)
print("GET", path, "HTTP", r["code"], (r["text"] or "")[:300])
out, err = d.sh(
"docker exec %s psql -U postgres -d dify -t -A -c "
"\"SELECT config_snapshot::json -> 'tools' "
"FROM agent_config_snapshots WHERE id='%s'\"" % (C.PG_CONTAINER, C.SNAP_ID)
)
print("\nsnapshot.tools:", out.strip() or err)
return 0
finally:
d.close()
if __name__ == "__main__":
sys.exit(main())