← 返回文章列表

Dify 企业级实验(12):外部系统集成——第三方系统如何通过 Dify API 双向编排?

1. 业务场景

先讲一个我们实际遇到的场景。

项目交付给客户,不是给一个网页,而是给一套可编程的 API + 一套能主动干活的工作流。

客户 OA 里点「智能问答」按钮,调用 Dify 工作流返回答案;另一边,Dify 工作流要主动查 OA 的审批数据。双向打通,Dify 才能真正嵌进客户现有系统——被调时是能力中台,主动时是执行者。我们第一次接这类需求时,第一反应也是「集成嘛,给个链接让客户自己调」。真正动手才发现——只给链接等于没交付:外部系统调不进来、Dify 也调不出去,两头不通,集成就是半吊子

这不是个例。任何「把 Dify 嵌进客户现有系统」的交付都是这个模式:外部系统调 Dify(Service API)+ Dify 调外部系统(HTTP/工具),两头都要通。

2. 场景痛点

这个流程的痛点,在交付方和客户对接人身上体现得最直接:

本质上,集成不是「给个链接」,是「双向可编程」——被调方要有干净的 API,主动方要有降级的能力

3. 方案:为什么是Service API + HTTP 双向集成

Dify 的 Service API + HTTP 节点(headers 模板 + fail-branch),正好实现双向集成。选它的理由:

这篇文章我们就用它搭一套「OA 双向集成」:知识问答(被调方)+ 主动查询(主动方)。

4. 整体架构

两个应用:被调方(知识问答)+ 主动方(主动查询)。

graph TD subgraph sub_called["被调方:知识问答(Dify 被 OA 调用)"] c_start["开始(question)"] cd_src["cd_src:按问题关键词生成引用来源(如退货 → 《售后政策》第 2 章)"] lm["lm:生成回答,引用来源编号"] c_end["结束(输出 answer/sources)"] c_start --> cd_src --> lm --> c_end %% OA 侧:POST /v1/workflows/run,Authorization: Bearer *** Key> end subgraph sub_caller["主动方:主动查询(Dify 调 OA)"] a_start["开始:query/token"] cd_token["cd_token:模拟登录,取访问令牌"] http_oa["http_oa:GET OA 接口,Authorization: Bearer token"] cd_parse["cd_parse:解析响应(成功/失败)"] if5{"if5:OA 是否正常"} end_ok["end_ok:输出查询结果"] cd_fallback["cd_fallback:降级提示"] end_fail["end_fail"] a_start --> cd_token --> http_oa --> cd_parse --> if5 if5 -- "ok" --> end_ok if5 -- "false" --> cd_fallback --> end_fail end

链路很清晰:被调方——OA 调 Service API 拿 answer/sources;主动方——模拟登录取 token → 带 token 调 OA → 成功输出 / 失败降级。两头都留好接口与降级,是双向集成的关键设计。

5. 模块设计

5.1 被调方:Service API 暴露

工作流发布后创建 API Key,给 OA 开发者的调用文档(交付物之一):

POST /v1/workflows/run

Authorization: Bearer app-xxxxxxxx          # 每个外部系统独立 Key

{"inputs": {"question": "如何申请退货?"}, "response_mode": "blocking", "user": "oa-1001"}

# 响应 data.outputs: {"answer": "...", "sources": "..."}

LLM 节点 system 提示词要求「基于知识回答问题,引用来源以编号形式标注,知识库没有的内容直接说明未找到,不要编造」。

5.2 主动方:登录取 token

cd_token 模拟登录(生产换真实登录接口),输出 token 供 http 节点引用:

def main(token: str) -> dict:

    return {"token": token or "mock-oa-token-abc123"}

5.3 调 OA:headers 模板引用

http 节点 headers 支持模板语法,动态带 token(实测要点):

url: "http://172.19.0.50:8123/echo?q={{#start.query#}}"

method: GET

headers: "Authorization: Bearer {{#cd_token.token#}}"

timeout: {connect: 10, read: 60, write: 20}

error_strategy: fail-branch

5.4 响应解析与降级

cd_parse 解析回显的查询词与 Authorization 头;查询词为空或解析失败 → success=false → cd_fallback 降级提示:

# cd_parse(节选)

data = json.loads(body or "{}")

q = data.get("args", {}).get("q", "")

ok = "true" if q else "false"

detail = "OA 接口返回:查询词「" + str(q) + "」,Authorization=" + str(data.get("headers", {}).get("Authorization", "无"))

return {"success": ok, "data": detail, "raw": str(body or "")[:300]}
# cd_fallback

return {"message": "OA 系统暂时不可用,请稍后重试。查询词「" + str(query or "") + "」已记录,恢复后自动补查。"}

6. 运行验证

输入 预期 实测
OA 调 Dify(带 Key,问题=如何申请退货) 返回 answer + sources(《售后政策》第 2 章等) 与预期一致,Service API 返回 data.outputs
Dify 调 OA(query=审批单 A2024) 回显查询词与 Authorization 头,走 end_ok 与预期一致,输出 OA 回显明细
Key 无效 401,错误码明确(文档含错误码表) 与预期一致
查询词为空 cd_parse 判定失败 → 降级提示 与预期一致,提示「OA 系统暂时不可用…」
OA 不可达 工作流不整体失败,走降级分支 与预期一致(error_strategy: fail-branch)

7. 实战坑

现象 修复
API Key 权限过大 一个 Key 通吃所有能力,泄露即全量风险 每个外部系统独立 Key + 独立授权(102/103 Key 管理实测)
外部 API token 过期未刷新 调用突然 401,链路中断 统一「登录取 token → 带 token 调用」链路,token 存 KV 供刷新(102-10 实测)
http 节点不会自动带鉴权头 OA 接口返回未授权 headers 用模板引用动态注入:Authorization: Bearer {{#cd_token.token#}}(实测)
外部系统不可达无降级 节点报错,工作流整体失败 error_strategy: fail-branch + cd_fallback 降级提示(102-17 实测)
无接口文档 外部开发对接全靠猜,反复返工 交付「请求/响应/错误码」调用文档(实验文档设计约束)

8. 实验文档及源码获取

文章聚焦核心配置与采坑点;实验的完整分步操作(节点搭建/参数表/调试指引)见实验文档原文。

联系我

15088711270

手机端点击号码可直接拨打 · 桌面端可复制

微信二维码

扫码加微信 · 备注「门户」更快通过