文章目录
- 1 大模型基本原理
- 1.1 model_context_tokens、max_tokens和prompt_tokens
- 1.1.1 三者之间的关系
- 1.1.2 总结对比
- 2 Dify源代码
- 2.0 前后端代码跑起来
- 【0】准备开发环境
- 【1】下载代码
- 【2】运行后端
- (1)Start the docker-compose stack
- (2) Copy `.env.example` to `.env`
- (3)Generate a `SECRET_KEY` in the `.env` file.
- (4)Create environment.
- (5)Install dependencies
- (6)Run migrate
- (7)Start backend
- 【3 运行前端】
- (0)环境要求
- (1)安装前端依赖库
- (2)创建一个配置文件
- (3)跑起来
- (4)看效果
- 2.1 后端
- 2.2 前端
1 大模型基本原理
1.1 model_context_tokens、max_tokens和prompt_tokens
- prompt_tokens
- 含义:
输入给模型的 ** 提示文本(Prompt)** 所包含的 token 数量。Token 是模型处理文本的基本单位(例如,一个英文单词可能被拆分为多个 tokens,中文可能按字符或词语拆分)。 - 作用:
计算费用:大多数 LLM 按 输入 token 数 + 输出 token 数 计费,prompt_tokens 直接影响成本。
上下文长度限制:prompt_tokens 必须小于等于 model_context_tokens,否则会导致截断或错误。
- max_tokens
- 含义:
模型生成的最大输出 token 数量。例如,设置 max_tokens=200,则模型最多生成 200 个 tokens 的回复。 - 作用:
控制响应长度:避免生成过长的内容(如无限循环或冗余回答)。
限制费用:减少不必要的 token 消耗。
- model_context_tokens
- 含义:
模型支持的最大上下文窗口大小,即输入(prompt_tokens)和输出(max_tokens)的总 token 数上限。 - 示例:
GPT-4 的 model_context_tokens 通常为 8192 或 32768(取决于版本)。
如果 prompt_tokens = 4000,则 max_tokens 最大只能设置为 8192 - 4000 = 4192。
1.1.1 三者之间的关系
prompt_tokens + max_tokens ≤ model_context_tokens
如果``prompt_tokens + max_tokens > model_context_tokens ,请求会失败(例如报错 “上下文长度超出限制”)。
1.1.2 总结对比
参数 | 含义 | 示例(GPT-4 8K) |
---|---|---|
prompt_tokens | 输入提示的 token 数量 | 例如:4000 tokens |
max_tokens | 输出结果的最大 token数量 | 设置为 ≤ 4192 tokens |
model_context_tokens | 模型支持的总上下文长度上限 | 固定值:8192 tokens |
2 Dify源代码
2.0 前后端代码跑起来
【0】准备开发环境
【Windows开发】
1、 安装并启用WSL2.
2、 安装Docker Desktop
3、 安装python 3.12或者以上的版本, 这个是dify源码的要求,源码中大量使用了高版本的Python才支持的一些特性。 为pip配置清华的源。
【1】下载代码
gitee下载地址:https://gitee.com/dify_ai/dify
【2】运行后端
无他, 总体思路就是按照api目录中的readme进行操作。
(1)Start the docker-compose stack
The backend require some middleware, including PostgreSQL, Redis, and Weaviate, which can be started together using docker-compose
.
cd ../dockercp middleware.env.example middleware.env# change the profile to other vector database if you are not using weaviatedocker compose -f docker-compose.middleware.yaml --profile weaviate -p dify up -dcd ../api
这一步牵扯到docker,最容易出问题。 但是这里也牵扯到了docker的好处,正是因为用了docker,才会保持环境一直, 基本上也不用考虑这么多中间件的安装。
【第一个问题: docker环境问题(个人认为这个问题是最常见的,我自己几台电脑中都有这个问题,这个不可回避也不能回避)】
问题:
Error response from daemon: Get "https://registry-1.docker.io/v2/": net/http: request canceled while waiting for connection (Client.Timeout exceeded while awaiting headers)
解决办法:
《1》为 docker desktop配置镜像源。我这里给出我的配置文件(虽然也是从网上copy过来的)。
{"builder": {"gc": {"defaultKeepStorage": "20GB","enabled": true}},"experimental": false,"registry-mirrors": ["https://docker.m.daocloud.io/","https://docker.mirrors.ustc.edu.cn","https://huecker.io/","https://registry.docker-cn.com","http://hub-mirror.c.163.com","https://mirror.ccs.tencentyun.com","https://dockerhub.timeweb.cloud","https://noohub.ru/","https://dockerproxy.com","https://docker.mirrors.ustc.edu.cn","https://docker.nju.edu.cn","https://xx4bwyg2.mirror.aliyuncs.com","http://f1361db2.m.daocloud.io","https://registry.docker-cn.com","https://docker.mirrors.ustc.edu.cn"]}
《2》增加请求超时时间:可以尝试增加 Docker 的默认超时时间。例如在 WSL 的 Ubuntu 环境下,可以增加 Docker 的客户端超时时间. 进入虚拟出来的Ubuntu系统(我这里是Ubuntu系统,因人而异,可能是Debian系统等), 执行如下命令:
export DOCKER_CLIENT_TIMEOUT=600
export COMPOSE_HTTP_TIMEOUT=600
参考:
https://www.cnblogs.com/OneSeting/p/18532166
(2) Copy .env.example
to .env
注意,这一步的执行是在api目录下面。 不是在docker目录下执行的。 否则会遇到问题,非常坎坷,还有一些些问题。
cp .env.example .env
(3)Generate a SECRET_KEY
in the .env
file.
bash for Linux
sed -i "/^SECRET_KEY=/c\SECRET_KEY=$(openssl rand -base64 42)" .env
bash for Mac
secret_key=$(openssl rand -base64 42)sed -i '' "/^SECRET_KEY=/c\\SECRET_KEY=${secret_key}" .env
如果是Windows系统的话,可以利用Git Bash,git bash里面是可以执行Linux命令的,直接执行上述的Linux命令即可。
(4)Create environment.
Dify API service uses UV to manage dependencies.
First, you need to add the uv package manager, if you don’t have it already.
pip install uv# Or on macOSbrew install uv
这里需要注意, 最好为pip配置一下清华的源。 否则会很慢很慢。
(5)Install dependencies
uv sync --dev
这一步也最容易出错,因为要安装好多好多的第三方的依赖库,很容易出问题。
【第一个问题:本地需要VC++的环境】
[stderr]error: Microsoft Visual C++ 14.0 or greater is required. Get it with "Microsoft C++ Build Tools": https://visualstudio.microsoft.com/visual-cpp-build-tools/hint: This usually indicates a problem with the package or the build environment.help: `chroma-hnswlib` (v0.7.6) was included because `dify-api:vdb` depends on `chromadb` (v0.5.20) which depends on `chroma-hnswlib`
解决办法:
就是下载相应的VC库。 我这里和参考文件中不一样的是,除了文档中说明的两个库之外,.net开发和C++桌面开发常用的开发库全部安装到位。(因为我本身有可能还是需要进行一些C#或者C++开发, 最起码是要看一些源代码的,需要这个环境,要方便一些)
参考:
https://zhuanlan.zhihu.com/p/165008313
(6)Run migrate
Before the first launch, migrate the database to the latest version.
uv run flask db upgrade
这一步我也是遇到了问题的。 不确定是什么原因(不知道是不是gitee的代码还是不太行,应该用github的。还是我追求了比较新的版本)。
【第一个问题:访问数据库的url路径没有密码】
问题:
Traceback (most recent call last):File "<frozen runpy>", line 198, in _run_module_as_mainFile "<frozen runpy>", line 88, in _run_codeFile "E:\dify\api\.venv\Scripts\flask.exe\__main__.py", line 10, in <module>File "E:\dify\api\.venv\Lib\site-packages\flask\cli.py", line 1129, in maincli.main()File "E:\dify\api\.venv\Lib\site-packages\click\core.py", line 1363, in mainrv = self.invoke(ctx)^^^^^^^^^^^^^^^^File "E:\dify\api\.venv\Lib\site-packages\click\core.py", line 1830, in invokereturn _process_result(sub_ctx.command.invoke(sub_ctx))^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^File "E:\dify\api\.venv\Lib\site-packages\click\core.py", line 1830, in invokereturn _process_result(sub_ctx.command.invoke(sub_ctx))^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^File "E:\dify\api\.venv\Lib\site-packages\click\core.py", line 1226, in invokereturn ctx.invoke(self.callback, **ctx.params)^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^File "E:\dify\api\.venv\Lib\site-packages\click\core.py", line 794, in invokereturn callback(*args, **kwargs)^^^^^^^^^^^^^^^^^^^^^^^^^File "E:\dify\api\.venv\Lib\site-packages\click\decorators.py", line 34, in new_funcreturn f(get_current_context(), *args, **kwargs)^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^File "E:\dify\api\.venv\Lib\site-packages\flask\cli.py", line 400, in decoratorreturn ctx.invoke(f, *args, **kwargs)^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^File "E:\dify\api\.venv\Lib\site-packages\click\core.py", line 794, in invokereturn callback(*args, **kwargs)^^^^^^^^^^^^^^^^^^^^^^^^^File "E:\dify\api\.venv\Lib\site-packages\flask_migrate\cli.py", line 154, in upgrade_upgrade(directory, revision, sql, tag, x_arg)File "E:\dify\api\.venv\Lib\site-packages\flask_migrate\__init__.py", line 111, in wrappedf(*args, **kwargs)File "E:\dify\api\.venv\Lib\site-packages\flask_migrate\__init__.py", line 200, in upgradecommand.upgrade(config, revision, sql=sql, tag=tag)File "E:\dify\api\.venv\Lib\site-packages\alembic\command.py", line 408, in upgradescript.run_env()File "E:\dify\api\.venv\Lib\site-packages\alembic\script\base.py", line 586, in run_envutil.load_python_file(self.dir, "env.py")File "E:\dify\api\.venv\Lib\site-packages\alembic\util\pyfiles.py", line 95, in load_python_filemodule = load_module_py(module_id, path)^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^File "E:\dify\api\.venv\Lib\site-packages\alembic\util\pyfiles.py", line 113, in load_module_pyspec.loader.exec_module(module) # type: ignore^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^File "<frozen importlib._bootstrap_external>", line 994, in exec_moduleFile "<frozen importlib._bootstrap>", line 488, in _call_with_frames_removedFile "E:\dify\api\migrations\env.py", line 109, in <module>run_migrations_online()File "E:\dify\api\migrations\env.py", line 93, in run_migrations_onlinewith connectable.connect() as connection:^^^^^^^^^^^^^^^^^^^^^File "E:\dify\api\.venv\Lib\site-packages\sqlalchemy\engine\base.py", line 3278, in connectreturn self._connection_cls(self)^^^^^^^^^^^^^^^^^^^^^^^^^^File "E:\dify\api\.venv\Lib\site-packages\sqlalchemy\engine\base.py", line 148, in __init__Connection._handle_dbapi_exception_noconnection(File "E:\dify\api\.venv\Lib\site-packages\sqlalchemy\engine\base.py", line 2442, in _handle_dbapi_exception_noconnectionraise sqlalchemy_exception.with_traceback(exc_info[2]) from eFile "E:\dify\api\.venv\Lib\site-packages\sqlalchemy\engine\base.py", line 146, in __init__self._dbapi_connection = engine.raw_connection()^^^^^^^^^^^^^^^^^^^^^^^File "E:\dify\api\.venv\Lib\site-packages\sqlalchemy\engine\base.py", line 3302, in raw_connectionreturn self.pool.connect()^^^^^^^^^^^^^^^^^^^File "E:\dify\api\.venv\Lib\site-packages\sqlalchemy\pool\base.py", line 449, in connectreturn _ConnectionFairy._checkout(self)^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^File "E:\dify\api\.venv\Lib\site-packages\sqlalchemy\pool\base.py", line 1263, in _checkoutfairy = _ConnectionRecord.checkout(pool)^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^File "E:\dify\api\.venv\Lib\site-packages\sqlalchemy\pool\base.py", line 712, in checkoutrec = pool._do_get()^^^^^^^^^^^^^^File "E:\dify\api\.venv\Lib\site-packages\sqlalchemy\pool\impl.py", line 179, in _do_getwith util.safe_reraise():File "E:\dify\api\.venv\Lib\site-packages\sqlalchemy\util\langhelpers.py", line 146, in __exit__raise exc_value.with_traceback(exc_tb)File "E:\dify\api\.venv\Lib\site-packages\sqlalchemy\pool\impl.py", line 177, in _do_getreturn self._create_connection()^^^^^^^^^^^^^^^^^^^^^^^^^File "E:\dify\api\.venv\Lib\site-packages\sqlalchemy\pool\base.py", line 390, in _create_connectionreturn _ConnectionRecord(self)^^^^^^^^^^^^^^^^^^^^^^^File "E:\dify\api\.venv\Lib\site-packages\sqlalchemy\pool\base.py", line 674, in __init__self.__connect()File "E:\dify\api\.venv\Lib\site-packages\sqlalchemy\pool\base.py", line 900, in __connectwith util.safe_reraise():File "E:\dify\api\.venv\Lib\site-packages\sqlalchemy\util\langhelpers.py", line 146, in __exit__raise exc_value.with_traceback(exc_tb)File "E:\dify\api\.venv\Lib\site-packages\sqlalchemy\pool\base.py", line 896, in __connectself.dbapi_connection = connection = pool._invoke_creator(self)^^^^^^^^^^^^^^^^^^^^^^^^^^File "E:\dify\api\.venv\Lib\site-packages\sqlalchemy\engine\create.py", line 643, in connectreturn dialect.connect(*cargs, **cparams)^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^File "E:\dify\api\.venv\Lib\site-packages\sqlalchemy\engine\default.py", line 621, in connectreturn self.loaded_dbapi.connect(*cargs, **cparams)^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^File "E:\dify\api\.venv\Lib\site-packages\psycopg2\__init__.py", line 122, in connectconn = _connect(dsn, connection_factory=connection_factory, **kwasync)^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
sqlalchemy.exc.OperationalError: (psycopg2.OperationalError) connection to server at "localhost" (::1), port 5432 failed: fe_sendauth: no password supplied(Background on this error at: https://sqlalche.me/e/20/e3q8)
解决办法:
我没有定位到原因, 但是我可以提供一个简单的规避方案:
在api/configs/middleware/__init__.py
文件中的数据库相关的配置类中,直接设置数据库的密码,这个密码就是.env
文件里面的。
class DatabaseConfig(BaseSettings):DB_HOST: str = Field(description="Hostname or IP address of the database server.",default="localhost",)DB_PORT: PositiveInt = Field(description="Port number for database connection.",default=5432,)DB_USERNAME: str = Field(description="Username for database authentication.",default="postgres",)DB_PASSWORD: str = Field(description="Password for database authentication.",# 这里就是我修改的内容default="difyai123456",)
(7)Start backend
uv run flask run --host 0.0.0.0 --port=5001 --debug
这里我也是遇到了问题的,不知道是不是下载的代码的问题,还是windows的原因还是我本地环境的原因, 这些不可考。
【第一个问题:】
问题现象:
(.venv) PS E:\dify\api> uv run flask run --host 0.0.0.0 --port=5001 --debug
warning: `VIRTUAL_ENV=E:\dify\.venv` does not match the project environment path `.venv` and will be ignored; use `--active` to target the active environment instead
2025-05-24 07:25:11,817.817 INFO [MainThread] [utils.py:149] - Note: NumExpr detected 22 cores but "NUMEXPR_MAX_THREADS" not set, so enforcing safe limit of 16.
2025-05-24 07:25:11,817.817 INFO [MainThread] [utils.py:162] - NumExpr defaulting to 16 threads.
Traceback (most recent call last):File "<frozen runpy>", line 198, in _run_module_as_mainFile "<frozen runpy>", line 88, in _run_codeFile "E:\dify\api\.venv\Scripts\flask.exe\__main__.py", line 10, in <module>File "E:\dify\api\.venv\Lib\site-packages\flask\cli.py", line 1129, in maincli.main()File "E:\dify\api\.venv\Lib\site-packages\click\core.py", line 1363, in mainrv = self.invoke(ctx)^^^^^^^^^^^^^^^^File "E:\dify\api\.venv\Lib\site-packages\click\core.py", line 1830, in invokereturn _process_result(sub_ctx.command.invoke(sub_ctx))^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^File "E:\dify\api\.venv\Lib\site-packages\click\core.py", line 1226, in invokereturn ctx.invoke(self.callback, **ctx.params)^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^File "E:\dify\api\.venv\Lib\site-packages\click\core.py", line 794, in invokereturn callback(*args, **kwargs)^^^^^^^^^^^^^^^^^^^^^^^^^File "E:\dify\api\.venv\Lib\site-packages\click\decorators.py", line 93, in new_funcreturn ctx.invoke(f, obj, *args, **kwargs)^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^File "E:\dify\api\.venv\Lib\site-packages\click\core.py", line 794, in invokereturn callback(*args, **kwargs)^^^^^^^^^^^^^^^^^^^^^^^^^File "E:\dify\api\.venv\Lib\site-packages\flask\cli.py", line 977, in run_commandraise e from NoneFile "E:\dify\api\.venv\Lib\site-packages\flask\cli.py", line 961, in run_commandapp: WSGIApplication = info.load_app() # pyright: ignore^^^^^^^^^^^^^^^File "E:\dify\api\.venv\Lib\site-packages\flask\cli.py", line 353, in load_appapp = locate_app(import_name, None, raise_if_not_found=False)^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^File "E:\dify\api\.venv\Lib\site-packages\flask\cli.py", line 245, in locate_app__import__(module_name)File "E:\dify\api\app.py", line 37, in <module>app = create_app()^^^^^^^^^^^^File "E:\dify\api\app_factory.py", line 32, in create_appinitialize_extensions(app)File "E:\dify\api\app_factory.py", line 96, in initialize_extensionsext.init_app(app)File "E:\dify\api\extensions\ext_storage.py", line 113, in init_appstorage.init_app(app)File "E:\dify\api\extensions\ext_storage.py", line 19, in init_appself.storage_runner = storage_factory()^^^^^^^^^^^^^^^^^File "E:\dify\api\extensions\ext_storage.py", line 31, in <lambda>return lambda: OpenDALStorage(dify_config.OPENDAL_SCHEME)^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^File "E:\dify\api\extensions\storage\opendal_storage.py", line 37, in __init__self.op = opendal.Operator(scheme=scheme, **kwargs) # type: ignore^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
opendal.exceptions.ConfigInvalid: ConfigInvalid (permanent) at => root is not specified
解决办法:
我也不是很了解, 我目前能给出一个规避办法,先让程序能run起来。在api/extensions/ext_storage.py
文件中,在创建OpenDALStorage实例的时候,直接指定root。
@staticmethoddef get_storage_factory(storage_type: str) -> Callable[[], BaseStorage]:match storage_type:case StorageType.S3:from extensions.storage.aws_s3_storage import AwsS3Storagereturn AwsS3Storagecase StorageType.OPENDAL:from extensions.storage.opendal_storage import OpenDALStorage# 指定名为shankai的目录作为根目录return lambda: OpenDALStorage(scheme = dify_config.OPENDAL_SCHEME, root = "shankai")
至此,终于运行起来了。 效果如下:
(.venv) PS E:\dify\api> uv run flask run --host 0.0.0.0 --port=5001 --debug
warning: `VIRTUAL_ENV=E:\dify\.venv` does not match the project environment path `.venv` and will be ignored; use `--active` to target the active environment instead
2025-05-24 07:39:49,895.895 INFO [MainThread] [utils.py:149] - Note: NumExpr detected 22 cores but "NUMEXPR_MAX_THREADS" not set, so enforcing safe limit of 16.
2025-05-24 07:39:49,895.895 INFO [MainThread] [utils.py:162] - NumExpr defaulting to 16 threads.
E:\dify\api\controllers\web\remote_files.py:7: UserWarning: To use python-magic guess MIMETYPE, you need to run `pip install python-magic-bin`from controllers.common import helpers* Debug mode: on
2025-05-24 07:39:56,383.383 INFO [MainThread] [_internal.py:97] - WARNING: This is a development server. Do not use it in a production deployment. Use a production WSGI server instead.* Running on all addresses (0.0.0.0)* Running on http://127.0.0.1:5001* Running on http://192.168.31.176:5001
2025-05-24 07:39:56,383.383 INFO [MainThread] [_internal.py:97] - Press CTRL+C to quit
2025-05-24 07:39:56,392.392 INFO [MainThread] [_internal.py:97] - * Restarting with stat
2025-05-24 07:39:58,569.569 INFO [MainThread] [utils.py:149] - Note: NumExpr detected 22 cores but "NUMEXPR_MAX_THREADS" not set, so enforcing safe limit of 16.
2025-05-24 07:39:58,569.569 INFO [MainThread] [utils.py:162] - NumExpr defaulting to 16 threads.
E:\dify\api\controllers\web\remote_files.py:7: UserWarning: To use python-magic guess MIMETYPE, you need to run `pip install python-magic-bin`from controllers.common import helpers
2025-05-24 07:40:00,606.606 WARNING [MainThread] [_internal.py:97] - * Debugger is active!
2025-05-24 07:40:00,629.629 INFO [MainThread] [_internal.py:97] - * Debugger PIN: 797-179-235
【3 运行前端】
(0)环境要求
Before starting the web frontend service, please make sure the following environment is ready.
- Node.js >= v22.11.x
- pnpm v10.x
(1)安装前端依赖库
First, install the dependencies:
pnpm install
(2)创建一个配置文件
Then, configure the environment variables. Create a file named .env.local
in the current directory and copy the contents from .env.example
. Modify the values of these environment variables according to your requirements:
cp .env.example .env.local
配置文件中一些比较关键的配置项
# For production release, change this to PRODUCTION
NEXT_PUBLIC_DEPLOY_ENV=DEVELOPMENT
# The deployment edition, SELF_HOSTED
NEXT_PUBLIC_EDITION=SELF_HOSTED
# The base URL of console application, refers to the Console base URL of WEB service if console domain is
# different from api or web app domain.
# example: http://cloud.dify.ai/console/api
NEXT_PUBLIC_API_PREFIX=http://localhost:5001/console/api
NEXT_PUBLIC_WEB_PREFIX=http://localhost:3000
# The URL for Web APP, refers to the Web App base URL of WEB service if web app domain is different from
# console or api domain.
# example: http://udify.app/api
NEXT_PUBLIC_PUBLIC_API_PREFIX=http://localhost:5001/api
NEXT_PUBLIC_PUBLIC_WEB_PREFIX=http://localhost:3000# SENTRY
NEXT_PUBLIC_SENTRY_DSN=
(3)跑起来
Finally, run the development server:
pnpm run dev
(4)看效果
Open http://localhost:3000 with your browser to see the result.
You can start editing the file under folder app
. The page auto-updates as you edit the file.
很明显的,有一个开发环境的标志。