Construindo uma Ferramenta em C# para Consulta Paralela e Sumarização de Múltiplos LLMs

No desenvolvimento de software moderno assistido por IA, muitas vezes enfrentamos o desafio de discernir qual solução proposta por um modelo de linguagem (LLM) é realmente viável. Um único modelo pode alucinar ou oferecer uma abordagem subótima. Uma estratégia eficaz para mitigar isso é consultar diversos modelos simultaneamente e identificar os padrões ou soluções recorrentes entre eles. Se três ou quatro modelos sugerem a mesma biblioteca ou algoritmo, a probabilidade de essa ser a escolha correta é significativamente maior.

Abaixo, exploramos como construir uma aplicação utilizando C# e o ecossistema .NET para disparar prompts em paralelo, exibir as respostas em tempo real via streaming e consoldiar um resumo final.

Interface de Usuário com Avalonia UI

Para a visualização, utilizaremos o Avalonia UI. A interface consiste em um campo de entrada para a pergunta e uma grade para exibir as respostas de seis modelos diferentes de forma simultânea.

<UserControl xmlns="https://github.com/avaloniaui"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:vm="using:MultiAI.ViewModels"
             x:DataType="vm:ConsensusViewModel"
             x:Class="MultiAI.Views.ConsensusView">
    <StackPanel Margin="10">
        <TextBox Text="{Binding UserPrompt}" Watermark="Digite sua dúvida técnica aqui..." />
        <Button Content="Consultar Especialistas" 
                Command="{Binding ExecuteParallelQueryCommand}" 
                HorizontalAlignment="Stretch" Margin="0,5"/>
        
        <ScrollViewer Height="600">
            <UniformGrid Columns="3" Rows="2">
                <!-- Repetir para cada modelo -->
                <StackPanel Margin="5">
                    <TextBlock Text="Modelo A" FontWeight="Bold"/>
                    <TextBox Text="{Binding Output1}" Height="250" TextWrapping="Wrap" AcceptsReturn="True" IsReadOnly="True"/>
                </StackPanel>
                <StackPanel Margin="5">
                    <TextBlock Text="Modelo B" FontWeight="Bold"/>
                    <TextBox Text="{Binding Output2}" Height="250" TextWrapping="Wrap" AcceptsReturn="True" IsReadOnly="True"/>
                </StackPanel>
                <!-- ... Outros modelos ... -->
            </UniformGrid>
        </ScrollViewer>
    </StackPanel>
</UserControl>

Implementação do Back end com Microsoft.Extensions.AI

Utilizaremos a abstração IChatClient fornecida pelas bibliotecas experimentais da Microsoft, que padronizam o acesso a diferentes provedores de IA (OpenAI, DeepSeek, modelos locais via Ollama, etc.).

A abordagem inicial sequencial é ineficiente. Para uma experiência de usuário fluida, implementamos chamadas assíncronas paralelas com processamento de fluxo (streaming).

public partial class ConsensusViewModel : ViewModelBase
{
    [ObservableProperty] private string _userPrompt = string.Empty;
    [ObservableProperty] private string _output1 = string.Empty;
    [ObservableProperty] private string _output2 = string.Empty;
    // ... propriedades para outros outputs

    private readonly IServiceProvider _services;

    [RelayCommand]
    private async Task ExecuteParallelQuery()
    {
        // Configuração base do cliente (Exemplo via SiliconFlow ou OpenAI)
        var auth = new ApiKeyCredential("SUA_CHAVE_API");
        var config = new OpenAIClientOptions { Endpoint = new Uri("https://api.provider.com/v1") };

        // Limpa os resultados anteriores
        ResetOutputs();

        // Lista de tarefas para execução simultânea
        var operations = new List<Task>
        {
            StreamToProperty("gpt-4o", auth, config, text => Output1 += text),
            StreamToProperty("deepseek-v3", auth, config, text => Output2 += text),
            StreamToProperty("claude-3-5-sonnet", auth, config, text => Output3 += text),
            StreamToProperty("llama-3.1-70b", auth, config, text => Output4 += text),
            StreamToProperty("qwen-2.5-72b", auth, config, text => Output5 += text),
            StreamToProperty("mistral-large", auth, config, text => Output6 += text)
        };

        await Task.WhenAll(operations);

        // Após coletar todas, gera a sumarização
        await GenerateSummary(auth, config);
    }

    private async Task StreamToProperty(string modelId, ApiKeyCredential auth, OpenAIClientOptions opt, Action<string> updater)
    {
        IChatClient client = new OpenAI.Chat.ChatClient(modelId, auth, opt).AsChatClient();

        await foreach (var chunk in client.GetStreamingResponseAsync(UserPrompt))
        {
            updater(chunk.ToString());
        }
    }
}

Lógica de Sumarização e Consenso

Assim que todos os modelos terminam suas respostas, enviamos o conteúdo acumulado para um "modelo juiz". O objetivo deste prompt é analisar as divergências e convergências entre as respostas.

private async Task GenerateSummary(ApiKeyCredential auth, OpenAIClientOptions opt)
{
    IChatClient summarizer = new OpenAI.Chat.ChatClient("gpt-4o", auth, opt).AsChatClient();
    
    string context = $"""
        Analise as propostas abaixo e resuma as 3 abordagens mais citadas pelos assistentes:
        1: {Output1}
        2: {Output2}
        3: {Output3}
        4: {Output4}
        5: {Output5}
        6: {Output6}
        """;

    var finalResult = await summarizer.GetResponseAsync(context);
    
    // Exibe o resultado em uma janela de diálogo ou componente de destaque
    ShowSummaryWindow(finalResult.ToString());
}

Considerações Técnicas

Ao implementar essa arquitetura, alguns pontos merecem atenção:

  • Custos de API: Consultar seis modelos simultaneamente consome tokens proporcionalmente à quantidade de modelos. É ideal usar provedores que ofereçam modelos rápidos e baratos para as consultas de base e um modelo mais robusto para a sumarização.
  • Modelos de Raciocínio (Reasoning): Modelos como o DeepSeek-R1 ou o o1 da OpenAI retornam blocos de "pensamento" (thought process). Atualmente, as abstrações padrão podem precisar de tratamento manual para separar o raciocínio da resposta final se você desejar limpar a interface.
  • Agregadores: Utilizar serviços que unificam várias APIs de IA simplifica a gestão de endpoints e chaves de autenticação no código C#.

Esta ferramenta transforma o processo de tentativa e erro com IA em um fluxo de trabalho baseado em consenso, reduzindo drasticamente o tempo gasto testando soluções incorretas.

Tags: C# .NET AvaloniaUI LLM Artificial Intelligence

Publicado em 7-27 13:08