用Dify构建本地知识库(上)

极少和医院打交道,所以把事情想当然了,医生确实打电话通知我入院,只不过排在了 2 周之后。不行的话,只能换家小医院去瞧瞧了


本文是应网友 姜不吃先生 的要求折腾的,文章比较长,分了 2 篇,上篇是安装,下篇是简单的应用示例

什么是 Dify ?

Dify(Do it for you) 是一个高精度的 LLMOps 平台,基于不同的大型语言模型能力,让更多人可以简单地创建可持续操作的原生 AI 应用。Dify 提供多种类型应用的可视化编排,应用可开箱即用,也能以“云端即服务”的 API 提供服务。其直观的界面结合了 AI 工作流程、RAG 管道、代理功能、模型管理、可观察性功能等,让您快速从原型转向生产。

通过 Dify 创建的应用包含了:

  • 开箱即用的 Web 站点,支持表单模式和聊天对话模式
  • 一套 API 即可包含插件、上下文增强等能力,代替你省下底层的编写工作
  • 可视化的对应用进行数据分析、考察日志或进行标注

安装

在群晖上以 Docker 方式安装。

在安装 Dify 之前,请确保您的计算机满足以下最低系统要求:

  • CPU >= 2
  • 内存 >= 4GB

创建目录

第一步需要我们建好目录,为了方便起见,全程都是通过 SSH 客户端登录到群晖,在命令行进行操作

1
2
3
4
5
# 新建文件夹 dify 和 子目录
mkdir -p /volume1/docker/dify/{db,nginx/conf.d,redis,storage,weaviate}

# 进入 dify 目录
cd /volume1/docker/dify

下一步就是准备好相关的文件,这些文件老苏已打包好了,https://github.com/wbsu2003/synology/raw/main/Dify/dify.zip

docker-compose.yml

官方的示例 docker-compose.yaml 中包含的容器比较多,例如:

  • 沙盒服务,它会确保恶意代码不会被执行,具体说明:https://docs.dify.ai/v/zh-hans/guides/workflow/node/code#ben-di-bu-shu

  • SSRF_PROXY 则能避免 SSRF攻击,具体说明:https://docs.dify.ai/v/zh-hans/learn-more/faq/install-faq#id-18.-wei-shi-mo-xu-yao-ssrfproxy

因为老苏并不打算部署到公网,所以做了些精简。将下面的内容保存为 docker-compose.yml 文件即可

  1. 中文注释由 kimichatgpt 翻译;
  2. 因为包含中文注释,保存时,请选择 UTF-8 格式
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
version: '3'

