Ir al contenido
wannacode

Costo y latencia: presupuesto, caché, un modelo más pequeño

En resumen: El costo de un modelo de lenguaje es tokens × precio, por separado para la entrada y para la salida; un presupuesto de tokens, una caché de respuestas y un modelo más pequeño bajan la cuenta, y la caché y el modelo más pequeño también reducen el tiempo de respuesta.

Problema

La cuenta a fin de mes

El asistente de soporte lleva un mes funcionando. Responde bien, y el conjunto de pruebas de la lección sobre la evaluación pasa. Entonces llegan dos quejas: la cuenta del modelo es más alta de lo esperado, y los clientes esperan cerca de un segundo por una respuesta.

Aquí está una llamada tal como la hace el asistente. Los precios de los tokens son ejemplos, en euros por millón de tokens:

var question = "¿Cuánto cuesta el envío?";
var r = client.Create(large, 1024, prompt + " " + allDocs, [new Message("user", question)]);
var m = models[large];
var euro = Cost(m, r.Usage);
var input = r.Usage.InputTokens * m.InPrice / 1_000_000;
Console.WriteLine($"entrada: {r.Usage.InputTokens} tokens, salida: {r.Usage.OutputTokens} tokens");
Console.WriteLine($"costo: {euro:F5} € (la entrada es {100 * input / euro:F0}%)");
Console.WriteLine($"tiempo de ejemplo: {Latency(m, r.Usage)} ms");
Salida
entrada: 386 tokens, salida: 40 tokens
costo: 0.00218 € (la entrada es 71%)
tiempo de ejemplo: 1238 ms

La pregunta «¿Cuánto cuesta el envío?» tiene 8 tokens, y la entrada tiene 386. Una parte de la cuenta es la respuesta, y la parte mayor es la entrada: el prompt de sistema y todos los documentos de la tienda viajan con cada pregunta. Y en el registro la mitad de las preguntas son iguales: cuánto cuesta el envío, cuándo atiende soporte.

La idea

A dónde van el dinero y el tiempo

Un modelo se paga por tokens (la lección sobre los tokens), por separado la entrada y la salida:

  • la entrada es todo lo que envías: el prompt de sistema, los documentos, el historial de la conversación, la pregunta. La API no tiene memoria, así que todo eso se envía cada vez (la lección sobre el contexto);
  • la salida es la respuesta. Un token de salida suele costar varias veces más que uno de entrada, aquí 4 veces.

Con el tiempo pasa algo parecido, con otro equilibrio. El modelo lee la entrada rápido y escribe la respuesta token a token. Así que una respuesta larga es lenta, y una entrada larga sobre todo es cara.

De ahí salen las tres soluciones que la lección mide con un programa:

  1. un presupuesto de tokens: menos entrada (solo lo necesario) y un tope para la salida;
  2. una caché: la misma pregunta no llega al modelo;
  3. un modelo más pequeño para las preguntas fáciles: un token más barato y más rápido.

Un presupuesto de tokens es un límite superior de tokens para una llamada, planeado de antemano, igual que planeas la memoria o el tiempo de respuesta de una petición.

Míralo

El asistente en código

El cliente falso es el mismo que en la lección sobre la evaluación: la forma de la API real, respuestas grabadas y tokens aproximados (cada palabra son 2 tokens). Las respuestas se graban según una palabra de la pregunta:

