2025年9月19日
5 分钟阅读
By bx
Dify&Coze工作流搭建 275f933cf6fb80fa8912ff605a780242

Dify&Coze工作流搭建

Dify实践

主要是对于Dify 和 Coze 这种 AI 应用开发/编排平台

Dify是可以本地化部署的,这里为了简化使用官方平台

GitHub - langgenius/dify: Production-ready platform for agentic workflow development.

创建一个工作流

具体先来一个简单的示例

GitHubUsername助手

[开始]
输入 username
[HTTP 请求]
GET https://api.github.com/users/{{username}}
带必要 Headers
[条件分支]
├── 如果 status_code == 200
│ ↓
│ [LLM 总结]
- 输入API JSON
- 输出整理后的用户信息
├── 如果 status_code == 404 403
│ ↓
│ [输出]
-用户不存在或无法访问
└── ELSE其它情况
[输出]
-请求失败状态码xxx
  1. 创建其实节点,要求传入Username参数

image.png

  1. 创建这个Http-fetch节点,请求api
https://api.github.com/users/{{input.username}}

demo:这里也可以

curl -s https://api.github.com/users/bx33661 \
-H "User-Agent: dify-workflow" \
-H "Accept: application/vnd.github+json" \
-H "X-GitHub-Api-Version: 2022-11-28"

image.png

  1. 分支条件节点,满足200的去传数据给LLM节点

不满足的返回错误,就是一个try-catch 思想

  1. LLM节点,这里很重要

主要就是设置

  • 系统提示词
  • 上下文内容
  • 传入数据

这里提示词如下

下面有 GitHub 用户的原始数据
!!!如果 API 返回里包含 "message": "Not Found"你必须原样输出用户不存在”,不要自己编造
请总结成中文要点
1. 用户名和昵称
2. 简介
3. 仓库数粉丝数关注数
4. 创建时间转成 YYYY-MM-DD
5. 主页链接

image.png

  1. 结束节点,输出结果

image.png

输出

1. 用户名bx33661昵称Bpple
2. 简介未填写
3. 仓库数37粉丝数12关注数22
4. 创建时间2023-07-02
5. 主页链接https://github.com/bx33661

就拿这个简单的总结一下

关键就是对于数据流的接入和输出要连接好

可以在运行结果这里,查看一下这个每个节点的输入输出流

image.png

题目示例-京津冀长城杯决赛Dify工作流搭建

京津冀长城杯决赛Dify工作流搭建

题目要求如下

核心任务是:在 AI 智能体搭建平台中编辑工作流,实现 “上传指定得分 WP 附件 → 自动提取并输出该题目的格式化考点”。

格式化考点要求:需清晰呈现题目名、题目类型、考点,确保内容准确、结构清晰,题目类型从Misc、Crypto、Web、PWN、Reverse、理论、Blockchain中选择。

示例:

[
{
"题目名": "xtea",
"题目类型": "Reverse",
"考点":"花指令,动态调试,xtea 算法逆向",
"考点1": "花指令",
"考点2": "动态调试",
"考点3": "xtea 算法逆向"
}
]
[
{
"题目名": "easycms",
"题目类型": "Web",
"考点":"php-代码审计,ssrf-攻击内网应用",
"考点1": "php-代码审计",
"考点2": "ssrf-攻击内网应用"
}
]

最终效果

最终搭建效果如下

image

  1. 起始节点允许上传pdf文件
  2. 加一个文件提取器节点去处理这个pdf
  3. LLM节点

因为这个流是严格处理文档,所以把模型温度调到0,严格输入

System-Prompt

你将把 CTF WP 文本抽取为严格 JSON只输出 JSON禁止额外说明

User-Prompt

{{#1758461559128.text#}}
你是一名资深 CTF 赛事助教现在给你一份参赛队伍的 WP可能是 PDFMarkdown图片 OCR 文本等)。
请从中**按题目**抽取题目名题目类型考点”,并以**严格的 JSON**数组输出不要出现任何多余文本)。
- 题目类型必须从此集合中二选一填写:["Misc","Crypto","Web","PWN","Reverse","理论","Blockchain"]
-考点字段为一句简明汇总花指令,动态调试,xtea 算法逆向”。
- 同时把考点拆成考点1/考点2/考点3三个字段按重要度排序若不足三条可省略末尾字段
- WP 中出现多题请逐题输出多条 JSON 对象若无法识别题目名或类型跳过该题
输出格式务必只输出 JSON):
[
{
"题目名": "...",
"题目类型": "Misc|Crypto|Web|PWN|Reverse|理论|Blockchain",
"考点": "..., ..., ...",
"考点1": "...",
"考点2": "...",
"考点3": "..."
}
]