services:
# API 服务
api:
image: langgenius/dify-api:0.6.8
container_name: dify-api
restart: always
environment:
# 启动模式,'api' 指启动为 API 服务器。
MODE: api
# 应用的日志级别。支持的值有 `DEBUG`, `INFO`, `WARNING`, `ERROR`, `CRITICAL`
LOG_LEVEL: INFO
# 用于安全签名会话 cookie 和加密数据库上敏感信息的密钥。你可以使用 `openssl rand -base64 42` 生成一个强密钥。
SECRET_KEY: sk-9f73s3ljTXVcMT3Blb3ljTqtsKiGHXVcMT3BlbkFJLK7U
# 控制台应用程序 Web 前端的基础 URL,如果控制台域与 API 或 Web 应用程序域不同,则指的是 WEB 服务的控制台基础 URL。
# 示例:http://cloud.dify.ai
CONSOLE_WEB_URL: 'http://192.168.0.197:8848'
# 用于管理员用户初始化的密码。
# # 如果未设置,创建初始管理员帐户时管理员用户将不会提示输入密码。
INIT_PASSWORD: ''
# 控制台应用程序 API 服务器的基础 URL,如果控制台域与 API 或 Web 应用程序域不同,则指的是 WEB 服务的控制台基础 URL。
# 示例: http://cloud.dify.ai
CONSOLE_API_URL: 'http://192.168.0.197:8848'
# 服务 API 端点的 URL 前缀,如果 API 域与控制台域不同,则指的是当前 API 服务的基础 URL。
# 示例: http://api.dify.ai
SERVICE_API_URL: 'http://192.168.0.197:8848'
# # Web 应用程序前端的 URL 前缀,如果 Web 应用程序域与控制台或 API 域不同,则指的是 WEB 服务的 Web 应用程序基础 URL。
# 示例: http://udify.app
APP_WEB_URL: 'http://192.168.0.197:8848'
# 文件预览或下载的 URL 前缀。
# 用于将文件预览或下载的 URL 显示给前端或作为多模型输入;
# URL 是签名的,并且具有过期时间。
FILES_URL: 'http://192.168.0.197:8848'
# 当启用时,应用程序启动之前将执行迁移,并在迁移完成后启动应用程序。
MIGRATION_ENABLED: 'true'
# PostgreSQL 数据库连接的配置。它与下面的 'db' 服务中的配置保持一致。
DB_USERNAME: postgres
DB_PASSWORD: difyai123456
DB_HOST: db
DB_PORT: 5432
DB_DATABASE: dify
# Redis 连接的配置。它与下面的 'redis' 服务中的配置保持一致。
REDIS_HOST: redis
REDIS_PORT: 6379
REDIS_USERNAME: ''
REDIS_PASSWORD: difyai123456
REDIS_USE_SSL: 'false'
# 使用 Redis 数据库 0 作为 Redis 缓存。
REDIS_DB: 0
# Celery 代理的配置。使用 Redis 作为代理,并使用 Redis 数据库 1 作为 Celery 代理。
CELERY_BROKER_URL: redis://:difyai123456@redis:6379/1
# 指定允许进行跨域请求的 Web API 的源,例如 https://dify.app 或 * 表示所有源都允许。
WEB_API_CORS_ALLOW_ORIGINS: '*'
# 指定允许对控制台 API 进行跨域请求的源,例如 https://cloud.dify.ai 或 * 表示所有源都允许。
CONSOLE_CORS_ALLOW_ORIGINS: '*'
# CSRF Cookie 设置
# 控制是否在跨站点请求中发送 cookie,以提供一定程度的跨站点请求伪造攻击防护。
#
# 默认值:`SameSite=Lax, Secure=false, HttpOnly=true`
# 此默认配置支持使用 HTTP 或 HTTPS 的同源请求,
# 但不支持跨源请求。它适用于本地调试目的。
#
# 如果您想启用跨源支持,
# 您必须使用 HTTPS 协议,并将配置设置为 `SameSite=None, Secure=true, HttpOnly=true`。
#
# 用于存储用户文件的存储类型。支持的值有 `local` 和 `s3` 和 `azure-blob` 和 `google-storage`,默认值:`local`
STORAGE_TYPE: local
# 本地存储目录的路径,相对于 API 服务代码的根路径或绝对路径。默认值为 storage 或 /home/john/storage。
# 仅当 STORAGE_TYPE 为 local 时可用。
STORAGE_LOCAL_PATH: storage
# 要使用的向量存储类型。支持的值有 `weaviate`, `qdrant`, `milvus`, `relyt`。
VECTOR_STORE: weaviate
# Weaviate 端点 URL。只有在 VECTOR_STORE 为 `weaviate` 时才可用。
WEAVIATE_ENDPOINT: http://weaviate:8080
# TWeaviate API 密钥。
WEAVIATE_API_KEY: WVF5YThaHlkYwhGUSmCRgsX3tD5ngdN8pkih
# Sentry 错误报告的 DSN。如果未设置,则将禁用 Sentry 错误报告。
SENTRY_DSN: ''
# Sentry 事件的采样率。默认值:`1.0`
SENTRY_TRACES_SAMPLE_RATE: 1.0
# Sentry 配置文件的采样率。默认值:`1.0`
SENTRY_PROFILES_SAMPLE_RATE: 1.0
depends_on:
- db
- redis
volumes:
# 将存储目录挂载到容器上,用于存储用户文件。
- ./storage:/app/api/storage
# 注释掉以暴露 dify-api 端口到主机
# ports:
# - "5001:5001"

# worker 服务
# 用于处理队列的 Celery 工作器。
worker:
image: langgenius/dify-api:0.6.8
container_name: dify-worker
restart: always
environment:
CONSOLE_WEB_URL: 'http://192.168.0.197:8848'
# 启动模式,设置为 'worker' 以启动用于处理队列的 Celery 工作器。
MODE: worker

# --- 下面的所有配置都与'api'服务中的相同。 ---

