Dify 1.17 升级实测(二):Agent V2 节点与技能包实测——配置在数据库,不在 DSL
📖 摘要:1.17 的 Agent V2 节点把配置从 DSL 搬进了数据库——DSL 只声明骨架,模型、提示词、工具全部走 composer API 管理。工作区技能包(Skill)则是全新的复用机制:版本化、可绑定 Agent,但「绑定」不等于「生效」,运行时注入靠 config_skills 引用。本文用完整实测链路讲清这两个新机制的配置姿势与坑。
一、实验目的:Agent 交付的新形态
1.16 及以前的 Agent 节点,配置全在 DSL 里:模型、提示词、工具列表,导出导入随 DSL 走。这套模式做交付很顺——给客户一个 yml,导入即用。
但 1.17 变了。Agent V2 节点的配置不在 DSL 里,模型、工具、任务提示词全部存在数据库,由一套 composer API 管理。同时新增了工作区技能包(Skill)——可版本化的复用技能,绑定到 Agent。
对做 Agent 类交付的人来说,这是两件必须搞清楚的事:Agent V2 怎么配、Skill 怎么用。本文就是这两件事的完整实测记录。
二、场景设计:一个带工具、带技能包的 Agent
设计了一个贴近交付的场景:一个「任务确认助手」Agent——
- 挂在工作流的 Agent V2 节点上
- 配了时间工具(Agent 需要回答「现在几点」这类问题)
- 绑定一个「摘要技能包」,要求回答必须遵守技能指令
验证三件事:Agent V2 节点的配置链路、工具调用是否真实发生、技能包是否真正影响 Agent 行为。
三、整体架构:Agent 运行时链路
Agent V2 节点不再在 api 容器内执行,运行时链路是三层:
关键点:Agent
的配置(AgentSoulConfig)存在数据库——agents、workflow_agent_bindings、agent_config_snapshots
三张表。DSL 里只有节点骨架。
四、Agent V2 节点:DSL 三条件 + composer 配置链路
4.1 DSL 侧:只声明骨架
- id: ag_x
data:
type: agent
version: "2" # 必须是字符串 "2"
agent_node_kind: dify_agent
agent_task: "任务模板" # 注意:这个字段不映射!
title: "Agent 节点"三个条件缺一不可:type: agent +
version: "2" +
agent_node_kind: dify_agent。version 写成数字 2 会报
Dify Agent Node v2 requires version='2'。
有个反直觉的坑:DSL 里的 agent_task
字段不映射——任务提示词实际在 composer API 的
node_job.workflow_prompt 里维护。纯 DSL 导入的 Agent V2
节点,运行时报
agent_model_not_configured(模型没配置)。
4.2 composer API:配置的真正入口
配置链路是两段式:
GET /apps/{app_id}/workflows/draft/nodes/{node_id}/agent-composer # 查状态
PUT /apps/{app_id}/workflows/draft/nodes/{node_id}/agent-composer # 保存(注意是 PUT 不是 POST)
保存时两个关键参数:
save_strategy:首次配置用node_job_only(自动创建 inline Agent + 绑定 + 快照);改配置用save_to_current_versionsoul_lock:保存后配置会锁定,再修改报agent_soul_locked_error——payload 里带"soul_lock": {"locked": false}解锁重存
AgentSoulConfig 的核心结构:
{
"schema_version": 1,
"prompt": {"system_prompt": "你是任务确认助手..."},
"tools": {
"dify_tools": [
{"enabled": true, "provider_type": "builtin", "provider_id": "time",
"tool_name": "current_time", "credential_type": "unauthorized"}
],
"cli_tools": []
},
"model": {"plugin_id": "langgenius/deepseek", "model_provider": "deepseek",
"model": "deepseek-v4-flash", "model_settings": {}},
"knowledge": {"sets": []},
"human": {"contacts": [], "tools": []}
}两个容易踩的配置点:
- 内置工具 vs 插件工具:time
这类内置工具,
provider_type必须是builtin+provider_id: time;缺plugin_id/provider_id会 422 - 默认工具面:不配工具时 Agent 自带
cli_tools(含 shell_run——在沙箱里执行 shell 命令的能力),交付时要做安全评估,不需要就关掉
五、Skill 技能包:从创建到生效的完整链路
Skill 是 1.17 的全新复用机制,生命周期五步:
创建 → 写文件树 → 发布版本 → 绑定 Agent → config_skills 注入(生效)
5.1 创建与文件树
POST /workspaces/current/skills # 创建(name 必须用 - 连接,下划线 400)
PUT /workspaces/current/skills/{id}/files # 写草稿文件树(SKILL.md 等)
POST /workspaces/current/skills/{id}/publish # 发布版本
写文件树时注意:SKILL.md 的 frontmatter 会被自动解析——description 字段会被提取更新技能元数据。所以草稿内容格式要对,否则元数据被带偏。
5.2 版本发布
发布 payload 字段是 publish_note +
version_name(写成 version_note 会
400)。发布后生成版本号 + 内容哈希(hash_code)+ 归档文件。
我们发布了三个版本(v1/v2/v3),版本管理正常:新版本发布后
latest 标记切换。
5.3 绑定 Agent:关键认知
绑定走:
PUT /workspaces/current/agents/{agent_id}/skills # 绑定 skill 到 agent
但绑定 ≠ 生效。绑定只写
agent_skill_bindings 关系表,Agent
运行时根本不读这张表——运行时加载的是 Agent 配置里的
config_skills 引用。
我们把 skill 绑定到 Agent 后测试:skill 里写了强指令「回答必须以【摘要】开头、不超过 30 字」,运行 Agent——回答完全没遵守。绑定表有记录,但运行时没加载。
5.4 config_skills 注入:真正的生效开关
要让 skill 生效,必须在 composer 保存 Agent 配置时显式带上
config_skills:
{
"name": "摘要技能包",
"description": "把内容总结为 30 字以内",
"file_id": "<skill_versions.archive_tool_file_id>",
"hash": "<hash_code>"
}这里有个隐蔽的坑:archive_tool_file_id 在 API
响应里不暴露——技能详情、版本列表里都没有这个字段。必须直接查数据库:
select archive_tool_file_id, hash_code from skill_versions
order by version_number desc limit 1;注入 config_skills 后重跑 Agent,回答变成了:
【摘要】知识蒸馏是模型压缩技术,学生学教师软标签。
以【摘要】开头、30 字以内——技能包真正生效了。
六、运行验证:两个黑盒证据
Agent V2 节点的验证有个特点:节点输出只有 text,工具调用细节不进 node-outputs。取证要看 agent_backend 容器日志:
docker logs docker-agent_backend-1 | grep "running tool"
# 02:36:38.879 running tool: current_time
# POST api/agent/tools/invoke| 验证项 | 方法 | 结果 |
|---|---|---|
| 工具调用真实发生 | agent_backend 日志 running tool: current_time |
✓ |
| Agent 用工具答对时间 | 问「现在几点」→ 返回真实时间 | ✓ |
| Skill 生效 | 强指令【摘要】开头 → 回答遵守 | ✓ |
| Skill 版本管理 | v1→v2→v3 发布 + latest 切换 | ✓ |
七、实战坑:配置链路 6 个坑
| 坑 | 现象 | 修复 |
|---|---|---|
| version 写数字 2 | 导入报 requires version='2' |
写字符串 "2" |
| agent_task 不映射 | DSL 写任务提示词无效 | 任务在 composer node_job.workflow_prompt |
| 纯 DSL 导入无模型 | 运行报 agent_model_not_configured |
composer API 配置 model |
| 保存被锁 | 报 agent_soul_locked_error |
payload 带 soul_lock.locked=false |
| 绑定不生效 | agent_skill_bindings 有记录但回答不遵守 | config_skills 注入归档 file_id(DB 查) |
| 内置工具 422 | dify_tools 缺 provider 信息 | provider_type=builtin + provider_id |
八、交付视角的结论
三句话总结这个实验对 Agent 交付的影响:
- Agent V2 无法纯 DSL 交付——批量生成 DSL 时,Agent 节点需要配套 composer 配置脚本(或者导出已配置节点作模板)
- Skill 的生效链路是「绑定 + config_skills 注入」两步——交付脚本要封装 DB 查 archive_tool_file_id 这步
- 版本钉扎:config_skills 引用的是特定版本归档——Skill 发新版不会自动更新 Agent 引用,要重新保存配置
对做 Agent 平台化交付的团队,这两套机制把「复用」和「版本」提到了平台层——代价是配置链路变长,建议提前沉淀成脚本,别每次手点。
📚 本系列其他篇:一、升级总览与 5 件事 | 三、循环内人工审批与图片直传实测
实验文档与源码获取
- Agent V2 节点实验记录(实验 02)
- Skill 管理实验记录(实验 03)
- 相关 DSL 与应用导出:dify-108 实验工作区
本文基于 Dify 1.17.0 + Hermes Agent v0.21.0 实测,配置在不同版本间可能变化,使用前请确认版本。AI 参与创作声明:本文由 AI 辅助写作,内容基于作者真实实测记录。
- Dify Agent 应用实战:Beta 版「真 Agent」的能力边界实测
- Dify workflow 与 Hermes Agent skill 的确定性对比
- Dify 意图分类节点总翻车?从 33% 失败率到兜底不崩——可靠性与韧性的三层加固
- Dify 标注回复实战:让智能客服记住人工答案的纠错闭环
- Dify 知识库元数据过滤实战:检索噪声 75% 降到 0 的确定性闸门
- RAG 建库,如何自动设置分段模式
- RAG知识库,如何进行持续更新运维
- RAG知识库的元数据过滤能力边界
- 数据库里的结构化数据,怎么建立 RAG 知识库?两条路线与选型判断
- 流程卡在「等人审批」?把审批链接送到企业微信和邮箱
- Dify 1.17 升级实测(一):从工作流平台到 Agent 平台,升级前必须知道的 5 件事
- Dify 应用上架门户:分享页每次回答都挂着内部流程节点?一个字段关掉
- RAG 知识库交付实战(上):4277 页手册喂给 AI——从凌晨故障到三模块方案
- RAG 知识库建库前,数据到底该怎么清洗?一条可复用的清洗管线实测
- 我们的门户机器人,为什么用 Dify 答、不把 skill 搬上云端 Hermes?
- 知识库从需求到交付:清洗、入库、维护全流程,照着走、每一步都能验证
- Dify 1.17 升级实测(二):Agent V2 节点与技能包实测——配置在数据库,不在 DSL
- RAG 知识库交付实战(中):三大深坑与修复实录——流程图截断/限流风暴/并联污染
- DeepSeek 思考模式什么情况下可以关?一次空输出事故的排查实录
- Dify 1.17 升级实测(三):循环内人工审批与图片直传实测——两个高频场景的新解法
- Dify 定时触发(trigger-schedule)实测:工作流到点自动跑,和三个必须知道的坑
- Dify 知识库三种分段模式实测:通用、父子、Q&A 到底怎么选?
- Dify 知识库接入 Notion/网页:先搞清三件事,再谈清洗
- RAG 知识库交付实战(下):18 条用例与成本测算
- 知识库数据清洗后,怎么知道洗得干不干净?一套三层质量门禁实测
- Dify 实战:供应商报价单格式五花八门,AI 怎么知道哪列是单价?