日习一技 - 2025年9月
type: channel
link: https://i-study-everyday.online/2025/09
description: 每天学一点新技术，新框架，新工具，新名词。关于编程语言，数据库，数据结构，算法，机器学习，云计算。
items: 深入 Dify 应用的会话流程之流式处理
items: 深入 Dify 应用的会话流程之限流策略
items: 梳理 Dify 应用的会话接口
items: 学习 Dify 的路由系统
items: 学习 Dify 的代码结构
items: 学习 Dify 的工作流和对话流应用
items: 学习 Dify 的文本生成和 Agent 应用
items: 使用 Dify 创建你的第一个 AI 应用
items: Dify 快速上手指南
items: 学习 Chat2Graph 的知识库服务

深入 Dify 应用的会话流程之流式处理
type: item
date: 2025-09-30T00:43:00+00:00
description: 在昨天的文章中，我们学习了 Dify 会话处理流程的核心服务 AppGenerateService，并通过分析它的 generate() 方法了解了 Dify 如何通过系统级和应用级两层限流策略来保障服务的稳定性。不过这个方法昨天只分析了一半，今天我们继续来看看剩下的部分。Dify 会根据不同的应用类型走不同的应用生成器逻辑，通过源码可以发现，无论是文本生成、聊天对话、智能体、工作流还是对话流，都遵循着固定的流式处理流程。比如文本生成：if app_model.mode == AppMode.COMPLETION.value: return rate_limit.generate( # 步骤1：限流包装 CompletionAppGenerator.convert_to_event_stream( # 步骤2：事件流转换 CompletionAppGenerator().generate( # 步骤3：具体应用逻辑 app_model=app_model, user=user, args=args, invoke_from=invoke_from, streaming=streaming ), ), request_id=request_id, )我们先不急着看具体的应用生成器，而是先看看外面的两层方法，学习 Dify 是如何统一处理流式和非流式响应的。限流生成器在 generate() 方法最后的 finally 语句里，有一点特别值得注意，这里有一个判断很奇怪，只有当请求是非流式时才调用 exit() 释放限流： finally: if not streaming: rate_limit.exit(request_id)在传统的非流式处理中，在 finally 块中释放限流确实是可以的；但在流式处理中，当 generate() 方法返回时，请求实际上还没有结束！ 客户端会持续从生成器中读取数据，直到生成器耗尽或发生异常。因此，我们需要一个机制来确保只有当生成器正常结束或异常时才释放限流，并且不影响原有生成器的任何功能。我们可以看看 Dify 是如何处理流式请求的限流的，核心就在 rate_limit.generate() 方法里：def generate(self, generator: Union[Generator[str, None, None], Mapping[str, Any]], request_id: str): if isinstance(generator, Mapping): # 非流式响应直接返回 return generator else: # 流式响应使用 RateLimitGenerator 包装 return RateLimitGenerator( rate_limit=self, generator=generator, request_id=request_id, )这里首先通过 generator 的类型自动区分流式响应（Generator）和非流式响应（Mapping），对于非流式响应直接返回，而对于流式响应，使用 RateLimitGenerator 进行包装而不影响原有接口。它的实现如下：class RateLimitGenerator: def __init__(self, rate_limit: RateLimit, generator: Generator[str, None, None], request_id: str): self.rate_limit = rate_limit self.generator = generator self.request_id = request_id self.closed = False def __iter__(self): return self def __next__(self): if self.closed: raise StopIteration try: # 正常情况下透传数据 return next(self.generator) except Exception: # 异常时自动释放资源 self.close() raise def close(self): if not self.closed: self.closed = True # 从 Redis 中移除活跃请求记录 self.rate_limit.exit(self.request_id) if self.generator is not None and hasattr(self.generator, "close"): self.generator.close()可以看到 RateLimitGenerator 是一个实现了 迭代器协议 的包装类，…

深入 Dify 应用的会话流程之限流策略
type: item
date: 2025-09-29T00:28:00+00:00
description: 在前面的文章中，我们梳理了 Dify 应用的各种会话接口，了解了不同蓝图下五种应用类型的接口实现，以及各自的认证方式和用户类型。如果我们仔细阅读源码就会发现，所有应用的会话接口背后处理逻辑几乎一样：def post(self, app_model: App, end_user: EndUser): response = AppGenerateService.generate( app_model=app_model, user=end_user, args=args, invoke_from=InvokeFrom.SERVICE_API, streaming=streaming ) return helper.compact_generate_response(response)都是通过统一调用核心服务 AppGenerateService 的 generate() 方法，然后返回响应。今天我们就看看这个核心服务的具体实现，深入探索 Dify 的会话流程，解析其中涉及的关键技术要点。统一的会话入口正如上文提到的，无论是 Console、Web 还是 Service API 蓝图下的会话接口，最终都会调用到 AppGenerateService 的 generate() 方法。这个方法是 Dify 会话处理的核心枢纽，负责协调不同类型应用的生成流程。让我们来看看这个方法的实现逻辑：@classmethod def generate( cls, app_model: App, user: Union[Account, EndUser], args: Mapping[str, Any], invoke_from: InvokeFrom, streaming: bool = True, ): # 如果是 sandbox 订阅计划 # 开启系统级限流：总请求数限流 if dify_config.BILLING_ENABLED: limit_info = BillingService.get_info(app_model.tenant_id) if limit_info["subscription"]["plan"] == "sandbox": if cls.system_rate_limiter.is_rate_limited(app_model.tenant_id): raise InvokeRateLimitError( "Rate limit exceeded, please upgrade your plan " f"or your RPD was {dify_config.APP_DAILY_RATE_LIMIT} requests/day" ) cls.system_rate_limiter.increment_rate_limit(app_model.tenant_id) # 应用级限流：并发请求数限流 max_active_request = cls._get_max_active_requests(app_model) rate_limit = RateLimit(app_model.id, max_active_request) request_id = RateLimit.gen_request_key() try: request_id = rate_limit.enter(request_id) # 调用不同类型的应用生成器 if app_model.mode == AppMode.COMPLETION.value: # 文本生成 elif app_model.mode == AppMode.AGENT_CHAT.value or app_model.is_agent: # 智能体 elif app_model.mode == AppMode.CHAT.value: # 聊天助手 elif app_model.mode == AppMode.ADVANCED_CHAT.value: # 对话流 elif app_model.mode == AppMode.WORKFLOW.value: # 工作流 else: raise ValueError(f"Invalid app mode {app_model.mode}") # 退出应用级限流 except Exception: rate_limit.exit(request_id) raise finally: if not streaming: rate_limit.exit(request_id)从这个核心方法可以看出，Dify 的会话处理流程包含以下几个关键步骤：系统级限流：基于应用的租户进行全局限流控制，开启账单功能后才有这个功能应用级限流：基于应用的并发请…

梳理 Dify 应用的会话接口
type: item
date: 2025-09-26T00:32:00+00:00
description: 在前面的文章中，我们学习了 Dify 的代码结构和路由系统，了解了 Dify 是如何通过 Flask Blueprint 和 Flask-RESTX 来组织其复杂的 API 架构的。今天，我们将深入探索 Dify 应用的会话 API 接口，分析其具体的实现细节，并结合我们之前学习的内容，看看不同蓝图下的实现以及各自的区别。五种应用 + 三大蓝图我们知道，Dify 有五种不同的应用类型：class AppMode(StrEnum): # 聊天助手 CHAT = "chat" # 文本生成 COMPLETION = "completion" # 智能体 AGENT_CHAT = "agent-chat" # 工作流 WORKFLOW = "workflow" # 对话流 ADVANCED_CHAT = "advanced-chat"不同的应用类型对应不同的会话接口，而根据应用的调用方式，这些会话接口又会出现在不同的蓝图下。因此 Dify 的会话接口有很多，如果第一次接触源码的话会很懵。会话接口主要分布在三个蓝图下：Console 蓝图：从管理控制台调用，又分为从工作室的预览调试和探索的已发布应用两个地方调用，接口统一以 /console/api 为前缀Web 蓝图：从前端的 Web 应用调用，Dify 会为每个应用生成一个公开可访问的页面，这个页面的调用统一以 /api 为前缀Service API 蓝图：第三方通过 HTTP API 或 SDK 集成调用，接口以 /v1 为前缀不同蓝图下虽然接口各异，但都实现了相同的核心功能，它们只是在认证方式和用户类型上有所区别，为不同的使用场景提供最合适的调用方式。下面就来对每个蓝图下的会话接口逐一分析。Console 蓝图当我们在 “工作室” 的预览页面对应用进行调试时：调用下面这些接口：# 文本生成 api.add_resource( CompletionMessageApi, "/apps/<uuid:app_id>/completion-messages" ) # 聊天助手 或 Agent 应用 api.add_resource( ChatMessageApi, "/apps/<uuid:app_id>/chat-messages" ) # 对话流 api.add_resource( AdvancedChatDraftWorkflowRunApi, "/apps/<uuid:app_id>/advanced-chat/workflows/draft/run" ) # 工作流 api.add_resource( DraftWorkflowRunApi, "/apps/<uuid:app_id>/workflows/draft/run" )我们还可以在 “探索” 中打开应用：此时调用接口如下：# 文本生成 api.add_resource( CompletionApi, "/installed-apps/<uuid:installed_app_id>/completion-messages", endpoint="installed_app_completion" ) # 聊天助手、Agent 应用 或 对话流 api.add_resource( ChatApi, "/installed-apps/<uuid:installed_app_id>/chat-messages", endpoint="installed_app_chat_completion" ) # 工作流 api.add_resource( InstalledAppWorkflowRunApi, "/installed-apps/<uuid:installed_app_id>/workflows/run" )Console 蓝图下的对话接口最大特点是 URL 上带有 app_id 参数，接口直接对该应用发起会话即可。另外，这个蓝图下的接口主要面向平台用户，需要对用户进行登录认证，所以接口的实现上都带有 @login_required 装饰器：class ChatMessageApi(Resource): @setup_required @login_required @account_initialization_required @get_app_model(mode=[AppMode.CHAT, AppMode.AGENT_CHAT]) def post(self, app_model): # ...Web 蓝图在应用的配置页，我们可以将应用发布成 Web 应用：该功能默认开启，会自动生成一个能够在互联网上公开访问的网址。Web 应用的页面适配了不同尺寸的设备，包括 PC，平板和手机，使用者无需登陆，即可使用。当用户…

学习 Dify 的路由系统
type: item
date: 2025-09-25T01:05:00+00:00
description: 我们昨天学习了 Dify 的代码架构和三种启动模式，不过在应用启动过程中，我们并没有看到路由注册的相关代码，这里的关键就在于它模块化的扩展系统。Dify 通过 ext_blueprints 模块注册路由，使用 Flask 的 Blueprint 和 Flask-RESTX 的 Namespace 实现模块化的 API 路由管理。我们今天就来学习这部分内容。Flask 框架在深入分析 Dify 的路由系统之前，我们先简单了解一下 Flask 框架。Flask 是一个基于 Python 的轻量级 Web 应用框架，它设计简洁、易于扩展，特别适合构建 API 服务。Flask 的主要优势包括：简单易用：代码简洁，学习曲线平缓灵活扩展：可以根据需要选择和集成各种扩展成熟稳定：经过多年发展，社区生态丰富适合 API：非常适合构建 RESTful API 服务Flask 的设计哲学是 微框架，它只提供 Web 开发的核心功能，其他功能通过扩展来实现。在 Dify 项目中采用了大量的 Flask 扩展，比如：Flask-RESTX：用于构建 RESTful API 和自动生成文档Flask-SQLAlchemy：ORM 数据库操作Flask-Migrate：数据库迁移管理Flask-Login：用户认证和会话管理Flask-CORS：跨域资源共享支持Flask-Compress：自动压缩 HTTP 响应内容Flask-orjson：使用 orjson（一个高性能的 JSON 库）替换 Flask 默认的 JSON 编码器和解码器Flask 基本使用下面是 Flask 框架的基本用法：# 创建应用 from flask import Flask app = Flask(__name__) # 注册路由 @app.route('/user/profile') def user_profile(): return 'user profile' @app.route('/user/settings') def user_settings(): return 'user settings' if __name__ == "__main__": app.run(host="0.0.0.0", port=6001)寥寥几行代码就可以创建一个 RESTful API 服务。可以看到，这里使用了 Flask 最原始的装饰器方式 @app.route 来注册路由，Flask 也支持手动注册路由，这种方式更灵活：# 手动注册路由 app.add_url_rule('/user/prifile', 'user_profile', user_profile) app.add_url_rule('/user/settings', 'user_settings', user_settings)使用 Blueprint 注册路由不过上述两种方式都存在着明显的缺点，所有路由都注册到同一个 app 对象上，难以按功能模块分离，导致代码组织混乱；如果是大型项目，路由会分散在各处，而且无法统一为一组相关路由设置 URL 前缀，维护起来很困难。于是 Flask 引入了 Blueprint 功能，也被称为 蓝图，允许你将相关的路由、视图函数、模板和静态文件组织在一起，形成一个可重用的组件。通过模块化和代码隔离，很好地解决了这些问题。下面演示下蓝图的基本用法，首先我们创建一个独立的 user.py 文件，内容如下：# 创建蓝图 from flask import Blueprint user_bp = Blueprint('user', __name__, url_prefix='/user') # 定义路由 @user_bp.route('/profile') def profile(): return 'user profile' @user_bp.route('/settings') def settings(): return 'user settings'在这个文件中，我们创建了一个名为 user 的蓝图，并约定了统一的 URL 前缀，然后通过装饰器 @user_bp.route 定义路由。接着我们创建主程序：# 创建应用 from flask import Flask app = Flask(__name__) # 注册蓝图 from user import user_bp app.register_blueprint(user_bp) if __name__ == "__main__": app.run(host="0.0.0.0", port=6001)在主程序中，我们导入刚刚的蓝图，并通过 app.register_blueprint() 注册蓝图，这样蓝图中定义的路…

学习 Dify 的代码结构
type: item
date: 2025-09-24T00:31:00+00:00
description: 在前面的系列文章中，我们从实用的角度学习了 Dify 的部署方式、应用创建和各种应用类型的使用方法。今天，我们将深入 Dify 的源码，从技术架构的角度来理解这个 LLM 应用开发平台是如何构建的。目录结构首先，让我们从 Dify 的源码目录结构开始，了解整个项目的组织方式：dify/ ├── api/ # 后端 API 服务 (Python Flask) ├── web/ # 前端 Web 应用 (Next.js 15 + React 19) ├── sdks/ # 多语言 SDK │ ├── python-client/ # Python SDK │ ├── nodejs-client/ # Node.js SDK │ └── php-client/ # PHP SDK ├── dev/ # 开发工具脚本 └── docker/ # Docker 部署配置从这个目录结构可以看出，Dify 采用了经典的前后端分离架构。后端 API 使用 Python Flask 框架提供 RESTful API 服务，前端 Web 使用 Next.js 构建现代化的用户界面，两者通过 HTTP API 进行通信。此外，Dify 还提供了多语言的 SDK，方便开发者在不同技术栈中集成 Dify 的能力。后端架构让我们继续深入后端 api/ 目录，这里是 Dify 的核心逻辑所在：api/ ├── app.py # 应用入口文件 ├── app_factory.py # Flask 应用工厂 ├── dify_app.py # 自定义 Flask 应用类 ├── controllers/ # 控制器层 (路由处理) ├── services/ # 服务层 (业务逻辑) ├── models/ # 模型层 (数据模型) ├── repositories/ # 仓储层 (数据访问) ├── core/ # 核心功能模块 ├── extensions/ # Flask 扩展 ├── libs/ # 工具库 ├── configs/ # 配置管理 ├── tasks/ # 异步任务 ├── migrations/ # 数据库迁移 └── tests/ # 测试代码很显然 Dify 采用了分层的设计思想，将代码按照功能职责进行了清晰的分层：控制器层（Controllers）：处理 HTTP 请求和响应，负责参数验证和路由分发；服务层（Services）：包含核心业务逻辑，协调各个组件完成复杂的业务操作；仓储层（Repositories）：封装数据访问逻辑，提供统一的数据操作接口；模型层（Models）：定义数据模型和实体关系；应用启动入口其中 app.py 文件是 Dify 的启动入口，核心代码如下：if is_db_command(): from app_factory import create_migrations_app app = create_migrations_app() else: from app_factory import create_app app = create_app() celery = app.extensions["celery"] if __name__ == "__main__": app.run(host="0.0.0.0", port=5001)Dify 应用有三种启动模式：数据库迁移模式在入门篇里我们学习过，首次运行 Dify 之前，需要运行下面的命令初始化数据库：$ flask db upgradeDify 通过判断命令行参数是否包含 flask db 子命令，如果包含则调用 create_migrations_app() 执行数据库迁移逻辑。这里使用了 Flask-SQLAlchemy 和 Flask-Migrate 库，其核心是通过 SQLAlchemy 的迁移工具 Alembic 管理数据库结构的版本化变更。在软件开发过程中，我们经常会对数据模型进行修改，这时如果手动写 SQL 同步表结构，极有可能会导致不一致或误操作。而 Flask-Migrate 会自动跟踪数据库模型的变更、生成版本化迁移脚本、执行脚本更新数据库表结构，让数据迁移变得非常容易。除了 flask db upgrade 命令，Flask-Migrate 还支持很多其他的 flask db 子命令，比如 init、migrate、downgrade 等。API 服务模式正常情况下我们通过 flask run 运行程序时，Dify 会调用 create_app() 函数来创建 DifyApp 实例（其实就是 Flask 应用实例）：def create_app() -> DifyApp: # 1. 创建 Flask 应用并加载配置 d…

学习 Dify 的工作流和对话流应用
type: item
date: 2025-09-23T01:03:00+00:00
description: 在前面的文章中，我们学习了 Dify 的聊天助手、文本生成和 Agent 应用，这些应用虽然功能强大，但在处理一些复杂业务逻辑时仍有局限性。今天，我们将学习 Dify 的 工作流（Workflow） 和 对话流（Chatflow） 应用，了解如何通过可视化编排构建更加复杂和灵活的 AI 应用。工作流基本概念工作流是 Dify 提供的一种可视化应用构建方式，它通过将复杂的任务分解成较小的步骤（节点）来降低系统复杂度，减少了对提示词技术和模型推理能力的依赖，提高了 LLM 应用面向复杂任务的性能，同时提升了系统的可解释性、稳定性和容错性。Dify 将工作流分为两种类型，每种都有不同的适用场景：Workflow（工作流）：面向自动化和批处理情景，比如高质量翻译、数据分析、内容生成、电子邮件自动化等，它的交互特点是单次输入输出，无法进行多轮对话；Chatflow（对话流）：面向对话类情景，比如客户服务、语义搜索、需要多步逻辑的对话式应用，它的交互特点是支持多轮对话交互，可以调整生成结果；Workflow 这个单词翻译成中文是工作流，但是在 Dify 的概念中，工作流指的是 Workflow 和 Chatflow 两种。不过我感觉这种分类容易让人混淆，所以我倾向于把 Workflow 就叫做工作流，Chatflow 叫做对话流。创建工作流我们进入 “工作室” 页面，点击 “创建空白应用”，应用类型选择 “工作流”：我们拿之前学习 Coze Studio 时用过的天气查询的例子，来体验下 Dify 的工作流。填写助手名称，以及可选的图标和描述，进入应用的配置页面：可以看出 Dify 和 Coze Studio 工作流差不多，也提供了大量的节点可供使用，包括：基础节点LLM：调用大语言模型的能力，根据给定的提示词处理广泛的任务类型，比如意图识别、文本生成、内容分类、文本转换、代码生成、RAG、图片理解等；知识检索：从知识库中检索与用户问题相关的文本内容，可作为下游 LLM 节点的上下文来使用，实现 RAG 问答；结束：每一个工作流在完整执行后都需要至少一个结束节点，用于输出完整执行的最终结果；若流程中出现条件分叉，则需要定义多个结束节点；Agent：通过集成不同的 Agent 推理策略，使大语言模型能够在运行时动态选择并执行工具，从而实现多步推理；问题理解问题分类器：通过大模型对用户输入进行分类，类似于条件分支，只不过是用自然语言来定义分支；逻辑条件分支：根据 if 条件表达式将工作流程拆分成多个分支；迭代：对数组中的元素依次执行相同的操作步骤，直至输出所有结果，可以理解为任务批处理器，支持并行模式；循环：用于执行依赖前一轮结果的重复任务，直到满足退出条件或达到最大循环次数；转换代码执行：支持执行 Python 或 JavaScript 代码，对输入变量进行处理；模版转换：借助 Jinja2 模板引擎灵活地进行数据转换、文本处理等；变量聚合器：将多路分支的变量聚合为一个变量，确保无论哪个分支被执行，其结果都能通过一个统一的变量来引用和访问；文档提取器：解析并读取文件，返回文件内容，支持 TXT、Markdown、PDF、HTML、DOCX 等格式；变量赋值：将工作流内的变量赋值到会话变量中用于临时存储，并可以在后续对话中持续引用；参数提取器：利用 LLM 从自然语言推理并提取结构化参数，用于后置的工具调用或 HTTP 请求；工具HTTP 请求：向指定的网络地址发送定制化的 HTTP 请求，实现与各种外部服务的互联互通；列表操作：对列表进行过滤、排序、取第 N 项或取前 N 项等操作；Dify 工具：支持调用平台上所有的工具，包括插件工具、自定义工具、工作流工具、MCP 工具等；相比于 Coze Studio 的工作流，Dify 的工作流少了文本处理（字符串拼接和分割）、知识库写入以及一些数据库相关的组件。编排工作流接下来我们开始创建 “天气小助手” 工作流，我们首先在 “开始节点” 上定义输入字段 city 表示要查询的城市名称：在 “开始节点” 中，除了我们定义的输入字段外，还有很多内置的系统变量，都以 sys 开头：sys.files：用户上传的文件sys.user_id：用户唯一标识sys.app_id：应用唯一标识sys.workflow_id：工作流标识sys.workflow_run_id：工作流运行标识这些参数面向具备开发能力的用户，以区分调用工作流的用户和应用或查询工作流或工作流的运行情况。假设我们要对接 高德的天气查询接口，这个接口通过城市编码查询该城市的天气详情。因此第二步是想办法将用户输入的城市名称转换为城市编码，这可以通过 “代码执行” 节点实现：这个节点的输入参数为 city_name 引用自 “开始节点”，输出参…

学习 Dify 的文本生成和 Agent 应用
type: item
date: 2025-09-22T00:52:00+00:00
description: 在前两篇文章中，我们介绍了 Dify 的基本概念和部署方式，并通过创建一个简单的翻译助手初步体验了聊天助手的构建流程。今天，我们将继续学习 Dify 的另外两种应用类型：文本生成应用 和 Agent 应用，了解它们的用法、特点以及应用场景。文本生成应用文本生成应用是 Dify 提供的一种专门用于内容创作的应用类型，它专注于根据用户输入生成特定格式的文本内容。与聊天助手的多轮对话不同，文本生成应用采用 单次输入、单次输出 的交互模式，非常适合批量处理和标准化内容生成场景。比如：内容创作：文章摘要、产品描述、营销文案文本处理：翻译、分类、情感分析模板化生成：邮件回复、报告生成、技术文档批量处理：大规模内容生成和数据处理等我们进入 “工作室” 页面，点击 “创建空白应用”，应用类型选择 “文本生成应用”：我们继续以之前翻译助手为例，填写助手名称，以及可选的图标和描述，进入应用的配置页面：文本生成应用和聊天助手的配置页面几乎完全一样，整个配置页面也是分为左侧的 编排 和 右侧的 调试与预览 两大块。在编排区域里，同样可以配置 提示词、变量、知识库 和 视觉 四个选项。我们在这里添加两个变量：lang - 目标语言，字段类型为下拉选项，选项配置有中文、英文、日文等query - 翻译文本，字段类型为段落然后在提示词中以 {{lang}} 和 {{query}} 占位符插入变量，完整的提示词如下：你是一个翻译助手，你的任务是将用户输入翻译成 {{lang}}用户输入：{{query}}这里定义的变量将以表单的形式显现在右侧的调试区域，和聊天助手不同的是，文本生成应用的对话页面就只有一个表单，用户填写的表单内容将自动替换提示词中的变量，然后调用大模型输出结果。使用变量Dify 变量支持的字段类型包括：文本（string）、段落（string）、下拉选项（string）、数字（number）和复选框（boolean）。这里不支持文件上传类型，功能其实是很受限的，如果有上传文件的需求，可以考虑使用工作流。此外，Dify 还支持以 API 扩展的方式创建 基于 API 的变量：关于 API 变量，我们后面在学习 API 扩展时再作讨论。批量生成文本生成应用的一个强大特性是支持 CSV 批量处理，非常适合批量数据处理或内容生产场景。点击右上角的 “发布” 按钮，可以看到 “批量运行” 的选项：点击后进入翻译应用，页面有 “Run Once” 和 “Run Batch” 两个标签页：要使用批量运行功能，需要准备一个 CSV 格式的文件，包含多条要处理的数据，文件内容要满足一定的格式要求，可以下载模版文件填写：翻译文本,目标语言 "Hello","中文" "What's your name?","中文"批量运行结果如下：运行的结果可以点击下载按钮导出。和聊天助手的区别文本生成应用和聊天助手在架构和使用方式上存在显著差异：特性文本生成应用聊天应用WebApp 界面表单 + 结果展示聊天对话框API 端点completion-messageschat-messages交互模式单次问答多轮对话上下文保持仅当前会话跨会话持久化开场白支持不支持支持批量处理支持 CSV 批量处理不支持Agent 应用Agent（智能体）是 Dify 中最强大的应用类型之一，它利用大语言模型的推理能力，能够 自主规划目标、分解任务、调用工具并迭代执行，无需人工干预即可完成复杂任务。我们进入 “工作室” 页面，点击 “创建空白应用”，应用类型选择 “Agent”：我们创建一个 “生活小能手”，可以调用各种小工具解答用户的各种生活问题，填写应用名称，以及可选的图标和描述，进入应用的配置页面：Agent 应用和聊天助手以及文本生成应用的配置页面也没有太多的区别，总的来说有两点不同：工具配置：可以使用工具扩展 Agent 应用的能力，比如联网搜索或科学计算等；Agent 设置：可以配置 Agent 的工作模式，默认支持 Function Calling 策略；Dify 很贴心地内置了几个小工具：语音转写：支持文本转语音（Text to Speech）和语音转文本（Speech to Text）；代码执行：运行一段代码并返回结果；时间计算：各种时间小工具，比如获取当前时间、计算星期几、时区转换等；网页抓取：根据网页链接获取网页内容；我们不妨全都加上：这样一个 “生活小能手” 智能体就做好了：工具配置值得注意的是，这里语音转写的两个工具需要配置后才能使用，可以点击工具右侧的 “信息和设置” 图标：在工具配置页面选择 TTS 或 ASR 模型即可：需要提前在设置中的模型供应商里配置对应的模型。不过经过我的测试，这两个工具配在智能体里其实有点多余。首先对话窗口不支持上传音频文件，因此调不了语音转文…

使用 Dify 创建你的第一个 AI 应用
type: item
date: 2025-09-19T00:29:00+00:00
description: 上一篇文章中，我们介绍了 Dify 这个开源 LLM 应用开发平台，并演示了两种主要的部署方式。今天，我们将进入实操阶段，学习如何使用 Dify 来构建我们的 AI 应用，Dify 提供了丰富的应用类型和强大的功能，让我们一步步来探索它的核心使用方法。模型配置成功部署 Dify 后，首次访问需要创建管理员账户。登录后，你会看到 Dify 的主界面，这里包含了 探索、工作室、知识库 和 工具 四个核心功能模块。默认进入的是工作室模块：这里是应用开发的核心区域，用于创建和管理 AI 应用，包括工作流、对话流、聊天助手、Agent 和文本生成应用。而探索模块可以体验自己创建的应用，或浏览社区其他用户创建的应用，并支持复制到自己的工作区：知识库和工具是辅助模块，为你的应用添砖加瓦，在知识库模块你可以导入自己的文本数据，为 RAG 应用提供知识支撑，还支持通过 WebHook 实时写入或连接外部知识库：在工具模块你可以自定义工具、工作流或 MCP 工具，还支持从 Dify 市场下载并安装第三方工具：但在使用这些功能之前，我们需要先在 Dify 中配置模型。点击右上角头像，选择 “设置” 进入设置页面，在左侧菜单中选择 “模型供应商”：这里可以看到所有支持的模型供应商，包括国外的 OpenAI、Anthropic、Google Gemini，国内的智谱、DeepSeek、通义千问、月之暗面等 60 多家供应商。Dify 将模型供应商实现成一种插件，因此需要安装。以 OpenAI 为例，在列表中找到 “OpenAI” 并点击 “安装”，安装完成后，点击 “配置”：输入你的 API Key 和其他必要信息并点击 “保存” 即可，我们可以为凭据取一个名字，方便后续使用。配置完成后，你就可以在创建应用时选择相应的模型了。值得注意的是，Dify 使用 PKCS1_OAEP 加密算法安全存储 API 密钥，每个租户都有独立的密钥对，确保数据安全。根据使用场景，Dify 将模型分为六大类：系统推理模型：应用的核心推理引擎，用于对话生成、文本处理等Embedding 模型：将文本转换为向量表示，用于知识库检索Rerank 模型：优化检索结果排序，提升 RAG 应用效果语音转文字模型：支持语音输入功能文字转语音模型：支持将文本输出转换为语音Moderation 模型：支持内容审查功能我们可以在 “系统模型设置” 中为每一类选择一个默认模型：应用的三种创建方式配置好模型后，我们来创建第一个 AI 应用。Dify 提供了三种创建方式：1. 从模板创建初次使用 Dify 时，你可能对于应用创建比较陌生。为了帮助新手用户快速了解在 Dify 上能够构建哪些类型的应用，Dify 提供了丰富的应用模板，涵盖了智能客服、文案写作、数据分析、代码助手等不同的场景，推荐新手从这里快速上手：任意选择某个模板，并将其添加到工作区即可。2. 创建空白应用如果需要从零开始创建应用，可以选择这项，适用于对 Dify 有一定了解的用户：Dify 提供了 5 种主要的应用类型，每种都适用于不同的场景：聊天助手（Chatbot）：最常见的 AI 应用类型，适合构建对话式的智能助手。它支持多轮对话、上下文记忆，可以用来创建客服机器人、个人助理等；文本生成（Text Generator）：这种应用专注于根据用户输入生成特定格式的文本内容，比如文章摘要、产品描述、邮件回复等。它通常是单次交互，输入提示词后直接输出结果；智能体（Agent）：Dify 的高级功能之一，它可以使用工具，比如调用外部 API、执行代码、搜索网络信息、处理文件等，这使得它能够处理需要多步骤操作的复杂任务；工作流（Workflow）：提供了可视化的节点编排界面，让你可以构建复杂的业务逻辑；对话流（Chatflow）：结合了聊天助手和工作流的优点，在对话式交互的基础上增加了复杂的流程控制能力。创建应用时，你需要给应用起一个名字，选择合适的图标，或者上传喜爱的图片用作图标，并使用一段清晰的文字描述此应用的用途，以便后续使用。3. 通过 DSL 文件创建这种方式不太常用，一般用于导入别人分享的应用，或者将应用从一个环境导入到另一个环境。DSL（Domain Specific Language） 是 Dify 定义的应用配置标准，采用 YAML 格式，文件内容包括应用的基本描述、模型参数、编排配置等信息。已经创建好的应用可以导出成 DSL 文件，这样可以在另一个环境导入，支持本地文件导入和 URL 导入：导入 DSL 文件时将校对文件版本号，如果 DSL 版本号差异较大，有可能会出现兼容性问题。创建你的第一个应用让我们以创建一个 “翻译小能手” 为例，简单了解下应用构建的基本流程。点击 “创建空白应用”，应用类型选择 “聊天助手”…

Dify 快速上手指南
type: item
date: 2025-09-18T00:26:00+00:00
description: 随着 AI 技术的快速发展，构建大语言模型应用已经成为了许多开发者和企业的重要需求。而 Dify 作为一个开源的 LLM 应用开发平台，凭借其直观的界面和强大的功能，正在成为这个领域的佼佼者。最近，Dify 发布了 v2.0.0 beta 版本，这个版本带来了许多重要的改进和新特性，正好趁着这个契机，我们来深入了解下这个平台。Dify 介绍Dify 是一个开源的 LLM 应用开发平台，其核心理念是让 AI 应用开发变得更加简单和高效。它不仅提供了可视化的工作流编排，还集成了 RAG 管道、智能体能力、模型管理和可观测性等功能，让开发者能够快速从原型迁移到生产环境。Dify 一词源自 Define + Modify，指的是定义并持续改进你的 AI 应用，它也可以当做 Do it for you 的缩写。它的核心功能包括：全面的模型支持：无缝集成包括 OpenAI 与 Anthropic 等数十个商业模型，支持 Hugging Face、OpenRouter 等 MaaS 供应商接口以及任意 OpenAI 兼容的接口，并提供了本地模型推理 Runtime 的支持；灵活的工作流：在可视化画布上构建和测试强大的 AI 工作流，分为 Chatflow 和 Workflow 两种类型；直观的提示词编排：用于制作提示词的直观界面，比较模型性能，并为基于聊天的应用添加文本转语音等附加功能；高质量的 RAG 管道：广泛的 RAG 功能，涵盖从文档摄取到检索的所有内容，支持从 PDF、PPT 和其他常见文档格式中提取文本；稳健的智能体框架：可以基于 LLM 的 Function Calling 或 ReAct 定义智能体，并为智能体添加自定义工具；丰富的工具系统：Dify 提供了 50 多个内置工具，如 Google Search、WolframAlpha 等；并支持轻松导入自定义的 API 工具或 MCP 工具；强大的插件生态：支持模型、工具、Agent 策略、扩展等插件类型，开发者可以根据需要方便的扩展 Dify 的功能；LLMOps：随时间监控和分析应用日志和性能，你可以基于生产数据和注释持续改进提示词、数据集和模型；后端即服务：Dify 的所有功能都提供相应的 API，因此你可以轻松地将 Dify 集成到你自己的业务逻辑中；本地部署准备工作Dify 提供了多种部署方式，最简单的方式是使用 Docker Compose。在开始之前，请确保你的机器满足以下最低系统要求：CPU >= 2 CoreRAM >= 4 GiB首先，我们需要克隆 Dify 的源代码：$ LATEST_TAG=$(curl -s https://api.github.com/repos/langgenius/dify/releases/latest | jq -r .tag_name) $ git clone --branch "$LATEST_TAG" https://github.com/langgenius/dify.git上面的命令会自动获取最新的稳定版本并克隆到本地，我在写这篇文章时最新版本是 v1.8.1。然后进入 docker 目录：$ cd dify/docker这个目录包含了 Dify 部署所需的所有配置文件，其中 docker-compose.yml 文件定义了 Dify 的完整架构，包括以下核心组件：api - Dify API 服务worker - Celery 后台任务处理器worker_beat - Celery 定时任务调度器web - 前端 Web 应用db - PostgreSQL 主数据库redis - Redis 缓存和消息队列sandbox - Dify 代码执行沙盒plugin_daemon - 插件守护进程ssrf_proxy - SSRF 代理 (Squid)nginx - 反向代理和负载均衡器weaviate - Weaviate 向量数据库这个文件还内置了大量的其他向量数据库组件配置，可以通过不同的 Profile 来切换：qdrant - Qdrant 向量数据库pgvector - pgvector 扩展的 PostgreSQLpgvecto-rs - pgvecto-rs 向量数据库chroma - Chroma 向量数据库milvus - 包括 etcd、minio、milvus 三个组件etcd - Milvus 的 etcd 配置存储minio - Milvus 的 MinIO 对象存储milvus-standalone - Milvus 向量数据库opensearch - 包括 opensearch 和 dashboards 两个组件opensearch - OpenSearch 向量数据库opensear…

学习 Chat2Graph 的知识库服务
type: item
date: 2025-09-17T00:05:00+00:00
description: 在前面的系列文章中，我们已经深入学习了 Chat2Graph 的多个核心模块：从智能体的协作机制，到任务规划与执行，再到工作流引擎，以及推理机和工具系统的实现。今天，我们将继续学习 Chat2Graph 的另一个关键组件——知识库服务，探索它如何为智能体系统提供强大的知识管理和检索能力。知识库为智能体提供持久化的知识存储和检索服务，使得智能体能够基于领域知识回答专业问题，而不仅仅依赖于大模型的训练数据。在 Chat2Graph 中，知识库的设计兼顾了向量检索和图检索两种方式，形成了一套完整的知识管理体系。知识库基本使用Chat2Graph 的知识库在使用上分为 全局知识库 与 会话知识库 两个层次：全局知识库：存储整个智能体系统的基础知识，任何会话都可以获取全局知识库中的知识；会话知识库：存储与当前会话相关的私有知识，与会话一一对应，只在当前会话中生效，不会被其他会话的知识干扰；可以在 “知识库管理” 页面对这两种知识库进行管理：另外，Chat2Graph 支持两种不同的知识存储和检索方式：向量知识库：基于 Chroma 设计的向量知识库，检索时根据向量相似度匹配与问题最接近的文档片段；图知识库：基于 TuGraph 设计的图知识库，检索时在知识图谱中匹配与问题相关的子图与社区摘要；尽管 Chat2Graph 支持 TuGraph 和 Neo4j 两种图数据库的管理，但是知识库这里暂时只支持 TuGraph。用户可以通过 .env 环境变量配置来选择使用哪种知识库类型。配置向量知识库：KNOWLEDGE_STORE_TYPE=VECTOR向量知识库默认存储在本地 Chroma 文件中，位于 ~/.chat2graph/knowledge_bases 目录。配置图知识库：KNOWLEDGE_STORE_TYPE=GRAPH # TuGraph 配置 GRAPH_KNOWLEDGE_STORE_HOST=127.0.0.1 GRAPH_KNOWLEDGE_STORE_PORT=17687 GRAPH_KNOWLEDGE_STORE_USERNAME=admin GRAPH_KNOWLEDGE_STORE_PASSWORD=password配置好知识库类型后，点击 “全局知识库” 或 “会话知识库”，上传文件：支持 PDF、TXT、XLSX、DOC、DOCX、MD 等文件格式。然后点击 “下一步” 进入数据处理的配置，这块目前很粗糙，就一个分块大小参数：然后点击 “确定” 完成知识的添加。知识库接口Chat2Graph 的知识库服务提供了一套完整的 RESTful API：# 获取所有知识库 GET /knowledgebases/ # 获取指定知识库 GET /knowledgebases/{kb_id} # 更新知识库信息 PUT /knowledgebases/{kb_id} # 清空/删除知识库 DELETE /knowledgebases/{kb_id}?drop=true # 向知识库添加文档 POST /knowledgebases/{kb_id}/files/{file_id} # 从知识库删除文档 DELETE /knowledgebases/{kb_id}/files/{file_id}上一节点击 “确实” 后实际上调用的就是 “向知识库添加文档” 这个接口：@knowledgebases_bp.route("/<string:knowledge_base_id>/files/<string:file_id>", methods=["POST"]) def load_knowledge_with_file_id(knowledge_base_id: str, file_id: str): manager = KnowledgeBaseManager() data: Dict[str, Any] = cast(Dict[str, Any], request.json) # 加载文档 result, message = manager.load_knowledge( kb_id=knowledge_base_id, file_id=file_id, knowledge_config=KnowledgeBaseViewTransformer.deserialize_knowledge_config( json.loads(data.get("config", "{}")) ), ) return make_response(data=result, message=message)KnowledgeBaseManager 通过核心服务 KnowledgeBaseService 实现知识的管理。它采用单例模式，负责：知识…