// un cliente falso: la forma de la API real, las respuestas están grabadas
record Message(string Role, string Content);
record Usage(int InputTokens, int OutputTokens);
record Response(string Text, string StopReason, Usage Usage);
// una respuesta grabada: modelo ("" = cualquiera), una palabra de la pregunta, texto que necesita el prompt
record Recorded(string Model, string Keyword, string Needs, string Text);
class FakeLlm(List<Recorded> recorded)
{
// a grandes rasgos: cada palabra son 2 tokens
public static int Tokens(string text) =>
2 * text.Split([' ', '\n'], StringSplitOptions.RemoveEmptyEntries).Length;
public Response Create(string model, int maxTokens, string system, List<Message> messages)
{
var question = messages[^1].Content;
var input = Tokens(system) + messages.Sum(m => Tokens(m.Content));
foreach (var r in recorded)
{
var forModel = r.Model == "" || r.Model == model;
if (forModel && question.Contains(r.Keyword) && system.Contains(r.Needs))
return Reply(r.Text, maxTokens, input);
}
return Reply("(no hay respuesta grabada)", maxTokens, input);
}
// max_tokens corta la respuesta
static Response Reply(string text, int maxTokens, int input)
{
var words = text.Split(' ');
if (2 * words.Length <= maxTokens)
return new Response(text, "end_turn", new Usage(input, 2 * words.Length));
var kept = maxTokens / 2;
var cut = string.Join(' ', words[..kept]);
return new Response(cut, "max_tokens", new Usage(input, 2 * kept));
}
}
List<Recorded> recorded =
[
new("", "cuesta", "", "El envío a domicilio cuesta 4,90 €, a una oficina 3,50 €, y a partir de 50 € es gratis."),
new("", "reembolso", "", "Sí, se puede pagar contra reembolso. La comisión es de 1,50 €."),
new("", "devolver", "", "Puedes devolver la mercancía hasta 14 días después de la entrega si está sin usar y con la etiqueta."),
new("", "atiende", "", "Soporte atiende de lunes a viernes, de 9 a 18 h."),
new("", "1042", "", "El pedido 1042 ya salió y llega el jueves."),
new("", "1077", "", "El pedido 1077 se está preparando y sale mañana."),
new("", "dañado", "", "¡Lo siento! Hazle una foto al paquete y a la etiqueta y escríbenos con el número del pedido. Te enviaremos uno nuevo o te devolveremos el dinero en un plazo de 5 días hábiles."),
new("", "días", "", "Los paquetes llegan en 2 a 4 días hábiles."),
new("", "por mayor", "", "No lo sé, te paso con un compañero."),
new("", "Mastercard", "", "Sí, aceptamos Visa y Mastercard."),
];

Los documentos de la tienda son cinco secciones. Cada una tiene palabras que la identifican:

var prompt = "Eres el asistente de soporte de una tienda en línea. Responde con brevedad y solo a partir de los documentos. Si la respuesta no está, di: «No lo sé, te paso con un compañero.»";
List<Doc> docs =
[
new(["envío", "paquete"], "Envío: los paquetes llegan en 2 a 4 días hábiles. El envío a domicilio cuesta 4,90 €, a una oficina de mensajería 3,50 €, y a partir de 50 € es gratis. Un paquete se sigue por su número."),
new(["devol", "dañado"], "Devoluciones: la mercancía se puede devolver hasta 14 días después de la entrega si está sin usar y con la etiqueta. Un paquete dañado se fotografía y se avisa a soporte. El dinero vuelve a la tarjeta en un plazo de 5 días hábiles."),
new(["pag", "tarjeta", "mastercard"], "Pago: aceptamos Visa y Mastercard. El pago contra reembolso tiene una comisión de 1,50 €. El pago con tarjeta está protegido y el importe se cobra cuando se confirma el pedido."),
new(["pedido"], "Pedidos: el estado de un pedido se ve en el perfil. Soporte revisa un pedido solo por su número y nunca pide los datos de la tarjeta."),
new(["atiende", "horario"], "Soporte: trabajamos de lunes a viernes, de 9 a 18 h. Escríbenos a help@shop.example."),
];
var allDocs = string.Join(" ", docs.Select(doc => doc.Text));
// una sección de los documentos y las palabras que la identifican
record Doc(List<string> Triggers, string Text);

Los modelos, los precios y los tiempos. Todos los números de aquí son ejemplos, y el tiempo sale de una fórmula, no está medido:

// precios de ejemplo en € por 1 000 000 de tokens y tiempo de ejemplo (no medidos)
const string large = "model-large", small = "model-small";
var models = new Dictionary<string, ModelInfo>
{
[large] = new(4.00, 16.00, 400, 10, 20),
[small] = new(0.40, 1.60, 150, 40, 5),
};
const int cacheMs = 5;
record ModelInfo(double InPrice, double OutPrice, int BaseMs, int InputPerMs, int MsPerToken);
// el costo de una llamada en €
static double Cost(ModelInfo m, Usage u) =>
(u.InputTokens * m.InPrice + u.OutputTokens * m.OutPrice) / 1_000_000;
// tiempo de ejemplo en ms: inicio + leer la entrada + generar
static int Latency(ModelInfo m, Usage u) =>
m.BaseMs + u.InputTokens / m.InputPerMs + u.OutputTokens * m.MsPerToken;

La respuesta para el pedido 1042 está grabada. En el asistente real el estado viene de una herramienta (la lección sobre las herramientas).

1_000_000 es lo mismo que 1000000. u.InputTokens / m.InputPerMs es una división entera y descarta el resto.

Pruébalo

Completa

El costo es los tokens de entrada por el precio de entrada más los tokens de salida por…

(u.InputTokens * m.InPrice + u.OutputTokens * ) / 1_000_000;

Míralo

Un día

Un día en soporte es una muestra de 20 preguntas. Algunas se repiten, a veces en minúsculas o con un espacio de más. Tres son sobre un pedido concreto:

List<string> questions =
[
"¿Cuánto cuesta el envío?",
"¿Cuándo atiende soporte?",
"¿Dónde está el pedido 1042?",
"¿cuánto cuesta el envío?",
"¿Puedo pagar contra reembolso?",
"¿Hasta cuándo puedo devolver la mercancía?",
"¿Cuánto cuesta el envío?",
"Mi paquete llegó dañado, ¿qué hago?",
"¿Cuándo atiende soporte?",
"¿Dónde está el pedido 1077?",
"¿Aceptan Mastercard?",
"¿Cuánto cuesta el envío? ",
"¿Cuántos días tarda un paquete a Monterrey?",
"¿Puedo pagar contra reembolso?",
"¿Venden al por mayor?",
"¿Hasta cuándo puedo devolver la mercancía?",
"¿Dónde está el pedido 1042?",
"¿Cuándo atiende soporte?",
"¿Cuánto cuesta el envío a una oficina?",
"¿Cómo puedo devolver la mercancía?",
];

day recorre las preguntas y suma el costo y el tiempo. Las tres banderas activan las tres soluciones, y por ahora están apagadas:

Totals Day(List<string> questions, bool budget,
bool cache, bool route)
{
var answers = new Dictionary<string, string>();
double euro = 0;
int ms = 0, hits = 0, onSmall = 0;
foreach (var question in questions)
{
var k = Key(question);
// acierto: sin modelo
if (cache && answers.ContainsKey(k))
{
hits++;
ms += cacheMs;
continue;
}
var model = route ? PickModel(question) : large;
var docs = budget ? Relevant(question) : allDocs;
var maxTokens = budget ? 200 : 1024;
var msg = new Message("user", question);
var r = client.Create(model, maxTokens,
prompt + " " + docs, [msg]);
var m = models[model];
euro += Cost(m, r.Usage);
ms += Latency(m, r.Usage);
if (model == small) onSmall++;
// un pedido es de un cliente: sin caché
if (cache && !k.Contains("pedido"))
answers[k] = r.Text;
}
return new Totals(euro, ms, hits, onSmall);
}
static void Row(string name, Totals t, int n) =>
Console.WriteLine($"{name}: {t.Euro / n * 1000:F2} € por 1000 preguntas, {t.Ms / n} ms de media");
static void Month(Totals t, int n) =>
Console.WriteLine($"mes con 3000 preguntas al día: {t.Euro / n * 3000 * 30:F2} €");
var all = Day(questions, false, false, false);
Row("modelo grande, todos los documentos", all, questions.Count);
Month(all, questions.Count);
Salida
modelo grande, todos los documentos: 2.02 € por 1000 preguntas, 1032 ms de media
mes con 3000 preguntas al día: 182.12 €

