SKILL de Otimização de Performance do Dify
Visão Geral
Esta SKILL fornece um guia completo de otimização de performance para workflows e plugins do Dify, cobrindo tópicos principais como otimização da estrutura do grafo, controle de custos de LLM, ajuste do pool de workers, otimização do pool de variáveis, processamento paralelo e monitoramento de desempenho.
Cenários de Aplicação
Você deve usar esta SKILL quando:
- ⏱️ O tempo de execução do workflow for muito longo, necessitando de otimização
- 💰 O custo da API LLM for muito alto, precisando reduzir o consumo de Tokens
- 🚀 A capacidade de processamento concorrente for insuficiente, exigindo maior throughput
- 📊 A utilização dos recursos do sistema for baixa, necessitando de ajuste de configuração
- 📈 Existirem gargalos de performance no processamento de dados em larga escala
- 🔍 For necessário realizar diagnóstico e monitoramento de performance
Valor Principal
- Efeitos de Otimização Quantificáveis: Execução paralela de branches reduz o tempo em 40-60%, cache de LLM reduz chamadas em 30-50%
- Orientado por Casos Práticos: 5 casos reais de otimização, com comparações antes e depois
- Estratégias de Otimização Abrangentes: Cobre todos os níveis de workflow, LLM, plugins e monitoramento
- Ferramentas de Diagnóstico Rápido: Checklist de diagnóstico em 5 dimensões
Checklist de Diagnóstico Rápido
Antes de iniciar a otimização, use o checklist abaixo para localizar rapidamente os problemas de performance:
📊 Diagnóstico da Estrutura do Grafo
- Existem muitas dependências em série?
- É possível usar branches paralelos? (v0.8.0+)
- Existem nós e conexões desnecessários?
- O número de nós excede 50?
- O padrão de design apropriado está sendo usado?
🤖 Diagnóstico de Uso de LLM
- A seleção do modelo é adequada? (tarefas leves com modelos leves)
- O Prompt é muito longo? (pode ser simplificado?)
- O cache de resposta do LLM está ativado?
- A saída estruturada está sendo usada? (JSON Schema)
- O consumo de Token está dentro do orçamento?
⚙️ Diagnóstico do Pool de Workers
- A configuração do número de Workers é razoável? (2-8 threads)
- A profundidade da fila é muito grande?
- Existem Workers ociosos desperdiçando recursos?
- A estratégia de escala para cima/baixo é razoável?
💾 Diagnóstico do Pool de Variáveis
- Objetos grandes estão sendo armazenados no pool de variáveis?
- As variáveis são limpas rapidamente?
- Referências estão sendo usadas em vez de cópias?
- O escopo das variáveis é razoável?
🔄 Diagnóstico de Processamento Concorrente
- O iterador está configurado com
parallel_nums? - A resposta em streaming está sendo usada?
- As tarefas assíncronas estão configuradas corretamente?
- Existem operações de bloqueio?
Parte 1: Otimização da Estrutura do Grafo
1.1 Reduzir Dependências em Série
Problema: Muitas dependências em série fazem com que o tempo de execução do workflow cresça linearmente.
Estratégias de Otimização:
- Identificar nós paralelizáveis: Analise as dependências entre nós e encontre aqueles que podem ser executados em paralelo
- Usar branches paralelos: Dify v0.8.0+ suporta a funcionalidade de branches paralelos
- Reestruturar o workflow: Transforme fluxos em série no padrão paralelo + agregação
Exemplo:
# Antes da otimização: Execução em série (tempo total = 3 + 2 + 4 = 9 segundos)
Início → Chamada API1(3s) → Chamada API2(2s) → Chamada API3(4s) → Fim
# Após a otimização: Execução paralela (tempo total = max(3,2,4) = 4 segundos)
Início → [Chamada API1(3s), Chamada API2(2s), Chamada API3(4s)] → Agregador de Variáveis → Fim
Efeito da Otimização: Redução de 40-60% no tempo de execução
1.2 Funcionalidade de Branches Paralelos (v0.8.0+)
O Dify v0.8.0 introduziu a funcionalidade de branches paralelos, permitindo que múltiplos branches sejam executados simultaneamente.
Como Usar:
- Crie múltiplos branches no editor de workflow
- Certifique-se de que não há dependência de dados entre os branches
- Use um agregador de variáveis para coletar os resultados
Cenários de Aplicação:
- Múltiplos nós HTTP Request chamados em paralelo
- Múltiplos nós Tool executados em paralelo
- Recuperação de Knowledge Base + Chamada de API processados em paralelo
- Inferência paralela com múltiplos modelos (cenário de comparação de modelos)
Exemplo de Configuração:
# Configuração de branches paralelos
parallel_branches:
- branch_1:
nodes: [http_request_1, code_1]
- branch_2:
nodes: [http_request_2, code_2]
- branch_3:
nodes: [tool_1, llm_1]
1.3 Evitar Nós Desnecessários
Problemas Comuns:
- Nós de transformação de dados redundantes
- Nós de variáveis intermediárias desnecessárias
- Nós de condição excessivos
Sugestões de Otimização:
- Mesclar lógicas de processamento similares
- Usar nós de código para substituir múltiplos nós simples
- Simplificar a lógica de condição
1.4 Padrões de Design de Estrutura de Grafo
Escolha o padrão de design adequado com base no tipo de tarefa:
- Pipeline Sequencial: Início → LLM → Fim (tarefas simples)
- Branch Condicional: Início → LLM → If-Else → Múltiplos caminhos (tarefas de decisão)
- Processamento Iterativo: Início → Código → Iteração → LLM (tarefas em lote)
- Recuperação de Conhecimento: Início → Recuperação de Conhecimento → LLM (aplicações RAG)
- Agregação Multifonte: Múltiplos Tool/HTTP → Agregador de Variáveis → LLM (agregação de dados)
Documentação Detalhada: Consulte workflow-optimization/graph-structure.md
Parte 2: Estratégias de Otimização de LLM
2.1 Estratégia de Seleção de Modelo
Escolher o modelo certo é chave para a otimização de custos.
Matriz de Seleção de Modelo:
| Tipo de Tarefa | Modelo Recomendado | Custo de Token | Cenário de Aplicação |
|---|---|---|---|
| Classificação Simples | Qwen-Turbo, Gemini Flash | Baixo | Classificação de texto, análise de sentimento |
| Geração de Texto | GPT-3.5-turbo, Qwen-Plus | Médio | Geração de conteúdo, sumarização |
| Raciocínio Complexo | GPT-4, Claude Opus | Alto | Análise complexa, tomada de decisão |
| Implantação Local | Ollama (Llama 3, Qwen) | Custo zero de API | Cenários sensíveis à privacidade |
Comparação de Custos:
- GPT-4: $0.03/1K tokens (entrada) + $0.06/1K tokens (saída)
- GPT-3.5-turbo: $0.0015/1K tokens (entrada) + $0.002/1K tokens (saída)
- Qwen-Turbo: ¥0.0008/1K tokens (cerca de 20x de diferença de custo)
Sugestões de Otimização:
- Tarefas leves usam modelos leves (Qwen/Gemini)
- Tarefas complexas usam modelos potentes (GPT-4/Claude)
- Considere usar modelos locais (Ollama) para reduzir custos
2.2 Técnicas de Otimização de Prompt
Simplificação de Prompt:
# Antes da otimização (150 tokens)
"""
Você é um assistente de suporte ao cliente profissional. Leia atentamente a pergunta do cliente abaixo e, com base em nossa base de conhecimento de produtos, forneça uma resposta detalhada, precisa e amigável. Ao responder, preste atenção aos seguintes pontos:
1. Mantenha um tom profissional e educado
2. Forneça soluções específicas
3. Se não tiver certeza, informe
4. Cite a documentação relevante do produto
Pergunta do cliente: {query}
"""
# Após a otimização (50 tokens)
"""
Como assistente de suporte ao cliente, responda à pergunta do cliente com base na base de conhecimento, mantendo profissionalismo e educação.
Pergunta: {query}
"""
Economia de Tokens: 66% (150 → 50 tokens)
Outras Técnicas de Otimização:
- Remova explicações e exemplos redundantes
- Use instruções concisas
- Evite contexto repetido
- Use saída estruturada para reduzir custos de parsing
2.3 Estratégias de Cache
Cache de Resposta do LLM:
Use Redis para armazenar em cache as respostas do LLM, evitando chamadas repetidas.
Implementação:
import hashlib
import redis
# Conectar ao Redis
r = redis.Redis(host='localhost', port=6379, db=0)
def get_llm_response_with_cache(prompt, model="gpt-3.5-turbo"):
# Gerar chave de cache
cache_key = f"llm:{model}:{hashlib.md5(prompt.encode()).hexdigest()}"
# Verificar cache
cached = r.get(cache_key)
if cached:
return cached.decode('utf-8')
# Chamar LLM
response = call_llm_api(prompt, model)
# Armazenar em cache (TTL: 1 hora)
r.setex(cache_key, 3600, response)
return response
Estratégias de Cache:
- Cache de Resposta do LLM: Mesmo Prompt retorna resultado em cache
- Cache de Recuperação da Base de Conhecimento: Mesma consulta retorna vetor em cache
- Cache de Resultado de Nó: Evita execução repetida do mesmo nó
Efeito da Otimização: Redução de 30-50% nas chamadas de API
2.4 Saída Estruturada
Use JSON Schema para garantir a estabilidade da saída do LLM, reduzindo erros de parsing e retentativas.
Exemplo de Configuração:
{
"type": "object",
"properties": {
"category": {
"type": "string",
"enum": ["Técnico", "Vendas", "Pós-venda"]
},
"priority": {
"type": "integer",
"minimum": 1,
"maximum": 5
},
"summary": {
"type": "string",
"maxLength": 100
}
},
"required": ["category", "priority", "summary"]
}
Efeito da Otimização:
- Reduz a quantidade de Tokens de saída
- Evita erros de parsing e retentativas
- Melhora a eficiência do processamento dos nós downstream
Documentação Detalhada: Consulte llm-optimization/
Parte 3: Ajuste do Pool de Workers
3.1 Pool de Threads de Trabalho Dinâmico
O Dify usa um pool de Workers dinâmico para executar nós em paralelo, com configuração padrão de 2-8 threads de trabalho.
Arquitetura do Pool de Workers:
GraphEngine
├── ReadyQueue (Fila de nós prontos)
├── EventQueue (Fila de eventos)
├── Dispatcher (Distribuidor de eventos)
└── WorkerPool (2-8 threads de trabalho)
├── Worker 1
├── Worker 2
├── ...
└── Worker N
3.2 Parâmetros de Configuração
Configurações Chave:
| Parâmetro | Valor Padrão | Descrição | Sugestão de Otimização |
|---|---|---|---|
| min_workers | 2 | Número mínimo de Workers | Definir com base na necessidade mínima de concorrência |
| max_workers | 8 | Número máximo de Workers | Definir com base no número de núcleos de CPU |
| queue_depth_threshold | 10 | Limiar para acionar escala | Ajustar com base na profundidade média da fila |
| idle_timeout | 60s | Tempo limite de ociosidade do Worker | Ajustar com base na frequência das tarefas |
Estratégia de Escala:
# Condição para escalar para cima
if queue_depth > queue_depth_threshold and workers < max_workers:
add_worker()
# Condição para escalar para baixo
if worker_idle_time > idle_timeout and workers > min_workers:
remove_worker()
3.3 Benchmark de Performance
Cenário de Teste: Workflow com 100 nós
| Número de Workers | Tempo de Execução | Throughput | Uso de CPU |
|---|---|---|---|
| 2 | 45s | 2.2 nós/s | 40% |
| 4 | 25s | 4.0 nós/s | 70% |
| 8 | 15s | 6.7 nós/s | 95% |
Efeito da Otimização: Aumentando o número de Workers de 2 para 8, o throughput aumenta 3x
3.4 Sugestões de Otimização
- Definir
max_workerscom base no número de núcleos de CPU: Geralmente, defina como 1-2 vezes o número de núcleos - Monitore a profundidade da fila: Se a profundidade da fila permanecer alta, aumente
max_workers - Evite escalar excessivamente: Muitos Workers podem causar overhead de troca de contexto
- Use I/O assíncrono: Para tarefas intensivas de I/O, use processamento assíncrono para aumentar a eficiência
Documentação Detalhada: Consulte workflow-optimization/parallel-execution.md
Parte 4: Otimização do Pool de Variáveis
4.1 Evitar Armazenar Objetos Grandes
Problema: Armazenar objetos grandes (como arquivos grandes, textos longos) no pool de variáveis consome muita memória.
Estratégias de Otimização:
# ❌ Não recomendado: Armazenar objetos grandes
variables = {
"large_file": open("large_file.pdf", "rb").read(), # 10MB
"long_text": "..." * 100000 # 1MB
}
# ✅ Recomendado: Armazenar referências
variables = {
"file_path": "/path/to/large_file.pdf",
"text_summary": summarize(long_text) # Armazenar apenas o resumo
}
4.2 Usar Referências em Vez de Cópias
Problema: Copiar variáveis aumenta o uso de memória e o tempo de processamento.
Estratégias de Otimização:
# ❌ Não recomendado: Copiar variáveis
result = process_data(data.copy())
# ✅ Recomendado: Usar referências
result = process_data(data) # Operações somente leitura usam referência
4.3 Limpar Variáveis Rapidamente
Problema: Variáveis não utilizadas ocupam memória.
Estratégias de Otimização:
# Limpar variáveis não utilizadas em nós de código
def main(args):
# Processar dados
large_data = process_large_data(args["input"])
result = extract_result(large_data)
# Limpar objeto grande
del large_data
return {"result": result}
4.4 Gerenciamento de Escopo de Variáveis
Tipos de Variáveis:
- Variáveis de Sistema:
sys.query,sys.files,sys.conversation_id - Variáveis de Nó:
{{#node_id.output#}} - Variáveis de Ambiente: Gerenciamento de configuração e chaves
- Variáveis de Iteração: Item atual e índice em loops
Sugestões de Otimização:
- Use o menor escopo possível
- Evite poluição por variáveis globais
- Libere variáveis temporárias rapidamente
Documentação Detalhada: Consulte workflow-optimization/variable-pool.md
Parte 5: Processamento Paralelo e Resposta em Streaming
5.1 Processamento Paralelo com Iteradores
Use o parâmetro parallel_nums do iterador para processar dados de array em paralelo.
Exemplo de Configuração:
iteration_node:
type: iteration
inputs:
items: "{{#code_node.output.items#}}"
config:
parallel_nums: 5 # Processar 5 itens em paralelo
Comparação de Performance:
| Volume de Dados | Processamento Serial | Processamento Paralelo (5) | Ganho |
|---|---|---|---|
| 10 itens | 20s | 5s | 4x |
| 50 itens | 100s | 25s | 4x |
| 100 itens | 200s | 50s | 4x |
5.2 Resposta em Streaming
Use resposta em streaming para melhorar a experiência do usuário, reduzindo o tempo até o primeiro byte (TTFB).
Implementação:
# Ativar resposta em streaming na chamada de API
response = requests.post(
"https://api.dify.ai/v1/workflows/run",
headers={"Authorization": f"Bearer {api_key}"},
json={"inputs": {...}, "response_mode": "streaming"},
stream=True
)
for line in response.iter_lines():
if line:
event = json.loads(line)
print(event["data"])
Efeito da Otimização:
- TTFB reduzido em 80%
- Tempo de resposta percebido pelo usuário reduzido em 50%
5.3 Processamento de Tarefas Assíncronas
Use Celery para processar tarefas de longa duração de forma assíncrona.
Arquitetura:
Servidor API → Fila Celery → Pool de Workers → Execução de Tarefas
Cenários de Aplicação:
- Processamento de arquivos grandes
- Importação de dados em lote
- Chamadas de API de longa duração
- Tarefas agendadas
5.4 Otimização da Arquitetura Orientada a Eventos
O Dify adota uma arquitetura orientada a eventos, onde a execução dos nós gera um fluxo de eventos.
Estratégias de Otimização:
- Use processamento de eventos não bloqueante
- Processe filas de eventos em lote
- Otimize a lógica de distribuição de eventos
Documentação Detalhada: Consulte workflow-optimization/parallel-execution.md
Parte 6: Casos de Otimização de Performance
Caso 1: Otimização de Consulta ao Banco de Dados (Problema N+1)
Cenário de Aplicação:
- O workflow precisa consultar múltiplos dados relacionados
- Existem consultas ao banco de dados em loops
- O tempo de execução cresce linearmente com o volume de dados
Características do Problema:
- Número de consultas = 1 + N (N é o número de registros)
- Conexões com o banco são abertas e fechadas com frequência
- Tempo de execução muito longo
Estado Antes da Otimização:
# Consultar lista de usuários
users = query("SELECT * FROM users LIMIT 100")
# Consultar pedidos para cada usuário (Problema N+1)
for user in users:
orders = query(f"SELECT * FROM orders WHERE user_id = {user.id}")
user.orders = orders
- Número de consultas: 101 (1 + 100)
- Tempo de execução: 10,5s
- Carga no banco de dados: Alta
Solução:
# Consultar todos os dados de uma vez
users = query("SELECT * FROM users LIMIT 100")
user_ids = [user.id for user in users]
# Consultar pedidos em lote
orders = query(f"SELECT * FROM orders WHERE user_id IN ({','.join(map(str, user_ids))})")
# Associar dados em memória
orders_by_user = {}
for order in orders:
if order.user_id not in orders_by_user:
orders_by_user[order.user_id] = []
orders_by_user[order.user_id].append(order)
for user in users:
user.orders = orders_by_user.get(user.id, [])
Resultado Após a Otimização:
- Número de consultas: 2 (redução de 98%)
- Tempo de execução: 2,1s (redução de 80%)
- Carga no banco de dados: Baixa
Benefícios Esperados:
- Curto prazo: Redução de 80% no tempo de execução, carga reduzida no banco
- Longo prazo: Suporte a volumes maiores de dados, escalabilidade do sistema melhorada
- ROI: Custo de desenvolvimento de 2 horas, economia mensal de 30% em custos de servidor
Caso 2: Otimização de Renderização de Nós em Grande Escala (100+ nós)
Cenário de Aplicação:
- Workflow contém 100+ nós
- A renderização do frontend fica lenta
- Resposta lenta no editor
Características do Problema:
- Tempo de carregamento da página > 5s
- Atraso perceptível ao arrastar nós
- Alto uso de memória do navegador
Estado Antes da Otimização:
- Número de nós: 150
- Tempo de carregamento da página: 8,5s
- Uso de memória: 500MB
- Experiência do usuário: Travamentos severos
Solução:
- Rolagem Virtual: Renderizar apenas os nós na área visível
- Carregamento Preguiçoso de Nós: Carregar detalhes dos nós sob demanda
- Otimização com Canvas: Usar Canvas em vez de renderização DOM
- Otimização do Gerenciamento de Estado: Reduzir re-renderizações desnecessárias
Resultado Após a Otimização:
- Tempo de carregamento da página: 2,1s (redução de 75%)
- Uso de memória: 150MB (redução de 70%)
- Experiência do usuário: Fluida
Benefícios Esperados:
- Curto prazo: Melhoria significativa na experiência do usuário
- Longo prazo: Suporte a workflows mais complexos
- ROI: Custo de desenvolvimento de 1 semana, aumento de 40% na satisfação do usuário
Caso 3: Otimização de Performance na Exclusão de Logs de Workflow
Cenário de Aplicação:
- Necessidade de limpar logs históricos periodicamente
- Grande volume de dados de log (milhões)
- Operação de exclusão demorada
Características do Problema:
- Operação de exclusão bloqueia o banco de dados
- Afeta as operações normais
- Tempo de execução imprevisível
Estado Antes da Otimização:
- Número de logs: 5 milhões
- Tempo de exclusão: 45 minutos
- Bloqueio do banco: Bloqueio prolongado de tabela
- Impacto nos negócios: Severo
Solução:
# Antes da otimização: Exclusão única
DELETE FROM workflow_logs WHERE created_at < '2024-01-01';
# Após a otimização: Exclusão em lotes
batch_size = 10000
while True:
deleted = DELETE FROM workflow_logs
WHERE created_at < '2024-01-01'
LIMIT batch_size;
if deleted < batch_size:
break
# Pausa breve para liberar bloqueio do banco
sleep(0.1)
Resultado Após a Otimização:
- Tempo de exclusão: 50 minutos (levemente maior, mas não bloqueia os negócios)
- Bloqueio do banco: Bloqueio curto (0,1s)
- Impacto nos negócios: Nenhum
Benefícios Esperados:
- Curto prazo: Negócios não são afetados
- Longo prazo: Estabilidade do banco de dados melhorada
- ROI: Custo de desenvolvimento de 4 horas, evita perdas por interrupção de negócios
Caso 4: Integração com Banco de Dados Distribuído TiDB
Cenário de Aplicação:
- Grande volume de dados na base de conhecimento (nível TB)
- Gargalo de performance com PostgreSQL monoinstância
- Necessidade de capacidade de escalonamento horizontal
Características do Problema:
- Tempo de resposta de consulta > 5s
- Uso de CPU do banco > 90%
- Impossibilidade de escalar ainda mais
Estado Antes da Otimização:
- Banco de dados: PostgreSQL monoinstância
- Volume de dados: 2TB
- Tempo de resposta de consulta: 8,5s
- Capacidade de escalonamento: Limitada
Solução:
- Migrar para TiDB: Banco de dados SQL distribuído
- Otimização de Índice de Vetor: Usar TiDB Vector para acelerar a recuperação
- Separação Leitura/Escrita: Distribuir requisições de leitura para múltiplas réplicas
- Tabelas Particionadas: Particionar por tempo para melhorar a eficiência da consulta
Resultado Após a Otimização:
- Tempo de resposta de consulta: 1,2s (redução de 86%)
- CPU do banco: 40% (redução de 50%)
- Capacidade de escalonamento: Suporte a 10x o volume de dados
Benefícios Esperados:
- Curto prazo: Melhoria significativa na performance de consulta
- Longo prazo: Suporte ao rápido crescimento dos negócios
- ROI: Custo de migração de 2 semanas, suporte a 10x de crescimento de negócios
Caso 5: Implantação de Alta Disponibilidade com Higress AI Gateway
Cenário de Aplicação:
- Ambiente de produção precisa de alta disponibilidade
- Balanceamento de carga entre múltiplos modelos LLM
- Necessidade de capacidade de failover
Características do Problema:
- Risco de ponto único de falha
- Chamadas de API LLM instáveis
- Incapacidade de lidar com picos de tráfego
Estado Antes da Otimização:
- Arquitetura: Instância única do Dify
- Disponibilidade: 95%
- Tempo de recuperação de falha: 10 minutos
- Pico de tráfego: Incapacidade de lidar
Solução:
# Configuração do Higress AI Gateway
apiVersion: networking.higress.io/v1
kind: McpBridge
metadata:
name: dify-gateway
spec:
replicas: 3 # 3 instâncias
loadBalancer:
algorithm: round-robin
healthCheck:
enabled: true
interval: 10s
failover:
enabled: true
maxRetries: 3
Arquitetura:
Requisição do usuário → Higress Gateway → [Instância Dify 1, Instância Dify 2, Instância Dify 3]
↓
Balanceamento de carga + Failover
Resultado Após a Otimização:
- Disponibilidade: 99,9%
- Tempo de recuperação de falha: < 1 segundo (failover automático)
- Pico de tráfego: Suporte a 10x o tráfego
Benefícios Esperados:
- Curto prazo: Melhoria significativa na estabilidade do sistema
- Longo prazo: Suporte a aplicações críticas de negócios
- ROI: Custo de implantação de 3 dias, evita perdas por interrupção de negócios
Parte 7: Testes e Monitoramento de Performance
7.1 Sistema de Indicadores de Performance
Indicadores de Execução de Workflow:
| Indicador | Valor Alvo | Descrição |
|---|---|---|
| Tempo Médio de Execução | < 2s | Tempo total de execução do workflow |
| Tempo de Execução P95 | < 5s | Tempo de execução para 95% das requisições |
| Tempo de Execução P99 | < 10s | Tempo de execução para 99% das requisições |
| Taxa de Sucesso de Nós | > 99% | Proporção de execuções de nós bem-sucedidas |
| Taxa de Sucesso de Chamadas de API | > 99,5% | Taxa de sucesso de chamadas de API externas |
| Capacidade de Processamento Concorrente | > 100 QPS | Número de requisições processadas por segundo |
Indicadores de Uso de Recursos:
| Indicador | Valor Alvo | Descrição |
|---|---|---|
| Uso de CPU | < 70% | Uso médio de CPU |
| Uso de Memória | < 80% | Uso médio de memória |
| Número de Conexões com o Banco | < 80% | Uso do pool de conexões |
| Memória do Redis | < 70% | Uso de memória do Redis |
Indicadores de Custo:
| Indicador | Valor Alvo | Descrição |
|---|---|---|
| Custo de Uso de Token | < Orçamento | Custo da API LLM |
| Custo de Infraestrutura | < Orçamento | Custo de servidores, banco de dados |
| Custo/Usuário | Em redução contínua | Custo por usuário |
7.2 Ferramentas de Monitoramento
Monitoramento LLMOps:
# Monitoramento embutido do Dify
from dify import Monitor
monitor = Monitor()
# Registrar execução do workflow
monitor.log_workflow_execution(
workflow_id="xxx",
execution_time=2.5,
node_count=10,
token_usage=1500,
cost=0.003
)
# Consultar estatísticas
stats = monitor.get_workflow_stats(
workflow_id="xxx",
time_range="7d"
)
Rastreamento de Execução:
- Histórico de execução do workflow
- Estatísticas de passos de execução por nó
- Estatísticas de uso do LLM
- Logs de erros e registros de retentativas
Monitoramento de Recursos:
# Prometheus + Grafana
# Monitorar CPU, memória, rede, disco
# Exemplo de consulta
rate(dify_workflow_execution_total[5m]) # Taxa de execução de workflows
histogram_quantile(0.95, dify_workflow_duration_seconds) # Tempo de execução P95
7.3 Métodos de Teste de Performance
Teste de Carga:
# Usar Locust para teste de carga
from locust import HttpUser, task, between
class DifyUser(HttpUser):
wait_time = between(1, 3)
@task
def run_workflow(self):
self.client.post(
"/v1/workflows/run",
headers={"Authorization": f"Bearer {self.api_key}"},
json={"inputs": {"query": "Pergunta de teste"}}
)
# Executar teste
# locust -f load_test.py --users 100 --spawn-rate 10
Teste de Estresse:
# Usar Apache Bench
ab -n 1000 -c 50 -H "Authorization: Bearer xxx" \
-p request.json \
https://api.dify.ai/v1/workflows/run
Teste de Benchmark:
# Teste de benchmark de performance
import time
def benchmark_workflow(workflow_id, iterations=100):
times = []
for i in range(iterations):
start = time.time()
run_workflow(workflow_id)
end = time.time()
times.append(end - start)
return {
"avg": sum(times) / len(times),
"p50": sorted(times)[len(times) // 2],
"p95": sorted(times)[int(len(times) * 0.95)],
"p99": sorted(times)[int(len(times) * 0.99)]
}
7.4 Ferramentas de Análise de Performance
Python Profiler:
import cProfile
import pstats
def profile_workflow():
# Perfilha a execução do workflow
profiler = cProfile.Profile()
profiler.enable()
# Executa o workflow
result = run_workflow("workflow_id")
profiler.disable()
# Salva e analisa os resultados
profiler.dump_stats("workflow_profile.prof")
p = pstats.Stats("workflow_profile.prof")
p.sort_stats("cumulative").print_stats(20)
Ferramentas de Análise de Banco de Dados:
- Explique planos de consulta (EXPLAIN)
- Identifique consultas lentas usando
slow_query_log - Verifique índices e otimize consultas
Análise de Rede:
# Use curl para medir o tempo de resposta da API
curl -w "@curl-format.txt" -o /dev/null -s \
-H "Authorization: Bearer xxx" \
-X POST https://api.dify.ai/v1/workflows/run \
-d '{"inputs": {"query": "test"}}'
Formato do arquivo curl-format.txt:
time_namelookup: %{time_namelookup}s
time_connect: %{time_connect}s
time_appconnect: %{time_appconnect}s
time_pretransfer: %{time_pretransfer}s
time_redirect: %{time_redirect}s
time_starttransfer: %{time_starttransfer}s
-----
time_total: %{time_total}s
Apêndice
A. Referência Rápida
| Categoria | Principais Ações | Ganho de Performance |
|---|---|---|
| Estrutura do Grafo | Paralelizar nós, otimizar dependências | Redução de 40-60% no tempo |
| LLM | Modelos leves, cache, prompts curtos | Redução de 30-50% nos custos |
| Pool de Workers | Ajustar número de Workers | Aumento de 3x no throughput |
| Pool de Variáveis | Referências, evitar cópias | Redução de 50% no uso de memória |
| Processamento Concorrente | Processamento em lote, streaming | Melhoria de 4x no throughput |