# 应用的日志级别。支持的值有 `DEBUG`, `INFO`, `WARNING`, `ERROR`, `CRITICAL`
LOG_LEVEL: INFO
# 用于安全签名会话 cookie 和加密数据库上敏感信息的密钥。你可以使用 `openssl rand -base64 42` 生成一个强密钥。
# 与 API 服务相同
SECRET_KEY: sk-9f73s3ljTXVcMT3Blb3ljTqtsKiGHXVcMT3BlbkFJLK7U
# postgres 数据库连接的配置。它与下面的'db'服务中的配置一致。
DB_USERNAME: postgres
DB_PASSWORD: difyai123456
DB_HOST: db
DB_PORT: 5432
DB_DATABASE: dify
# redis 缓存连接的配置。
REDIS_HOST: redis
REDIS_PORT: 6379
REDIS_USERNAME: ''
REDIS_PASSWORD: difyai123456
REDIS_DB: 0
REDIS_USE_SSL: 'false'
# celery 代理的配置。
CELERY_BROKER_URL: redis://:difyai123456@redis:6379/1
# 用于存储用户文件的存储类型。支持的值有 `local` 和 `s3` 和 `azure-blob` 和 `google-storage`,默认值:`local`
STORAGE_TYPE: local
STORAGE_LOCAL_PATH: storage
# 要使用的向量存储类型。支持的值有 `weaviate`, `qdrant`, `milvus`, `relyt`, `pgvector`。
VECTOR_STORE: weaviate
# Weaviate 端点 URL。只有在 VECTOR_STORE 为 `weaviate` 时才可用。
WEAVIATE_ENDPOINT: http://weaviate:8080
# Weaviate API 密钥。
WEAVIATE_API_KEY: WVF5YThaHlkYwhGUSmCRgsX3tD5ngdN8pkih
depends_on:
- db
- redis
volumes:
# 将存储目录挂载到容器上,用于存储用户文件。
- ./storage:/app/api/storage

# 前端 web 应用程序。
web:
image: langgenius/dify-web:0.6.8
container_name: dify-web
restart: always
environment:
# 控制台应用程序 API 服务器的基础 URL,如果控制台域与 api 或 web 应用程序域不同,指的是 WEB 服务的控制台基础 URL。
# 示例: http://cloud.dify.ai
CONSOLE_API_URL: 'http://192.168.0.197:8848'
# Web APP api 服务器的 URL,如果 web 应用程序域与控制台或 api 域不同,指的是 WEB 服务的 Web 应用程序基础 URL。
# 示例: http://udify.app
APP_API_URL: 'http://192.168.0.197:8848'
# Sentry 错误报告的 DSN。如果未设置,Sentry 错误报告将被禁用。
SENTRY_DSN: ''
# 注释掉以暴露 dify-web 端口到主机
# ports:
# - "3000:3000"

# postgres数据库。
db:
image: postgres:15-alpine
container_name: dify-db
restart: always
environment:
PGUSER: postgres
# 默认 postgres 用户的密码。
POSTGRES_PASSWORD: difyai123456
# 默认 postgres 数据库的名称。
POSTGRES_DB: dify
TZ: Asia/Shanghai
# postgres 数据目录
PGDATA: /var/lib/postgresql/data/pgdata
volumes:
- ./db:/var/lib/postgresql/data
# 注释掉以暴露 db(postgresql) 端口到主机
# ports:
# - "5432:5432"
healthcheck:
test: [ "CMD", "pg_isready" ]
interval: 1s
timeout: 3s
retries: 30

# redis 缓存。
redis:
image: redis:6-alpine
container_name: dify-redis
restart: always
volumes:
# 将 redis 数据目录挂载到容器上。
- ./redis:/data
# Set the redis password when startup redis server.
command: redis-server --requirepass difyai123456
healthcheck:
test: [ "CMD", "redis-cli", "ping" ]
# 注释掉以暴露 redis 端口到主机
# ports:
# - "6379:6379"

# Weaviate 向量存储。
weaviate:
image: semitechnologies/weaviate:1.19.0
container_name: dify-weaviate
restart: always
volumes:
# 将 Weaviate 数据目录挂载到容器上。
- ./weaviate:/var/lib/weaviate
environment:
# Weaviate 配置
# 你可以查阅 [Weaviate](https://weaviate.io/developers/weaviate/config-refs/env-vars) 文档以获取更多信息。
QUERY_DEFAULTS_LIMIT: 25
AUTHENTICATION_ANONYMOUS_ACCESS_ENABLED: 'false'
PERSISTENCE_DATA_PATH: '/var/lib/weaviate'
DEFAULT_VECTORIZER_MODULE: 'none'
CLUSTER_HOSTNAME: 'node1'
AUTHENTICATION_APIKEY_ENABLED: 'true'
AUTHENTICATION_APIKEY_ALLOWED_KEYS: 'WVF5YThaHlkYwhGUSmCRgsX3tD5ngdN8pkih'
AUTHENTICATION_APIKEY_USERS: 'hello@dify.ai'
AUTHORIZATION_ADMINLIST_ENABLED: 'true'
AUTHORIZATION_ADMINLIST_USERS: 'hello@dify.ai'
# 注释掉以暴露 weaviate 端口到主机
# ports:
# - "8080:8080"