El costo por 1000 preguntas ronda los 2 €. Con 3000 preguntas al día el mes sale en unos 182 €, y una pregunta espera de media cerca de un segundo.

La idea

Un presupuesto de tokens

La primera solución es la entrada. La pregunta sobre el envío solo necesita la sección del envío. relevant toma las secciones cuyas palabras están en la pregunta, y si no hay ninguna, las envía todas (la pregunta sobre la venta al por mayor tiene que verlo todo para decir «No lo sé»):

// presupuesto: solo las secciones cuyas palabras están en la pregunta
string Relevant(string question)
{
var low = question.ToLowerInvariant();
var parts = docs.Where(doc => doc.Triggers.Any(low.Contains)).Select(doc => doc.Text).ToList();
return parts.Count == 0 ? allDocs : string.Join(" ", parts);
}

El segundo tope es max_tokens: como máximo 200 tokens por respuesta. No hace las respuestas más cortas. Dice cuánto puede costar como máximo una llamada.

var all = Day(questions, false, false, false);
Row("modelo grande, todos los documentos", all, questions.Count);
var budget = Day(questions, true, false, false);
Row("+ presupuesto de tokens", budget, questions.Count);
Salida
modelo grande, todos los documentos: 2.02 € por 1000 preguntas, 1032 ms de media
+ presupuesto de tokens: 1.11 € por 1000 preguntas, 1009 ms de media

El costo baja casi a la mitad. El tiempo apenas se mueve: la entrada se lee rápido, y la respuesta es la misma.

Aquí las secciones se eligen por palabras. Cómo elegirlas por significado, con vectores, está en el módulo sobre la búsqueda semántica (RAG).

doc.Triggers.Any(low.Contains) es verdadero si al menos una palabra de la sección está en la pregunta. low.Contains se pasa como función.

Pruébalo

Predice la salida

max_tokens es 10, y la pregunta es sobre un paquete dañado. ¿Qué imprimirá?

var r = client.Create(large, 10, prompt, [new Message("user", "Mi paquete llegó dañado, ¿qué hago?")]);
Console.WriteLine(r.Text);
Console.WriteLine($"{r.StopReason}, {r.Usage.OutputTokens}");
Respuesta

La idea

Una caché de respuestas

La segunda solución es la repetición. Si la misma pregunta se hizo hace un momento, la respuesta es la misma: no hace falta preguntarle de nuevo al modelo. Es cache-aside de la lección «Caché»: miras en la caché, y si no está, le preguntas al modelo y guardas una copia.

La clave es la pregunta en minúsculas con un solo espacio entre palabras, así que «¿cuánto cuesta el envío? » es lo mismo que «¿Cuánto cuesta el envío?»:

// la clave de la caché: minúsculas, un espacio cada uno
static string Key(string question) =>
string.Join(' ', question.ToLowerInvariant().Split(' ', StringSplitOptions.RemoveEmptyEntries));

En day son las líneas con answers: un acierto devuelve la respuesta guardada en 5 ms y gratis. Una pregunta sobre un pedido no se guarda en la caché. La respuesta es de un solo cliente, y el estado cambia.

var all = Day(questions, false, false, false);
Row("modelo grande, todos los documentos", all, questions.Count);
var budget = Day(questions, true, false, false);
Row("+ presupuesto de tokens", budget, questions.Count);
var cached = Day(questions, true, true, false);
Row("+ caché", cached, questions.Count);
Console.WriteLine($"desde la caché: {cached.Hits} de {questions.Count}");
Salida
modelo grande, todos los documentos: 2.02 € por 1000 preguntas, 1032 ms de media
+ presupuesto de tokens: 1.11 € por 1000 preguntas, 1009 ms de media
+ caché: 0.74 € por 1000 preguntas, 640 ms de media
desde la caché: 7 de 20

