为什么要着急升级?觉得能为社区贡献的可能也就这点儿了。整体来看,升级还是很平滑的,除了个别小的 bug
外。升级步骤完全参考文献[4]提供步骤即可,亦可配合参考文献[8]。(前后端源码部署:Dify v0.15.0升级v1.0.0-beta.1的尝试:https://z0yrmerhgi8.feishu.cn/wiki/OBFxw2GtDiULLXk9QSlcHIkunhb)。
Dify v1.0.0-beta.1
建议本地测试,不用于生产环境。该版本最大的变化就是 Dify 市场的推出,包括模型、工具、Agent
策略、扩展和插件集等,这样就与 Dify
主干进行解耦了。为什么要这样做呢?举个稍微极端点儿的例子,假如工具的数量有 1 一亿呢,可以想想 Dify
源码有多么庞大。总之,解耦后主干归主干(大脑),生态归生态(四肢)。在 AIGC
生产领域,把质量做精,把性能做高。在 Dify
市场中,还可以搞个提示功能模块。
看下 Dify
官方对这次版本的更新日志吧。Dify v1.0.0-beta
已经推出全新的插件系统和插件市场。作为插即用的模块化组件,现在可使用 Dify
插件为 AI
应用扩展新功能。Dify
市场包含以下插件 [2][3][5]:
(1)模型和工具:可以独立开发、部署和维护,并拥有灵活的版本控制和系统安全性能的提升。
(2)Agent
策略:创建自定义推理策略,实现更复杂、更精细的多步骤推理。
(3)扩展:构建自定义 API
并连接外部服务,以更高的灵活度处理复杂工作流和数据。
(4)插件集:将多个插件组合成一个单一包以简化部署流程。
此外还在工作流中推出了 Agent
节点 [7],通过结合 LLM、工具和推理策略,Agent 节点能够实现自主的多步骤工具调用,以完成工作流程中的任务。
一.前置条件
1.关闭以前中间件容器
docker compose -f docker-compose.middleware.yaml -p "dify" down
2.拉取最新代码到当前分支
git clone https://github.com/langgenius/dify.git
git checkout [1.0.0-beta.1](https://github.com/langgenius/dify/releases/tag/1.0.0-beta.1)
3.修改前端和后端配置文件参数
根据参考文献[8]修改对应的前端和后端配置文件参数。由于启动中间件服务时会用到配置文件,比如 .env
或者 middleware.env
。但是拉取最新代码的时候,拉取的是 .env.example
或者 middleware.env.example
,所以需要同步更新 .env
或者 middleware.env
配置文件。需要修改 4
个位置,如下所示:
dify\api\.env
dify\docker\.env
dify\docker\middleware.env
dify\web\.env
4.安装前端和后端依赖包
(1)前端
pnpm install
(2)后端
cd api
poetry install
5.启动当前版本中间件容器
cd docker
docker compose -f docker-compose.middleware.yaml -p "dify" up -d
二.插件迁移
注意: 如果要从旧版本升级至
v1.0.0
,需要执行一些基础迁移步骤。
首先,需要将当前环境所使用的工具和模型安装到新的插件环境中。请确保在进行数据库迁移前完成插件的安装。运行以下命令:
poetry run flask extract-plugins --workers=20
此命令会提取当前环境中的所有模型和工具。workers
参数决定提取时的并发进程数,请根据需求调整。最终结果将保存在 plugins.jsonl
文件中,其中包含当前 Dify
实例所有工作区的插件信息。
确保网络可正常访问 https://marketplace.dify.ai,然后运行以下命令:
poetry run flask install-plugins
该命令将从 Marketplace
下载并安装所需的插件到最新的环境中。
1.extract-plugins 步骤
(1)Failed to resolve plugin
执行命令 poetry run flask extract-plugins --workers=20
,可能报错 Failed to resolve 'plugin'
,如下所示:
INFO:numexpr.utils:NumExpr defaulting to 16 threads.
INFO:numexpr.utils:NumExpr defaulting to 16 threads.
INFO:services.plugin.plugin_migration:Extracting unique plugins from plugins.jsonl
INFO:services.plugin.plugin_migration:Installing 3 plugin instances for fake tenant 9d2379d5c93642049bcb9ae068346064
INFO:httpx:HTTP Request: GET https://marketplace.dify.ai/api/v1/plugins/download?unique_identifier=langgenius/openai:0.0.3@3e53c5bef8e4b2bf7173a455dc06ba2601e3b383f376beb76f41df376c0a4f48 "HTTP/1.1 200 OK"
INFO:httpx:HTTP Request: GET https://marketplace.dify.ai/api/v1/plugins/download?unique_identifier=langgenius/siliconflow:0.0.1@3ae44ef62760c41c6b52ce8d179ca5dee2ed9c681d6294ced89b1790f9236fd9 "HTTP/1.1 200 OK"
INFO:httpx:HTTP Request: GET https://marketplace.dify.ai/api/v1/plugins/download?unique_identifier=langgenius/comfyui:0.0.1@944b3b503029df1de688fc08ab181eee7a65a23a6c3513f3c88f3970946fa383 "HTTP/1.1 200 OK"
<strong>ERROR</strong>:core.plugin.manager.base:Request to Plugin Daemon Service failed
Traceback (most recent call last):
File "F:\Dify资料\ai408_dify\api\.venv\Lib\site-packages\urllib3\connection.py", line 198, in _new_conn
sock = connection.create_connection(
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "F:\Dify资料\ai408_dify\api\.venv\Lib\site-packages\urllib3\util\connection.py", line 60, in create_connection
for res in socket.getaddrinfo(host, port, family, socket.SOCK_STREAM):
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "F:\Dify资料\ai408_dify\api\.venv\Lib\site-packages\gevent\_socketcommon.py", line 221, in getaddrinfo
addrlist = get_hub().resolver.getaddrinfo(host, port, family, type, proto, flags)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "F:\Dify资料\ai408_dify\api\.venv\Lib\site-packages\gevent\resolver\thread.py", line 63, in getaddrinfo
return self.pool.apply(_socket.getaddrinfo, args, kwargs)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "F:\Dify资料\ai408_dify\api\.venv\Lib\site-packages\gevent\pool.py", line 161, in apply
return self.spawn(func, *args, **kwds).get()
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "src\\gevent\\event.py", line 330, in gevent._gevent_cevent.AsyncResult.get
File "src\\gevent\\event.py", line 360, in gevent._gevent_cevent.AsyncResult.get
File "src\\gevent\\event.py", line 348, in gevent._gevent_cevent.AsyncResult.get
File "src\\gevent\\event.py", line 328, in gevent._gevent_cevent.AsyncResult._raise_exception
File "F:\Dify资料\ai408_dify\api\.venv\Lib\site-packages\gevent\_compat.py", line 50, in reraise
raise value.with_traceback(tb)
File "F:\Dify资料\ai408_dify\api\.venv\Lib\site-packages\gevent\threadpool.py", line 173, in __run_task
thread_result.set(func(*args, **kwargs))
^^^^^^^^^^^^^^^^^
socket.gaierror: [Errno 11001] getaddrinfo failed
The above exception was the direct cause of the following exception:
Traceback (most recent call last):
File "F:\Dify资料\ai408_dify\api\.venv\Lib\site-packages\urllib3\connectionpool.py", line 787, in urlopen
response = self._make_request(
^^^^^^^^^^^^^^^^^^^
File "F:\Dify资料\ai408_dify\api\.venv\Lib\site-packages\urllib3\connectionpool.py", line 493, in _make_request
conn.request(
File "F:\Dify资料\ai408_dify\api\.venv\Lib\site-packages\urllib3\connection.py", line 445, in request
self.endheaders()
File "D:\Python311\Lib\http\client.py", line 1298, in endheaders
self._send_output(message_body, encode_chunked=encode_chunked)
File "D:\Python311\Lib\http\client.py", line 1058, in _send_output
self.send(msg)
File "D:\Python311\Lib\http\client.py", line 996, in send
self.connect()
File "F:\Dify资料\ai408_dify\api\.venv\Lib\site-packages\urllib3\connection.py", line 276, in connect
self.sock = self._new_conn()
^^^^^^^^^^^^^^^^
File "F:\Dify资料\ai408_dify\api\.venv\Lib\site-packages\urllib3\connection.py", line 205, in _new_conn
raise NameResolutionError(self.host, self, e) from e
<strong>urllib3.exceptions.NameResolutionError: <urllib3.connection.HTTPConnection object at 0x000001B041F02310>: Failed to resolve 'plugin' ([Errno 11001] getaddrinfo failed)</strong>
解决方案为修改 plugin
为 127.0.0.1
,原理是 dify-plugin_daemon-1
本地容器运行。如下所示:
(2)小的格式 bug
命令执行完毕后,自动生成 dify\api\plugins.jsonl
文件,如下所示:
{"tenant_id": "56f205c6-6d2c-45b5-8584-483b9e41b6d6", "plugins": ["langgenius/openai", "langgenius/siliconflow", "langgenius/comfyui"]}
2.install-plugins 步骤
(1)PluginDaemonUnauthorizedError
(dify-api-py3.11) PS F:\Dify资料\ai408_dify\api> poetry run flask install-plugins
2025-01-11 02:03:52,242,242 INFO [utils.py:162] NumExpr defaulting to 16 threads.
Input file [plugins.jsonl]:
Output file [installed_plugins.jsonl]:
Starting install plugins.
2025-01-11 03:31:36,119,119 INFO [plugin_migration.py:334] Extracting unique plugins from plugins.jsonl
100%|████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████| 3/3 [00:02<00:00, 1.27it/s]
2025-01-11 03:31:38,594,594 INFO [plugin_migration.py:368] Installing 3 plugin instances for fake tenant c0742b0f47db4378afe86cdd39580178
2025-01-11 03:31:41,253,253 INFO [_client.py:1038] HTTP Request: GET https://marketplace.dify.ai/api/v1/plugins/download?unique_identifier=langgenius/siliconflow:0.0.1@3ae44ef62760c41c6b52ce8d179ca5dee2ed9c681d6294ced89b1790f9236fd9 "HTTP/1.1 200 OK"
2025-01-11 03:31:41,269,269 INFO [_client.py:1038] HTTP Request: GET https://marketplace.dify.ai/api/v1/plugins/download?unique_identifier=langgenius/comfyui:0.0.1@944b3b503029df1de688fc08ab181eee7a65a23a6c3513f3c88f3970946fa383 "HTTP/1.1 200 OK"
2025-01-11 03:31:41,302,302 INFO [_client.py:1038] HTTP Request: GET https://marketplace.dify.ai/api/v1/plugins/download?unique_identifier=langgenius/openai:0.0.3@3e53c5bef8e4b2bf7173a455dc06ba2601e3b383f376beb76f41df376c0a4f48 "HTTP/1.1 200 OK"
************************************
<Response [401]>
************************************
<Response [401]>
************************************
<Response [401]>
Traceback (most recent call last):
File "<frozen runpy>", line 198, in _run_module_as_main
File "<frozen runpy>", line 88, in _run_code
File "F:\Dify资料\ai408_dify\api\.venv\Scripts\flask.exe\__main__.py", line 7, in <module>
File "F:\Dify资料\ai408_dify\api\.venv\Lib\site-packages\flask\cli.py", line 1129, in main
cli.main()
File "F:\Dify资料\ai408_dify\api\.venv\Lib\site-packages\click\core.py", line 1082, in main
rv = self.invoke(ctx)
^^^^^^^^^^^^^^^^
File "F:\Dify资料\ai408_dify\api\.venv\Lib\site-packages\click\core.py", line 1697, in invoke
return _process_result(sub_ctx.command.invoke(sub_ctx))
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "F:\Dify资料\ai408_dify\api\.venv\Lib\site-packages\click\core.py", line 1443, in invoke
return ctx.invoke(self.callback, **ctx.params)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "F:\Dify资料\ai408_dify\api\.venv\Lib\site-packages\click\core.py", line 788, in invoke
return __callback(*args, **kwargs)
^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "F:\Dify资料\ai408_dify\api\commands.py", line 716, in install_plugins
PluginMigration.install_plugins(input_file, output_file)
File "F:\Dify资料\ai408_dify\api\services\plugin\plugin_migration.py", line 372, in install_plugins
response = cls.handle_plugin_instance_install(fake_tenant_id, plugins["plugins"])
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "F:\Dify资料\ai408_dify\api\services\plugin\plugin_migration.py", line 470, in handle_plugin_instance_install
future.result() # This will raise any exceptions that occurred
^^^^^^^^^^^^^^^
File "D:\Python311\Lib\concurrent\futures\_base.py", line 456, in result
return self.__get_result()
^^^^^^^^^^^^^^^^^^^
File "D:\Python311\Lib\concurrent\futures\_base.py", line 401, in __get_result
raise self._exception
File "D:\Python311\Lib\concurrent\futures\thread.py", line 58, in run
result = self.fn(*self.args, **self.kwargs)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "F:\Dify资料\ai408_dify\api\services\plugin\plugin_migration.py", line 464, in download_and_upload
manager.upload_pkg(tenant_id, plugin_package, verify_signature=True)
File "F:\Dify资料\ai408_dify\api\core\plugin\manager\plugin.py", line 53, in upload_pkg
return self._request_with_plugin_daemon_response(
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "F:\Dify资料\ai408_dify\api\core\plugin\manager\base.py", line 152, in _request_with_plugin_daemon_response
self._handle_plugin_daemon_error(error.error_type, error.message)
File "F:\Dify资料\ai408_dify\api\core\plugin\manager\base.py", line 235, in _handle_plugin_daemon_error
raise PluginDaemonUnauthorizedError(description=message)
core.plugin.manager.exc.PluginDaemonUnauthorizedError: PluginDaemonUnauthorizedError: unauthorized
(特别感谢微信群大佬 非法操作和 Junjie.M 的答疑)经提醒 plugin_api_key
和 plugin_daemon_key
不一致导致的,根据日志定位如下接口不通:
最后发现应该是 dify_config.PLUGIN_DAEMON_KEY
,而不是 dify_config.PLUGIN_API_KEY
。当时为了着急测试,直接将 plugin_daemon_inner_api_key
写固定了。需要修改 2
个地方,如下所示:
三.数据库迁移
在完成插件安装后,按照 Dify
的常规升级流程更新数据库结构至最新版本:
poetry run flask db upgrade
Dify v1.0
对旧数据提供了兼容。正常情况下,可以继续使用。但为了更好地兼容未来版本,在确认不会回退到旧版本后,可以运行以下数据迁移命令:
poetry run flask migrate-data-for-plugin
此命令会在数据库中为现有的模型和工具供应商名称加上 langgenius
前缀,例如将 openai
转变为 langgenius/openai/openai
。请注意,这样的操作可能会影响旧版本 Dify 的正常运行,所以在执行此命令前,请务必备份数据库,以免出现无法挽回的问题。
四.其它事项
1.DB_PLUGIN_DATABASE
如果全部容器部署,docker\docker-compose.yaml
有个小的 bug
,修改 dify-plugin
为 dify_plugin
,如下所示:
2.启动后端服务
3.启动前端服务
4.Dify 新版页面
(1)查看版本和市场
通过版本可以看到现在已经是 Dify v1.0.0-beta.1
版本,如下所示:
现在看到的插件就是迁移过来的插件,如下所示:
(2)查看市场报错
在浏览器 Console
中看到报错了,如下所示:
解决方案是修改 dify\web\.env
配置文件,如下所示:
# The APIFREX for MARKETPLACE
NEXT_PUBLIC_MARKETPLACE_API_PREFIX=https://marketplace.dify.ai/api/v1
# The URL for MARKETPLACE
NEXT_PUBLIC_MARKETPLACE_URL_PREFIX=https://marketplace.dify.ai
(2)安装插件(模型)
以安装插件(模型)deepseek
为例,如下所示:
稍等一会儿,即可看到已经安装成功,如下所示:
在查看详情中可看到该插件的详细介绍,如下所示:
然后在设置-> 模型供应商中配置 API Key 即可,如下所示:
(3)dify-plugin_daemon 容器报错 [9]
虽然插件(模型)安装成功了,但是发现 dify-plugin_daemon
容器报错,如下所示:
发现新安装的插件(模型)deepseek
成功了,但是从 Dify v0.15.0
迁移 Dify v1.0.0-beta.1
过来的某些插件(比如 openai
、siliconflow
)的 dify_plugin
包安装失败。解决方案就是删除后重新安装了,但是会遇到超时后 kill signal
问题,如下所示:
(特别感谢微信群大佬 非法操作 的答疑和贡献)解决方案[10]为修改 60 为 180 即可,如下所示:
然后重新打个镜像,修改 dify\docker\docker-compose.middleware.yaml
中 plugin_daemon
的 image
为 langgenius/dify-plugin-daemon:0.0.2-local
。其中,tag 自定义命名即可。
docker build -t langgenius/dify-plugin-daemon:0.0.2-local -f docker/local.dockerfile .
4.dify_plugin 库的数据表
该版本除了 dify
数据库,还新增了 dify_plugin
数据库,该库相关的数据表,如下所示:
觉的还有部分也可以解耦出来,就是现在 Dify
被吐槽最多的 RAG
,可以拆分为通用文档解析部分,知识库或知识图谱部分。还有类似 LangChain
的多智能体,以及 LangGraph
功能等。当然还有 Dify
的工作流等性能问题亟待解决。虽说现在仅仅是迈出了万里长征的第一步,但更是新的开端。
参考文献
[1] 11 – Dify 版本升级日志:https://z0yrmerhgi8.feishu.cn/wiki/OcxPwxdGeivl0SkmpJOcT7VNnZe
[2] Dify 插件模块:https://docs.dify.ai/zh-hans/plugins/introduction
[3] Dify 市场:https://marketplace.dify.ai/
[4] Dify v1.0.0-beta.1:https://github.com/langgenius/dify/releases
[5] Dify v1.0.0-beta:插件开启公测:https://mp.weixin.qq.com/s/PNjuWj8nIFuyZKwr5W30Rg
[6] 和 Dify.AI 后端工程师 Yeuoly 聊聊插件系统的用例和开发初衷:https://www.bilibili.com/video/BV1sVcLeVEGb/
[7] Agent 节点:https://docs.dify.ai/zh-hans/guides/workflow/node/agent
[8] 4 – Dify 中 Docker Compose 和源码混合部署升级指南:https://z0yrmerhgi8.feishu.cn/wiki/T96lwPyKQiO6UvkMtKgcoVksnAf
[9] no module named dify_plugin #12657:https://github.com/langgenius/dify/issues/12657
[10] change default process kill time #8:https://github.com/langgenius/dify-plugin-daemon/pull/8
[11] 前后端源码部署:Dify v0.15.0升级v1.0.0-beta.1的尝试:https://z0yrmerhgi8.feishu.cn/wiki/OBFxw2GtDiULLXk9QSlcHIkunhb
(文:NLP工程化)