模型提供商、工具生态与插件架构
前置知识
- ›第 1-3 篇:架构、请求流程与工作流引擎
- ›了解 LLM API 及基于 token 的计费方式
- ›熟悉 LLM 中的函数调用 / 工具使用机制
模型提供商、工具生态与插件架构
Dify 的核心价值在于抽象能力——通过统一接口连接任意 LLM 提供商、工具和数据源,让工作流构建者和 API 消费者无需关心底层细节。在本系列的最后一篇文章中,我们将深入探讨三个相互关联的系统:对 100 余家 LLM 提供商进行标准化的模型提供商抽象层、为 Agent 和工作流提供外部能力的工具分类体系,以及在隔离进程中安全运行不受信任扩展的插件守护进程架构。
ProviderManager 与凭据解析
Dify 中的每次模型调用都始于凭据解析。ProviderManager 负责根据租户、提供商类型和配置层级,解析当前模型调用应使用哪套凭据。
flowchart TD
Request[Model invocation request] --> PM[ProviderManager]
PM --> TenantLookup[Lookup tenant providers]
TenantLookup --> CredCheck{Credential source?}
CredCheck -->|Custom| Custom[Custom provider credentials<br/>user-supplied API keys]
CredCheck -->|System| System[System-configured credentials<br/>admin-provisioned]
CredCheck -->|Plugin| Plugin[Plugin daemon credentials<br/>from installed plugins]
Custom --> PC[ProviderConfiguration]
System --> PC
Plugin --> PC
PC --> PMB[ProviderModelBundle<br/>credentials + model type instance]
PMB --> MI[ModelInstance]
ProviderManager 从多张数据库表中读取数据:Provider(租户与提供商的绑定关系)、ProviderCredential(加密凭据存储)、ProviderModel(单模型配置)以及 LoadBalancingModelConfig(多端点负载分配)。
凭据解析遵循以下优先级链:
- 自定义模型凭据 — 用户为特定模型设置的 API key
- 自定义提供商凭据 — 用户在提供商层级设置的 API key
- 系统凭据 — 管理员配置的共享凭据
- 托管配额 — Dify Cloud 内置的模型访问权限,分为试用和付费层级
凭据通过 ProviderCredentialsCache 进行缓存,采用 TTL 过期策略,避免每次模型调用都直接访问数据库。
ModelInstance:统一的 LLM 抽象
ModelInstance 类为任意 LLM 提供商提供一致的调用接口。无论是 OpenAI、Anthropic、本地部署的 Ollama,还是通过插件提供的自定义模型,调用方看到的都是同一套 API。
classDiagram
class ModelInstance {
+provider_model_bundle: ProviderModelBundle
+model_name: str
+credentials: dict
+load_balancing_manager
+invoke_llm()
+invoke_text_embedding()
+invoke_rerank()
+invoke_tts()
+invoke_speech2text()
+invoke_moderation()
}
class ProviderModelBundle {
+configuration: ProviderConfiguration
+model_type_instance: ModelTypeInstance
}
class ProviderConfiguration {
+provider: ProviderEntity
+get_current_credentials()
}
class LoadBalancingManager {
+invoke_with_fallback()
}
ModelInstance --> ProviderModelBundle
ProviderModelBundle --> ProviderConfiguration
ModelInstance --> LoadBalancingManager
ModelInstance 的核心功能包括:
- 负载均衡 — 当存在
LoadBalancingModelConfig配置时,管理器会将请求分发到同一模型的多个 API 端点,有效应对生产环境中单个 API key 触达速率限制的问题。 - 凭据管理 — 从
ProviderModelBundle获取凭据并在实例上缓存。 - 模型 Schema 解析 —
get_model_schema()返回描述模型能力的AIModelEntity,包含上下文窗口大小、支持的功能和定价信息。 - 统一调用接口 —
invoke_llm()、invoke_text_embedding()、invoke_rerank()等方法提供一致的调用规范。
HostingConfiguration 负责管理 Dify Cloud 的托管模型提供商,支持带用量限制的试用配额和付费层级。
提示: 当模型调用抛出
ProviderTokenNotInitError时,问题几乎都出在凭据解析环节——该租户没有为对应的提供商和模型组合配置有效凭据。可以直接检查Provider和ProviderCredential表。
工具类型分类体系
Dify 支持五类工具,每类工具具有不同的运行时特性:
classDiagram
class Tool {
<<abstract>>
+entity: ToolEntity
+runtime: ToolRuntime
+invoke()
+tool_provider_type()
}
class BuiltinTool {
Built-in tools shipped with Dify
}
class PluginTool {
Tools from installed plugins
}
class ApiTool {
OpenAPI/Swagger defined tools
}
class MCPTool {
Model Context Protocol tools
}
class WorkflowTool {
Workflows exposed as tools
}
Tool <|-- BuiltinTool
Tool <|-- PluginTool
Tool <|-- ApiTool
Tool <|-- MCPTool
Tool <|-- WorkflowTool
基类 Tool 定义了以下核心契约:
invoke()— 公开入口点,负责合并运行时参数、转换参数类型,并委托给_invoke()执行_invoke()— 抽象方法,由各工具子类具体实现tool_provider_type()— 标识工具所属类别fork_tool_runtime()— 基于不同运行时上下文创建工具副本
ToolManager 负责跨五种类型解析工具提供商,其发现来源分别为:
- 内置工具 — 来自
core/tools/builtin_tool/providers/目录 - 插件工具 — 通过
PluginToolManager从插件守护进程获取 - API 工具 — 来自数据库中的
ApiToolProvider记录 - MCP 工具 — 来自已配置的 MCP 服务器连接
- 工作流工具 — 来自数据库中的
WorkflowToolProvider记录
每种工具类型都有对应的 provider controller(如 BuiltinToolProviderController、ApiToolProviderController、MCPToolProviderController),分别负责凭据管理、参数 Schema 解析和工具实例化。
ToolEngine:工具的运行时执行
ToolEngine 提供工具执行的运行时环境,统一处理参数解析、调用执行、文件管理和错误处理等复杂逻辑。
sequenceDiagram
participant Agent/Node
participant ToolEngine
participant Tool
participant Callback
Agent/Node->>ToolEngine: agent_invoke(tool, parameters)
ToolEngine->>ToolEngine: Parse parameters (str → dict)
ToolEngine->>Callback: on_tool_start()
ToolEngine->>Tool: invoke(user_id, parameters)
Tool-->>ToolEngine: Generator[ToolInvokeMessage]
ToolEngine->>ToolEngine: Process messages<br/>transform files, extract text
ToolEngine->>Callback: on_tool_end()
ToolEngine-->>Agent/Node: (text, file_ids, meta)
tool_engine.py#L47-L79 中的 agent_invoke() 静态方法处理了一个较为棘手的边界情况:LLM 有时会以原始字符串而非 JSON 对象的形式传入工具参数。如果该工具只有一个 LLM 类型的参数,则直接使用该字符串;否则尝试 JSON 解析,并在失败时进行优雅降级。
工具调用的返回结果是 ToolInvokeMessage 生成器,可以 yield 文本、图片、文件、链接或 JSON。ToolFileMessageTransformer 负责将二进制文件输出转换为带签名 URL 的上传文件。
插件守护进程与反向调用
插件守护进程是 Dify 安全运行不受信任代码的解决方案。它是一个独立的 Go 服务,在隔离进程中执行插件,并通过双向通道与主 Dify API 进行通信。
flowchart TD
subgraph Dify API Process
API[Flask API Server]
InnerAPI[Inner API Blueprint<br/>/inner/api]
PluginImpl[core/plugin/impl/]
end
subgraph Plugin Daemon Process
Daemon[dify-plugin-daemon<br/>Go service]
PluginRuntime[Plugin Runtime<br/>isolated process per plugin]
end
API -->|Forward call| PluginImpl
PluginImpl -->|HTTP| Daemon
Daemon --> PluginRuntime
PluginRuntime -->|Backwards invocation| InnerAPI
InnerAPI --> API
style PluginRuntime fill:#f9f,stroke:#333
该架构包含两个通信方向:
正向调用 — 当 Dify 需要使用插件能力(模型推理、工具执行、数据源访问)时,core/plugin/impl/ 中的实现类通过 HTTP 调用插件守护进程,由守护进程将请求路由到对应的插件运行时。
反向调用 — 当插件需要回调 Dify(调用模型、访问存储、加密数据或执行节点)时,它调用守护进程,守护进程再将请求转发至 Dify 的 Inner API(/inner/api)。core/plugin/backwards_invocation/ 中的反向调用处理器涵盖六个类别:
| 模块 | 用途 |
|---|---|
model.py |
插件调用 LLM 模型 |
tool.py |
插件调用其他工具 |
node.py |
插件执行工作流节点 |
app.py |
插件与应用状态交互 |
encrypt.py |
插件加密/解密凭据 |
base.py |
共享调用基础设施 |
PluginModelAssembly 根据 tenant_id 懒加载构建完整的模型调用栈(runtime → factory → provider manager → model manager),为插件提供的模型访问提供清晰的入口点。
docker-compose.yaml#L998-L1068 中的插件守护进程 Docker Compose 配置清晰展示了安全边界:它通过 DIFY_INNER_API_URL 和 DIFY_INNER_API_KEY 与 API 通信,通过签名验证(FORCE_VERIFYING_SIGNATURE)运行插件,并支持配置超时时间和缓冲区大小。
提示: 插件开发通过
PLUGIN_REMOTE_INSTALL_HOST和PLUGIN_REMOTE_INSTALL_PORT配置项进行,这两个配置会暴露一个调试端点。开发期间,插件连接到该端点即可实现热重载测试,无需重新构建守护进程。
MCP 集成与多租户
Dify 在 core/mcp/ 下实现了 MCP(Model Context Protocol)集成,用于连接支持 MCP 协议的外部工具服务器。core/tools/mcp_tool/ 中的 MCPToolProviderController 和 MCPTool 类将 MCP 服务器连接封装为 Dify 工具,使其可在工作流和 Agent 配置中直接使用。
多租户设计贯穿整个模型和工具系统。每项凭据、配置和配额都以租户为作用域进行隔离。账户模型中的 TenantAccountRole 枚举定义了 RBAC 权限:
- Owner — 对工作区设置拥有完全控制权
- Admin — 管理模型、工具和数据集
- Editor — 创建和修改应用及工作流
- Normal — 使用应用和工作流
- DatasetOperator — 仅管理数据集
模型凭据采用租户级加密,工具提供商按租户解析,速率限制按租户和应用双维度应用。这确保了 Dify 多工作区架构下的完全隔离。
系列总结
在这五篇文章中,我们完整走过了 Dify 的全貌:从 Docker Compose 拓扑结构,到 Flask 启动序列、请求执行管道、工作流图引擎、RAG 管道,最终来到支撑整个系统运转的模型与工具抽象层。这是一个体量庞大的代码库,但其中的设计模式高度一致:
- 工厂模式 用于扩展性(节点工厂、向量数据库工厂、索引处理器工厂)
- 分层模式 用于横切关注点(配额、可观测性、持久化)
- 队列模式 用于解耦(runner 与 pipeline 之间基于 Redis 的 pub/sub,以及 Celery 异步任务)
- 适配器模式 用于集成(32 种向量数据库、100 余家模型提供商、5 种工具类型)
理解这些模式,而非死记个别文件的细节,才是在 Dify 这个拥有 6000 余个文件的代码库中自信导航的真正关键。