Dify踩坑记录(续)

Dify踩坑记录(续)

Dify踩坑记录

在前文中,做了一个反思翻译,下面开始做一个长文翻译,长文翻译的思路就是,由于大模型的每次发送和接收的数据大小是有限制的,对于一些长的文章,没法一次完成,解决办法就是,把长文分段,一段一段翻译,然后再整合在一起。

这次我就一步一步讲工作流了,工作流在文章末尾,直接导入后就能看到每一个步骤了。整体的流程看起来这样。

这里着重要将的是我遇到的两个问题,以及如何解决他们的。

问题1: sandbox问题

安装三方库

在分片的节点中,我们需要用到三方的python库。

1
2
3
import tiktoken
from icecream import ic
from langchain_text_splitters import RecursiveCharacterTextSplitter

由于是sandbox镜像,事先并没有我们要的三方库。实际上sandbox项目留了这个配置。

dify/docker/volumes/sandbox/dependencies/python-requirements.txt中增加就可以。

1
2
3
tiktoken==0.6.0
langchain-text-splitters>=0.0.1
icecream==2.1.3

沙盒权限问题

如何在sandbox限制了一些系统调用,即时你安装了三方库,也用不了。这个花了好好几个小时,希望能够给你一些帮助。在github上,发现很多人都有遇到这个问题。https://github.com/langgenius/dify/issues/4993https://github.com/langgenius/dify/issues/4344,我也尝试一堆方案,比如典型的一个建议就是,类似这样,增加`security_opt`配置,然而并没有成功。假如你也遇到这样的问题,就不要再花时间了。

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
# The DifySandbox
sandbox:
image: langgenius/dify-sandbox:0.2.8
restart: always
privileged: true
user: "root"
read_only: false
cap_add:
- SYS_ADMIN
security_opt:
- no-new-privileges:false
- "seccomp=unconfined"
environment:
# The DifySandbox configurations
# Make sure you are changing this key for your deployment with a strong key.
# You can generate a strong key using `openssl rand -base64 42`.
API_KEY: ${SANDBOX_API_KEY:-dify-sandbox}
GIN_MODE: ${SANDBOX_GIN_MODE:-release}
WORKER_TIMEOUT: ${SANDBOX_WORKER_TIMEOUT:-15}
ENABLE_NETWORK: ${SANDBOX_ENABLE_NETWORK:-true}
HTTP_PROXY: ${SANDBOX_HTTP_PROXY:-http://ssrf_proxy:3128}
HTTPS_PROXY: ${SANDBOX_HTTPS_PROXY:-http://ssrf_proxy:3128}
SANDBOX_PORT: ${SANDBOX_PORT:-8194}
volumes:
- ./volumes/sandbox/dependencies:/dependencies
healthcheck:
test: [ "CMD", "curl", "-f", "http://localhost:8194/health" ]
networks:
- ssrf_proxy_network

我的解决方案就是修改镜像,这也是在官方的faq里面的处理方法。https://github.com/langgenius/dify-sandbox/blob/main/FAQ.md#2-my-python-code-returns-an-operation-not-permitted-error。

下载dify-sandbox源代码

打开internal/static/python_syscall/syscalls_arm64.go,修改其中ALLOW_SYSCALLS

注意,faq里面写的探测需要哪些权限的步骤我并没有做成功,有知道的小伙伴请分享你的经验。由于我不知道究竟缺少什么权限,所以就直接全部写上0-500。

这是我修改后的代码

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
var ALLOW_SYSCALLS = []int{
0, 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, 244, 245, 246, 247, 248, 249,
250, 251, 252, 253, 254, 255, 256, 257, 258, 259,
260, 261, 262, 263, 264, 265, 266, 267, 268, 269,
270, 271, 272, 273, 274, 275, 276, 277, 278, 279,
280, 281, 282, 283, 284, 285, 286, 287, 288, 289,
290, 291, 292, 293, 294, 295, 296, 297, 298, 299,
300, 301, 302, 303, 304, 305, 306, 307, 308, 309,
310, 311, 312, 313, 314, 315, 316, 317, 318, 319,
320, 321, 322, 323, 324, 325, 326, 327, 328, 329,
330, 331, 332, 333, 334, 335, 336, 337, 338, 339,
340, 341, 342, 343, 344, 345, 346, 347, 348, 349,
350, 351, 352, 353, 354, 355, 356, 357, 358, 359,
360, 361, 362, 363, 364, 365, 366, 367, 368, 369,
370, 371, 372, 373, 374, 375, 376, 377, 378, 379,
380, 381, 382, 383, 384, 385, 386, 387, 388, 389,
390, 391, 392, 393, 394, 395, 396, 397, 398, 399,
400, 401, 402, 403, 404, 405, 406, 407, 408, 409,
410, 411, 412, 413, 414, 415, 416, 417, 418, 419,
420, 421, 422, 423, 424, 425, 426, 427, 428, 429,
430, 431, 432, 433, 434, 435, 436, 437, 438, 439,
440, 441, 442, 443, 444, 445, 446, 447, 448, 449,
450, 451, 452, 453, 454, 455, 456, 457, 458, 459,
460, 461, 462, 463, 464, 465, 466, 467, 468, 469,
470, 471, 472, 473, 474, 475, 476, 477, 478, 479,
480, 481, 482, 483, 484, 485, 486, 487, 488, 489,
490, 491, 492, 493, 494, 495, 496, 497, 498, 499,
500,
}

修改了之后,需要执行install.sh,以及./build/build_[amd64|arm64].sh完成go的构建。

1
2
./install.sh 
./build/build_arm64.sh

构建完成,会生成envmain两个可执行程序。

下一步就是就用docker重新构建镜像。

1
docker build  --progress=plain  -t mysandbox -f docker/arm64/dockerfile .

修改docker/docker-compose.yaml的sandbox的image,改成刚刚构建的镜像

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

# The DifySandbox
sandbox:
image: mysandbox
restart: always
privileged: true
cap_add:
- SYS_ADMIN
security_opt:
- no-new-privileges:false
- "seccomp=unconfined"
environment:
# The DifySandbox configurations
# Make sure you are changing this key for your deployment with a strong key.
# You can generate a strong key using `openssl rand -base64 42`.
API_KEY: ${SANDBOX_API_KEY:-dify-sandbox}
GIN_MODE: ${SANDBOX_GIN_MODE:-release}
WORKER_TIMEOUT: ${SANDBOX_WORKER_TIMEOUT:-15}
ENABLE_NETWORK: ${SANDBOX_ENABLE_NETWORK:-true}
HTTP_PROXY: ${SANDBOX_HTTP_PROXY:-http://ssrf_proxy:3128}
HTTPS_PROXY: ${SANDBOX_HTTPS_PROXY:-http://ssrf_proxy:3128}
SANDBOX_PORT: ${SANDBOX_PORT:-8194}
volumes:
- ./volumes/sandbox/dependencies:/dependencies
healthcheck:
test: [ "CMD", "curl", "-f", "http://localhost:8194/health" ]
networks:
- ssrf_proxy_network

运行新的容器,回界面测试

1
docker compose up -d

临时目录权限问题

到目前为止,权限的问题解决了,但马上就会有新的问题。错误看起来像这样

1
An error occurred: [Errno 2] No usable temporary directory found in ['/tmp', '/var/tmp', '/usr/tmp', '/']

这个问题的原因是sandbox的执行的用户没有写tmp目录的权限。https://dify.ai/blog/dify-ai-blog-introducing-difysandbox,在官方博客中介绍大致是这个意思,每一个沙盒会在`/var/sandbox/`隔离。sandbox的执行用户是sandbox,我不知道是什么原因原始镜像中并没有给这个设置好权限。

于是就手工在容器中执行

1
2
cd /var/sandbox/
chmod 1777 -R *

工作池问题

现在你可以去测试工作流了,马上就会遇到新的问题。

1
Max submit count 100 of workflow thread pool reached.

为什么是100,这个问题比较容易,通过google搜索社区的内容,按照api容器就好。

https://github.com/langgenius/dify/issues/8659#issuecomment-2367260559

修改完成之后重新构建docker镜像,修改docker-compose文件,使用新的镜像,注意里面有两个容器,apiworker,都用api的镜像。

结束

到此为止,长文翻译的工作流也就算配置完成了。整个事情大概忙了我10多个小时,中间那个权限问题消耗了7个小时。很多概念都不清楚,比如什么seccomp,只是马虎的把问题趟过去了。

另外,这是一个很有用的工具,后边想想能用它来做点什么,或者你有什么好点子也欢迎一起。

附录

工作流文件

长文翻译.yml