This entry is part 6 of 25 in the series Introducción a Microsoft Semantic Kernel

Introducción

El prompt engineering es el arte de diseñar instrucciones efectivas para modelos de lenguaje. Un buen prompt puede ser la diferencia entre resultados mediocres y excepcionales. En este tutorial aprenderás técnicas probadas para crear prompts efectivos.

Principios Fundamentales

1. Claridad y Especificidad

❌ Prompt vago:

Escribe sobre perros

✅ Prompt específico:

Escribe un artículo de 500 palabras sobre los beneficios de tener un perro como mascota, 
enfocándote en aspectos de salud mental, ejercicio físico y compañía.

2. Estructura Clara

var promptTemplate = """
CONTEXTO: Eres un experto en {{$dominio}}.

TAREA: {{$tarea}}

RESTRICCIONES:
- Máximo {{$maxPalabras}} palabras
- Usa ejemplos concretos
- Formato {{$formato}}

EJEMPLO:
{{$ejemplo}}
""";

3. Ejemplos (Few-Shot Learning)

var promptConEjemplos = """
Clasifica el sentimiento de estos mensajes como positivo, negativo o neutral.

Ejemplos:
- "Me encanta este producto" → positivo
- "No funciona bien" → negativo
- "Es de color azul" → neutral

Ahora clasifica: "{{$mensaje}}"
""";

Técnicas de Prompt Engineering

Chain-of-Thought (Cadena de Pensamiento)

Pedir al modelo que “piense paso a paso”:

var chainOfThoughtPrompt = """
Resuelve este problema paso a paso:

Problema: {{$problema}}

Piensa en voz alta y muestra tu razonamiento:
1. ¿Qué información tengo?
2. ¿Qué necesito calcular?
3. ¿Cómo lo resuelvo?
4. ¿Cuál es la respuesta final?
""";

Zero-Shot vs Few-Shot vs Many-Shot

// Zero-Shot: Sin ejemplos
var zeroShot = "Traduce al inglés: {{$texto}}";

// Few-Shot: Pocos ejemplos (2-5)
var fewShot = """
Traduce al inglés:
- "Hola" → "Hello"
- "Adiós" → "Goodbye"
- "{{$texto}}" → 
""";

// Many-Shot: Muchos ejemplos (10+)
var manyShot = """
Traduce al inglés:
- "Buenos días" → "Good morning"
- "Buenas tardes" → "Good afternoon"
- "Buenas noches" → "Good night"
- "Por favor" → "Please"
- "Gracias" → "Thank you"
- "De nada" → "You're welcome"
[... más ejemplos ...]
- "{{$texto}}" → 
""";

Role Prompting

Asignar un rol específico al modelo:

var rolePrompt = """
Eres un {{$rol}} con {{$experiencia}} años de experiencia.

Tu estilo de comunicación es:
- {{$estilo1}}
- {{$estilo2}}
- {{$estilo3}}

Responde a: {{$pregunta}}
""";

// Ejemplo concreto
var expertPrompt = """
Eres un arquitecto de software senior con 15 años de experiencia en sistemas distribuidos.

Tu estilo de comunicación es:
- Técnico pero accesible
- Usa ejemplos concretos
- Menciona trade-offs y consideraciones importantes

Responde a: ¿Cómo diseñarías un sistema de caché distribuido?
""";

Structured Output

Solicitar formato específico:

var structuredPrompt = """
Analiza el siguiente texto y responde en formato JSON:

{
  "resumen": "string (máximo 100 palabras)",
  "temas_principales": ["string"],
  "sentimiento": "positivo|negativo|neutral",
  "entidades": [{"nombre": "string", "tipo": "string"}],
  "palabras_clave": ["string"]
}

Texto: {{$texto}}
""";

Patrones Avanzados

Template Method Pattern

public abstract class PromptTemplate
{
    public string Build(Dictionary<string, string> variables)
    {
        var prompt = GetSystemMessage();
        prompt += "\n\n" + GetTaskDescription(variables);
        prompt += "\n\n" + GetConstraints();
        prompt += "\n\n" + GetExamples();
        prompt += "\n\n" + GetUserInput(variables);
        
        return prompt;
    }
    
    protected abstract string GetSystemMessage();
    protected abstract string GetTaskDescription(Dictionary<string, string> variables);
    protected abstract string GetConstraints();
    protected abstract string GetExamples();
    protected abstract string GetUserInput(Dictionary<string, string> variables);
}

