LangGraph-style Multi-Agent Orchestration for .NET
Uma implementação em C# do paradigma LangGraph para construção de agentes de IA com grafos de estado, roteamento condicional e human-in-the-loop.
O ecossistema de agentes de IA é dominado por Python (LangChain, LangGraph, AutoGen, CrewAI). Mas e quem trabalha com .NET?
O Semantic Kernel da Microsoft é ótimo, mas não implementa o conceito de grafo de estados com nós e arestas condicionais — o padrão que o LangGraph popularizou.
Esse projeto preenche essa lacuna.
| Feature | Status | Descrição |
|---|---|---|
| StateGraph | ✅ | Grafo de estados com nós e arestas |
| Conditional Edges | ✅ | Roteamento dinâmico baseado no estado |
| Checkpointing | ✅ | Persistência de estado entre execuções |
| Human-in-the-Loop | ✅ | Pausar execução para aguardar input do usuário |
| Multi-Agent | ✅ | Orquestração de múltiplos agentes especializados |
| Streaming | ✅ | Eventos em tempo real via SSE |
| Retry + Circuit Breaker | ✅ | Resiliência para chamadas de LLM |
| Tool Calling | ✅ | Integração com function calling da OpenAI |
┌─────────────────────────────────────────────────────────────────┐
│ ChatController │
│ │ │
│ ▼ │
│ ChatService │
│ │ │
│ ▼ │
│ ┌─────────────────── StateGraph ───────────────────┐ │
│ │ │ │
│ │ ┌──────────────┐ │ │
│ │ │ Orchestrator │ ← Entry Point │ │
│ │ └──────┬───────┘ │ │
│ │ │ │ │
│ │ ▼ (conditional edge) │ │
│ │ ┌──────┴──────┬──────────────┐ │ │
│ │ ▼ ▼ ▼ │ │
│ │ ┌────────┐ ┌──────────┐ ┌─────────┐ │ │
│ │ │ Pedido │ │Financeiro│ │ Usuario │ │ │
│ │ │ Agent │ │ Agent │ │ Agent │ │ │
│ │ └────┬───┘ └────┬─────┘ └────┬────┘ │ │
│ │ │ │ │ │ │
│ │ └──────────┴────────────┘ │ │
│ │ │ │ │
│ │ ▼ (conditional edge) │ │
│ │ ┌────────────┴────────────┐ │ │
│ │ ▼ ▼ │ │
│ │ ┌─────────────┐ ┌─────────────────┐ │ │
│ │ │ Human Input │ │ Response Builder│ ← END │ │
│ │ └─────────────┘ └─────────────────┘ │ │
│ │ │ │
│ └───────────────────────────────────────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────────┘
# Clone o repositório
git clone https://github.com/seu-usuario/MultiAgentGraph.git
cd MultiAgentGraph
# Configure sua API key da OpenAI
# Via variável de ambiente:
$env:OPENAI_API_KEY = "sk-..."
# Ou via appsettings.json:
# { "OpenAI": { "ApiKey": "sk-..." } }
# Execute
dotnet runcurl -X POST http://localhost:5000/api/chat \
-H "Content-Type: application/json" \
-d '{"message": "Quero cancelar meu pedido 12345", "clienteId": "999"}'var graph = new StateGraph()
.AddNode("orchestrator", orchestrator.ExecuteAsync)
.AddNode("pedido_agent", pedidoAgent.ExecuteAsync)
.AddNode("financeiro_agent", financeiroAgent.ExecuteAsync)
.AddNode("human_input", HumanInputNode)
.AddNode("response_builder", BuildResponse)
.SetEntryPoint("orchestrator")
.AddConditionalEdge("orchestrator", RouteAfterOrchestrator)
.AddConditionalEdge("pedido_agent", RouteAfterAgent)
.SetFinishPoint("response_builder")
.Compile(new MemoryCheckpointer());
var result = await graph.InvokeAsync(initialState);public static string RouteAfterOrchestrator(GraphState state)
{
var targetAgent = state.Get<string>("target_agent", "unknown");
return targetAgent switch
{
"pedido" => "pedido_agent",
"financeiro" => "financeiro_agent",
"usuario" => "usuario_agent",
_ => "response_builder"
};
}public class MeuAgent : BaseAgent
{
public MeuAgent(ILlmClient llm, SharedMemory memory, ToolRegistry tools, IEventEmitter emitter)
: base("meu_agent", "Descrição do agente", llm, memory, emitter)
{
Skills.Add(new MinhaSkill(tools));
}
public override async Task<GraphState> ExecuteAsync(GraphState state)
{
var action = state.Get<string>("target_action", "");
var skill = FindSkillForAction(action);
if (skill != null)
{
var result = await skill.ExecuteAsync(action, GetParamsFromState(state));
state.Set("response", result);
}
return state;
}
}public class BuscarPedidoTool : ITool
{
public string Name => "buscar_pedido";
public string Description => "Busca informações de um pedido pelo ID";
public List<string> RequiredParams => new() { "pedido_id" };
public Task<ToolResult> ExecuteAsync(Dictionary<string, string> parameters)
{
var pedidoId = parameters["pedido_id"];
// Sua lógica aqui (banco de dados, API, etc.)
var pedido = new { Id = pedidoId, Status = "Ativo", Produto = "Notebook" };
return Task.FromResult(ToolResult.Success(pedido));
}
}Quando o agente precisa de mais informações:
Usuário: "Cancela meu pedido"
Bot: "Qual o número do pedido?" + sessionId: "abc123"
[Estado salvo no SessionManager]
Usuário: "12345" + sessionId: "abc123"
[Estado restaurado, grafo continua de onde parou]
Bot: "Pedido 12345 cancelado com sucesso!"
MultiAgentGraph/
├── Agents/ # Agentes do sistema
│ ├── BaseAgent.cs
│ ├── AgentRegistry.cs
│ ├── OrchestratorAgent.cs
│ ├── PedidoAgent.cs
│ ├── FinanceiroAgent.cs
│ └── UsuarioAgent.cs
├── Core/ # Engine do grafo
│ ├── StateGraph.cs
│ ├── CompiledGraph.cs
│ ├── GraphState.cs
│ └── Constants.cs
├── Tools/ # Ferramentas por domínio
│ ├── ITool.cs
│ ├── ToolRegistry.cs
│ ├── Financeiro/
│ ├── Pedido/
│ └── Usuario/
├── Skills/ # Skills dos agentes
├── LLM/ # Abstração do LLM
├── Memory/ # Memória compartilhada
├── Events/ # Sistema de eventos/streaming
├── Checkpointing/ # Persistência de estado
├── Resilience/ # Circuit breaker + retry
├── Sessions/ # Gerenciamento de sessões
├── Service/ # Serviços da aplicação
├── Controllers/ # API endpoints
└── Models/ # DTOs
| Conceito | LangGraph (Python) | MultiAgentGraph (C#) |
|---|---|---|
| StateGraph | ✅ | ✅ |
| add_node() | ✅ | ✅ AddNode() |
| add_edge() | ✅ | ✅ AddEdge() |
| add_conditional_edges() | ✅ | ✅ AddConditionalEdge() |
| Checkpointer | ✅ | ✅ ICheckpointer |
| Human-in-the-loop | ✅ | ✅ |
| Streaming | ✅ | ✅ SSE |
| Subgraphs | ✅ | ❌ (roadmap) |
| State Reducers | ✅ | ❌ (roadmap) |
| Parallel Execution | ✅ | ❌ (roadmap) |
Cobertura aproximada: ~80% das features core do LangGraph
- Subgraphs (grafos aninhados)
- State Reducers (append/merge de valores)
- Parallel Node Execution
- SQL Server SessionStore
- Redis Checkpointer
- Breakpoints (interrupt_before/after)
- Time Travel (replay de checkpoints)
- Dashboard de visualização do grafo
Contribuições são bem-vindas!
- Fork o projeto
- Crie sua branch (
git checkout -b feature/MinhaFeature) - Commit suas mudanças (
git commit -m 'Adiciona MinhaFeature') - Push para a branch (
git push origin feature/MinhaFeature) - Abra um Pull Request
Este projeto está sob a licença MIT. Veja o arquivo LICENSE para mais detalhes.
Se esse projeto te ajudou, deixa uma ⭐ no repositório!
Feito com 💙 e muito C#