Prepare seu app Delphi para agentes

· Componentes
App Delphi pronto para agentes: TsgcAIAgent

Fazer uma pergunta a um modelo de linguagem é a parte fácil. Um agente vai além. O modelo decide qual das suas funções chamar, a sua aplicação as executa, os resultados voltam ao modelo e o ciclo continua até o modelo ter uma resposta. Escrever esse ciclo é só o começo. Uma aplicação em produção também precisa manter o modelo longe do que ele não deve tocar, manter os dados pessoais na máquina, sobreviver ao dia em que um provedor aposenta um modelo e saber quanto cada usuário custa.

O sgcWebSockets 2026.11 adiciona aos componentes sgcAI as peças para tudo isso, para Delphi 7 a 13:

O loop do agente em um só componente

Entregue ao agente um TsgcAIChat configurado, descreva uma ferramenta e chame Run. O agente envia o prompt com as definições das ferramentas, executa cada ferramenta que o modelo pede, devolve os resultados e repete até o modelo responder em texto simples. Run retorna essa resposta.

oChat := TsgcAIChat.Create(nil);
oChat.Provider := aicpAnthropic;
oChat.ChatOptions.ApiKey := 'API_KEY';
oChat.ChatOptions.Model := 'claude-opus-5-5';

oAgent := TsgcAIAgent.Create(nil);
oAgent.Chat := oChat;

oTool := oAgent.Tools.Add('get_weather', 'Current weather of a city');
oTool.AddParam('city', aatpString, 'City name');
oTool.ReadOnly := True;
oTool.OnExecute := DoGetWeather;

Memo1.Lines.Add(oAgent.Run('Do I need an umbrella in Paris today?'));

A ferramenta recebe os argumentos como o objeto JSON que o modelo escreveu e devolve o resultado como texto, normalmente JSON:

procedure TForm1.DoGetWeather(Sender: TObject; const aArguments: string;
  var aResult: string);
begin
  // aArguments is a JSON object, for example {"city":"Paris"}
  aResult := '{"city":"Paris","celsius":18,"sky":"rain"}';
end;

O agente trabalha sobre o TsgcAIChat.ChatWithTools, que agora suporta tool calling em todos os provedores. Trocar um modelo hospedado por um modelo Ollama local é uma mudança de Provider e Model, e as ferramentas continuam as mesmas. Se você prefere executar o loop por conta própria, ChatWithTools e AddToolResult também são públicos.

Controle o loop

Options.MaxSteps limita o número de requisições ao modelo em uma execução, Cancel interrompe uma execução a partir de um botão, de um timer ou de outra thread, e StopReason informa por que a execução terminou. Quando uma resposta é cortada pelo limite de tokens, a execução termina com aasrMaxTokens e as chamadas de ferramenta dessa resposta não são executadas, porque seus argumentos podem estar incompletos. OnStep reporta cada passo à medida que acontece, para o usuário ver o que o agente está fazendo.

oAgent.Options.MaxSteps := 5;
oAgent.OnStep := oAgentStep;
vAnswer := oAgent.Run('Plan a three day trip to Rome');
case oAgent.StopReason of
  aasrCompleted:
    Memo1.Lines.Add(vAnswer);
  aasrMaxSteps:
    Memo1.Lines.Add('Stopped after 5 model requests');
  aasrMaxTokens:
    Memo1.Lines.Add('Cut by the token limit (' + oChat.LastFinishReason + ')');
  aasrCancelled:
    Memo1.Lines.Add('Cancelled');
end;
procedure TForm1.oAgentStep(Sender: TObject; const aStep: TsgcAIAgentStep);
begin
  case aStep.Kind of
    aaskToolCall:
      Memo1.Lines.Add('Calling ' + aStep.ToolName + ' ' + aStep.Arguments);
    aaskToolResult, aaskToolDenied:
      Memo1.Lines.Add(aStep.ToolName + ': ' + aStep.Content);
    aaskFinal:
      Memo1.Lines.Add('Answer: ' + aStep.Content);
  end;
end;

Uma ferramenta que falha não encerra a execução. A exceção volta ao modelo como texto de erro, e o modelo pode tentar outra coisa. Um erro do próprio chat, uma falha de rede por exemplo, encerra a execução com aasrError e a exceção chega ao seu código. OnUsage reporta os tokens de cada requisição ao modelo da execução.

Seus métodos Delphi como ferramentas