public class ClassificationPromptTemplate : PromptTemplate
{
    protected override string GetSystemMessage()
    {
        return "Eres un clasificador experto que analiza texto y lo categoriza con precisión.";
    }
    
    protected override string GetTaskDescription(Dictionary<string, string> variables)
    {
        return $"Clasifica el siguiente texto en una de estas categorías: {variables["categories"]}";
    }
    
    protected override string GetConstraints()
    {
        return """
        REGLAS:
        - Selecciona solo UNA categoría
        - Justifica tu decisión brevemente
        - Si no estás seguro, indica tu nivel de confianza
        """;
    }
    
    protected override string GetExamples()
    {
        return """
        EJEMPLOS:
        Texto: "Necesito un fontanero urgente"
        Categoría: servicios_hogar
        Confianza: 95%
        
        Texto: "¿Dónde puedo comprar pan?"
        Categoría: alimentación
        Confianza: 90%
        """;
    }
    
    protected override string GetUserInput(Dictionary<string, string> variables)
    {
        return $"Texto a clasificar: {variables["text"]}";
    }
}

Prompt Chaining

Encadenar múltiples prompts para tareas complejas:

public class PromptChainService
{
    private readonly Kernel _kernel;
    
    public async Task<string> AnalyzeArticleAsync(string article)
    {
        // Paso 1: Extraer temas principales
        var topicsPrompt = $"""
        Extrae los 3 temas principales de este artículo.
        Responde solo con la lista de temas, uno por línea.
        
        Artículo: {article}
        """;
        
        var topics = await InvokePromptAsync(topicsPrompt);
        
        // Paso 2: Resumir cada tema
        var summaries = new List<string>();
        foreach (var topic in topics.Split('\n'))
        {
            var summaryPrompt = $"""
            Resume cómo se trata el tema "{topic}" en el siguiente artículo.
            Usa máximo 50 palabras.
            
            Artículo: {article}
            """;
            
            var summary = await InvokePromptAsync(summaryPrompt);
            summaries.Add($"{topic}: {summary}");
        }
        
        // Paso 3: Crear resumen ejecutivo
        var executiveSummaryPrompt = $"""
        Basándote en estos resúmenes por tema, crea un resumen ejecutivo del artículo.
        
        {string.Join("\n\n", summaries)}
        """;
        
        return await InvokePromptAsync(executiveSummaryPrompt);
    }
    
    private async Task<string> InvokePromptAsync(string prompt)
    {
        var function = _kernel.CreateFunctionFromPrompt(prompt);
        var result = await _kernel.InvokeAsync(function);
        return result.GetValue<string>() ?? "";
    }
}

Self-Consistency

Generar múltiples respuestas y tomar la más común:

public class SelfConsistentService
{
    private readonly Kernel _kernel;
    
    public async Task<string> GetConsistentAnswerAsync(
        string question,
        int iterations = 5)
    {
        var answers = new List<string>();
        
        var prompt = $"""
        Responde la siguiente pregunta:
        
        {question}
        
        Piensa paso a paso y proporciona tu respuesta final.
        """;
        
        // Generar múltiples respuestas con temperatura alta
        for (int i = 0; i < iterations; i++)
        {
            var settings = new OpenAIPromptExecutionSettings
            {
                Temperature = 0.8
            };
            
            var function = _kernel.CreateFunctionFromPrompt(prompt, settings);
            var result = await _kernel.InvokeAsync(function);
            answers.Add(result.GetValue<string>() ?? "");
        }
        
        // Encontrar respuesta más común o consenso
        return FindConsensus(answers);
    }
    
    private string FindConsensus(List<string> answers)
    {
        // Implementación simplificada: retornar la más frecuente
        return answers
            .GroupBy(a => a)
            .OrderByDescending(g => g.Count())
            .First()
            .Key;
    }
}

Anti-Patrones (Qué Evitar)

❌ Prompts Ambiguos

// MAL
var malPrompt = "Háblame de eso";

// BIEN
var buenPrompt = """
Proporciona una explicación detallada sobre {{$tema}}, incluyendo:
1. Definición
2. Casos de uso principales
3. Ventajas y desventajas
4. Ejemplo práctico
""";

❌ Instrucciones Contradictorias

