DownloadToolkit POML
Resumen General
El Toolkit POML es un motor de orquestación basado en PHP diseñado para gestionar flujos de trabajo complejos de prompts utilizando un lenguaje basado en XML personalizado llamado POML (Prompt Orchestration Markup Language). Su propósito principal es permitir a los desarrolladores definir, analizar y ejecutar cadenas de prompts de IA multi-paso que se integren con modelos de lenguaje, herramientas personalizadas, lógica condicional y gestión de estado. Este toolkit es particularmente útil para construir aplicaciones impulsadas por IA donde los prompts necesitan ser secuenciados, variables extraídas de respuestas y decisiones tomadas basadas en condiciones en tiempo de ejecución.
Características Clave
-
Ejecución de Prompts: Enviar prompts a modelos de IA a través de conectores (por ejemplo, dummy para pruebas o HTTP para APIs reales como OpenAI).
-
Integración de Herramientas: Llamar funciones PHP como herramientas dentro del flujo de trabajo, con resolución de parámetros desde el estado.
-
Lógica Condicional: Soporte para pasos if/else con evaluación simple de condiciones (por ejemplo, `{{var}} == 'value'`).
-
Extracción de Variables: Extracción automática de valores de respuestas JSON en variables de estado.
-
Gestión de Estado: Estado persistente a través de pasos para compartir variables y rastrear resultados.
-
Manejo de Errores: Excepciones personalizadas para errores del motor y del analizador.
Arquitectura
El toolkit sigue un diseño modular con los siguientes componentes principales:
-
Pasos (Implementan StepInterface): Interfaz abstracta para pasos ejecutables.
- `PromptStep`: Ejecuta un prompt a través de un conector y extrae variables.
- `ToolStep`: Invoca un callable PHP registrado con parámetros resueltos.
- `ConditionalStep`: Evalúa una condición y ejecuta ramas then/else.
-
Orchestration: Contenedor para una secuencia de pasos analizados desde XML POML.
-
Conectores (Implementan ModelConnectorInterface): Interfaces para interacciones con modelos de IA.
- `DummyConnector`: Para pruebas, devuelve respuestas predefinidas.
- `HttpConnector`: Para llamadas API basadas en HTTP reales (por ejemplo, a OpenAI).
-
PomlParser: Analiza XML POML usando SimpleXML, validando estructura y construyendo objetos de pasos.
-
OrchestrationEngine: Ejecutor central que registra conectores/herramientas, ejecuta la orquestación y gestiona el estado a través de `StateManager`.
-
StateManager: Maneja la resolución de variables (por ejemplo, `{{var}}`), almacenamiento y recuperación.
-
Excepciones: `EngineException` para errores en tiempo de ejecución, `ParserException` para problemas de XML.
Dependencias
De composer.json:
- PHP ^8.0 (tipos estrictos enforced).
- Autocarga vía PSR-4 para el namespace Poml\Toolkit\ mapeado a src/.
No se requieren bibliotecas externas más allá de las extensiones integradas de PHP (por ejemplo, SimpleXML para análisis, cURL implícitamente vía conector HTTP si se usa).
Diagrama de Arquitectura
graph TD
A[Poml XML Input] --> B[PomlParser]
B --> C[Orchestration Object with Steps]
C --> D[OrchestrationEngine]
D --> E[Register Connectors and Tools]
E --> F[Run Orchestration]
F --> G[StateManager for Variables and Results]
G --> H[Execute Steps: Prompt, Tool, Conditional]
H --> I[Connectors: Dummy or HTTP]
I --> J[Tools: PHP Callables]
J --> G
H --> K[Variable Extraction from JSON]
K --> G
L[Conditional Evaluation] --> M[Then/Else Branches]
M --> H
Cambios e Mejoras Implementados
Esta versión incluye varias mejoras basadas en las mejores prácticas para robustez y mantenibilidad:
-
Mejoras en el Autoloader: Cambiado a autocarga compatible con PSR-4 para una mejor organización de namespaces e integración con Composer.
-
Refactor de Manejo de Errores: Introducidas excepciones específicas (`EngineException`, `ParserException`) en lugar de genéricas. Por ejemplo, conector/herramienta no encontrado lanza `EngineException`; XML inválido lanza `ParserException` con errores detallados de libxml.
-
Refactorizaciones de Pasos: `StepInterface` ahora impone un contrato limpio `execute(StateManager $state): mixed`. Subclases como `PromptStep` manejan decodificación JSON de manera segura con verificaciones `json_last_error()`. `ConditionalStep` usa regex para análisis simple de condiciones (por ejemplo, verificaciones de igualdad) con fallback a evaluación truthy.
-
Optimizaciones: El análisis usa SimpleXML eficiente con supresión de errores internos y limpieza. La ejecución del motor evita problemas de profundidad de recursión procesando pasos linealmente; las ramas condicionales se ejecutan secuencialmente sin bucles. La resolución de variables en `StateManager` (no mostrado pero inferido) usa reemplazo de strings para eficiencia.
Estos cambios mejoran la fiabilidad, reducen el boilerplate y mejoran la depuración.
Instrucciones de Instalación
-
Prerrequisitos: Asegúrate de que PHP 8.0+ esté instalado con la extensión SimpleXML habilitada.
-
Clonar o Descargar: Coloca el proyecto en tu espacio de trabajo (por ejemplo, `c:/Users/kuasa/Documents/VScode/poml`).
-
Instalar Dependencias:
composer install
Esto configura el autoloader; no se necesitan paquetes adicionales.
-
Configuración:
- Para pruebas: No se requiere configuración (usa DummyConnector).
- Para modelos de IA reales: Establece variables de entorno, por ejemplo, `export OPENAI_API_KEY=your_key_here` (o usa `putenv()` en PHP).
- Edita conectores en el código si es necesario (por ejemplo, registra `HttpConnector` con URL de API y clave).
-
Ejecución:
- Ejecuta el ejemplo: `php example.php`
- Esto analiza un XML POML de muestra, registra una herramienta y conector, y ejecuta el flujo de trabajo, imprimiendo salidas.
Si surgen problemas (por ejemplo, extensiones faltantes), verifica los logs de errores de PHP.
Ejemplos de Uso
El example.php demuestra un flujo de trabajo completo: generar JSON, extraer una variable y llamar condicionalmente a una herramienta.
<?php
declare(strict_types=1);
require 'vendor/autoload.php';
use Poml\Toolkit\OrchestrationEngine;
use Poml\Toolkit\Parsing\PomlParser;
use Poml\Toolkit\Connectors\DummyConnector;
use Poml\Toolkit\Connectors\HttpConnector;
echo "--- POML Toolkit Advanced Example ---\n\n";
// 1. Define a tool (a simple PHP function)
function send_notification(string $message): string {
$output = "NOTIFICATION SENT: {$message}\n";
echo $output;
return "Sent successfully";
}
// 2. Define the complex POML workflow
$pomlXml = <<<'XML'
<?xml version="1.0"?>
<poml>
<prompt model="json-generator">
<message>Generate a JSON object with a user 'name' and a 'status' of 'active'.</message>
<!-- Extract the status field from the JSON response into a variable called 'user_status' -->
<variable name="user_status" from="json" path="status"/>
</prompt>
<!-- Check the variable we just extracted -->
<if condition="{{user_status}} == 'active'">
<tool function="notify">
<param name="message">User is active, proceeding to next step.</param>
</tool>
<else>
<tool function="notify">
<param name="message">User is not active, aborting.</param>
</tool>
</else>
</if>
</poml>
XML;
// 3. Set up the Orchestration Engine
$engine = new OrchestrationEngine();
$parser = new PomlParser();
// 4. Register tools and connectors
$engine->registerTool('notify', 'send_notification');
// Use a DummyConnector that returns a valid JSON for this example.
class JsonDummyConnector extends DummyConnector {
public function execute(string $prompt): string {
return '{"name": "John Doe", "status": "active"}';
}
}
$engine->registerConnector('json-generator', new JsonDummyConnector());
/*
To use a real HTTP endpoint, you would do this instead:
$apiKey = getenv('OPENAI_API_KEY'); // It's best practice to use environment variables
$apiUrl = 'https://api.openai.com/v1/chat/completions';
$engine->registerConnector(
'gpt-4',
new HttpConnector($apiUrl, 'gpt-4', $apiKey)
);
*/
// 5. Parse and run the orchestration
try {
echo "Parsing POML...\n";
$orchestration = $parser->parse($pomlXml);
echo "Running orchestration...\n\n";
$finalResult = $engine->run($orchestration);
echo "\nOrchestration finished.\n";
echo "Final Result (from 'last_result'): " . print_r($finalResult, true) . "\n";
} catch (\Exception $e) {
echo "\nAn error occurred: " . $e->getMessage() . "\n";
echo "Trace: \n" . $e->getTraceAsString() . "\n";
}
?>
La salida esperada incluye la ejecución del POML analizado, notificación enviada y resultado final.
Mejores Prácticas
-
Variables de Entorno: Siempre usa `getenv()` para datos sensibles como claves de API para evitar hardcoding.
-
Validación de Entradas: En herramientas personalizadas, valida parámetros para prevenir ataques de inyección (por ejemplo, sanitiza strings).
-
Manejo de Errores: Envuelve `run()` en try-catch para manejar `EngineException` o `ParserException` de manera graceful.
-
Pruebas: Usa `DummyConnector` para pruebas unitarias; mockea respuestas para integración.
-
Escalabilidad: Para flujos complejos, divide en múltiples orquestaciones; monitorea el tamaño del estado para evitar problemas de memoria.
-
Diseño POML: Mantén el XML conciso; usa nombres de variables significativos; prueba condiciones exhaustivamente.
Notas sobre Seguridad y Vulnerabilidades
-
Vulnerabilidades Resueltas:
- Errores de Conectores: Anteriormente no manejados, los conectores faltantes ahora lanzan `EngineException`, previniendo fallos silenciosos.
- Problemas de Análisis: El análisis de XML usa `libxml_use_internal_errors(true)` para suprimir advertencias y lanza `ParserException` en estructura inválida, mitigando riesgos de inyección XML.
- Invocación de Herramientas: Los parámetros se resuelven pero no se ejecutan como código; usa tipos estrictos en herramientas para evitar errores de tipo.
-
Ineficiencias Corregidas:
- Optimización de Análisis: SimpleXML es ligero; no hay problemas de profundidad de análisis recursivo. La extracción de variables es solo de nivel superior para velocidad.
- Evaluación de Condiciones: Basada en regex para ops simples, evitando parsers de expresiones completos; no hay bucles infinitos ya que las ramas son lineales.
-
Consideraciones de Seguridad:
- Validación de Entradas: El XML POML debe ser confiable o sanitizado externamente; `resolve()` en StateManager reemplaza `{{var}}` pero no ejecuta código?extiende con filtros si es necesario.
- Claves de API: Nunca commitea claves; usa archivos `.env` (agrega a `.gitignore`).
- Manejo de JSON: `json_decode` con verificaciones de errores previene crashes por respuestas malformadas.
- Recomendaciones: Ejecuta en entornos aislados para POML no confiable; audita herramientas para efectos secundarios; usa HTTPS para `HttpConnector`.
Para contribuciones o problemas, por favor refiérete a la estructura de código en src/.
|