Uma ferramenta é um nome, uma descrição, parâmetros tipados e um manipulador, como acima. Quando você já tem um método que faz o trabalho, AddMethod o publica como está. O nome da ferramenta é o nome do método, e os parâmetros, seus tipos e o resultado são lidos com RTTI estendido, então esta opção exige Delphi 2010 ou mais recente.

function TForm1.Forecast(const aCity: string; aDays: Integer): string;
begin
  Result := Format('%s: sunny for %d days', [aCity, aDays]);
end;
oAgent.Tools.AddMethod(Self, 'Forecast',
  'Weather forecast of a city for the next days');

Para uma ferramenta com uma entrada mais rica, defina InputSchema com o seu próprio JSON schema. Enabled tira uma ferramenta das próximas execuções sem removê-la.

Ferramentas dos seus servidores MCP

Adicione um ou mais clientes MCP a MCPClients e o agente oferece as ferramentas desses servidores junto com as suas. Elas são listadas uma vez por execução e chamadas por meio do cliente quando o modelo as pede. Uma ferramenta que o servidor marca com readOnlyHint conta como somente leitura, e quando uma ferramenta local e uma de servidor têm o mesmo nome, a local vence.

oMCP := TsgcWSAPIClient_MCP.Create(nil);
oMCP.MCPOptions.HttpOptions.URL := 'http://127.0.0.1:8080/mcp';
oAgent.MCPClients.Add(oMCP);

Memo1.Lines.Add(oAgent.Run('List the support tickets opened today'));

Aprovação antes de qualquer mudança

Toda ferramenta tem um sinalizador ReadOnly. Ferramentas somente leitura executam assim que o modelo as pede. Uma ferramenta que altera dados, envia um e-mail ou gasta dinheiro continua sem o sinalizador, e o agente pergunta a OnToolApproval antes de executá-la, com o nome da ferramenta e os argumentos exatos que o modelo escolheu.

oTool := oAgent.Tools.Add('send_reminder', 'Sends a payment reminder');
oTool.AddParam('invoice', aatpString, 'Invoice number');
oTool.OnExecute := DoSendReminder; // ReadOnly is False: it changes data

oAgent.OnToolApproval := oAgentToolApproval;
procedure TForm1.oAgentToolApproval(Sender: TObject; const aToolName,
  aArguments: string; var aApproved: Boolean);
begin
  aApproved := MessageDlg('Run ' + aToolName + ' with ' + aArguments + '?',
    mtConfirmation, [mbYes, mbNo], 0) = mrYes;
end;

Uma ferramenta recusada não é um erro. O modelo é informado de que a ferramenta não foi aprovada e pode responder ao usuário sem ela. Com guardrails atribuídos, como na próxima seção, uma ferramenta que precisa de aprovação e não encontra manipulador é recusada, então um evento esquecido nunca deixa passar uma ferramenta de escrita.

Guardrails

TsgcAIGuardrails é um componente separado que você atribui ao chat, então as mesmas regras valem para o agente e para as requisições de chat simples. Ele tem três funções.

oGuard := TsgcAIGuardrails.Create(nil);
// tools: reading is allowed, deleting never
oGuard.AllowedTools.Add('get_*');
oGuard.AllowedTools.Add('list_*');
oGuard.AllowedTools.Add('send_reminder');
oGuard.DeniedTools.Add('*delete*');
oGuard.ToolApproval := aigaNotReadOnly;
// personal data never leaves the application
oGuard.PII.Enabled := True;
oGuard.PII.CustomPatterns.Add('EmployeeId=EMP-####');
// structured answers must match the schema
oGuard.Schema.Enabled := True;
oGuard.Schema.JSONSchema := '{"type":"object","properties":' +
  '{"price":{"type":"number","minimum":0}},"required":["price"]}';

oChat.Guardrails := oGuard;

Você pode chamar o mascaramento por conta própria para ver o que o provedor vai receber e o que a sua aplicação recebe de volta:

vText := oGuard.Redact('Mail bob@example.com, call +34 600 111 222, ' +
  'employee EMP-1234');
// Mail [EMAIL_1], call [PHONE_1], employee [EMPLOYEEID_1]
vText := oGuard.Restore(vText);
// Mail bob@example.com, call +34 600 111 222, employee EMP-1234

Fixe as ferramentas dos seus servidores MCP

A descrição e o schema de entrada de uma ferramenta MCP são lidos pelo modelo como instruções. Um servidor que os altera depois de você confiar nele, porque foi comprometido ou porque o dono mudou, pode esconder novas instruções em uma ferramenta que você já usa. Isso é conhecido como tool poisoning.

