工作流调试、版本管理与性能分析
第12章:工作流调试、版本管理与性能分析
构建工作流只是开始;系统性的调试方法、严格的版本管理和持续的性能分析,才是让工作流在生产环境中长期可靠运行的保障。
本章导读
一个工作流从"能跑"到"稳定运行在生产环境"之间,有一段很长的路要走。常见的问题包括:
- 工作流偶发性失败,但日志不够详细,无从定位原因
- 修改了工作流的某个节点,却导致其他看似无关的功能出现问题
- 随着业务增长,工作流变慢了,但不知道瓶颈在哪里
- 想回滚到上一个稳定版本,却发现版本历史不清晰
本章将系统地讲解:
- Dify 工作流的调试工具和技巧:从单步执行到条件断点
- 版本管理最佳实践:发布策略、回滚机制、多环境管理
- 性能分析:找到瓶颈节点,优化 LLM 调用、减少不必要的开销
- 监控体系:建立生产环境的可观测性基础设施
Level 1:基础认知(1-3 年经验)
1.1 Dify 工作流的内置调试工具
调试模式
在工作流编辑器右上角点击「运行」进入调试模式,此时:
- 每个节点执行后,界面上会显示该节点的输入值和输出值
- 执行失败的节点会高亮显示,并展示详细错误信息
- 可以看到整个执行过程的时间线
节点输入/输出检查
点击任意已执行的节点,在右侧面板可以查看:
- Input:该节点接收到的所有变量值(包括从上游传来的变量)
- Output:该节点执行后输出的所有变量值
- Elapsed time:该节点的执行耗时(毫秒)
- Error(如果有):详细的错误类型和堆栈信息
运行历史
工作流保存了最近 N 次运行的详细记录:
- 每次运行的输入参数
- 每个节点的执行状态和耗时
- 最终输出结果
- Token 消耗统计
路径:工作流 → 运行历史(左侧面板)
1.2 系统性调试流程
当工作流出现问题时,建议按以下流程排查:
第一步:复现问题
用固定的测试输入重现问题,而不是依赖随机的用户输入。创建测试用例:
{
"test_case_01_normal": {
"description": "正常简历,应该输出 recommend",
"inputs": {
"resume_text": "张三,5年Python开发经验,熟悉机器学习...",
"job_title": "AI 工程师"
},
"expected_output": {
"verdict": "recommend",
"score_min": 70
}
},
"test_case_02_edge": {
"description": "空简历,应该输出验证错误",
"inputs": {
"resume_text": "",
"job_title": "AI 工程师"
},
"expected_output": {
"error_type": "validation_error"
}
}
}
第二步:隔离失败节点
在调试模式中运行,观察哪个节点标红(失败)。如果多个节点都失败,找到第一个失败的节点(因为后续节点的失败可能是上游失败导致的连锁反应)。
第三步:检查节点输入
点击失败节点,查看它接收到的输入值:
- 变量是否为 null 或 undefined?(上游节点没有输出该变量)
- 变量类型是否正确?(字符串 vs 数字 vs 对象)
- 变量内容是否符合预期?(LLM 输出的格式是否正确)
第四步:修复并验证
修复问题后,用所有测试用例验证,确保修复没有引入新问题。
1.3 日志与标注系统
Dify 的日志系统(「日志与标注」)为每次应用调用(包括工作流)保存完整记录:
查看运行日志:
- 应用 → 日志与标注 → 选择时间范围
- 每条记录显示:时间、用户、输入、输出、状态、耗时、Token 数
标注功能: 对质量不符合预期的运行结果进行标注:
- 点击某条日志记录
- 点击「标注」按钮
- 选择类型:正面/负面,并写下备注
标注数据可以用于:
- 追踪质量问题的来源(是哪个测试场景触发的?)
- 积累评测数据集(标注过的对话可以导出为评测集)
1.4 Dify 的版本管理
Dify 工作流支持版本管理,每次发布(Publish)就创建一个版本快照:
版本管理操作:
| 操作 | 说明 |
|---|---|
| 保存(Save) | 保存当前草稿,不影响线上版本 |
| 发布(Publish) | 将当前草稿发布为新版本,成为线上版本 |
| 查看历史版本 | 工作流设置 → 版本历史 |
| 回滚 | 选择历史版本 → 恢复为当前版本 |
最佳实践:
- 每次发布前写清楚变更说明(Dify 支持在发布时填写描述)
- 发布新版本前先在测试环境验证
- 重大变更创建新的工作流应用,而不是修改现有工作流(保留旧版本作为对照)
Level 2:机制深解(3-5 年经验)
2.1 条件断点与分步调试
Dify 的调试模式支持在特定节点暂停,检查当前状态:
设置断点节点: 在工作流编辑器中,右键任意节点 → 「设为断点」。工作流执行到该节点时会暂停,你可以:
- 查看当前所有变量的值
- 修改变量值(测试不同场景)
- 选择继续执行(Step Over)或停止
手动测试复杂分支:
对于有多个 IF/ELSE 分支的工作流,用不同的测试数据分别触发每个分支:
# 测试脚本:覆盖所有分支路径
test_cases = {
"branch_high_score": {
"inputs": {"score": 85}, # 触发 score >= 80 分支
"expected_branch": "tier_1"
},
"branch_medium_score": {
"inputs": {"score": 65}, # 触发 60 <= score < 80 分支
"expected_branch": "tier_2"
},
"branch_low_score": {
"inputs": {"score": 30}, # 触发 score < 60 分支
"expected_branch": "tier_3"
}
}
for name, case in test_cases.items():
result = run_workflow(case["inputs"])
assert result["tier"] == case["expected_branch"], \
f"分支测试 {name} 失败: 期望 {case['expected_branch']}, 实际 {result.get('tier')}"
print(f"✓ {name}: 通过")
2.2 性能分析:找到瓶颈节点
分析每次运行的节点耗时:
在工作流运行历史中,点击某次运行记录,查看每个节点的耗时分解:
工作流总耗时:4.85秒
节点耗时分解:
├── start_node: <1ms
├── validation_code: 12ms
├── knowledge_retrieval: 187ms ← 占 3.9%
├── llm_analysis: 3,240ms ← 占 66.8%(主要瓶颈)
├── json_parser_code: 8ms
├── score_calculator_code: 5ms
├── email_generator_llm: 1,380ms ← 占 28.5%(次要瓶颈)
└── end_node: <1ms
LLM 节点通常是最大瓶颈,优化方向:
- 减少不必要的 LLM 调用:检查哪些 LLM 节点可以合并(减少调用次数)
- 选择更快的模型:对于简单任务,用 GPT-4o mini 代替 GPT-4o(速度 3x,成本 10x 低)
- 减少 Max Tokens:设置合理的最大输出长度,避免模型生成过多无用内容
- 缓存相似查询:对相似的查询使用语义缓存(需要外部缓存层)
2.3 多环境管理:开发、测试、生产
企业部署 Dify 时,建议至少维护两个环境:
环境配置矩阵:
| 配置项 | 开发环境 | 测试环境 | 生产环境 |
|---|---|---|---|
| Dify 版本 | 最新 | 稳定版 | 上一个稳定版 |
| LLM 模型 | GPT-4o mini | GPT-4o mini | GPT-4o |
| 知识库数据 | 测试数据 | 全量数据 | 全量数据 |
| API Key | 开发专用 | 测试专用 | 生产专用(严格保管) |
| 日志级别 | DEBUG | INFO | WARNING |
| 速率限制 | 宽松 | 中等 | 严格 |
工作流跨环境迁移:
Dify 支持导出/导入工作流定义(DSL 格式):
# 导出工作流(获取 DSL 文件)
curl -X GET "https://dev-dify.company.com/api/apps/{app_id}/export" \
-H "Authorization: Bearer DEV_API_KEY" \
> workflow_v2.1.dsl
# 导入到生产环境
curl -X POST "https://prod-dify.company.com/api/apps/import" \
-H "Authorization: Bearer PROD_API_KEY" \
-H "Content-Type: application/json" \
-d @workflow_v2.1.dsl
注意:导入时需要检查并更新环境特定的配置(API Keys、数据库连接、知识库 ID 可能在不同环境中不同)。
2.4 工作流的自动化测试
为工作流编写自动化测试,确保每次修改都能快速验证:
# workflow_tests.py
import pytest
import requests
import os
DIFY_BASE_URL = os.getenv("DIFY_BASE_URL", "http://localhost/v1")
WORKFLOW_API_KEY = os.getenv("WORKFLOW_API_KEY")
def run_workflow(inputs: dict) -> dict:
"""运行工作流并返回输出"""
response = requests.post(
f"{DIFY_BASE_URL}/workflows/run",
headers={"Authorization": f"Bearer {WORKFLOW_API_KEY}"},
json={
"inputs": inputs,
"response_mode": "blocking",
"user": "test-runner"
},
timeout=60
)
response.raise_for_status()
data = response.json()
if data["data"]["status"] != "succeeded":
raise AssertionError(
f"工作流失败: {data['data'].get('error', '未知错误')}"
)
return data["data"]["outputs"]
class TestResumeAnalysisWorkflow:
def test_normal_resume_high_score(self):
"""正常简历应返回推荐结果"""
outputs = run_workflow({
"resume_text": "Jane Doe,8年机器学习工程师经验,发表10篇论文,熟悉PyTorch、TensorFlow...",
"job_title": "AI 研究工程师"
})
assert outputs["verdict"] == "recommend"
assert outputs["score"] >= 75
assert len(outputs["highlights"]) > 0
def test_empty_resume_validation(self):
"""空简历应触发验证错误"""
outputs = run_workflow({
"resume_text": "",
"job_title": "软件工程师"
})
assert outputs["success"] == False
assert "简历内容太短" in outputs.get("error_message", "")
def test_irrelevant_background(self):
"""不相关背景应返回拒绝结果"""
outputs = run_workflow({
"resume_text": "李四,15年厨师经验,擅长粤菜和川菜...",
"job_title": "前端工程师"
})
assert outputs["verdict"] == "reject"
assert outputs["score"] < 40
@pytest.mark.parametrize("score,expected_tier", [
(85, "tier_1"),
(65, "tier_2"),
(35, "tier_3")
])
def test_score_tiers(self, score, expected_tier):
"""测试分级逻辑"""
# 通过构造特定 score 输入来测试分级
# (实际项目中需要 mock 某些节点)
...
if __name__ == "__main__":
pytest.main([__file__, "-v"])
2.5 Token 消耗分析与成本控制
Token 消耗统计:
Dify 在每次工作流运行记录中提供 Token 消耗详情:
- 每个 LLM 节点的 prompt tokens(输入)和 completion tokens(输出)
- 总 token 消耗
- 基于定价模型的估算费用
优化 Token 消耗的方法:
- 压缩提示词:删除冗余的解释性文字,保留关键指令
# 冗余版本(150 tokens)
你是一个专业的简历分析助手,你的工作是帮助招聘团队评估候选人的简历。
请仔细阅读以下简历内容,并根据岗位要求进行全面、客观的分析...
# 精简版本(50 tokens)
分析简历,评估候选人与岗位的匹配度。
输出 JSON:{"score": 0-100, "verdict": "recommend/reject", "reason": "理由"}
-
限制输出长度:设置
Max Tokens= 200-500(根据任务需要),避免模型过度生成 -
使用结构化输出(减少格式错误重试成本):
# 在代码节点中处理 JSON,而不是让 LLM 反复尝试生成正确格式
# 一次生成失败 + 重试 = 2x token 消耗
# 用代码解析容错版本 = 1x token 消耗
- 缓存频繁查询:
import hashlib
import json
def get_cache_key(inputs: dict) -> str:
"""为输入生成缓存键"""
return hashlib.sha256(
json.dumps(inputs, sort_keys=True).encode()
).hexdigest()[:16]
def cached_workflow_run(inputs: dict, cache_ttl: int = 3600) -> dict:
"""带缓存的工作流调用"""
cache_key = get_cache_key(inputs)
# 检查缓存
cached = redis_client.get(f"workflow_cache:{cache_key}")
if cached:
return json.loads(cached)
# 调用工作流
result = run_workflow(inputs)
# 缓存结果
redis_client.setex(
f"workflow_cache:{cache_key}",
cache_ttl,
json.dumps(result)
)
return result
Level 3:源码与原理(5 年以上)
3.1 工作流执行记录的存储结构
Dify 的工作流执行记录(WorkflowRun)存储在 PostgreSQL 中:
-- 工作流运行记录表(简化版)
CREATE TABLE workflow_runs (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
tenant_id VARCHAR(36) NOT NULL,
app_id VARCHAR(36) NOT NULL,
workflow_id VARCHAR(36) NOT NULL,
-- 执行信息
status VARCHAR(20) NOT NULL, -- 'running' | 'succeeded' | 'failed' | 'stopped'
inputs JSONB,
outputs JSONB,
error TEXT,
-- 性能指标
elapsed_time DECIMAL(10, 3), -- 单位:秒
total_tokens INTEGER,
total_steps INTEGER,
-- 时间戳
created_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP,
finished_at TIMESTAMP WITH TIME ZONE,
INDEX idx_app_id (app_id),
INDEX idx_status (status),
INDEX idx_created_at (created_at)
);
-- 节点执行记录表
CREATE TABLE workflow_node_executions (
id UUID PRIMARY KEY,
workflow_run_id UUID REFERENCES workflow_runs(id),
node_id VARCHAR(36) NOT NULL,
node_type VARCHAR(50) NOT NULL,
title VARCHAR(200),
-- 执行结果
status VARCHAR(20) NOT NULL,
inputs JSONB,
outputs JSONB,
process_data JSONB, -- 内部处理细节(调试用)
error TEXT,
-- 性能指标
elapsed_time DECIMAL(10, 3),
execution_metadata JSONB, -- {tokens: {prompt: N, completion: N}, ...}
created_at TIMESTAMP WITH TIME ZONE
);
查询慢执行节点(SQL 分析):
-- 找出过去7天中,平均执行时间最长的节点
SELECT
node_type,
title,
COUNT(*) as execution_count,
AVG(elapsed_time) as avg_elapsed_seconds,
PERCENTILE_CONT(0.95) WITHIN GROUP (ORDER BY elapsed_time) as p95_elapsed,
SUM(CASE WHEN status = 'failed' THEN 1 ELSE 0 END) as failure_count,
ROUND(100.0 * SUM(CASE WHEN status = 'failed' THEN 1 ELSE 0 END) / COUNT(*), 2) as failure_rate
FROM workflow_node_executions wne
JOIN workflow_runs wr ON wne.workflow_run_id = wr.id
WHERE wr.app_id = 'your-app-id'
AND wne.created_at > NOW() - INTERVAL '7 days'
GROUP BY node_type, title
ORDER BY avg_elapsed_seconds DESC
LIMIT 10;
3.2 工作流 DSL 格式解析
Dify 工作流以 DSL(Domain-Specific Language)格式存储,实质上是 YAML/JSON:
# 工作流 DSL 示例(简化版)
app:
name: "简历分析工作流"
version: "0.10.0"
workflow:
graph:
nodes:
- id: "start"
type: "start"
data:
variables:
- variable: "resume_text"
type: "paragraph"
required: true
- variable: "job_title"
type: "text"
required: true
- id: "llm_analysis"
type: "llm"
data:
model:
provider: "openai"
name: "gpt-4o-mini"
mode: "chat"
completion_params:
temperature: 0.3
max_tokens: 800
prompt_template:
- role: "system"
text: "你是一个专业的 HR 助手。"
- role: "user"
text: |
分析简历:{{resume_text}}
职位:{{job_title}}
输出 JSON。
- id: "code_parser"
type: "code"
data:
code_language: "python3"
code: |
import json
def main(llm_output: str) -> dict:
return {"parsed": json.loads(llm_output)}
outputs:
- name: "parsed"
type: "object"
edges:
- id: "e1"
source: "start"
target: "llm_analysis"
- id: "e2"
source: "llm_analysis"
target: "code_parser"
版本控制的 DSL:将 DSL 文件纳入 Git 管理:
# 将工作流 DSL 导出并提交到 Git
dify-cli export --app-id xxx --output ./workflows/resume_analyzer_v2.1.dsl
git add workflows/resume_analyzer_v2.1.dsl
git commit -m "feat: 增加薪资期望提取功能"
3.3 性能追踪与 OpenTelemetry 集成
Dify v0.10+ 支持 OpenTelemetry 追踪,可以将工作流执行数据发送到 Jaeger、Grafana Tempo 或 Datadog:
# dify 配置文件中启用 OpenTelemetry
ENABLE_OTEL_TRACE: "true"
OTEL_EXPORTER_OTLP_ENDPOINT: "http://jaeger:4317"
OTEL_SERVICE_NAME: "dify-workflow"
OTEL_TRACES_SAMPLER: "traceidratio"
OTEL_TRACES_SAMPLER_ARG: "0.1" # 10% 采样率(生产环境防止数据量过大)
Jaeger 中的追踪视图:
Trace: workflow_run_abc123 (total: 4.85s)
├── start_node (0.001s)
├── validation_code (0.012s)
├── knowledge_retrieval (0.187s)
│ ├── vector_search (0.145s)
│ └── bm25_search (0.038s)
├── llm_analysis (3.240s)
│ ├── token_counting (0.002s)
│ ├── api_call_gpt4o (3.215s) ← 核心瓶颈
│ └── response_parsing (0.023s)
└── code_parser (0.008s)
通过 OpenTelemetry,可以:
- 跨服务追踪整个调用链(Dify → 向量数据库 → LLM API)
- 设置 P95/P99 延迟告警
- 对比不同模型的性能
- 追踪特定用户的请求路径
3.4 工作流执行的分布式追踪
对于生产环境中的复杂场景,需要理解工作流的分布式特性:
# 工作流执行的追踪 ID 传播
# 每次工作流运行都有唯一的 workflow_run_id 和 task_id
# 可以用这两个 ID 在日志中追踪完整执行路径
import logging
import uuid
class WorkflowTracer:
def __init__(self, workflow_run_id: str):
self.run_id = workflow_run_id
self.trace_events = []
def record_node_start(self, node_id: str, node_type: str, inputs: dict):
self.trace_events.append({
"event": "node_start",
"node_id": node_id,
"node_type": node_type,
"timestamp": time.time(),
"inputs_preview": str(inputs)[:200] # 截断,防止日志过大
})
def record_node_end(
self,
node_id: str,
status: str,
outputs: dict,
elapsed_ms: float
):
self.trace_events.append({
"event": "node_end",
"node_id": node_id,
"status": status,
"elapsed_ms": elapsed_ms,
"outputs_preview": str(outputs)[:200]
})
def export_trace(self) -> dict:
return {
"workflow_run_id": self.run_id,
"events": self.trace_events,
"total_nodes": len([e for e in self.trace_events if e["event"] == "node_end"]),
"failed_nodes": [
e["node_id"] for e in self.trace_events
if e["event"] == "node_end" and e["status"] == "failed"
]
}
Level 4:生产陷阱与决策(专家视角)
4.1 陷阱一:版本管理的常见误区
误区1:在生产工作流上直接修改
有些团队为了快速修复,直接在生产工作流上修改,不走发布流程。这会导致:
- 修改过程中工作流处于不一致状态(某些节点是新的,某些是旧的)
- 没有回滚点(因为没有发布记录)
- 无法追踪是谁做了什么修改
正确做法:
- 所有修改在 Dify 的「草稿(Draft)」模式下进行
- 测试通过后,通过「发布」创建新版本
- 线上流量自动切换到新版本
- 出问题时,通过「历史版本」一键回滚
误区2:不写版本描述
发布时不填写变更描述,三个月后完全不记得某个版本改了什么。
规范:采用类似 conventional commits 的格式:
feat: 新增薪资期望提取功能
fix: 修复高并发下 JSON 解析偶发失败
perf: 将模型从 GPT-4o 换为 GPT-4o mini,降低 80% 成本
refactor: 将验证逻辑拆分为独立代码节点,提高可测试性
4.2 陷阱二:调试时"幽灵问题"的排查
症状:工作流在生产环境偶发失败(失败率 < 1%),但在调试模式下无法复现。
常见原因:
-
数据相关:特定的用户输入触发了边缘情况(如特殊字符、超长文本、非 UTF-8 字符)
- 解决:在日志中记录触发失败的完整输入(注意脱敏)
-
时序相关:并发请求导致竞争条件,在顺序调试中不会出现
- 解决:增加并发测试,用负载测试工具(k6、Locust)重现
-
模型不确定性:LLM 输出在某些情况下格式不符合预期
- 解决:加强输入格式的验证和容错处理
-
外部依赖抖动:外部 API 偶发超时(在调试时不会触发)
- 解决:设置合理超时 + 重试,在日志中记录外部 API 的响应时间
建立"问题重现日志":
# 在代码节点中记录可重现信息
def main(data: str) -> dict:
import hashlib
import json
# 计算输入哈希(用于后续重现)
input_hash = hashlib.md5(data.encode()).hexdigest()[:8]
try:
result = process(data)
return {
"result": result,
"_input_hash": input_hash, # 方便用日志搜索具体输入
"success": True
}
except Exception as e:
return {
"error": str(e),
"_input_hash": input_hash,
"_input_preview": data[:100], # 保留输入片段辅助调试
"success": False
}
4.3 陷阱三:性能优化中的过早优化
警告:不要在不知道瓶颈在哪里的情况下开始优化。
优化工作流性能的正确顺序:
第一步:度量(Measure)
先用真实的生产数据运行,获取各节点的 P50/P95/P99 耗时。不要猜测瓶颈在哪里。
第二步:分析(Analyze)
通常 80% 的耗时来自 20% 的节点(帕累托法则)。找到那 20%。
常见的瓶颈分布:
- LLM 调用:占总时间 60-90%(这是"本质瓶颈",很难压缩)
- 知识库检索:占总时间 5-20%(可优化)
- 外部 API:占总时间 5-30%(可优化)
- 代码节点:通常 < 1%(除非有复杂计算)
第三步:针对性优化
基于分析结果,只优化真正的瓶颈:
LLM 是瓶颈?
→ 换更快的模型(GPT-4o mini, Claude 3 Haiku)
→ 减少 max_tokens
→ 合并多个 LLM 调用为一个
知识库检索是瓶颈?
→ 增加向量数据库索引
→ 减小 Top-K
→ 跳过 Rerank(如果精度可以接受)
外部 API 是瓶颈?
→ 增加本地缓存
→ 并行调用多个 API
→ 引入本地 fallback
第四步:验证(Validate)
优化后重新度量,确认确实改善了,没有引入新问题。
4.4 建立生产监控体系
监控体系是工作流长期稳定运行的保障:
告警规则(推荐配置):
# Prometheus 告警规则示例
groups:
- name: dify_workflow_alerts
rules:
# 工作流失败率 > 5%(过去5分钟)
- alert: WorkflowHighFailureRate
expr: |
rate(dify_workflow_run_failed_total[5m]) /
rate(dify_workflow_run_total[5m]) > 0.05
for: 2m
labels:
severity: warning
annotations:
summary: "工作流失败率过高"
description: "过去5分钟失败率 {{ $value | humanizePercentage }}"
# P95 延迟 > 10秒
- alert: WorkflowHighLatency
expr: |
histogram_quantile(0.95,
rate(dify_workflow_elapsed_seconds_bucket[5m])
) > 10
for: 5m
labels:
severity: warning
annotations:
summary: "工作流 P95 延迟过高"
# Token 消耗速率突增(可能是异常循环)
- alert: AbnormalTokenConsumption
expr: |
rate(dify_workflow_tokens_total[5m]) >
avg_over_time(rate(dify_workflow_tokens_total[5m])[1h:5m]) * 3
for: 5m
labels:
severity: critical
annotations:
summary: "Token 消耗异常,可能存在死循环"
Grafana 监控大盘核心指标:
| 面板 | 指标 | 告警阈值 |
|---|---|---|
| 工作流执行量 | requests/min | 异常低(可能宕机) |
| 成功率 | success/total | < 95% |
| P50 延迟 | 中位数耗时 | > 5s |
| P99 延迟 | 长尾耗时 | > 30s |
| Token 消耗 | tokens/min | 突增 3x |
| 节点失败热图 | 各节点失败次数 | 任意节点突增 |
本章小结
调试、版本管理和性能分析是工作流走向生产成熟度的三个核心支柱:
调试:建立系统化的测试用例库,覆盖正常路径、边缘案例和错误处理路径。不要依赖手工测试,而是自动化测试脚本。
版本管理:严格执行草稿 → 发布的流程,每次发布写清楚变更说明。将 DSL 文件纳入 Git 版本控制,保留完整历史。
性能分析:先度量后优化,不要猜测瓶颈。LLM 调用是本质瓶颈,用更快的模型或减少调用次数是最有效的优化方向。
监控体系:在生产环境建立完整的可观测性基础设施(日志、指标、追踪),设置告警规则,在问题影响用户之前主动发现。
关键清单:
- 每个工作流有覆盖所有分支的测试用例集
- 自动化测试脚本已建立,集成到 CI/CD 流程
- 发布流程规范:草稿 → 测试 → 发布,附变更说明
- DSL 文件已纳入 Git 版本控制
- 各节点耗时已通过生产数据度量
- 基于真实瓶颈实施了有针对性的优化
- 监控告警已配置(失败率、延迟、Token 异常)
- OpenTelemetry 追踪已启用(生产环境推荐 5-10% 采样率)