Przygotuj aplikację Delphi na agentów

· Komponenty
Delphi gotowe na agenty z TsgcAIAgent

Zadanie pytania modelowi językowemu to łatwa część. Agent idzie dalej. Model decyduje, którą z twoich funkcji wywołać, twoja aplikacja je wykonuje, wyniki wracają do modelu, a pętla trwa, dopóki model nie ma odpowiedzi. Napisanie tej pętli to dopiero początek. Wdrożona aplikacja musi też trzymać model z dala od tego, czego nie wolno mu dotykać, zatrzymywać dane osobowe na maszynie, przetrwać dzień, w którym dostawca wycofa model, i wiedzieć, ile kosztuje każdy użytkownik.

sgcWebSockets 2026.11 dodaje do komponentów sgcAI elementy na to wszystko, dla Delphi od 7 do 13:

Pętla agenta w jednym komponencie

Przekaż agentowi skonfigurowany TsgcAIChat, opisz narzędzie i wywołaj Run. Agent wysyła prompt wraz z definicjami narzędzi, wykonuje każde narzędzie, o które prosi model, odsyła wyniki i powtarza, aż model odpowie zwykłym tekstem. Run zwraca tę odpowiedź.

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?'));

Narzędzie otrzymuje argumenty jako obiekt JSON napisany przez model, a wynik zwraca jako tekst, zwykle 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;

Agent działa na bazie TsgcAIChat.ChatWithTools, które obsługuje teraz wywoływanie narzędzi u każdego dostawcy. Przejście z modelu hostowanego na lokalny model Ollama to zmiana Provider i Model, a narzędzia pozostają te same. Jeśli wolisz prowadzić pętlę samodzielnie, ChatWithTools i AddToolResult są również publiczne.

Kontrola pętli

Options.MaxSteps ogranicza liczbę żądań do modelu w jednym przebiegu, Cancel zatrzymuje przebieg z przycisku, timera lub innego wątku, a StopReason mówi, dlaczego przebieg się zakończył. Gdy odpowiedź zostanie ucięta przez limit tokenów, przebieg kończy się z aasrMaxTokens, a wywołania narzędzi z tej odpowiedzi nie są wykonywane, ponieważ ich argumenty mogą być niekompletne. OnStep raportuje każdy krok w chwili, gdy się dzieje, więc użytkownik widzi, co robi agent.

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;

Narzędzie, które zawiedzie, nie kończy przebiegu. Jego wyjątek wraca do modelu jako tekst błędu, a model może spróbować czegoś innego. Błąd samego czatu, na przykład awaria sieci, kończy przebieg z aasrError, a wyjątek trafia do twojego kodu. OnUsage raportuje tokeny każdego żądania do modelu w przebiegu.

Twoje metody Delphi jako narzędzia

Narzędzie to nazwa, opis, typowane parametry i procedura obsługi, jak powyżej. Gdy masz już metodę, która wykonuje zadanie, AddMethod udostępnia ją bez zmian. Nazwa narzędzia to nazwa metody, a parametry, ich typy i wynik są odczytywane przez rozszerzone RTTI, więc ta opcja wymaga Delphi 2010 lub nowszego.

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');

Dla narzędzia z bogatszym wejściem ustaw InputSchema na własny schemat JSON. Enabled wyłącza narzędzie z kolejnych przebiegów bez jego usuwania.

Narzędzia z twoich serwerów MCP

Dodaj jednego lub kilku klientów MCP do MCPClients, a agent zaoferuje narzędzia tych serwerów obok twoich własnych. Są listowane raz na przebieg i wywoływane przez klienta, gdy model o nie poprosi. Narzędzie, które serwer oznaczy przez readOnlyHint, jest traktowane jako tylko do odczytu, a gdy narzędzie lokalne i narzędzie serwera mają tę samą nazwę, wygrywa lokalne.

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'));

Zatwierdzenie, zanim cokolwiek się zmieni

Każde narzędzie ma flagę ReadOnly. Narzędzia tylko do odczytu działają, gdy tylko model o nie poprosi. Narzędzie, które zmienia dane, wysyła pocztę lub wydaje pieniądze, pozostaje bez tej flagi, a agent pyta OnToolApproval przed jego uruchomieniem, podając nazwę narzędzia i dokładne argumenty wybrane przez model.

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;

Odrzucone narzędzie nie jest błędem. Model dowiaduje się, że narzędzie nie zostało zatwierdzone, i może odpowiedzieć użytkownikowi bez niego. Gdy przypisano guardrails, jak w następnej sekcji, narzędzie wymagające zatwierdzenia, które nie znajdzie procedury obsługi, jest odrzucane, więc zapomniane zdarzenie nigdy nie przepuści narzędzia zapisującego.

Guardrails

TsgcAIGuardrails to osobny komponent, który przypisujesz do czatu, więc te same reguły obowiązują agenta i zwykłe żądania czatu. Ma trzy zadania.

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;

Możesz wywołać maskowanie samodzielnie, aby zobaczyć, co otrzyma dostawca i co dostanie z powrotem twoja aplikacja:

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

Przypnij narzędzia swoich serwerów MCP

Opis i schemat wejściowy narzędzia MCP są czytane przez model jako instrukcje. Serwer, który zmieni je po tym, jak mu zaufałeś, ponieważ został przejęty lub ponieważ jego właściciel go zmienił, może ukryć nowe instrukcje w narzędziu, którego już używasz. Nazywa się to tool poisoning.