Com o tool pinning, o TsgcWSAPIClient_MCP guarda uma impressão digital SHA-256 do nome, da descrição, do schema de entrada e das anotações de cada ferramenta na primeira vez que a lista. Quando uma listagem posterior devolve uma definição diferente, a ferramenta é bloqueada. Ela é removida da lista, o agente nunca a oferece, e uma chamada a ela lança uma exceção antes de qualquer envio. OnMCPToolChanged permite aceitar a mudança ou manter a ferramenta bloqueada para revisão, e as outras ferramentas do servidor continuam funcionando.

oMCP.MCPOptions.ToolPinning.Enabled := True;
oMCP.MCPOptions.ToolPinning.FileName := 'mcp_pins.json';
oMCP.OnMCPToolChanged := oMCPMCPToolChanged;
procedure TForm1.oMCPMCPToolChanged(Sender: TObject; const aToolName,
  aOldHash, aNewHash: string; var aAccept: Boolean);
begin
  // the definition of a trusted tool changed: keep it blocked
  // until somebody reviews it, then call oMCP.PinTool(aToolName)
  Memo1.Lines.Add('Tool ' + aToolName + ' changed, blocked for review');
  aAccept := False;
end;

Um modelo aposentado não vai parar um exe em produção

Os nomes dos modelos mudam mais rápido que as aplicações instaladas. Um nome de modelo compilado em um exe deixa de funcionar no dia em que o provedor o aposenta, e todo cliente precisa de um novo build. Com aliases de modelo, o código pede smart ou fast, e o alias decide o modelo e, se você quiser, o provedor. A lista carrega de um arquivo, de JSON ou de uma URL, então migrar para um modelo novo é uma mudança no seu servidor, não uma nova versão.

oChat.ModelAliases.Add('fast=gpt-6-luna');
oChat.ModelAliases.Add('smart=anthropic:claude-opus-5-5');
oChat.ProviderApiKeys.Add('anthropic=ANTHROPIC_KEY');
oChat.ChatOptions.Model := 'smart';

// or keep the list on your server and change it without a new build
oChat.LoadModelAliasesFromURL('https://config.example.com/ai/models.json');

Os fallbacks cobrem as quedas. Quando o provedor falha com um erro de conexão, um HTTP 5xx, um HTTP 429 ou um modelo que ele não conhece, a mesma requisição vai para o próximo provedor e modelo da lista. O histórico da conversa, as ferramentas e as respostas JSON são mantidos, e OnFallback avisa que isso aconteceu. Um modelo Ollama local é um bom último recurso.

oChat.Provider := aicpOpenAI;
oChat.ChatOptions.ApiKey := 'OPENAI_KEY';
oChat.ChatOptions.Model := 'gpt-6-luna';

oFallback := oChat.Fallbacks.Add;
oFallback.Provider := aicpGemini;
oFallback.Model := 'gemini-3-flash';
oFallback.ApiKey := 'GEMINI_KEY';

oFallback := oChat.Fallbacks.Add;
oFallback.Provider := aicpOllama;
oFallback.Model := 'llama3.1';

oChat.OnFallback := oChatFallback;
procedure TForm1.oChatFallback(Sender: TObject; const aFromProvider,
  aFromModel, aToProvider, aToModel, aError: string);
begin
  Memo1.Lines.Add(aFromProvider + ' ' + aFromModel + ' failed (' + aError +
    '), trying ' + aToProvider + ' ' + aToModel);
end;

Saiba quanto cada requisição custa

TsgcAIUsageMeter registra os tokens de cada requisição, inclusive os tokens de entrada em cache, calcula o custo deles com a lista de preços que você fornece e mantém totais por usuário e por sessão. Atribua-o ao chat e defina UserId e SessionId. Como o medidor fica no chat, toda requisição ao modelo de uma execução do agente também é contada.

oMeter := TsgcAIUsageMeter.Create(nil);
// example prices per million tokens, use the ones of your contract
oPrice := oMeter.Prices.Add;
oPrice.Provider := 'openai';
oPrice.Model := 'gpt-6*';
oPrice.InputPerMillion := 1.25;
oPrice.OutputPerMillion := 10;
oPrice.CachedPerMillion := 0.125;

oChat.UserId := 'user-1';
oChat.SessionId := 's-42';
oChat.UsageMeter := oMeter;
oChat.Chat('Hello');

Memo1.Lines.Add(Format('user-1 spent %.6f %s and %d tokens',
  [oMeter.TotalCost('user-1'), oMeter.Currency, oMeter.TotalTokens('user-1')]));