// MAL: Instrucciones que se contradicen
var contradictorio = """
Sé muy breve pero incluye todos los detalles posibles.
""";

// BIEN: Instrucciones claras y coherentes
var claro = """
Proporciona un resumen ejecutivo de 200 palabras que destaque 
los 3 puntos más importantes.
""";

❌ Formato Inconsistente

// MAL
var inconsistente = """
dame info sobre:
Tema: {{$tema}}
quiero saber todo
formato: lista
""";

// BIEN
var consistente = """
TEMA: {{$tema}}

FORMATO REQUERIDO:
- Lista con viñetas
- Máximo 5 puntos
- Cada punto: 1-2 oraciones

PROFUNDIDAD:
Proporciona información intermedia, adecuada para alguien con 
conocimientos básicos del tema.
""";

Prompts para Casos de Uso Comunes

Clasificación

var classificationPrompt = """
Clasifica el siguiente mensaje según su intención.

CATEGORÍAS POSIBLES:
- pregunta: El usuario hace una pregunta
- queja: El usuario expresa insatisfacción
- elogio: El usuario expresa satisfacción
- solicitud: El usuario pide algo específico
- otro: No encaja en las categorías anteriores

REGLAS:
1. Responde con UNA sola palabra (el nombre de la categoría)
2. Si hay duda entre dos, elige la más específica

MENSAJE: {{$mensaje}}

CATEGORÍA:
""";

Extracción de Información

var extractionPrompt = """
Extrae información estructurada del siguiente texto.

INFORMACIÓN A EXTRAER:
- Nombre de persona(s)
- Fechas
- Ubicaciones
- Organizaciones
- Números de contacto

FORMATO DE SALIDA:
{
  "personas": ["string"],
  "fechas": ["string"],
  "ubicaciones": ["string"],
  "organizaciones": ["string"],
  "contactos": ["string"]
}

Si no encuentras información de algún tipo, usa un array vacío [].

TEXTO: {{$texto}}

JSON:
""";

Generación Creativa

var creativePrompt = """
Genera {{$tipo}} con las siguientes características:

ESTILO: {{$estilo}}
TONO: {{$tono}}
LONGITUD: {{$longitud}} palabras
AUDIENCIA: {{$audiencia}}

REQUISITOS:
- Original y creativo
- Apropiado para la audiencia
- Mantén el tono consistente
{{#if incluir_ejemplos}}
- Incluye ejemplos concretos
{{/if}}

TEMA: {{$tema}}

{{$tipo}}:
""";

Análisis y Resumen

var analysisPrompt = """
Analiza el siguiente contenido y proporciona:

1. RESUMEN (100 palabras máximo)
   - Idea principal
   - Puntos clave

2. ANÁLISIS
   - Fortalezas del contenido
   - Debilidades o áreas de mejora
   - Público objetivo

3. RECOMENDACIONES
   - 3 sugerencias específicas de mejora

CONTENIDO:
{{$contenido}}

---

ANÁLISIS:
""";

Testing de Prompts

public class PromptTester
{
    private readonly Kernel _kernel;
    
    public async Task<PromptTestResult> TestPromptAsync(
        string promptTemplate,
        Dictionary<string, string> testCases)
    {
        var results = new List<TestCase>();
        
        foreach (var testCase in testCases)
        {
            var prompt = promptTemplate.Replace("{{$input}}", testCase.Value);
            
            var function = _kernel.CreateFunctionFromPrompt(prompt);
            var result = await _kernel.InvokeAsync(function);
            var output = result.GetValue<string>() ?? "";
            
            results.Add(new TestCase
            {
                Input = testCase.Value,
                Output = output,
                Expected = testCase.Key
            });
        }
        
        return new PromptTestResult
        {
            TestCases = results,
            SuccessRate = CalculateSuccessRate(results)
        };
    }
    
    private double CalculateSuccessRate(List<TestCase> results)
    {
        // Implementar lógica de evaluación
        return 0.0;
    }
}

public class TestCase
{
    public required string Input { get; init; }
    public required string Output { get; init; }
    public required string Expected { get; init; }
}

public class PromptTestResult
{
    public required List<TestCase> TestCases { get; init; }
    public double SuccessRate { get; init; }
}

Optimización de Prompts

A/B Testing

public class PromptOptimizer
{
    private readonly Kernel _kernel;
    
