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

Introducción

Los parámetros de configuración de LLMs como temperatura, max_tokens, top_p controlan el comportamiento y la calidad de las respuestas. En este tutorial aprenderás a configurar estos parámetros para diferentes casos de uso.

Parámetros Principales

Temperature (0.0 – 2.0)

Controla la aleatoriedad de las respuestas:

// Determinístico (misma respuesta siempre)
var settingsDeterminista = new OpenAIPromptExecutionSettings
{
    Temperature = 0.0  
};

// Balanceado
var settingsBalanceado = new OpenAIPromptExecutionSettings
{
    Temperature = 0.7
};

// Muy creativo
var settingsCreativo = new OpenAIPromptExecutionSettings
{
    Temperature = 1.5
};

Casos de uso:
0.0-0.3: Clasificación, extracción de datos, respuestas precisas
0.4-0.7: Conversaciones naturales, asistentes
0.8-1.2: Contenido creativo, brainstorming
1.3-2.0: Muy experimental (raramente usado)

Max Tokens

Limita la longitud de la respuesta:

var settings = new OpenAIPromptExecutionSettings
{
    MaxTokens = 150  // Aproximadamente 100-120 palabras
};

// Reglas generales:
// - 1 token ≈ 0.75 palabras en inglés
// - 1 token ≈ 0.6 palabras en español
// - GPT-4: max 8,192 tokens (entrada + salida)
// - GPT-4-32k: max 32,768 tokens

Top P (Nucleus Sampling)

Controla la diversidad considerando probabilidad acumulativa:

var settings = new OpenAIPromptExecutionSettings
{
    TopP = 0.9  // Considera tokens que suman hasta 90% de probabilidad
};

// Valores típicos:
// - 0.1: Muy conservador
// - 0.9: Estándar (recomendado)
// - 1.0: Considera todas las opciones

Nota: Generalmente se usa temperature O top_p, no ambos.

Frequency Penalty y Presence Penalty

var settings = new OpenAIPromptExecutionSettings
{
    FrequencyPenalty = 0.5f,  // Reduce repetición de tokens frecuentes (-2.0 a 2.0)
    PresencePenalty = 0.5f    // Fomenta temas nuevos (-2.0 a 2.0)
};

// Frequency Penalty: Penaliza por frecuencia de uso
// Presence Penalty: Penaliza por presencia (sí/no), sin importar frecuencia

Configuraciones por Caso de Uso

1. Clasificación/Categorización

var classificationSettings = new OpenAIPromptExecutionSettings
{
    Temperature = 0.1,       // Muy baja para consistencia
    MaxTokens = 50,          // Respuestas cortas
    TopP = 0.1,              // Muy conservador
    FrequencyPenalty = 0,
    PresencePenalty = 0
};

var prompt = """
Clasifica el siguiente texto en una de estas categorías: deportes, tecnología, política.

Texto: {{$text}}

Categoría:
""";

2. Chat Conversacional

var chatSettings = new OpenAIPromptExecutionSettings
{
    Temperature = 0.7,       // Balance entre creatividad y coherencia
    MaxTokens = 500,         // Respuestas medianas
    TopP = 0.9,
    FrequencyPenalty = 0.3f, // Evitar repetición moderada
    PresencePenalty = 0.3f   // Fomentar variedad
};

3. Generación Creativa

var creativeSettings = new OpenAIPromptExecutionSettings
{
    Temperature = 0.9,       // Alta creatividad
    MaxTokens = 1000,        // Respuestas largas
    TopP = 0.95,
    FrequencyPenalty = 0.5f,
    PresencePenalty = 0.5f
};

4. Extracción de Información

var extractionSettings = new OpenAIPromptExecutionSettings
{
    Temperature = 0.0,       // Determinístico
    MaxTokens = 200,
    ResponseFormat = "json_object", // Formato estructurado
    FrequencyPenalty = 0,
    PresencePenalty = 0
};

5. Resumen de Texto

var summarySettings = new OpenAIPromptExecutionSettings
{
    Temperature = 0.3,       // Baja, pero permite algo de variación
    MaxTokens = 300,
    TopP = 0.8,
    FrequencyPenalty = 0.2f,
    PresencePenalty = 0.2f
};

6. Código/Programación

var codeSettings = new OpenAIPromptExecutionSettings
{
    Temperature = 0.2,       // Preciso pero con algo de flexibilidad
    MaxTokens = 1500,
    TopP = 0.9,
    FrequencyPenalty = 0,
    PresencePenalty = 0
};

Servicio de Configuración Dinámica

public class LLMConfigurationService
{
    public enum TaskType
    {
        Classification,
        Conversation,
        Creative,
        Extraction,
        Summary,
        Code,
        Translation
    }

