如何为 Dify 的 ops tracing 开发并注册自定义观测后端 provider
【免费下载链接】difyBuild Agentic workflows, RAG pipelines, with rich AI model and tool support on one collaborative workspace. Deploy on cloud, VPC, or self-hosted, so teams move from prototype to production without rebuilding the stack.项目地址: https://gitcode.com/GitHub_Trending/di/dify
如果你的 Dify 应用产生的 ops tracing 数据(工作流、消息、工具调用、内容审核等)需要发送到一个 Dify 官方没有内置的观测后端,就需要自己开发一个 trace provider 包,并在 API 核心中完成注册。本文基于仓库中 trace providers 说明 和现有参考实现(trace-langfuse、trace-langsmith、trace-opik、trace-mlflow等),给出从建包到注册的完整操作路径。
先明确一个架构前提:与 VDB provider 不同,trace provider不会通过 entry points 自动发现。API 核心会在你注册 provider id 与映射之后,从 ops_trace_manager.py 显式导入你的包。因此开发分四步:建包、实现 config 与 trace 实例、在 API 核心注册、接入apiuv workspace。
三层结构的分工如下:
| 层 | 位置 | 职责 |
|---|---|---|
| 契约 | api/core/ops/base_trace_instance.py、api/core/ops/entities/trace_entity.py、api/core/ops/entities/config_entity.py | BaseTraceInstance、BaseTracingConfig以及带类型的*TraceInfo载荷 |
| 注册表 | api/core/ops/ops_trace_manager.py | TracingProviderEnum、OpsTraceProviderConfigMap—— 将 provider 字符串映射到 config 类、加密键和 trace 类 |
| 你的包 | api/providers/trace/trace-<name>/ | Pydantic config +BaseTraceInstance子类 |
运行时,OpsTraceManager会解密已存储的凭据、构建你的 config 模型、缓存 trace 实例,并用具体的BaseTraceInfo子类型调用trace(trace_info)。
创建 provider 包
每个 provider 是api/providers/trace/下普通的 uv workspace 成员。按 README 给出的布局,以trace-mybackend为例(下文代码中的mybackend、MyBackend均为示例名,请整体替换为你自己的 provider 名):
api/providers/trace/trace-mybackend/pyproject.toml—— 项目名dify-trace-mybackend,依赖你的后端 SDK;api/providers/trace/trace-mybackend/src/dify_trace_mybackend/—— 包含config.py、mybackend_trace.py、可选的entities/目录,以及一个空的py.typed文件(PEP 561),让 API 的类型检查器把该包当作有类型标注处理;按 README 要求,在pyproject.toml的[tool.setuptools.package-data]中为该导入名列出py.typed。
pyproject.toml的最小形式可参考现有包 trace-mlflow/pyproject.toml:
[project] name = "dify-trace-mybackend" version = "0.0.1" dependencies = [ "你的后端 SDK>=版本", ] description = "Dify ops tracing provider (MyBackend)." [tool.setuptools.packages.find] where = ["src"]写 config 前建议先读一个参考实现,例如 MLflow config 和 MLflow trace 类。
实现配置模型:BaseTracingConfig 子类
在包内新建config.py,从core.ops.entities.config_entity继承BaseTracingConfig,用 Pydantic validator 校验字段,并在适当处复用core.ops.utils里的辅助函数(README 明确列出的有validate_url、validate_url_with_path、validate_project_name)。参考实现中的字段校验写法:
@field_validator("tracking_uri") @classmethod def tracking_uri_validator(cls, v, info: ValidationInfo): if isinstance(v, str) and v.startswith("databricks"): raise ValueError(...) return validate_url_with_path(v, "http://localhost:5000")(以上片段摘自 config.py 中MLflowConfig的真实代码。)
config 的字段按 manager 的使用方式分两类,你必须在后文注册时如实地列出它们:
secret_keys—— 存储时会被加密的字段名(API key、token、密码);other_keys—— 非密钥的连接设置(host、project 名、endpoint)。
manager 的encrypt_tracing_config/decrypt_tracing_config会依据这两个列表做加解密与合并;若列表与实际字段不符,加密/解密逻辑就会出错。
实现 trace 实例:BaseTraceInstance 子类
在包内新建mybackend_trace.py,继承 BaseTraceInstance 并实现:
def trace(self, trace_info: BaseTraceInfo) -> None: ...在方法内用isinstance对具体类型分发(README 建议参考trace_langfuse或trace_langsmith的完整写法)。载荷类型定义在api/core/ops/entities/trace_entity.py,包括:
WorkflowTraceInfo、WorkflowNodeTraceInfo、DraftNodeExecutionTraceMessageTraceInfo、ToolTraceInfo、ModerationTraceInfo、SuggestedQuestionTraceInfoDatasetRetrievalTraceInfo、GenerateNameTraceInfo、PromptGenerationTraceInfo
你可以忽略后端不支持的类别,现有 provider 常常对未处理的类型做 no-op 处理,不必强行覆盖全部类型。
如果需要租户范围的账户上下文,可调用基类提供的get_service_account_with_tenant(app_id)(它会返回带有已设置 tenant 的服务账户Account,见 base_trace_instance.py)。
另外,OpsTraceManager还保留了三个会调用你实例方法的入口(见 ops_trace_manager.py):
check_trace_config_is_effective:用你的 config 类构建实例后调用trace_instance(config).api_check();get_trace_config_project_key:调用trace_instance(config).get_project_key();get_trace_config_project_url:调用trace_instance(config).get_project_url()。
如果你的后端能提供“配置是否可用”的自检或项目地址,就实现这三个方法,让控制台侧的配置校验链路走通。
在 API 核心中注册 provider
这是必须修改上游代码的部分,Dify 需要两处改动才知道你的 provider 存在:
TracingProviderEnum(config_entity.py)—— 新增一个成员,其值是存储在 app tracing 配置中的稳定字符串(README 示例为"mybackend"):
class TracingProviderEnum(StrEnum): ARIZE = "arize" ... MYBACKEND = "mybackend"OpsTraceProviderConfigMap.__getitem__(ops_trace_manager.py)—— 为该枚举成员新增一个match分支,返回:config_class:你的 Pydantic config 类型secret_keys/other_keys:上面列出的字段名列表trace_instance:你的BaseTraceInstance子类
在你的分支内部懒加载导入包,这样未安装可选依赖时会抛出清晰的
ImportError(该方法会把ImportError包装成Provider {key} is not installed.):
case TracingProviderEnum.MYBACKEND: from dify_trace_mybackend.config import MyBackendConfig from dify_trace_mybackend.mybackend_trace import MyBackendDataTrace return { "config_class": MyBackendConfig, "secret_keys": ["api_key"], "other_keys": ["host"], "trace_instance": MyBackendDataTrace, }secret_keys/other_keys必须与config.py中的字段一一对应(示例中的"api_key"、"host"仅为占位,按你的实际字段替换)。
如果漏掉这个match分支,provider 字符串将无法解析,该应用的 tracing 会被直接禁用(get_ops_trace_instance遇到KeyError时返回None)。
接入 api workspace 并同步依赖
在 api/pyproject.toml 中做两处改动(现有 provider 的写法见该文件[tool.uv.sources]与[dependency-groups]段):
[tool.uv.sources]—— 添加dify-trace-mybackend = { workspace = true };[dependency-groups]—— 添加trace-mybackend = ["dify-trace-mybackend"];如果该 provider 要随默认捆绑一起发行,再把dify-trace-mybackend加进trace-all组。
改完元数据后,在api/目录下执行:
uv sync验证与限制
可用的判定方式都来自文档与注册链路的实际行为:
- 依赖可导入:
uv sync成功后,match分支内的懒加载导入不再抛ImportError。若包未安装,manager 会报Provider {key} is not installed.。 - provider 字符串可解析:在
provider_config_map[tracing_provider]处(即get_ops_trace_instance内部)能命中你的分支;README 明确说明缺失match分支时,provider 字符串无法解析、tracing 对该应用失效。 - 配置自检:如果你的实例实现了
api_check(),控制台保存 tracing 配置时的有效性检查(check_trace_config_is_effective)会真正调用它并依据其返回判断配置是否生效。
需要注意的边界:trace plugin 不走 entry points 发现机制,注册完全依赖上述显式导入;secret_keys中的值在落库前由encrypt_token(tenant_id, value)加密,"*"前缀的掩码值会保留原配置项,因此字段名列表写错会直接影响加密/解密正确性。后续扩展时,可对照 trace-mlflow 的 trace 类 看一个 provider 如何把WorkflowTraceInfo、MessageTraceInfo等类型映射到具体后端的 span 结构。
【免费下载链接】difyBuild Agentic workflows, RAG pipelines, with rich AI model and tool support on one collaborative workspace. Deploy on cloud, VPC, or self-hosted, so teams move from prototype to production without rebuilding the stack.项目地址: https://gitcode.com/GitHub_Trending/di/dify
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考