06-04-04 — Desafio: mesmo agente em LangGraph e Agent Framework 1.0

⏱ 10 minFontes validadas em: 2026-04-29

TL;DR

Implementamos o mesmo agente — busca clima → recomenda roupa — em LangGraph (Python) e Agent Framework 1.0 (C#). Resultado: LangGraph requer mais código explícito mas dá controle total sobre o grafo; AF 1.0 é mais declarativo e tem observabilidade integrada. Para times .NET, AF 1.0 vence na produtividade. Para Python-first com lógica complexa customizada, LangGraph vence no controle.

O cenário

Agente simples mas representativo:

  1. Usuário pergunta: "O que devo vestir hoje em São Paulo?"
  2. Agente consulta API de clima para SP
  3. Agente retorna recomendação de roupa baseada no clima

Este cenário testa: tool calling, loop de raciocínio, formatação de resposta e estado.

Implementação 1: LangGraph (Python)

## LANGGRAPH — Agente clima/roupa
## Linhas de código: ~70
## Arquivos: 1 (main.py)

from typing import TypedDict, Annotated, List
import operator
from langgraph.graph import StateGraph, END
from langchain_openai import ChatOpenAI
from langchain_core.messages import BaseMessage, HumanMessage, ToolMessage
from langchain_core.tools import tool
import httpx

# 1. FERRAMENTAS
@tool
def buscar_clima(cidade: str) -> str:
    """Busca temperatura e condição climática de uma cidade."""
    # Usando wttr.in como API pública
    resp = httpx.get(f"https://wttr.in/{cidade}?format=j1", timeout=10)
    data = resp.json()
    weather = data["current_condition"][0]
    temp = weather["temp_C"]
    descricao = weather["weatherDesc"][0]["value"]
    return f"Temperatura: {temp}°C, Condição: {descricao}"

@tool
def recomendar_roupa(temperatura_c: int, condicao: str) -> str:
    """Recomenda roupa baseado na temperatura e condição."""
    if temperatura_c < 15:
        base = "casaco pesado, calça comprida, bota"
    elif temperatura_c < 22:
        base = "jaqueta leve, calça comprida, tênis"
    elif temperatura_c < 28:
        base = "camiseta, calça jeans ou saia, tênis"
    else:
        base = "camiseta leve, shorts ou saia, sandália"

    if "rain" in condicao.lower() or "chuva" in condicao.lower():
        base += ", guarda-chuva"
    return f"Recomendação: {base}"

tools = [buscar_clima, recomendar_roupa]
tools_by_name = {t.name: t for t in tools}

# 2. MODELO
llm = ChatOpenAI(model="gpt-4o-mini").bind_tools(tools)

# 3. ESTADO
class AgentState(TypedDict):
    messages: Annotated[List[BaseMessage], operator.add]

# 4. NÓS
def chamar_llm(state: AgentState) -> dict:
    resposta = llm.invoke(state["messages"])
    return {"messages": [resposta]}

def executar_ferramentas(state: AgentState) -> dict:
    ultimo = state["messages"][-1]
    resultados = []
    for tc in ultimo.tool_calls:
        resultado = tools_by_name[tc["name"]].invoke(tc["args"])
        resultados.append(ToolMessage(content=str(resultado), tool_call_id=tc["id"]))
    return {"messages": resultados}

def decidir_proximo(state: AgentState) -> str:
    ultimo = state["messages"][-1]
    if hasattr(ultimo, "tool_calls") and ultimo.tool_calls:
        return "ferramentas"
    return END

# 5. GRAFO
grafo = StateGraph(AgentState)
grafo.add_node("llm", chamar_llm)
grafo.add_node("ferramentas", executar_ferramentas)
grafo.set_entry_point("llm")
grafo.add_conditional_edges("llm", decidir_proximo, {"ferramentas": "ferramentas", END: END})
grafo.add_edge("ferramentas", "llm")
app = grafo.compile()

# 6. EXECUTAR
resultado = app.invoke({
    "messages": [HumanMessage(content="O que devo vestir hoje em São Paulo?")]
})
print(resultado["messages"][-1].content)

Implementação 2: Agent Framework 1.0 C#

// AGENT FRAMEWORK 1.0 — Agente clima/roupa
// Linhas de código: ~55 (excluindo Program.cs boilerplate)
// Arquivos: 3 (Program.cs, ClimaPlugin.cs, appsettings.json)

// ClimaPlugin.cs
using Microsoft.SemanticKernel;
using System.ComponentModel;

public class ClimaPlugin
{
    [KernelFunction("buscar_clima")]
    [Description("Busca temperatura e condição climática de uma cidade")]
    public async Task<string> BuscarClimaAsync(
        [Description("Nome da cidade")] string cidade)
    {
        using var http = new HttpClient();
        var json = await http.GetStringAsync($"https://wttr.in/{cidade}?format=j1");
        var data = JsonDocument.Parse(json);
        var cond = data.RootElement
            .GetProperty("current_condition")[0];
        var temp = cond.GetProperty("temp_C").GetString();
        var desc = cond.GetProperty("weatherDesc")[0]
            .GetProperty("value").GetString();
        return $"Temperatura: {temp}°C, Condição: {desc}";
    }

    [KernelFunction("recomendar_roupa")]
    [Description("Recomenda roupa baseado na temperatura e condição climática")]
    public string RecomendarRoupa(
        [Description("Temperatura em graus Celsius")] int temperaturaC,
        [Description("Condição climática")] string condicao)
    {
        var base_ = temperaturaC switch
        {
            < 15 => "casaco pesado, calça comprida, bota",
            < 22 => "jaqueta leve, calça comprida, tênis",
            < 28 => "camiseta, calça jeans ou saia, tênis",
            _    => "camiseta leve, shorts ou saia, sandália"
        };

        if (condicao.Contains("rain", StringComparison.OrdinalIgnoreCase))
            base_ += ", guarda-chuva";

        return $"Recomendação: {base_}";
    }
}

// Program.cs
using Microsoft.AgentFramework;
using Microsoft.SemanticKernel;
using Microsoft.SemanticKernel.Connectors.AzureOpenAI;

var builder = WebApplication.CreateBuilder(args);
builder.Services.AddAgentFramework(options =>
{
    options.AddAzureOpenAI(
        deploymentName: "gpt-4o-mini",
        endpoint: builder.Configuration["AzureOpenAI:Endpoint"]!,
        apiKey: builder.Configuration["AzureOpenAI:Key"]!);
    options.AddPlugin<ClimaPlugin>();
});

var app = builder.Build();
var kernel = app.Services.GetRequiredService<Kernel>();

var settings = new AzureOpenAIPromptExecutionSettings
{
    FunctionChoiceBehavior = FunctionChoiceBehavior.Auto()
};

var resposta = await kernel.InvokePromptAsync(
    "O que devo vestir hoje em São Paulo?",
    new KernelArguments(settings));

Console.WriteLine(resposta);
await app.RunAsync();

Comparação lado a lado

DimensãoLangGraph (Python)AF 1.0 (C#)
Linhas de código~70~55 (excl. boilerplate)
Arquivos13
Curva para time .NETAlta (Python + LangChain)Baixa (C# nativo)
Controle do fluxo✅ Total (grafo explícito)⚠️ Delegado ao tool calling
Adicionar nó condicional5 linhasNovo plugin/função
ObservabilidadeLangSmith (pago/cloud)App Insights (Azure nativo)
Deploy em AzureContainer + App ServiceApp Service nativo / Foundry
Copilot Studio integration❌ Manual via API✅ Nativo
Human-in-the-loopinterrupt() nativo✅ Via workflow graph
Type safetyTypedDict (parcial)✅ C# nativo

Diagrama de fluxo — o que acontece internamente

sequenceDiagram participant U as Usuário participant F as Framework participant LLM as GPT-4o-mini participant T1 as buscar_clima participant T2 as recomendar_roupa U->>F: "O que vestir em SP?" F->>LLM: prompt + tools disponíveis LLM-->>F: tool_call: buscar_clima("São Paulo") F->>T1: executar T1-->>F: "28°C, parcialmente nublado" F->>LLM: resultado da tool LLM-->>F: tool_call: recomendar_roupa(28, "parcialmente nublado") F->>T2: executar T2-->>F: "camiseta leve, shorts, sandália" F->>LLM: resultado da tool LLM-->>F: "Hoje em SP faz 28°C e está parcialmente nublado. Use camiseta leve, shorts e sandália." F-->>U: resposta final

Quando cada abordagem vence

Use LangGraph quando: você precisa de controle explícito sobre cada step do grafo, lógica de retry customizada por nó, depuração visual do estado em cada passo, ou o time é Python-first e não quer aprender .NET.
Use AF 1.0 (C#) quando: o time já é .NET, a infra é Azure, você precisa integrar com Copilot Studio ou M365, ou precisa de SLA de suporte Microsoft para o framework.

Como isso se conecta

  • 06-01-02 LangGraph — implementação detalhada do framework usado neste desafio
  • 06-03-03 Agent Framework 1.0 — implementação detalhada do AF 1.0
  • 06-04-03 Decision matrix — a matriz que fundamenta a escolha entre os dois
  • Módulo 07 — MCP e A2A — próximo módulo: os protocolos de interoperabilidade que conectam agentes de diferentes frameworks

Fontes

  1. LangGraph Docs — Introduction Tutorial (agente com tools)
  2. Microsoft Docs — Agent Framework Getting Started
  3. wttr.in — Weather API Documentation
  4. Microsoft Docs — Function Choice Behaviors (tool calling automático)