Przy przypinaniu narzędzi TsgcWSAPIClient_MCP przechowuje odcisk SHA-256 nazwy, opisu, schematu wejściowego i adnotacji każdego narzędzia przy pierwszym jego wylistowaniu. Gdy późniejsza lista zwróci inną definicję, narzędzie jest blokowane. Jest usuwane z listy, agent nigdy go nie oferuje, a jego wywołanie zgłasza wyjątek, zanim cokolwiek zostanie wysłane. OnMCPToolChanged pozwala zaakceptować zmianę albo pozostawić narzędzie zablokowane do przeglądu, a pozostałe narzędzia serwera nadal działają.

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;

Wycofany model nie zatrzyma wdrożonego pliku exe

Nazwy modeli zmieniają się szybciej niż zainstalowane aplikacje. Nazwa modelu wkompilowana w plik exe przestaje działać w dniu, w którym dostawca ją wycofa, a każdy klient potrzebuje nowego buildu. Dzięki aliasom modeli kod prosi o smart lub fast, a alias decyduje o modelu i, jeśli chcesz, o dostawcy. Lista jest wczytywana z pliku, z JSON lub z adresu URL, więc przejście na nowy model to zmiana na twoim serwerze, a nie nowe wydanie.

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');

Fallbacki pokrywają awarie. Gdy dostawca zawiedzie z błędem połączenia, HTTP 5xx, HTTP 429 lub nieznanym modelem, to samo żądanie trafia do następnego dostawcy i modelu z listy. Historia rozmowy, narzędzia i odpowiedzi JSON są przenoszone, a OnFallback informuje, że to się stało. Lokalny model Ollama to dobre ostatnie wyjście.

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;

Wiedz, ile kosztuje każde żądanie

TsgcAIUsageMeter rejestruje tokeny każdego żądania, łącznie z tokenami wejściowymi z pamięci podręcznej, wycenia je według podanego cennika i prowadzi sumy dla każdego użytkownika i każdej sesji. Przypisz go do czatu i ustaw UserId oraz SessionId. Ponieważ miernik siedzi na czacie, liczone jest także każde żądanie do modelu w przebiegu agenta.

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')]));

Cennik dopasowuje dostawcę i model za pomocą symboli wieloznacznych i można go wczytać z JSON lub z pliku, więc zmiana ceny również nie wymaga nowego buildu. Budżety zamieniają miernik w limit. Budżet obejmuje całą aplikację, każdego użytkownika lub każdą sesję, na dzień, miesiąc lub łącznie, w pieniądzach lub w tokenach. Gdy budżet się wyczerpie, następne żądanie jest odrzucane przed wysłaniem, więc budżet może też zatrzymać przebieg agenta w połowie.

// 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;

Ustaw BlockWhenExceeded na False dla budżetu, który tylko zgłasza OnBudgetExceeded jako alert. Do raportów rekordy trafiają do pliku CSV lub do dowolnego TDataSet. Przy włączonym OpenTelemetry każde żądanie staje się spanem zgodnym z konwencjami semantycznymi GenAI i trafia do twojego kolektora OTLP/HTTP w tle, bez spowalniania czatu.

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

oMeter.SaveToCSV('usage.csv');

Demo: asystent faktur

Nowe demo Delphi w Demos\15.AI\02.Applications\11.AIAgent to asystent dla listy niezapłaconych faktur. Agent ma trzy narzędzia. list_unpaid_invoices i get_invoice są tylko do odczytu, a send_reminder zmienia dane i najpierw prosi o twoją zgodę. Agent działa w wątku w tle, więc okno pozostaje responsywne podczas jego pracy. Demo pozwala też wypróbować resztę tego wpisu: zablokowane narzędzia i maskowanie PII, budżet na sesję z licznikiem tokenów i kosztów na żywo oraz eksportem do CSV, aliasy modeli, zapasowego dostawcę i serwer MCP z przypiętymi narzędziami.

Dokumentacja, którą może przeczytać twój agent kodujący

Agent kodujący pisze dobry kod tylko dla bibliotek, które zna. Każdy komponent sgcAI, sgcHTML, sgcCrypto i pozostałych pakietów sgcWebSockets ma teraz własną stronę Markdown dla modeli językowych, łącznie 224 strony. Każda strona mówi, co robi komponent, i wskazuje jego stronę produktu, a większość wymienia jego najważniejsze właściwości, metody i zdarzenia. Strona TsgcAIAgent, ai-agent.md, zawiera też kompletny przykład użycia. llms.txt kieruje Claude Code, Copilota, Cursora i innych agentów do tych stron, dzięki czemu agent czyta prawdziwe API, zanim napisze choć jedną linię.

Umiejętności agentów sgcWebSockets poznają również nowe komponenty. Umiejętność AI z wersji 2026.11.0 ma gotowe wzorce dla pętli narzędzi, zatwierdzania narzędzi, guardrails, aliasów modeli z fallbackiem i miernika użycia, a każdy wzorzec pochodzi z kodu, który się kompiluje. Umiejętności agentów AI dla Delphi, C++Builder i .NET wyjaśnia, jak je zainstalować.

Dostępność

TsgcAIAgent, TsgcAIGuardrails, TsgcAIUsageMeter, aliasy modeli i fallbacki TsgcAIChat oraz przypinanie narzędzi MCP pojawiają się w sgcWebSockets 2026.11.0, dla Delphi od 7 do 13 i C++Builder. Są częścią komponentów sgcAI, zawartych w edycjach Enterprise i All-Access oraz w samodzielnym produkcie sgcAI. Pomoc opisuje każdą właściwość, metodę i zdarzenie, ze stronami o pętli agenta, narzędziach, aliasach i fallbackach, maskowaniu PII, walidacji schematu i przypinaniu narzędzi.

Więcej przeczytasz na stronach komponentów TsgcAIAgent, TsgcAIGuardrails i TsgcAIUsageMeter.

Czytaj dalej

Masz pytania lub uwagi? Skontaktuj się z nami. Otrzymasz odpowiedź od osób, które napisały ten kod.