【人工智能-agent】--使用python调用dify工作流
在dify中搭建好了工作流,然后需要在python中使用,怎么办呢,
dify提供了Workflow 应用 API,使用curl网络响应可以直接访问结果
curl -X POST 'http://127.0.0.1/v1/workflows/run' \
--header 'Authorization: Bearer {api_key}' \
--header 'Content-Type: application/json' \
--data-raw '{"inputs": {},"response_mode": "streaming","user": "abc-123"
}'
目录
1.传入参数
1.1.input
1.2. response_mode
2.输出参数
2.1.CompletionResponse
2.2.ChunkCompletionResponse
3.Errors
4.获取workflow执行情况
5.上传文件
6.获取应用的基本信息
7.获取参数信息
8.python连接dify实例一(输入文本)
9.python连接dify实例二(输入文件)
1.传入参数
1.1.input
inputs
(object) Required 允许传入 App 定义的各变量值。 inputs 参数包含了多组键值对(Key/Value pairs),每组的键对应一个特定变量,每组的值则是该变量的具体值。变量可以是文件列表类型。 文件列表类型变量适用于传入文件结合文本理解并回答问题,仅当模型支持该类型文件解析能力时可用。如果该变量是文件列表类型,该变量对应的值应是列表格式,其中每个元素应包含以下内容:
type (string) | 具体类型 | 传递方式 (transfer_method) |
---|---|---|
document | TXT, MD, MARKDOWN, PDF, HTML, XLSX, XLS, DOCX, CSV, EML, MSG, PPTX, PPT, XML, EPUB | remote_url 或 local_file |
image | JPG, JPEG, PNG, GIF, WEBP, SVG | remote_url 或 local_file |
audio | MP3, M4A, WAV, WEBM, AMR | remote_url 或 local_file |
video | MP4, MOV, MPEG, MPGA | remote_url 或 local_file |
custom | 其他未列出的文件类型 | remote_url 或 local_file |
transfer_method
(string) 传递方式,remote_url
图片地址 /local_file
上传文件url
(string) 图片地址(仅当传递方式为remote_url
时)upload_file_id
(string) 上传文件 ID(仅当传递方式为local_file
时)
{"inputs": {"{variable_name}": [{"transfer_method": "local_file","upload_file_id": "{upload_file_id}","type": "{document_type}"}]}
}
1.2. response_mode
response_mode
(string) Required 返回响应模式,支持:streaming
流式模式(推荐)。基于 SSE(Server-Sent Events)实现类似打字机输出方式的流式返回。blocking
阻塞模式,等待执行完毕后返回结果。(请求若流程较长可能会被中断)。 由于 Cloudflare 限制,请求会在 100 秒超时无返回后中断。
Response
当
response_mode
为blocking
时,返回 CompletionResponse object。 当response_mode
为streaming
时,返回 ChunkCompletionResponse object 流式序列。
user
(string) Required 用户标识,用于定义终端用户的身份,方便检索、统计。 由开发者定义规则,需保证用户标识在应用内唯一。
2.输出参数
Response
当 response_mode
为 blocking
时,返回 CompletionResponse object。 当 response_mode
为 streaming
时,返回 ChunkCompletionResponse object 流式序列。
2.1.CompletionResponse
返回完整的 App 结果,Content-Type
为 application/json
。
字段 | 类型 | 说明 |
---|---|---|
workflow_run_id | string | Workflow 执行 ID |
task_id | string | 任务 ID,用于请求跟踪和停止响应接口 |
data | object | 详细内容 |
data.id | string | Workflow 执行 ID(与 workflow_run_id 相同) |
data.workflow_id | string | 关联的 Workflow ID |
data.status | string | 执行状态:running (运行中)succeeded (成功)failed (失败)stopped (已停止) |
data.outputs | json | 输出内容(执行成功时返回) |
data.error | string | 错误原因(执行失败时返回) |
data.elapsed_time | float | 耗时(秒) |
data.total_tokens | int | 总使用 tokens |
data.total_steps | int | 总步数(冗余),默认 0 |
data.created_at | timestamp | 开始时间 |
data.finished_at | timestamp | 结束时间(仅当 status 不是 running 时返回) |
{"workflow_run_id": "djflajgkldjgd","task_id": "9da23599-e713-473b-982c-4328d4f5c78a","data": {"id": "fdlsjfjejkghjda","workflow_id": "fldjaslkfjlsda","status": "succeeded","outputs": {"text": "Nice to meet you."},"error": null,"elapsed_time": 0.875,"total_tokens": 3562,"total_steps": 8,"created_at": 1705407629,"finished_at": 1727807631}
}
2.2.ChunkCompletionResponse
返回 App 输出的流式块,Content-Type
为 text/event-stream
。 每个流式块均为 data: 开头,块之间以 \n\n
即两个换行符分隔,如下所示:
data: {"event": "workflow_started", "task_id": "5ad4cb98-f0c7-4085-b384-88c403be6290", "workflow_run_id": "5ad498-f0c7-4085-b384-88cbe6290", "data": {"id": "5ad498-f0c7-4085-b384-88cbe6290", "workflow_id": "dfjasklfjdslag", "sequence_number": 1, "created_at": 1679586595}}data: {"event": "node_started", "task_id": "5ad4cb98-f0c7-4085-b384-88c403be6290", "workflow_run_id": "5ad498-f0c7-4085-b384-88cbe6290", "data": {"id": "5ad498-f0c7-4085-b384-88cbe6290", "node_id": "dfjasklfjdslag", "node_type": "start", "title": "Start", "index": 0, "predecessor_node_id": "fdljewklfklgejlglsd", "inputs": {}, "created_at": 1679586595}}data: {"event": "node_finished", "task_id": "5ad4cb98-f0c7-4085-b384-88c403be6290", "workflow_run_id": "5ad498-f0c7-4085-b384-88cbe6290", "data": {"id": "5ad498-f0c7-4085-b384-88cbe6290", "node_id": "dfjasklfjdslag", "node_type": "start", "title": "Start", "index": 0, "predecessor_node_id": "fdljewklfklgejlglsd", "inputs": {}, "outputs": {}, "status": "succeeded", "elapsed_time": 0.324, "execution_metadata": {"total_tokens": 63127864, "total_price": 2.378, "currency": "USD"}, "created_at": 1679586595}}data: {"event": "workflow_finished", "task_id": "5ad4cb98-f0c7-4085-b384-88c403be6290", "workflow_run_id": "5ad498-f0c7-4085-b384-88cbe6290", "data": {"id": "5ad498-f0c7-4085-b384-88cbe6290", "workflow_id": "dfjasklfjdslag", "outputs": {}, "status": "succeeded", "elapsed_time": 0.324, "total_tokens": 63127864, "total_steps": "1", "created_at": 1679586595, "finished_at": 1679976595}}data: {"event": "tts_message", "conversation_id": "23dd85f3-1a41-4ea0-b7a9-062734ccfaf9", "message_id": "a8bdc41c-13b2-4c18-bfd9-054b9803038c", "created_at": 1721205487, "task_id": "3bf8a0bb-e73b-4690-9e66-4e429bad8ee7", "audio": "qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq"}data: {"event": "tts_message_end", "conversation_id": "23dd85f3-1a41-4ea0-b7a9-062734ccfaf9", "message_id": "a8bdc41c-13b2-4c18-bfd9-054b9803038c", "created_at": 1721205487, "task_id": "3bf8a0bb-e73b-4690-9e66-4e429bad8ee7", "audio": ""}
event 类型 | 说明 | 必填字段 | 可选字段 |
---|---|---|---|
workflow_started | Workflow 开始执行 | task_id , workflow_run_id , event , data data.id , data.workflow_id , data.sequence_number , data.created_at | 无 |
node_started | 节点开始执行 | task_id , workflow_run_id , event , data data.id , data.node_id , data.node_type , data.title , data.index , data.inputs , data.created_at | data.predecessor_node_id |
text_chunk | 文本片段流式输出 | task_id , workflow_run_id , event , data.text | data.from_variable_selector |
node_finished | 节点执行结束(成功/失败) | task_id , workflow_run_id , event , data data.id , data.node_id , data.index , data.inputs , data.status , data.execution_metadata , data.created_at | data.predecessor_node_id , data.process_data , data.outputs , data.error , data.elapsed_time , data.total_tokens , data.total_price , data.currency |
workflow_finished | Workflow 执行结束(成功/失败) | task_id , workflow_run_id , event , data data.id , data.workflow_id , data.status , data.total_steps , data.created_at | data.outputs , data.error , data.elapsed_time , data.total_tokens , data.finished_at |
tts_message | TTS 音频流片段(Base64 编码) | task_id , message_id , audio , created_at | 无 |
tts_message_end | TTS 音频流结束 | task_id , message_id , created_at | audio (空字符串) |
ping | 心跳保活(每 10s 一次) | 无 |
3.Errors
- 400,
invalid_param
,传入参数异常 - 400,
app_unavailable
,App 配置不可用 - 400,
provider_not_initialize
,无可用模型凭据配置 - 400,
provider_quota_exceeded
,模型调用额度不足 - 400,
model_currently_not_support
,当前模型不可用 - 400,
workflow_request_error
,workflow 执行失败 - 500,服务内部异常
4.获取workflow执行情况
根据 workflow 执行 ID 获取 workflow 任务当前执行结果
Path
workflow_run_id
(string) workflow_run_id,可在流式返回 Chunk 中获取
Response
id
(string) workflow 执行 IDworkflow_id
(string) 关联的 Workflow IDstatus
(string) 执行状态running
/succeeded
/failed
/stopped
inputs
(json) 任务输入内容outputs
(json) 任务输出内容error
(string) 错误原因total_steps
(int) 任务执行总步数total_tokens
(int) 任务执行总 tokenscreated_at
(timestamp) 任务开始时间finished_at
(timestamp) 任务结束时间elapsed_time
(float) 耗时(s)
curl -X GET 'http://127.0.0.1/v1/workflows/run/:workflow_run_id' \
-H 'Authorization: Bearer {api_key}' \
-H 'Content-Type: application/json'
{"id": "b1ad3277-089e-42c6-9dff-6820d94fbc76","workflow_id": "19eff89f-ec03-4f75-b0fc-897e7effea02","status": "succeeded","inputs": "{\"sys.files\": [], \"sys.user_id\": \"abc-123\"}","outputs": null,"error": null,"total_steps": 3,"total_tokens": 0,"created_at": 1705407629,"finished_at": 1727807631,"elapsed_time": 30.098514399956912
}
5.上传文件
上传文件并在发送消息时使用,可实现图文多模态理解。 支持您的工作流程所支持的任何格式。 上传的文件仅供当前终端用户使用。
分类 | 字段/参数 | 类型 | 必填 | 说明 |
---|---|---|---|---|
请求方式 | POST | - | 是 | 使用 multipart/form-data 格式 |
请求参数 | file | file | 是 | 要上传的文件(二进制数据) |
user | string | 是 | 用户标识,需与消息接口的 user 一致 | |
成功响应 | id | uuid | 是 | 文件唯一 ID |
name | string | 是 | 文件名(含扩展名) | |
size | int | 是 | 文件大小(字节) | |
extension | string | 是 | 文件后缀(如 PDF ) | |
mime_type | string | 是 | 文件的 MIME 类型(如 application/pdf ) | |
created_by | uuid | 是 | 上传用户 ID | |
created_at | timestamp | 是 | 上传时间 | |
错误响应 | 400 no_file_uploaded | - | - | 未提供文件 |
400 too_many_files | - | - | 只允许上传单个文件 | |
400 unsupported_preview | - | - | 文件不支持预览 | |
400 unsupported_estimate | - | - | 文件不支持估算 | |
413 file_too_large | - | - | 文件大小超过服务器限制 | |
415 unsupported_file_type | - | - | 文件类型不支持(仅接受文档类文件) | |
503 s3_connection_failed | - | - | 无法连接 S3 服务 | |
503 s3_permission_denied | - | - | 无 S3 上传权限 | |
503 s3_file_too_large | - | - | 文件超过 S3 大小限制 |
curl -X POST 'http://127.0.0.1/v1/files/upload' \
--header 'Authorization: Bearer {api_key}' \
--form 'file=@localfile;type=image/[png|jpeg|jpg|webp|gif] \
--form 'user=abc-123'
{"id": "72fa9618-8f89-4a37-9b33-7e1178a24a67","name": "example.png","size": 1024,"extension": "png","mime_type": "image/png","created_by": 123,"created_at": 1577836800,
}
6.获取应用的基本信息
$response = curl.exe -X GET 'http://127.0.0.1/v1/info' -H 'Authorization: Bearer app-1aarTqkLkyhE48MvprdQcf3V'
[System.Text.Encoding]::UTF8.GetString([System.Text.Encoding]::ASCII.GetBytes($response)) | ConvertFrom-Json
7.获取参数信息
用于进入页面一开始,获取功能开关、输入参数名称、类型及默认值等使用。
字段/控件类型 | 子字段 | 类型 | 必填 | 说明 |
---|---|---|---|---|
text-input | - | object | - | 文本输入控件 |
label | string | 是 | 控件展示标签名 | |
variable | string | 是 | 控件 ID(唯一标识) | |
required | bool | 是 | 是否必填(true /false ) | |
default | string | 否 | 默认值 | |
paragraph | - | object | - | 段落文本输入控件(多行文本) |
label | string | 是 | 控件展示标签名 | |
variable | string | 是 | 控件 ID | |
required | bool | 是 | 是否必填 | |
default | string | 否 | 默认值 | |
select | - | object | - | 下拉控件 |
label | string | 是 | 控件展示标签名 | |
variable | string | 是 | 控件 ID | |
required | bool | 是 | 是否必填 | |
default | string | 否 | 默认选中值 | |
options | array[string] | 是 | 选项列表(如 ["选项1", "选项2"] ) | |
file_upload | - | object | - | 文件上传配置 |
file_upload.image | - | object | - | 图片上传设置 |
enabled | bool | 是 | 是否开启图片上传(true /false ) | |
number_limits | int | 否 | 图片数量限制(默认 3 ) | |
transfer_methods | array[string] | 是 | 传递方式:remote_url (远程URL)或 local_file (本地文件),至少选一个 | |
system_parameters | - | object | - | 系统参数配置 |
file_size_limit | int | 否 | 文档上传大小限制(MB) | |
image_file_size_limit | int | 否 | 图片文件上传大小限制(MB) | |
audio_file_size_limit | int | 否 | 音频文件上传大小限制(MB) | |
video_file_size_limit | int | 否 | 视频文件上传大小限制(MB) |
curl.exe -X GET 'http://127.0.0.1/v1/parameters' -H 'Authorization: Bearer app-1aarTqkLkyhE48MvprdQcf3V'
8.python连接dify实例一(输入文本)
其实就是对api内容的解析过程
import requests
import jsondef run_dify_workflow():# 配置参数url = "http://127.0.0.1/v1/workflows/run"api_key = "app-1aarTqkLkyhE48MvprdQcf3V" # 你的API密钥user_id = "abc-123" # 用户标识# 请求头headers = {"Authorization": f"Bearer {api_key}","Content-Type": "application/json;charset=UTF-8","Accept-Charset": "UTF-8"}# 请求体payload = {"inputs": {"input": "普钢综合,2025.1.2-2.2的数据,并画出其相关的趋势图表。"},"response_mode": "streaming","user": user_id}try:# 发送POST请求response = requests.post(url,headers=headers,json=payload,stream=True # 重要:启用流式响应)print(f"请求成功,状态码: {response.status_code}")# 检查响应状态if response.status_code != 200:print(f"请求失败,状态码: {response.status_code}")print(f"错误信息: {response.text}")return# 处理流式响应print("开始接收流式响应...")for line in response.iter_lines():if line:# 确保使用正确的编码解码decoded_line = line.decode('utf-8').strip()if decoded_line.startswith('data:'):decoded_line = decoded_line[5:].strip()try:# 解析JSON数据if decoded_line: # 确保不是空字符串data = json.loads(decoded_line)print("收到数据:", json.dumps(data, ensure_ascii=False, indent=2))except json.JSONDecodeError as e:print("收到非JSON数据:", decoded_line)except requests.exceptions.RequestException as e:print(f"请求发生错误: {e}")if __name__ == "__main__":run_dify_workflow()
9.python连接dify实例二(输入文件)
import requests
import json
import urllib.parse
import osdef upload_file(file_path, user):upload_url = "http://10.24.39.143/v1/files/upload"headers = {"Authorization": "Bearer app-Qgy3rAk5SJgyEL4L2ut3Ijnn",}try:print("上传文件中...")# 将文件名编码为 URL 编码encoded_file_name = urllib.parse.quote(os.path.basename(file_path), safe="")with open(file_path, 'rb') as file:files = {'file': (encoded_file_name, file, 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet') # 确保文件以适当的MIME类型上传}data = {"user": user,"type": "xlsx" # 设置文件类型为TXT}response = requests.post(upload_url, headers=headers, files=files, data=data)if response.status_code == 201: # 201 表示创建成功print("文件上传成功")return response.json().get("id") # 获取上传的文件 IDelse:print(f"文件上传失败,状态码: {response.status_code}")return Noneexcept Exception as e:print(f"发生错误: {str(e)}")return Nonedef run_workflow(file_ids, user, response_mode="blocking"):workflow_url = "http://10.24.39.143/v1/workflows/run"headers = {"Authorization": "Bearer app-Qgy3rAk5SJgyEL4L2ut3Ijnn","Content-Type": "application/json"}# 假设 file_ids 是一个字典,包含 test 和 guifan 的文件 IDdata = {"inputs": {"test": [ # test 字段需要文件列表{"transfer_method": "local_file","upload_file_id": file_ids["test"],"type": "document"}]# "guifan": { # guifan 字段需要单文件# "transfer_method": "local_file",# # "upload_file_id": file_ids["guifan"],# "type": "document"# }},"response_mode": response_mode,"user": user}try:print("运行工作流...")response = requests.post(workflow_url, headers=headers, json=data)if response.status_code == 200:print("工作流执行成功")return response.json()else:print(f"工作流执行失败,状态码: {response.status_code}")print("错误详情:", response.text) # 打印错误详情return {"status": "error", "message": f"Failed to execute workflow, status code: {response.status_code}"}except Exception as e:print(f"发生错误: {str(e)}")return {"status": "error", "message": str(e)}# 使用示例
file_paths = {"test": "C:\pythonProject\项目五(钢铁价格预测)\我的钢铁网\gyp4.xlsx",# "guifan": "processed_data/小类.xlsx"
}file_ids = {}# 上传文件
for field, path in file_paths.items():file_id = upload_file(path, "difyuser")if file_id:file_ids[field] = file_idelse:print(f"{field} 文件上传失败,无法执行工作流")exit()# 文件上传成功,继续运行工作流
result = run_workflow(file_ids, "difyuser")
print(result)