7 de 20 preguntas salen de la caché. Ahora también baja el tiempo, porque un acierto no espera al modelo.

Pruébalo

Encuentra el error

Un compañero simplifica la caché. Las pruebas de costo pasan, y un día después un cliente se queja de que el asistente le dijo el estado del pedido de otra persona. ¿Qué línea tiene el error?

Elige la línea con el error.

La idea

Un modelo más pequeño para lo fácil

La tercera solución es el modelo. El modelo pequeño es 10 veces más barato por token y escribe más rápido. En la lección sobre la evaluación el conjunto de pruebas mostró dónde se defiende bien: el precio del envío, el pago, las devoluciones. Y dónde no: el plazo de entrega y la pregunta fuera de los documentos. Así que recibe solo los temas aprobados:

// los temas fáciles: el conjunto de pruebas mostró que el modelo pequeño los resuelve
string PickModel(string question)
{
string[] easy = ["cuesta", "reembolso", "devolver", "Mastercard"];
return easy.Any(question.Contains) ? small : large;
}
var all = Day(questions, false, false, false);
Row("modelo grande, todos los documentos", all, questions.Count);
var budget = Day(questions, true, false, false);
Row("+ presupuesto de tokens", budget, questions.Count);
var cached = Day(questions, true, true, false);
Row("+ caché", cached, questions.Count);
var routed = Day(questions, true, true, true);
Row("+ modelo pequeño para lo fácil", routed, questions.Count);
Console.WriteLine($"en el modelo pequeño: {routed.OnSmall} de {questions.Count}");
Month(all, questions.Count);
Month(routed, questions.Count);
Salida
modelo grande, todos los documentos: 2.02 € por 1000 preguntas, 1032 ms de media
+ presupuesto de tokens: 1.11 € por 1000 preguntas, 1009 ms de media
+ caché: 0.74 € por 1000 preguntas, 640 ms de media
+ modelo pequeño para lo fácil: 0.43 € por 1000 preguntas, 419 ms de media
en el modelo pequeño: 6 de 20
mes con 3000 preguntas al día: 182.12 €
mes con 3000 preguntas al día: 39.06 €

El mes baja de unos 182 € a unos 39 €, y el tiempo medio de 1032 a 419 ms. Los números salen de precios de ejemplo y de una fórmula de ejemplo, pero el orden de las soluciones es real.

Míralo

La cuenta, solución por solución

Totals Day(List<string> questions, bool budget,
bool cache, bool route)
{
var answers = new Dictionary<string, string>();
double euro = 0;
int ms = 0, hits = 0, onSmall = 0;
foreach (var question in questions)
{
var k = Key(question);
// acierto: sin modelo
if (cache && answers.ContainsKey(k))
{
hits++;
ms += cacheMs;
continue;
}
var model = route ? PickModel(question) : large;
var docs = budget ? Relevant(question) : allDocs;
var maxTokens = budget ? 200 : 1024;
var msg = new Message("user", question);
var r = client.Create(model, maxTokens,
prompt + " " + docs, [msg]);
var m = models[model];
euro += Cost(m, r.Usage);
ms += Latency(m, r.Usage);
if (model == small) onSmall++;
// un pedido es de un cliente: sin caché
if (cache && !k.Contains("pedido"))
answers[k] = r.Text;
}
return new Totals(euro, ms, hits, onSmall);
}
Paso a paso, en palabras
  1. Una llamada: entran el prompt, todos los documentos y la pregunta (386 tokens) y sale la respuesta (40). Los documentos son la mayor parte de la cuenta: 0,00218 €.
  2. El presupuesto de tokens: solo la sección que busca la pregunta y un tope para la respuesta. 154 tokens de entrada, 0,00126 € por la misma respuesta.
  3. Un día de 20 preguntas, por 1000 preguntas: 2,02 € con todos los documentos, 1,11 € con el presupuesto. El tiempo casi no cambia: es sobre todo la respuesta.
  4. La caché: 7 de 20 preguntas son repetidas y no llegan al modelo. Las preguntas sobre un pedido nunca se guardan en la caché.
  5. El modelo pequeño se encarga de los temas fáciles que aprobó el conjunto de pruebas: 6 de 20 preguntas. Es más barato y más rápido.
  6. De 2,02 € a 0,43 € por 1000 preguntas (79 % menos) y de 1032 a 419 ms. Los precios y los tiempos son ejemplos.