最后输出结果需要格式化,对应json-scheme

{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"title": "WP考点抽取结果",
"type": "object",
"required": [
"items"
],
"properties": {
"items": {
"type": "array",
"items": {
"type": "object",
"required": [
"题目名",
"题目类型",
"考点"
],
"additionalProperties": false,
"properties": {
"题目名": {
"type": "string",
"minLength": 1
},
"题目类型": {
"type": "string",
"enum": [
"Misc",
"Crypto",
"Web",
"PWN",
"Reverse",
"理论",
"Blockchain"
]
},
"考点": {
"type": "string",
"minLength": 1
},
"考点1": {
"type": "string"
},
"考点2": {
"type": "string"
},
"考点3": {
"type": "string"
}
}
}
}
},
"additionalProperties": false
}
  1. Code节点

对于Python代码的编写需要符合这个dify文档规范

就是输入输出变量需要在规定定义,有点像这个做IO算法题的流程,只是一个中间处理

image.png

使用Python对结果进行处理

from typing import Any, Dict, List, Optional, Union
import json
ALLOWED = {"Misc","Crypto","Web","PWN","Reverse","理论","Blockchain"}
def _to_list(x: Union[dict, list, str, None]) -> List[Dict[str, Any]]:
"""把 object / list / json-string / {"items":[...]} 统统变成 list[dict]"""
if x is None:
return []
if isinstance(x, list):
return [e for e in x if isinstance(e, dict)]
if isinstance(x, dict):
if "items" in x and isinstance(x["items"], list):
return [e for e in x["items"] if isinstance(e, dict)]
return [x]
if isinstance(x, str):
try:
y = json.loads(x)
return _to_list(y)
except Exception:
return []
return []
def main(arg1: Union[dict, list, str, None] = None,
arg_text: Optional[str] = None) -> dict:
items = _to_list(arg1)
if not items and arg_text:
items = _to_list(arg_text)
out: List[Dict[str, Any]] = []
for item in items:
name = str(item.get("题目名","")).strip()
typ = str(item.get("题目类型","")).strip()
pts = str(item.get("考点","")).strip()
if not name or typ not in ALLOWED or not pts:
continue
raw_parts = pts.replace(",", ",").split(",")
parts, seen = [], set()
for p in (x.strip(" ,,;;") for x in raw_parts):
if p and p not in seen:
seen.add(p); parts.append(p)
obj = {"题目名": name, "题目类型": typ, "考点": ", ".join(parts)}
for i, p in enumerate(parts[:3], start=1):
obj[f"考点{i}"] = p
out.append(obj)
return {"result" :out}
  1. 输出节点,输出result变量

最后结果

{
"result": [
{
"题目名": "SQL注入盲注",
"题目类型": "Web",
"考点": "布尔盲注, 字符绕过, 信息获取",
"考点1": "布尔盲注",
"考点2": "字符绕过",
"考点3": "信息获取"
}
]
}

其他

模型设置

可以根据需要下载对应模型

image.png

是支持接api,直接接上就可以使用

image.png

http-request

官方文档

HTTP Request - Dify Docs

导出DSL

DSL(Domain Specific Language,领域专用语言)

在 Dify 里 导出 DSL 的意思是:把你在可视化画布里“拖拽出来的工作流”转成一份 流程定义文件(YAML/JSON 格式)

image.png

具体就是yaml文件,标记画布的具体内容

image.png

具体简化版如下,只展现一下具体结构

nodes:
- id: start
type: input
variables:
- name: username
type: string
required: true
- id: fetch_user
type: http_request
method: GET
url: "https://api.github.com/users/{{username}}"
headers:
User-Agent: dify-workflow
Accept: application/vnd.github+json
- id: branch
type: if
conditions:
- case: "{{ fetch_user.status_code == 200 }}"
next: summarize
- case: "{{ fetch_user.status_code in [404,403] }}"
next: not_found
- else: error
- id: summarize
type: llm
prompt: |
请总结以下 JSON
{{ fetch_user.body }}
- id: not_found
type: output
value: "用户不存在"
- id: error
type: output
value: "请求失败,状态码:{{ fetch_user.status_code }}"

Debug

最关键的功能

运行测试,对于每个节点,建立后可以进行运行测试

image.png