    public OpenAIPromptExecutionSettings GetSettingsForTask(TaskType taskType)
    {
        return taskType switch
        {
            TaskType.Classification => new OpenAIPromptExecutionSettings
            {
                Temperature = 0.1f,
                MaxTokens = 50,
                TopP = 0.1f,
                FrequencyPenalty = 0,
                PresencePenalty = 0
            },

            TaskType.Conversation => new OpenAIPromptExecutionSettings
            {
                Temperature = 0.7f,
                MaxTokens = 500,
                TopP = 0.9f,
                FrequencyPenalty = 0.3f,
                PresencePenalty = 0.3f
            },

            TaskType.Creative => new OpenAIPromptExecutionSettings
            {
                Temperature = 0.9f,
                MaxTokens = 1000,
                TopP = 0.95f,
                FrequencyPenalty = 0.5f,
                PresencePenalty = 0.5f
            },

            TaskType.Extraction => new OpenAIPromptExecutionSettings
            {
                Temperature = 0.0f,
                MaxTokens = 200,
                ResponseFormat = "json_object",
                FrequencyPenalty = 0,
                PresencePenalty = 0
            },

            TaskType.Summary => new OpenAIPromptExecutionSettings
            {
                Temperature = 0.3f,
                MaxTokens = 300,
                TopP = 0.8f,
                FrequencyPenalty = 0.2f,
                PresencePenalty = 0.2f
            },

            TaskType.Code => new OpenAIPromptExecutionSettings
            {
                Temperature = 0.2f,
                MaxTokens = 1500,
                TopP = 0.9f,
                FrequencyPenalty = 0,
                PresencePenalty = 0
            },

            TaskType.Translation => new OpenAIPromptExecutionSettings
            {
                Temperature = 0.3f,
                MaxTokens = 1000,
                TopP = 0.9f,
                FrequencyPenalty = 0,
                PresencePenalty = 0
            },

            _ => new OpenAIPromptExecutionSettings
            {
                Temperature = 0.7f,
                MaxTokens = 500
            }
        };
    }
}

Estimación de Tokens

public class TokenEstimator
{
    // Estimación aproximada (no exacta)
    public int EstimateTokens(string text)
    {
        // Regla simple: ~1.3 caracteres por token en español
        return (int)Math.Ceiling(text.Length / 1.3);
    }

    public bool WillFitInContext(string prompt, string response, int maxContextTokens = 8192)
    {
        var promptTokens = EstimateTokens(prompt);
        var responseTokens = EstimateTokens(response);

        return (promptTokens + responseTokens) < maxContextTokens;
    }

    public int CalculateMaxResponseTokens(string prompt, int maxContextTokens = 8192, int safetyMargin = 100)
    {
        var promptTokens = EstimateTokens(prompt);
        return Math.Max(0, maxContextTokens - promptTokens - safetyMargin);
    }
}

Optimización de Costos

public class CostOptimizedLLMService
{
    private readonly Kernel _kernel;
    private readonly TokenEstimator _tokenEstimator;

    public async Task<string> GenerateWithCostLimitAsync(
        string prompt,
        int maxCostTokens = 1000)
    {
        var estimatedPromptTokens = _tokenEstimator.EstimateTokens(prompt);
        var remainingTokens = maxCostTokens - estimatedPromptTokens;

        if (remainingTokens <= 0)
        {
            throw new InvalidOperationException("Prompt excede límite de costo");
        }

        var settings = new OpenAIPromptExecutionSettings
        {
            Temperature = 0.7f,
            MaxTokens = Math.Min(remainingTokens, 500) // Limitar respuesta
        };

        var function = _kernel.CreateFunctionFromPrompt(prompt, settings);
        var result = await _kernel.InvokeAsync(function);

        return result.GetValue<string>() ?? string.Empty;
    }
}

Testing de Configuraciones

public class SettingsTester
{
    private readonly Kernel _kernel;

    public async Task<SettingsTestResult> TestSettingsAsync(
        string prompt,
        List<OpenAIPromptExecutionSettings> settingsVariations,
        int iterations = 3)
    {
        var results = new List<TestIteration>();

        foreach (var settings in settingsVariations)
        {
            var responses = new List<string>();

            for (int i = 0; i < iterations; i++)
            {
                var function = _kernel.CreateFunctionFromPrompt(prompt, settings);
                var result = await _kernel.InvokeAsync(function);
                responses.Add(result.GetValue<string>() ?? "");
            }

            results.Add(new TestIteration
            {
                Settings = settings,
                Responses = responses,
                Consistency = CalculateConsistency(responses),
                AverageLength = responses.Average(r => r.Length)
            });
        }

        return new SettingsTestResult
        {
            Iterations = results,
            BestSettings = results.OrderByDescending(r => r.Consistency).First().Settings
        };
    }