# nginx 反向代理
# 用于 API 服务和 Web 服务的反向代理。
nginx:
image: nginx:latest
container_name: dify-nginx
restart: always
volumes:
- ./nginx/nginx.conf:/etc/nginx/nginx.conf
- ./nginx/proxy.conf:/etc/nginx/proxy.conf
- ./nginx/conf.d:/etc/nginx/conf.d
#- ./nginx/ssl:/etc/ssl
depends_on:
- api
- web
ports:
- "8848:80"
#- "443:443"

因为涉及的容器比较多,请务必仔细检查各个参数、环境变量,以免填错。老苏为了节省篇幅,将 kimi 对照翻译的版本放在了这里:https://github.com/wbsu2003/synology/blob/main/Dify/docker-compose.yml

  • 容器 dify-api:提供 API 服务,使用 API 模式启动
  • 容器 dify-worker:使用 worker模式启动,是 Celery 分布式任务队列系统的一部分,用于处理任务队列中的工作
  • 容器 dify-web:前端 Web 应用
  • 容器 dify-dbPostgres 数据库
  • 容器 dify-redis:缓存 Redis
  • 容器 dify-weaviate:向量数据库 weaviate
  • 容器 dify-nginx:反向代理服务器,代理 APIWeb 服务

关于 CONSOLE_WEB_URLCONSOLE_API_URLSERVICE_API_URLAPP_WEB_URLFILES_URL ,在局域网使用的情况下,如果 nginx 的容器端口设置的是 80,可以设置为 '',但如果不是的话,需要设置为 IP + 端口,否则发布的时候会截端口,上面的示例中,192.168.0.197 是群晖主机的 IP8848 则是 nginx 中的容器端口,你可以根据需要进行修改

docker-compose.yml 放入 dify 根目录

nginx 设置

nginx 的配置文件来自官方,文件地址:https://github.com/langgenius/dify/tree/main/docker/nginx,老苏未做任何修改

其中 nginx.confNginx 的主配置文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
user  nginx;
worker_processes auto;

error_log /var/log/nginx/error.log notice;
pid /var/run/nginx.pid;


events {
worker_connections 1024;
}


http {
include /etc/nginx/mime.types;
default_type application/octet-stream;

log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';

access_log /var/log/nginx/access.log main;

sendfile on;
#tcp_nopush on;

keepalive_timeout 65;

#gzip on;
client_max_body_size 15M;

include /etc/nginx/conf.d/*.conf;
}

proxy.conf 用于定义反向代理的具体行为

1
2
3
4
5
6
7
8
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_http_version 1.1;
proxy_set_header Connection "";
proxy_buffering off;
proxy_read_timeout 3600s;
proxy_send_timeout 3600s;

以上两个文件放在 /dify/nginx 目录中

default.conf 提供了默认的服务器配置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
server {
listen 80;
server_name _;

location /console/api {
proxy_pass http://api:5001;
include proxy.conf;
}

location /api {
proxy_pass http://api:5001;
include proxy.conf;
}

location /v1 {
proxy_pass http://api:5001;
include proxy.conf;
}

location /files {
proxy_pass http://api:5001;
include proxy.conf;
}

location / {
proxy_pass http://web:3000;
include proxy.conf;
}

# If you want to support HTTPS, please uncomment the code snippet below
#listen 443 ssl;
#ssl_certificate ./../ssl/your_cert_file.cer;
#ssl_certificate_key ./../ssl/your_cert_key.key;
#ssl_protocols TLSv1.1 TLSv1.2 TLSv1.3;
#ssl_prefer_server_ciphers on;
#ssl_session_cache shared:SSL:10m;
#ssl_session_timeout 10m;
}

该文件在 /dify/nginx/conf.d 目录中

一键启动

当文件准备好之后,就可以开始启动了

1
2
3
4
5
6
7
8
# 进入 dify 目录
cd /volume1/docker/dify

# 如果出现超时,可以设置大一点的值,例如下面👇这样
export COMPOSE_HTTP_TIMEOUT=1200

# 一键启动
docker-compose up -d

稍等一会儿,如果设置没问题的话,你会看到 7 个容器启动了

参考文档

langgenius/dify: One API for plugins and datasets, one interface for prompt engineering and visual operation, all for creating powerful AI applications.
地址:https://github.com/langgenius/dify

Dify - 易用的 LLMOps 平台,定义你的 AI 原生应用
地址:https://dify.ai/zh

欢迎使用 Dify - Dify
地址:https://docs.dify.ai/v/zh-hans/getting-started/readme

接入 Ollama 部署的本地模型 - Dify
地址:https://docs.dify.ai/v/zh-hans/guides/model-configuration/ollama