Nexttag.Ai.Agents
1.6.0
dotnet add package Nexttag.Ai.Agents --version 1.6.0
NuGet\Install-Package Nexttag.Ai.Agents -Version 1.6.0
<PackageReference Include="Nexttag.Ai.Agents" Version="1.6.0" />
<PackageVersion Include="Nexttag.Ai.Agents" Version="1.6.0" />
<PackageReference Include="Nexttag.Ai.Agents" />
paket add Nexttag.Ai.Agents --version 1.6.0
#r "nuget: Nexttag.Ai.Agents, 1.6.0"
#:package Nexttag.Ai.Agents@1.6.0
#addin nuget:?package=Nexttag.Ai.Agents&version=1.6.0
#tool nuget:?package=Nexttag.Ai.Agents&version=1.6.0
Nexttag.Ai.Agents
Loop de agente com tool-calling, streaming, gating de aprovação e busca web — plugue qualquer LLM OpenAI-compatível.
Instalar
dotnet add package Nexttag.Ai.Agents
Requer .NET 10. Depende de: Microsoft.Extensions.AI, Microsoft.Extensions.AI.OpenAI.
Registrar (Program.cs)
Não há método de DI obrigatório. Instancie diretamente ou registre como singleton:
// Program.cs — singleton recomendado (client é thread-safe)
builder.Services.AddSingleton<IChatClient>(_ =>
NexttagChatClient.OpenAiCompativel(
endpoint: builder.Configuration["Ai:Endpoint"]!,
model: builder.Configuration["Ai:Model"]!,
apiKey: builder.Configuration["Ai:ApiKey"]));
builder.Services.AddScoped<AgentRunner>();
Configurar
{
"Ai": {
"Endpoint": "http://localhost:4000/v1",
"Model": "qwen3:14b",
"ApiKey": "sk-..."
}
}
| Provedor | Endpoint | ApiKey |
|---|---|---|
| litellm (recomendado) | http://localhost:4000/v1 |
virtual key |
| Ollama (local) | http://localhost:11434/v1 |
null |
| OpenAI | https://api.openai.com/v1 |
sk-... |
| Gemini (OpenAI-compat) | https://generativelanguage.googleapis.com/v1beta/openai/ |
API key |
O modelo precisa suportar tool-calling.
maxIteracoes(default 12) limita rodadas do loop.
Usar
Execução simples
using Microsoft.Extensions.AI;
using Nexttag.Ai.Agents;
IChatClient client = NexttagChatClient.OpenAiCompativel(
endpoint: "http://localhost:4000/v1",
model: "qwen3:14b");
var runner = new AgentRunner(client);
var context = new AgentRunContext();
AgentRunResult r = await runner.RunAsync(
systemPrompt: "Você é um assistente objetivo. Responda em português.",
task: "Explique o que é idempotência em 2 frases.",
tools: [],
context: context);
Console.WriteLine(r.FinalText);
Adicionando tools
using System.ComponentModel;
using Microsoft.Extensions.AI;
var context = new AgentRunContext();
AITool horaAtual = AIFunctionFactory.Create(
() =>
{
context.Step("hora_servidor", "consultou hora");
return DateTimeOffset.UtcNow.ToString("o");
},
"hora_servidor",
"Retorna a data e hora atual do servidor (UTC ISO 8601).");
AITool buscarDocs = AIFunctionFactory.Create(
async ([Description("termos de busca")] string consulta) =>
{
var trechos = await meuRag.BuscarAsync(consulta, topK: 5);
context.Step("buscar_documentos", $"{trechos.Count} trechos");
return System.Text.Json.JsonSerializer.Serialize(trechos);
},
"buscar_documentos",
"Busca trechos relevantes nos documentos. Cite o título na resposta.");
AgentRunResult r = await runner.RunAsync(systemPrompt, task,
tools: [horaAtual, buscarDocs], context: context);
Streaming (SSE / WebSocket)
await foreach (AgentEvent ev in runner.RunStreamingAsync(systemPrompt, task, tools, context))
{
switch (ev)
{
case AgentTextEvent t: Console.Write(t.Delta); break;
case AgentStepEvent s: Log(s.Step.Tool, s.Step.Summary); break;
case AgentProposalEvent p: Log(p.Proposal.Title); break;
case AgentDoneEvent d: Log($"fim ({d.FinalText.Length} chars)"); break;
case AgentErrorEvent e: Log($"erro: {e.Message}"); break;
}
}
Histórico de conversa
var mensagens = new List<ChatMessage>
{
new(ChatRole.System, systemPrompt),
new(ChatRole.User, "turno anterior..."),
new(ChatRole.Assistant, "resposta anterior..."),
new(ChatRole.User, novaPergunta),
};
AgentRunResult r = await runner.RunAsync(mensagens, tools, context);
Gating de aprovação (propor em vez de aplicar)
AITool renomear = AIFunctionFactory.Create(
([Description("id do documento")] string docId,
[Description("novo título")] string titulo) =>
{
var id = context.Propose(
kind: "renomear_documento",
title: $"Renomear para "{titulo}"",
rationale: "Usuário pediu título mais claro.",
data: new Dictionary<string, string?> { ["docId"] = docId, ["titulo"] = titulo });
return $"Proposta registrada (id {id}). Aguardando aprovação.";
},
"renomear_documento",
"Propõe renomear um documento. Só é aplicado após aprovação.");
// após o Run:
foreach (var p in r.Proposals)
// host aplica usando p.Kind + p.Data quando usuário aprovar
Console.WriteLine($"[{p.Kind}] {p.Title}");
Receitas
Agente com busca web (Tavily):
var web = new HttpWebSearch(http, new WebSearchOptions { Provider = "tavily", ApiKey = tavilyKey });
if (web.Enabled)
tools.Add(AIFunctionFactory.Create(
async ([Description("termos")] string q) =>
System.Text.Json.JsonSerializer.Serialize(await web.SearchAsync(q, 5)),
"buscar_web", "Busca atuais na web. Cite a fonte (url)."));
Telemetria (registrar o ActivitySource):
tracerProviderBuilder.AddSource(AgentTelemetry.SourceName); // "Nexttag.Ai.Agents"
IChatClient client = NexttagChatClient.OpenAiCompativel(endpoint, model, apiKey,
configurarPipeline: b => b.UseOpenTelemetry().UseLogging(loggerFactory));
Rastreio por usuário/sessão (Langfuse via litellm):
var options = new AgentRunOptions(UserId: userId, SessionId: sessionId);
AgentRunResult r = await runner.RunAsync(mensagens, tools, context, options);
Notas
- Crie um
AgentRunContextpor execução — ele acumula passos/propostas daquela rodada. - Tools de leitura executam direto; tools de escrita devem usar
context.Propose(...). - A lib é stateless por execução — persistência de conversa é responsabilidade do host.
NexttagChatClient.OpenAiCompativeljá habilita o loop de tool-calling (FunctionInvokingChatClient).- Embeddings, RAG e banco vetorial estão em
Nexttag.Ai.Embeddings— fora do escopo desta lib.
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net10.0 is compatible. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
-
net10.0
- Microsoft.Extensions.AI (>= 10.6.0)
- Microsoft.Extensions.AI.OpenAI (>= 10.6.0)
NuGet packages (3)
Showing the top 3 NuGet packages that depend on Nexttag.Ai.Agents:
| Package | Downloads |
|---|---|
|
Nexttag.Ai.Tools
Tools prontas para o Nexttag.Ai.Agents: busca web (Tavily/Brave/SearXNG), leitura de URL, calculadora, wiki (Outline) e ClickUp. Um builder (AgentToolset) compõe as tools padrão + as de domínio do host — basta passar a API key de cada integração. |
|
|
Nexttag.Ai.Graph
Orquestracao de agentes de IA em grafo de estado (estilo LangGraph) para .NET. Fachada estavel e idiomatica sobre o Microsoft Agent Framework Workflows: nos-funcao e nos-agente, arestas condicionais/ciclos, reducers por anotacao, checkpoint, human-in-the-loop e modelo visual (GraphView) para front-ends como React Flow. Sobre Microsoft.Extensions.AI. |
|
|
Nexttag.Chat
Chat multi-canal channel-agnostic: abstracao de canal (IChatChannel, IncomingMessage/OutgoingMessage) + orquestracao generica de bot-chat (BotChatRunner) sobre Nexttag.Ai.Agents. O host pluga o adaptador de canal (Telegram/Teams/Discord) e as tools; a lib roda o agente e devolve a resposta. |
GitHub repositories
This package is not used by any popular GitHub repositories.
1.3.0: sobrecargas de RunAsync/RunStreamingAsync que aceitam a lista completa de mensagens (IReadOnlyList<ChatMessage>) para suportar HISTORICO de conversa. As versoes string (systemPrompt+task) seguem funcionando (delegam para a nova).