    private double CalculateConsistency(List<string> responses)
    {
        // Implementación simplificada
        if (responses.Count < 2) return 1.0;

        var firstLength = responses[0].Length;
        var variance = responses.Average(r => Math.Abs(r.Length - firstLength));

        return 1.0 - (variance / firstLength);
    }
}

public class TestIteration
{
    public required OpenAIPromptExecutionSettings Settings { get; init; }
    public required List<string> Responses { get; init; }
    public double Consistency { get; init; }
    public double AverageLength { get; init; }
}

public class SettingsTestResult
{
    public required List<TestIteration> Iterations { get; init; }
    public required OpenAIPromptExecutionSettings BestSettings { get; init; }
}

Monitoreo de Configuraciones

public class SettingsMonitor
{
    private readonly Dictionary<string, SettingsMetrics> _metrics = new();

    public void TrackRequest(
        string configName,
        OpenAIPromptExecutionSettings settings,
        int promptTokens,
        int completionTokens,
        TimeSpan latency)
    {
        if (!_metrics.ContainsKey(configName))
        {
            _metrics[configName] = new SettingsMetrics { ConfigName = configName };
        }

        var metrics = _metrics[configName];
        metrics.TotalRequests++;
        metrics.TotalPromptTokens += promptTokens;
        metrics.TotalCompletionTokens += completionTokens;
        metrics.TotalLatencyMs += latency.TotalMilliseconds;
        metrics.LastUsed = DateTime.UtcNow;
    }

    public SettingsMetrics GetMetrics(string configName)
    {
        return _metrics.GetValueOrDefault(configName) ?? new SettingsMetrics { ConfigName = configName };
    }

    public List<SettingsMetrics> GetAllMetrics()
    {
        return _metrics.Values.OrderByDescending(m => m.TotalRequests).ToList();
    }
}

public class SettingsMetrics
{
    public required string ConfigName { get; init; }
    public long TotalRequests { get; set; }
    public long TotalPromptTokens { get; set; }
    public long TotalCompletionTokens { get; set; }
    public double TotalLatencyMs { get; set; }
    public DateTime? LastUsed { get; set; }

    public double AveragePromptTokens => TotalRequests > 0 ? (double)TotalPromptTokens / TotalRequests : 0;
    public double AverageCompletionTokens => TotalRequests > 0 ? (double)TotalCompletionTokens / TotalRequests : 0;
    public double AverageLatencyMs => TotalRequests > 0 ? TotalLatencyMs / TotalRequests : 0;
}

Mejores Prácticas

1. Comenzar Conservador

// ✅ Empezar con settings conservadores
var initialSettings = new OpenAIPromptExecutionSettings
{
    Temperature = 0.5f,  // Medio
    MaxTokens = 300      // Moderado
};

// Ajustar basándose en resultados

2. Documentar Configuraciones

/// <summary>
/// Configuración para clasificación de tickets de soporte.
/// Temperature baja (0.1) para consistencia en categorías.
/// MaxTokens limitado (50) ya que solo necesitamos nombre de categoría.
/// </summary>
var ticketClassificationSettings = new OpenAIPromptExecutionSettings
{
    Temperature = 0.1f,
    MaxTokens = 50
};

3. A/B Testing

public async Task<string> ABTestSettingsAsync(string prompt)
{
    var settingsA = new OpenAIPromptExecutionSettings { Temperature = 0.5f };
    var settingsB = new OpenAIPromptExecutionSettings { Temperature = 0.7f };

    // Alternar entre configuraciones y medir resultados
    var useA = Random.Shared.Next(2) == 0;
    var settings = useA ? settingsA : settingsB;

    // Trackear qué configuración se usó
    TrackConfigUsage(useA ? "A" : "B");

    var function = _kernel.CreateFunctionFromPrompt(prompt, settings);
    return (await _kernel.InvokeAsync(function)).GetValue<string>() ?? "";
}

Conclusión

La configuración correcta de temperatura, tokens y otros parámetros es crucial para obtener resultados óptimos de LLMs. Cada caso de uso requiere un balance diferente entre creatividad, consistencia y costo. Experimenta con diferentes configuraciones, mide resultados, y ajusta basándote en datos reales.


Palabras clave: LLM configuration, temperature, tokens, top_p, GPT-4, prompt settings, OpenAI parameters

Share this content:

Introducción a Microsoft Semantic Kernel

. Integración de Azure OpenAI en Aplicaciones .NET . Estrategias de Caché para Servicios de IA

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.