    public async Task<string> FindBestPromptAsync(
        List<string> promptVariants,
        List<string> testInputs)
    {
        var scores = new Dictionary<string, double>();
        
        foreach (var prompt in promptVariants)
        {
            var totalScore = 0.0;
            
            foreach (var input in testInputs)
            {
                var result = await TestPromptWithInputAsync(prompt, input);
                totalScore += result.Quality;
            }
            
            scores[prompt] = totalScore / testInputs.Count;
        }
        
        return scores.OrderByDescending(kvp => kvp.Value).First().Key;
    }
    
    private async Task<(string Output, double Quality)> TestPromptWithInputAsync(
        string prompt,
        string input)
    {
        // Implementar testing y scoring
        return ("", 0.0);
    }
}

Iteración Basada en Feedback

public class PromptIterator
{
    public string ImprovePrompt(
        string originalPrompt,
        List<PromptFeedback> feedbacks)
    {
        var improvements = new List<string>();
        
        // Analizar feedback común
        var commonIssues = feedbacks
            .SelectMany(f => f.Issues)
            .GroupBy(i => i)
            .OrderByDescending(g => g.Count())
            .Take(3)
            .Select(g => g.Key);
        
        foreach (var issue in commonIssues)
        {
            improvements.Add(GetImprovementForIssue(issue));
        }
        
        return ApplyImprovements(originalPrompt, improvements);
    }
    
    private string GetImprovementForIssue(string issue)
    {
        return issue switch
        {
            "too_vague" => "Agregar más especificidad y ejemplos",
            "inconsistent" => "Estandarizar formato y estructura",
            "too_long" => "Simplificar y reducir instrucciones",
            _ => "Revisar claridad general"
        };
    }
    
    private string ApplyImprovements(string prompt, List<string> improvements)
    {
        // Implementar lógica de mejora
        return prompt;
    }
}

public class PromptFeedback
{
    public required string PromptVersion { get; init; }
    public required List<string> Issues { get; init; }
    public int Rating { get; init; }
}

Mejores Prácticas Resumidas

1. Estructura

  • Usa secciones claramente delimitadas
  • Instrucciones antes de datos
  • Formato consistente

2. Claridad

  • Sé específico sobre lo que quieres
  • Proporciona ejemplos cuando sea útil
  • Define el formato de salida esperado

3. Contexto

  • Da contexto relevante al modelo
  • Define el rol o perspectiva
  • Establece restricciones claras

4. Testing

  • Prueba con múltiples entradas
  • Itera basándote en resultados
  • Mantén registro de versiones

5. Temperatura

  • Baja (0.0-0.3) para tareas determinísticas
  • Media (0.4-0.7) para balance
  • Alta (0.8-1.0) para creatividad

Conclusión

El prompt engineering es una habilidad esencial para trabajar efectivamente con LLMs. Buenos prompts son claros, estructurados y específicos. La práctica y la iteración basada en resultados te ayudarán a crear prompts cada vez más efectivos. Recuerda que no existe un “prompt perfecto” universal – cada caso de uso requiere adaptación y optimización.


Palabras clave: prompt engineering, LLM, GPT, Azure OpenAI, few-shot learning, chain-of-thought, structured output

Share this content:

Introducción a Microsoft Semantic Kernel

. Vector Embeddings y Búsqueda Semántica con .NET . Integración de Azure OpenAI en Aplicaciones .NET

por David Cantón Nadales

David Cantón Nadales, ingeniero de software de Sevilla, España, es autor del bestseller Build Your own Metaverse with Unity. Reconocido como Microsoft MVP y Top Voices en Aplicaciones Móviles de LinkedIn. Con más de 20 años de experiencia, David ha liderado cientos proyectos a lo largo de su carrera, incluyendo videojuegos y aplicaciones de realidad virtual y aumentada con Oculus, Hololens, HTC Vive, DayDream y LeapMotion. Ha trabajado como Tech Lead en importantes multinacionales como Grupo Viajes El Corte Inglés y actualmente en SCRM Lidl del Grupo Schwarz. Fue embajador de la comunidad Samsung Dev Spain y organizador del Google Developers Group Sevilla. Durante el confinamiento por COVID-19, destacó como emprendedor social con la creación de Grita, una red social que facilitaba el apoyo psicológico entre personas. En 2022, ganó los Samsung Top Developers Awards.