La idea

Ejecútalo en tu computadora

La respuesta real dice cuántos tokens usó. Aquí está la petición con el presupuesto para la pregunta sobre el envío, y la respuesta. El texto y los números vienen del cliente falso:

Petición
{
"model": "<nombre del modelo>",
"max_tokens": 200,
"system": "<el prompt de sistema>",
"messages": [
{
"role": "user",
"content": "¿Cuánto cuesta el envío?"
}
]
}
Respuesta
{
"content": [
{
"type": "text",
"text": "El envío a domicilio cuesta 4,90 €, a una oficina 3,50 €, y a partir de 50 € es gratis."
}
],
"stop_reason": "end_turn",
"usage": {
"input_tokens": 154,
"output_tokens": 40
}
}

Los campos son usage.input_tokens y usage.output_tokens, y stop_reason dice si la respuesta está completa (end_turn) o si el tope la cortó (max_tokens). Con ellos el programa calcula la misma cuenta que aquí, solo que con números reales.

Los proveedores publican SDK oficiales para Java, C#, Python y JavaScript con la misma forma: mensajes, roles, tokens, herramientas. Los nombres exactos de las clases y los métodos están en la documentación del proveedor. Aquí la petición va por el cliente HTTP estándar del lenguaje, sin SDK. La dirección y el modelo son marcadores:

using System.Text;
using System.Text.Json;
// solo para mostrar: la dirección y la cabecera de la clave están en la documentación del proveedor
const string Endpoint = "https://<proveedor>/...";
var http = new HttpClient();
async Task<JsonElement> Ask(string system, string question)
{
var body = JsonSerializer.Serialize(new
{
model = "<nombre del modelo>",
max_tokens = 200,
system,
messages = new[] { new { role = "user", content = question } },
});
var request = new HttpRequestMessage(HttpMethod.Post, Endpoint)
{
Content = new StringContent(body, Encoding.UTF8, "application/json"),
};
var key = Environment.GetEnvironmentVariable("LLM_API_KEY");
request.Headers.Add("authorization", "Bearer " + key);
var response = await http.SendAsync(request);
var json = await response.Content.ReadAsStringAsync();
return JsonDocument.Parse(json).RootElement; // JSON: content, stop_reason, usage
}
var reply = await Ask(prompt + " " + Relevant(question), question);
var usage = reply.GetProperty("usage");
Console.WriteLine($"{reply.GetProperty("stop_reason")} "
+ $"{usage.GetProperty("input_tokens")} {usage.GetProperty("output_tokens")}");

Este código no se ejecuta en la comprobación de código del sitio. La clave está en la variable de entorno LLM_API_KEY, no en el código (la lección «Secretos en el código y en git»), necesitas una cuenta con un proveedor, y cada ejecución cuesta dinero.

JsonSerializer y JsonDocument son de System.Text.Json, y SendAsync es asíncrono, de ahí el await.

La idea

Cuando duele

  • Un presupuesto que recorta lo necesario. Si relevant no encuentra la sección con la respuesta, el modelo dice «No lo sé» o, peor, inventa. Un max_tokens demasiado bajo da media respuesta. Todo cambio del presupuesto pasa por el conjunto de pruebas.
  • Una caché que miente. El precio del envío cambia, y la caché da el viejo. Una caché tiene caducidad (TTL) y se vacía cuando cambian los documentos. Las respuestas que dependen del cliente o del momento no entran.
  • Un modelo pequeño sin conjunto de pruebas. «Parece sencillo» no es un argumento. El modelo pequeño toma un tema solo después de que el conjunto de pruebas lo pasó, y el conjunto se ejecuta de nuevo con cada cambio.
  • Un ahorro que no vale la pena. Si el asistente recibe 50 preguntas al día, la cuenta son unos pocos euros al mes. La complejidad de la caché y del enrutador puede costar más que eso. Primero mide.
