Por que escolher entre workflow e agente se você pode usar os dois?
Quando construímos uma aplicação com LLMs, uma das primeiras decisões de design é sobre a arquitetura de execução. O paradigma de workflow (fluxo de trabalho) segue uma sequência predefinida: cada etapa é conhecida, a ordem é fixa e temos controle total sobre como a informação flui. Já o paradigma de agente começa com um objetivo e decide quais ações tomar ao longo do caminho — mais flexível, porém com menos previsibilidade.
Mas por que escolher um modelo único para a aplicação inteira? Na prática, muitos sistemas contêm os dois tipos de trabalho. Algumas etapas realizam transformações conhecidas (workflow é ideal), enquanto outras precisam se adaptar com base em resultados intermediários (agente é a escolha natural).
Neste artigo, exploramos o padrão híbrido workflow-agente — uma abordagem que combina a clareza do fluxo predefinido com a flexibilidade da experimentação autônoma — através de um estudo de caso completo: ajuste de hiperparâmetros assistido por LLM.
1. Estudo de caso: ajuste de hiperparâmetros com LLM
O objetivo é construir uma aplicação que recebe um dataset rotulado e uma solicitação em linguagem natural, executa experimentos de classificação e recomenda a melhor configuração encontrada. Naturalmente, dividimos o trabalho em três estágios:
1.1 Preparação do experimento
Traduz a solicitação de modelagem em um briefing com objetivo, métrica de avaliação e configuração de validação cruzada. Como a entrada, a operação desejada e a saída esperada são conhecidas, uma única chamada ao LLM com saída estruturada resolve este estágio.
1.2 Ajuste de hiperparâmetros (o agente)
Aqui está o coração da aplicação. Sabemos o objetivo — encontrar o melhor classificador e seus hiperparâmetros — mas não sabemos a sequência exata de experimentos para chegar lá. O próximo teste útil depende dos resultados observados até o momento. Este estágio é delegado a um agente que escolhe dinamicamente configurações de classificadores, avalia cada uma com validação cruzada e continua explorando.
1.3 Sumarização e relatório
Com o briefing, o histórico de experimentos e a recomendação já disponíveis, transformar tudo em um relatório estruturado é uma operação conhecida. Uma única chamada ao LLM é suficiente novamente.
O resultado é um fluxo claro: a sequência geral é fixa (preparação → exploração → relatório), mas introduzimos autonomia apenas no estágio intermediário, onde o caminho não pode ser determinado antecipadamente.
2. Construindo o workflow de três estágios
A aplicação completa pode ser expressa em três chamadas:
experiment_spec = prepare_experiment(modeling_request, dataset_summary)
recommendation, trial_history = await explore_configurations(
experiment_spec, dataset_summary
)
report = summarize_run(experiment_spec, trial_history, recommendation)2.1 Preparando o experimento com saída estruturada
O primeiro estágio converte a solicitação de modelagem e o resumo do dataset em um briefing compacto. Usamos structured output (saída estruturada) do LLM — um recurso que garante que a resposta siga um formato predefinido, simplificando o consumo downstream.
Definimos o schema de saída com Pydantic:
from pydantic import BaseModel, Field
class ExperimentSpec(BaseModel):
objective: str
primary_metric: str = Field(
description="A valid scikit-learn scoring name"
)
cv_folds: intEm seguida, a instrução do LLM e a função que monta o prompt:
PREPARER_INSTRUCTION = (
"Create an experiment brief from the modeling request "
"and dataset summary."
)
def build_preparer_prompt(request: str, dataset_summary: dict) -> str:
return f"Modeling request:\n{request}\n\n"
f"Dataset summary:\n{json.dumps(dataset_summary, indent=2)}"E a chamada ao LLM via API Responses da OpenAI:
from openai import AzureOpenAI
llm_client = AzureOpenAI(
api_key=os.environ["OPENAI_API_KEY"],
azure_endpoint=os.environ["OPENAI_API_BASE"],
api_version=os.environ["OPENAI_API_VERSION"],
)
def prepare_experiment(request: str, dataset_summary: dict) -> ExperimentSpec:
response = llm_client.responses.parse(
model="gpt-5.4",
reasoning={"effort": "medium"},
instructions=PREPARER_INSTRUCTION,
input=build_preparer_prompt(request, dataset_summary),
text_format=ExperimentSpec,
)
return response.output_parsed2.2 Construindo o agente de experimentação
Este é o único estágio autônomo do workflow. O agente precisa decidir quais configurações testar com base nos scores observados. Usamos o SDK openai-agents para orquestrar o loop agente-ferramenta.
Primeiro, configuramos o cliente assíncrono:
from openai import AsyncAzureOpenAI
from agents import OpenAIResponsesModel
agent_client = AsyncAzureOpenAI(
api_key=os.environ["OPENAI_API_KEY"],
azure_endpoint=os.environ["OPENAI_API_BASE"],
api_version=os.environ["OPENAI_API_VERSION"],
)
agent_model = OpenAIResponsesModel(
model="gpt-5.4",
openai_client=agent_client,
)Depois, definimos o schema de saída da recomendação:
class AgentRecommendation(BaseModel):
model_name: str
hyperparameters_json: str
rationale: str
AGENT_INSTRUCTION = "Find a strong classifier for the supplied problem."A ferramenta que o agente usa para executar um experimento é intencionalmente simples — ela apenas avalia a configuração de classificador fornecida pelo agente usando scikit-learn:
from agents import function_tool
from sklearn.model_selection import cross_val_score
from sklearn.utils import all_estimators
def build_experiment_tool(X, y, experiment_spec, trial_history):
classifiers = dict(all_estimators(type_filter="classifier"))
@function_tool
def run_experiment(model_name: str, hyperparameters_json: str) -> str:
# Evaluate one scikit-learn classifier configuration
parameters = json.loads(hyperparameters_json)
classifier = classifiers[model_name](**parameters)
scores = cross_val_score(
classifier, X, y,
cv=experiment_spec.cv_folds,
scoring=experiment_spec.primary_metric,
)
result = {
"model_name": model_name,
"hyperparameters": parameters,
"mean_score": round(float(scores.mean()), 4),
}
trial_history.append(result)
return json.dumps(result)
return run_experimentO agente pode escolher qualquer classificador do registro do scikit-learn e fornecer argumentos do construtor como JSON. Para o loop principal, usamos o Runner do SDK:
from agents import Agent, ModelSettings, Runner
async def explore_configurations(X, y, experiment_spec, dataset_summary):
trial_history = []
run_experiment = build_experiment_tool(
X, y, experiment_spec, trial_history
)
agent = Agent(
name="Model selection agent",
instructions=AGENT_INSTRUCTION,
model=agent_model,
model_settings=ModelSettings(
reasoning={"effort": "medium"},
parallel_tool_calls=True, # Permite testar várias configs em paralelo
),
tools=[run_experiment],
output_type=AgentRecommendation,
)
result = await Runner.run(
agent,
build_agent_prompt(experiment_spec, dataset_summary),
max_turns=10,
)
return result.final_output, trial_historyDestaque:parallel_tool_calls=True permite que o agente solicite várias configurações simultaneamente, acelerando a exploração.
2.3 Sumarizando a execução
O estágio final transforma a execução completa em um relatório conciso. É uma tarefa fechada — uma única chamada ao LLM resolve:
class ModelSelectionReport(BaseModel):
selected_model: str
selected_hyperparameters: str
mean_cv_score: float
summary: str
def summarize_run(experiment_spec, trial_history, agent_recommendation):
response = llm_client.responses.parse(
model="gpt-5.4",
reasoning={"effort": "medium"},
instructions="Summarize the completed model-selection run.",
input=build_reporter_prompt(
experiment_spec, trial_history, agent_recommendation
),
text_format=ModelSelectionReport,
)
return response.output_parsed3. Testando com classificação de dígitos manuscritos
Para validar a aplicação, usamos o dataset de dígitos manuscritos do scikit-learn (1.797 amostras, 64 features, 10 classes):
from sklearn.datasets import load_digits
digits = load_digits()
X, y = digits.data, digits.target
dataset_summary = {
"n_samples": X.shape[0],
"n_features": X.shape[1],
"n_classes": len(set(y)),
}
modeling_request = (
"Build a classifier for handwritten digit images. "
"Use cross-validation to compare candidate models. "
"Recommend a strong configuration."
)Resultado do primeiro estágio — o LLM produziu o seguinte experiment spec:
{
"objective": "Build and evaluate a classifier for handwritten digit images.",
"primary_metric": "accuracy",
"cv_folds": 5
}Resultado do agente — 19 experimentos foram executados. Entre os 5 primeiros:
[
{"model": "LogisticRegression", "params": {"max_iter": 1000}, "score": 0.9132},
{"model": "RandomForestClassifier", "params": {"n_estimators": 100}, "score": 0.9382},
{"model": "SVC", "params": {"C": 1, "kernel": "rbf"}, "score": 0.9638},
{"model": "KNeighborsClassifier", "params": {"n_neighbors": 3}, "score": 0.9661},
{"model": "SVC", "params": {"C": 10, "kernel": "rbf"}, "score": 0.9750}
]O agente explorou LogisticRegression, RandomForest, SVC, KNeighbors e refinou a melhor configuração: SVC com C=10 e kernel RBF alcançou 97,5% de acurácia em validação cruzada de 5 folds.
Relatório final:
{
"selected_model": "SVC",
"selected_hyperparameters": '{"C": 10, "kernel": "rbf", "gamma": "scale"}',
"mean_cv_score": 0.975,
"summary": "O SVC com C=10 e kernel RBF obteve o melhor score
de validação cruzada entre os candidatos testados."
}4. Quando usar este padrão
Ao construir sua próxima aplicação com LLM, a pergunta não deve ser “toda a aplicação deve ser um workflow ou um agente?”, mas sim:
Onde a aplicação precisa de autonomia?
- Se um estágio tem uma operação conhecida, use uma chamada estruturada ao LLM (workflow).
- Se um estágio tem um objetivo claro, mas o próximo passo depende do que o sistema observar, use um agente.
- Decomponha o caminho da solução em estágios e coloque autonomia apenas onde o caminho precisa ser descoberto.
É assim que você mantém a clareza e o controle de um workflow enquanto aproveita a flexibilidade dos agentes para resolver problemas de forma mais eficaz.
Por que isso importa agora
Com o SDK openai-agents e as APIs de saída estruturada se tornando maduros em 2026, o padrão híbrido workflow-agente deixou de ser um conceito teórico para se tornar uma arquitetura prática e implementável em produção. Empresas que estão construindo pipelines de ML assistidos por IA — desde AutoML até experimentação automatizada — podem adotar este padrão hoje para combinar o melhor dos dois mundos: previsibilidade onde é necessária e adaptabilidade onde é valiosa.
Descubra mais sobre noticiAI
Assine para receber nossas notícias mais recentes por e-mail.



