Hacerle una pregunta a un modelo de lenguaje es la parte fácil. Un agente va más lejos. El modelo decide a cuál de tus funciones llamar, tu aplicación las ejecuta, los resultados vuelven al modelo y el bucle continúa hasta que el modelo tiene una respuesta. Escribir ese bucle es solo el principio. Una aplicación en producción también tiene que mantener al modelo lejos de lo que no debe tocar, conservar los datos personales en la máquina, sobrevivir el día en que un proveedor retira un modelo y saber cuánto cuesta cada usuario.
sgcWebSockets 2026.11 añade a los componentes sgcAI las piezas para todo eso, para Delphi 7 a 13:
TsgcAIAgentejecuta el bucle de herramientas con los siete proveedores deTsgcAIChat: OpenAI, Anthropic, Gemini, DeepSeek, Ollama, Grok y Mistral. Sus herramientas son tus métodos Delphi y las herramientas de tus servidores MCP, y pregunta antes de que una herramienta modifique datos.TsgcAIGuardrailsdecide qué herramientas pueden ejecutarse, redacta los datos personales antes de la petición y los restaura en la respuesta, y comprueba las respuestas estructuradas con un esquema JSON.- El pinning de herramientas MCP bloquea una herramienta de servidor cuya definición cambia después de que confiaras en ella.
- Los alias de modelo y el fallback de proveedor mantienen un exe en producción respondiendo cuando se retira un modelo o un proveedor está caído.
TsgcAIUsageMetercuenta tokens, calcula su precio, aplica presupuestos y envía cada petición a OpenTelemetry.
El bucle del agente en un componente
Dale al agente un TsgcAIChat configurado, describe una herramienta y llama a Run. El agente envía el prompt con las definiciones de herramientas, ejecuta cada herramienta que pide el modelo, devuelve los resultados y repite hasta que el modelo responde en texto plano. Run devuelve esa respuesta.
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?'));
La herramienta recibe sus argumentos como el objeto JSON que escribió el modelo, y devuelve su 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;
El agente trabaja sobre TsgcAIChat.ChatWithTools, que ahora admite tool calling en todos los proveedores. Pasar de un modelo alojado a un modelo local de Ollama es un cambio de Provider y Model, y las herramientas siguen siendo las mismas. Si prefieres ejecutar el bucle tú mismo, ChatWithTools y AddToolResult también son públicos.
Controla el bucle
Options.MaxSteps limita el número de peticiones al modelo en una ejecución, Cancel detiene una ejecución desde un botón, un temporizador u otro hilo, y StopReason te dice por qué terminó. Cuando una respuesta se corta por el límite de tokens, la ejecución termina con aasrMaxTokens y las llamadas a herramientas de esa respuesta no se ejecutan, porque sus argumentos pueden estar incompletos. OnStep informa de cada paso según ocurre, de modo que el usuario puede ver lo que hace el agente.
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;
Una herramienta que falla no termina la ejecución. Su excepción vuelve al modelo como texto de error, y el modelo puede probar otra cosa. Un error del propio chat, por ejemplo un fallo de red, termina la ejecución con aasrError y la excepción llega a tu código. OnUsage informa de los tokens de cada petición al modelo de la ejecución.
Tus métodos Delphi como herramientas
Una herramienta es un nombre, una descripción, parámetros tipados y un manejador, como arriba. Cuando ya tienes un método que hace el trabajo, AddMethod lo publica tal cual. El nombre de la herramienta es el nombre del método, y los parámetros, sus tipos y el resultado se leen con RTTI extendido, así que esta opción necesita Delphi 2010 o posterior.
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 una herramienta con una entrada más rica, asigna a InputSchema tu propio esquema JSON. Enabled saca una herramienta de las siguientes ejecuciones sin eliminarla.
Herramientas de tus servidores MCP
Añade uno o varios clientes MCP a MCPClients y el agente ofrece las herramientas de esos servidores junto a las tuyas. Se listan una vez por ejecución y se llaman a través del cliente cuando el modelo las pide. Una herramienta que el servidor marca con readOnlyHint cuenta como de solo lectura, y cuando una herramienta local y una de servidor comparten nombre, gana la local.
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'));
Aprobación antes de que cambie algo
Cada herramienta tiene un indicador ReadOnly. Las herramientas de solo lectura se ejecutan en cuanto el modelo las pide. Una herramienta que modifica datos, envía un correo o gasta dinero no es de solo lectura, y el agente pregunta a OnToolApproval antes de ejecutarla, con el nombre de la herramienta y los argumentos exactos que eligió el modelo.
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;
Una herramienta rechazada no es un error. Se le dice al modelo que la herramienta no fue aprobada y puede responder al usuario sin ella. Con guardrails asignados, como en la siguiente sección, una herramienta que necesita aprobación y no encuentra manejador se rechaza, de modo que un evento olvidado nunca deja pasar una herramienta de escritura.
Guardrails
TsgcAIGuardrails es un componente aparte que asignas al chat, de modo que las mismas reglas se aplican al agente y a las peticiones de chat normales. Tiene tres funciones.
- Reglas de herramientas.
AllowedToolsyDeniedToolsaceptan nombres con comodines*, y una denegación siempre gana. Una herramienta que no está permitida nunca se ofrece al modelo.ToolApprovalelige qué herramientas necesitan aprobación: ninguna, las que no son de solo lectura, o todas. - Datos personales. Con
PII.Enabled, las direcciones de correo, los números de teléfono, los números de tarjeta, los IBAN, las direcciones IP y tus propios patrones se sustituyen por marcadores antes de que la petición salga de la aplicación, y los originales se restauran en la respuesta. - Esquema de respuesta. Con
Schema.Enabled, una respuesta estructurada que no coincide con el esquema JSON se rechaza con la ruta del error, por ejemplo$.price: expected number, yOnSchemaViolationte avisa.
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;
Puedes llamar tú mismo a la redacción para ver lo que recibirá el proveedor y lo que recupera tu aplicación:
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
Fija las herramientas de tus servidores MCP
El modelo lee la descripción y el esquema de entrada de una herramienta MCP como instrucciones. Un servidor que las cambia después de que confiaras en él, porque fue comprometido o porque su propietario lo modificó, puede ocultar nuevas instrucciones en una herramienta que ya usas. Esto se conoce como tool poisoning.
Con el pinning de herramientas, TsgcWSAPIClient_MCP guarda una huella SHA-256 del nombre, la descripción, el esquema de entrada y las anotaciones de cada herramienta la primera vez que la lista. Cuando una lista posterior devuelve una definición distinta, la herramienta se bloquea. Se elimina de la lista, el agente nunca la ofrece y una llamada a ella lanza una excepción antes de enviar nada. OnMCPToolChanged te permite aceptar el cambio o mantener la herramienta bloqueada para revisarla, y las demás herramientas del servidor siguen 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;
Un modelo retirado no detendrá un exe en producción
Los nombres de modelo cambian más rápido que las aplicaciones instaladas. Un nombre de modelo compilado en un exe deja de funcionar el día en que el proveedor lo retira, y cada cliente necesita una compilación nueva. Con los alias de modelo, el código pide smart o fast, y el alias decide el modelo y, si quieres, el proveedor. La lista se carga desde un archivo, desde JSON o desde una URL, de modo que pasar a un modelo nuevo es un cambio en tu servidor, no una nueva versión.
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');
Los fallbacks cubren las caídas. Cuando el proveedor falla con un error de conexión, un HTTP 5xx, un HTTP 429 o un modelo que no conoce, la misma petición pasa al siguiente proveedor y modelo de la lista. El historial de la conversación, las herramientas y las respuestas JSON se conservan, y OnFallback te avisa de que ocurrió. Un modelo local de Ollama es un buen ú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;
Sabe lo que cuesta cada petición
TsgcAIUsageMeter registra los tokens de cada petición, incluidos los tokens de entrada en caché, calcula su precio con la lista de precios que le des, y mantiene totales por usuario y por sesión. Asígnalo al chat y establece UserId y SessionId. Como el medidor está en el chat, también se cuenta cada petición al modelo de una ejecución del agente.
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')]));
La lista de precios hace coincidir proveedor y modelo con comodines y puede cargarse desde JSON o desde un archivo, así que un cambio de precio tampoco necesita una compilación nueva. Los presupuestos convierten el medidor en un límite. Un presupuesto cubre toda la aplicación, cada usuario o cada sesión, por día, por mes o en total, en dinero o en tokens. Cuando se agota un presupuesto, la siguiente petición se rechaza antes de enviarse, de modo que un presupuesto también puede detener una ejecución del agente a medias.
// 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;
Asigna False a BlockWhenExceeded para un presupuesto que solo lanza OnBudgetExceeded como alerta. Para informes, los registros van a un archivo CSV o a cualquier TDataSet. Con OpenTelemetry activado, cada petición se convierte en un span que sigue las convenciones semánticas GenAI y va a tu colector OTLP/HTTP en segundo plano, sin ralentizar el chat.
oMeter.OpenTelemetry.Endpoint := 'http://localhost:4318';
oMeter.OpenTelemetry.ServiceName := 'invoice-assistant';
oMeter.OpenTelemetry.Enabled := True;
oMeter.SaveToCSV('usage.csv');
La demo: un asistente de facturas
La nueva demo de Delphi en Demos\15.AI\02.Applications\11.AIAgent es un asistente para una lista de facturas impagadas. El agente tiene tres herramientas. list_unpaid_invoices y get_invoice son de solo lectura, mientras que send_reminder modifica datos y pide tu aprobación primero. El agente se ejecuta en un hilo en segundo plano, así que la ventana sigue respondiendo mientras trabaja. La demo también te permite probar el resto de este artículo: herramientas denegadas y redacción de PII, un presupuesto por sesión con un contador de tokens y coste en vivo y exportación a CSV, alias de modelo, un proveedor de fallback y un servidor MCP cuyas herramientas están fijadas.
Documentación que tu agente de código puede leer
Un agente de código solo escribe buen código para las bibliotecas que conoce. Cada componente de sgcAI, sgcHTML, sgcCrypto y de los demás packs de sgcWebSockets tiene ahora su propia página Markdown para modelos de lenguaje, 224 páginas en total. Cada página explica qué hace el componente y enlaza su página de producto, y la mayoría enumera sus propiedades, métodos y eventos principales. La página de TsgcAIAgent, ai-agent.md, incluye además un ejemplo de uso completo. llms.txt dirige a Claude Code, Copilot, Cursor y otros agentes hacia estas páginas, de modo que el agente lee la API real antes de escribir una línea.
Las skills de agente de sgcWebSockets también aprenden los nuevos componentes. La skill de IA de 2026.11.0 trae patrones listos para el bucle del agente, la aprobación de herramientas, los guardrails, los alias de modelo con fallback y el medidor de uso, y cada patrón sale de código que compila. Skills de agentes de IA para Delphi, C++Builder y .NET explica cómo instalarlas.
Disponibilidad
TsgcAIAgent, TsgcAIGuardrails, TsgcAIUsageMeter, los alias de modelo y los fallbacks de TsgcAIChat y el pinning de herramientas MCP llegan en sgcWebSockets 2026.11.0, para Delphi 7 a 13 y C++Builder. Forman parte de los componentes sgcAI, incluidos en las ediciones Enterprise y All-Access y en el producto independiente sgcAI. La ayuda documenta cada propiedad, método y evento, con páginas sobre el bucle del agente, las herramientas, los alias y fallbacks, la redacción de PII, la validación de esquemas y el pinning de herramientas.
Lee más en las páginas de componente de TsgcAIAgent, TsgcAIGuardrails y TsgcAIUsageMeter.
Sigue leyendo
- Crea un agente de IA en Delphi: function calling y uso de herramientas con MCP, el bucle del agente explicado paso a paso
- Cliente MCP para Delphi
- OpenAI vs Anthropic vs Gemini en Delphi: ¿qué API de IA deberías usar?
¿Preguntas o comentarios? Ponte en contacto. Recibirás respuesta de las personas que escribieron el código.
