AI知识库

53AI知识库

学习大模型的前沿技术与行业应用场景


Dify + FastAPI 创建自定义工具
发布日期:2024-08-06 21:50:39 浏览次数: 2651 来源:数翼


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

大家不喜欢命令的话,可以直接打开文件直接编辑,比如我就是。

初始化Python环境

我们仍然使用 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

自定义开发 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

IDE 运行

对 Dify 接口不熟悉的同学肯定希望在开发的过程中进行调试,大家可以在喜欢的 IDE 用 Flask 程序标准的方式进行调试。

比如我用的 PyCharm,从 IDE 启动调试配置如下:

自定义工具

我们现在看一看如何自定义工具。

FastAPI 服务

我们现在实现一个 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 的显示(猜的然后换阵了下确实可以), 这样我们就可以拿来做一些复杂数据的展示,比如超链接、问价下载、图片展示等:

细心看上面截图,可以看到回复信息不是那么 干净,有引号等信息。

JSON解析节点

刚才我们看到,虽然返回内容支持 「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+中大型企业

联系我们

售前咨询
186 6662 7370
预约演示
185 8882 0121

微信扫码

与创始人交个朋友

回到顶部

 
扫码咨询