微信扫码
与创始人交个朋友
我要投稿
Dify 提供了强大的流程编排能力和众多丰富的工具,但是很多时候我们还要实现个性化的需求。 最常见的就是和我们私有的服务集成,今天就演示如何使用 FastAPI 开发一个自定义工具。
文章主要内容:
• 源码运行 Dify
• 容器挂载插件代码
• FastAPI 服务
• 自定义工具
• JSON解析节点
• 条件判断和汇总节点
先看下最终结果:
使用中间件和源码分离的方式运行 Dify 不是本文必须的。
我们可以参考 使用源代码启动 Dify[1] 在本地启动 dify 服务。
首先是克隆项目
git clone https://github.com/langgenius/dify.git
cd dify
复制 env 文件
cp middleware.env.example middleware.env
如果你本机部署过 Postgresql 等组件,要记得修改端口,避免重复,比如我就改了端口号:
EXPOSE_POSTGRES_PORT=5542
EXPOSE_REDIS_PORT=6389
EXPOSE_SANDBOX_PORT=8594
EXPOSE_SSRF_PROXY_PORT=3528
EXPOSE_WEAVIATE_PORT=8580
用 Compose 启动容器,
docker compose -f docker-compose.middleware.yaml up -d
我检查了 compose 文件,确实设置了 middleware.env
,但是在我的环境li并没有起作用, 我又重新指定了下 env 文件,有遇到过同样问题的可以参考下面命令:
docker-compose --env-file middleware.env -f docker-compose.middleware.yaml up -d
运行成功的输出大概如下:
> docker-compose --env-file middleware.env -f docker-compose.middleware.yaml up
[+] Building 0.0s (0/0)
[+] Running 6/6
✔ Network docker_default Created 0.1s
✔ Network docker_ssrf_proxy_network Created 0.0s
✔ Container docker-ssrf_proxy-1 Created 0.3s
✔ Container docker-sandbox-1 Created 0.2s
✔ Container docker-db-1 Created 0.2s
✔ Container docker-redis-1 Created 0.2s
Dify 应用代码 在 api
目录下,我们进入到 api
目录启动应用。
cd api
修改 .env
文件,设置 SECURITY_KEY。
MacOS 系统的命令:
openssl rand -base64 42
sed -i '' 's/SECRET_KEY=.*/SECRET_KEY=<your-key>/g' .env
Linux 系统的命令:
openssl rand -base64 42
sed -i 's/SECRET_KEY=.*/SECRET_KEY=<your-key>/' .env
大家不喜欢命令的话,可以直接打开文件直接编辑,比如我就是。
我们仍然使用 Conda 初始化一个新的 Python 环境,并激活:
conda env create -n dify python=3.10
conda activate dify
Dify 使用 Poetry 管理,我们安装 Poetry 和依赖:
pip install poetry
poetry install
数据迁移和初始化:
# poetry shell
flask db upgrade
运行应用:
flask run --host 0.0.0.0 --port=5001 --debug
前端运行,前端运行比较简单:
cd web
pnpm install
pnpm start
大概看到如下的输出:
> pnpm start
> dify-web@0.6.16 start dify/web
> cp -r .next/static .next/standalone/.next/static && cp -r public .next/standalone/public && cross-env PORT=$npm_config_port HOSTNAME=$npm_config_host node .next/standalone/server.js
▲ Next.js 14.2.4
- Local: http://localhost:3000
- Network: http://0.0.0.0:3000
✓ Starting...
✓ Ready in 144ms
浏览器访问前端就可以看到我们的界面了(如果是新数据库需要设置用户名密码):
• http://localhost:3000[2]
自定义开发 Dify 组件一般都只需要新增文件,我们其实可以不适用源码运行,而是用文件挂载的方式增加代码。
比如在 Compose 文件里面增加一个 volume 可以达到一样的效果:
volumes:
# Mount the storage directory to the container, for storing user files.
- ./volumes/app/storage:/app/api/storage
- ./external_data_tool/weather_search:/app/api/core/external_data_tool/weather_search
对 Dify 接口不熟悉的同学肯定希望在开发的过程中进行调试,大家可以在喜欢的 IDE 用 Flask 程序标准的方式进行调试。
比如我用的 PyCharm,从 IDE 启动调试配置如下:
我们现在看一看如何自定义工具。
我们现在实现一个 FastAPI 服务,让 Dify 程序调用。
程序比较简单,
• 实现一个简单的认证,密码为 123456
• 接收并打印收到的消息
• 返回一个简单的JSON
程序如下,不做过多的解释了:
rom fastapi import FastAPI, Body, HTTPException, Header
from fastapi.responses import FileResponse
from pydantic import BaseModel
app = FastAPI(servers=[
{"url": "http://localhost:8000"}
])
class InputData(BaseModel):
prompt: str
params: dict
@app.post("/api/dify/receive")
async def dify_receive(data: InputData = Body(...), authorization: str = Header(None)):
"""
Receive API query data from Dify.
"""
expected_api_key = "123456"
auth_scheme, _, api_key = authorization.partition(' ')
if auth_scheme.lower() != "bearer" or api_key != expected_api_key:
raise HTTPException(status_code=401, detail="Unauthorized")
return {
"result": "ok"
}
启动应用程序,可以使用如下命令:
uvicorn main:app --reload --host 0.0.0.0
然后访问:http://127.0.0.1:8000/docs#/
可以看到文档 Swagger 文档:
访问 http://127.0.0.1:8000/openapi.json
可以看到 OpenAPI 格式的 Json 文件,基本把他拷贝下来。
现在回到 Dify 界面,点击 工具
->自定义
->创建自定义工具
。
在弹框中填写名称,并把刚才拷贝的 JSON 填写进去,
鉴权方式选择 API Key
->Bearer
,保存。
然后创建一个空白应用,选择 聊天助手
和 工作流编排
类型:
右键添加添加节点的时候选择我们刚刚创建的自定义节点:
节点配置如下:
当然,认证信息可以在工具创建的时候配置。
然后我们重新连接节点,发个消息测试下,数据已经按照希望的数据返回了。
可以看到返回信息是按照文本显示,返回信息也支持 Markdown 的显示(猜的然后换阵了下确实可以), 这样我们就可以拿来做一些复杂数据的展示,比如超链接、问价下载、图片展示等:
细心看上面截图,可以看到回复信息不是那么 干净,有引号等信息。
刚才我们看到,虽然返回内容支持 「Markdown」展示,但是内容要么是JSON, 要么字符串都是引号开头的。如何能干净的显示文件内容呢,这就是用到JSON解析了。
我们现在把文件返回改成:
return {
'success': True,
'text': data.prompt,
'image': ''
}
添加一个 JSON 解析节点:
流程和节点如下配置:
再测试,可以看到聊天能干净的返回图片了:
下面我们再看看如何分支,实现如下场景:
• 当请求 success
的时候,显示图片
• 否则,显示text
的内容
增加一个条件分支如下:
那之前的JSON 解析
节点配置在分支的 IF
后面, 再添加一个JSON 解析
节点配置在分支的 ELSE
后面,
然后增加一个变量聚合器
,不用配置,连线如下图:
调整代码返回如下:
return {
'success': data.prompt=='hello',
'prompt': data.prompt,
'xlsx': '[Prompts.xlsx](http://localhost:3001/api/v1/openai/chat/completions)',
'image': ''
'text': """## 生成式 AI 应用创新引擎..."""
调试运行程序,聊天窗口输入 world
,可以得到回复:
通过自定义工具、配合流程编排以及JSON解析等节点,我们可以实现很多常用的逻辑处理。
唯一美中不足的就是,Dify 对于消息的入参、出参定义还是比较克制,我们需要使用 AI 时代的程序编排思维去使用 Dify, 还有就是不支持上传文件(可以上传图片),无法集成一些文件处理功能,比如之前实现的对 Excel 文件的问答填写。
53AI,企业落地应用大模型首选服务商
产品:大模型应用平台+智能体定制开发+落地咨询服务
承诺:先做场景POC验证,看到效果再签署服务协议。零风险落地应用大模型,已交付160+中大型企业
2024-04-25
2024-04-24
2024-07-20
2024-07-16
2024-05-08
2024-05-07
2024-05-09
2024-06-21
2024-04-25
2024-08-06