A lista de preços associa provedor e modelo com curingas e pode ser carregada de JSON ou de um arquivo, então uma mudança de preço também não exige um novo build. Os orçamentos transformam o medidor em um limite. Um orçamento cobre a aplicação inteira, cada usuário ou cada sessão, por um dia, um mês ou no total, em dinheiro ou em tokens. Quando um orçamento se esgota, a próxima requisição é recusada antes de ser enviada, então um orçamento também pode interromper uma execução do agente no meio.

// every user can spend 2 USD a day
oBudget := oMeter.Budgets.Add;
oBudget.Scope := aubsUser;
oBudget.Period := aubpDay;
oBudget.MaxCost := 2;
// the whole application can spend 500 USD a month
oBudget := oMeter.Budgets.Add;
oBudget.Scope := aubsGlobal;
oBudget.Period := aubpMonth;
oBudget.MaxCost := 500;
try
  Memo1.Lines.Add(oAgent.Run('Remind every customer with an unpaid invoice'));
except
  on E: EsgcAIChat do
    // Usage budget "each user, day" for user-1 exceeded: ...
    Memo1.Lines.Add(E.Message);
end;

Defina BlockWhenExceeded como False para um orçamento que apenas dispara OnBudgetExceeded como alerta. Para relatórios, os registros vão para um arquivo CSV ou para qualquer TDataSet. Com o OpenTelemetry ativado, cada requisição vira um span que segue as convenções semânticas GenAI e vai para o seu coletor OTLP/HTTP em segundo plano, sem atrasar o chat.

oMeter.OpenTelemetry.Endpoint := 'http://localhost:4318';
oMeter.OpenTelemetry.ServiceName := 'invoice-assistant';
oMeter.OpenTelemetry.Enabled := True;

oMeter.SaveToCSV('usage.csv');

A demo: um assistente de faturas

A nova demo Delphi em Demos\15.AI\02.Applications\11.AIAgent é um assistente para uma lista de faturas em aberto. O agente tem três ferramentas. list_unpaid_invoices e get_invoice são somente leitura, enquanto send_reminder altera dados e pede a sua aprovação antes. O agente roda em uma thread em segundo plano, então a janela continua responsiva enquanto ele trabalha. A demo também permite experimentar o resto deste artigo: ferramentas negadas e mascaramento de PII, um orçamento por sessão com um contador ao vivo de tokens e custo e uma exportação para CSV, aliases de modelo, um provedor de fallback e um servidor MCP cujas ferramentas estão fixadas.

Documentação que seu agente de código consegue ler

Um agente de código só escreve bom código para as bibliotecas que conhece. Cada component de sgcAI, sgcHTML, sgcCrypto e dos demais packs do sgcWebSockets agora tem sua própria página Markdown para modelos de linguagem, 224 páginas no total. Cada página explica o que o component faz e aponta para a sua página de produto, e a maioria lista as principais propriedades, métodos e eventos. A página do TsgcAIAgent, ai-agent.md, traz também um exemplo de uso completo. O llms.txt direciona o Claude Code, o Copilot, o Cursor e outros agentes para essas páginas, de modo que o agente lê a API real antes de escrever uma linha.

As skills de agente do sgcWebSockets também aprendem os novos components. A skill de IA da 2026.11.0 traz padrões prontos para o loop do agente, a aprovação de ferramentas, os guardrails, os aliases de modelo com fallback e o medidor de uso, e cada padrão vem de código que compila. Skills de Agente de IA para Delphi, C++Builder e .NET explica como instalá-las.

Disponibilidade

TsgcAIAgent, TsgcAIGuardrails, TsgcAIUsageMeter, os aliases de modelo e os fallbacks do TsgcAIChat e o tool pinning do MCP chegam no sgcWebSockets 2026.11.0, para Delphi 7 a 13 e C++Builder. Fazem parte dos componentes sgcAI, incluídos nas edições Enterprise e All-Access e no produto autônomo sgcAI. A ajuda documenta cada propriedade, método e evento, com páginas sobre o loop do agente, sobre ferramentas, sobre aliases e fallbacks, sobre o mascaramento de PII, sobre a validação de schema e sobre o tool pinning.

Leia mais nas páginas dos componentes TsgcAIAgent, TsgcAIGuardrails e TsgcAIUsageMeter.

Leia a seguir

Dúvidas ou feedback? Entre em contato. Você receberá uma resposta das pessoas que escreveram o código.