Más precisamente, para curiosos

Guardar el inicio del prompt. Muchos proveedores guardan el inicio repetido del prompt (el prompt de sistema y los documentos) y cobran menos por volver a leerlo. Es otra caché: el modelo igual responde, pero la entrada sale más barata. Funciona si el inicio es idéntico hasta el último carácter, por eso las partes que cambian (la pregunta, el nombre del cliente) van al final.

Una caché por significado. «¿Cómo puedo devolver la mercancía?» y «¿Hasta cuándo puedo devolver la mercancía?» son claves distintas. Una caché con vectores (la lección sobre los vectores) las trata como una sola pregunta. Encuentra más aciertos, y también falsos: «¿Puedo devolver unos zapatos?» y «¿Puedo devolver un regalo?» están cerca, y las respuestas pueden diferir.

Una respuesta en flujo. La respuesta puede llegar palabra a palabra (streaming). El tiempo total es el mismo, pero el cliente ve las primeras palabras a los cien ms en lugar de al segundo. Es rapidez para la persona, no para la cuenta.

Lotes. El trabajo que ningún cliente espera (resumir 10 000 reseñas de noche) puede pasar por un modo por lotes: más lento y más barato.

El tiempo en producción. El promedio esconde la cola: el 95 % de las respuestas pueden tardar menos de un segundo y el 5 % más de 5 segundos. Mide percentiles, como en la lección «Requisitos no funcionales que puedes medir» de «Ingeniería de software». Vigilar el costo y el tiempo en producción forma parte de MLOps y se enseña en ZeroToOps.

[large] = new(...) es un inicializador de diccionario por clave, y string.Join(" ", ...) une los textos con un espacio.

Ejercicio

Qué solución ahorra más

Resuélvelo en tu editor.

El programa aplica las soluciones de forma acumulativa, así que no ves cuánto da cada una por sí sola. Ejecuta day tres veces, cada vez con una sola bandera, e imprime las filas junto a la que no tiene soluciones:

Salida
modelo grande, todos los documentos: 2.02 € por 1000 preguntas, 1032 ms de media
solo presupuesto: 1.11 € por 1000 preguntas, 1009 ms de media
solo caché: 1.30 € por 1000 preguntas, 654 ms de media
solo modelo pequeño: 0.99 € por 1000 preguntas, 599 ms de media

Por sí solo, el modelo pequeño es el más barato, y el presupuesto se le acerca. El presupuesto casi no ahorra tiempo, y la caché y el modelo pequeño lo reducen más, porque no esperan a que escriba el modelo grande. Las tres ahorran en sitios distintos, por eso juntas dan más.

Más tareas

  • Un tema fácil más. Añade «atiende» a los temas fáciles. ¿Cuánto baja el costo? ¿Qué tienes que hacer antes de ponerlo en producción? (Pista: la lección sobre la evaluación.)
  • Un tope para el día. Deja de preguntarle al modelo grande cuando el costo del día pase de 0,01 €, y responde «Te paso con un compañero». ¿A cuántas preguntas se queda sin respuesta del modelo?

Test

Ponte a prueba

1. La pregunta tiene 8 tokens, y la cuenta de la llamada es por 386 tokens de entrada. ¿De dónde sale el resto?
2. El presupuesto de tokens redujo el costo casi a la mitad, y el tiempo medio apenas se movió. ¿Por qué?
3. ¿Qué pregunta no debe entrar en la caché de respuestas?
4. ¿Cómo eliges qué preguntas atiende el modelo pequeño?
5. max_tokens es 10, y la respuesta necesita 30 tokens. ¿Qué obtienes?

Creado por Ivo Gergov como parte de la campaña de Evo Tech por una educación accesible en programación ·