> ## Documentation Index
> Fetch the complete documentation index at: https://docs.cosvec.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Primitivas (Preguntas)

> Los tres tipos de pregunta de CosVec (Choice, Score, Noul), las respuestas tipadas que devuelven, cómo elegir entre ellas y cómo hacer varias a la vez.

export function TypesafeExample({example, display, title}) {
  const keyStrUriSafe = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+-$";
  function compressToEncodedURIComponent(input) {
    if (input == null) return "";
    return _compress(input, 6, function (a) {
      return keyStrUriSafe.charAt(a);
    });
  }
  function _compress(uncompressed, bitsPerChar, getCharFromInt) {
    if (uncompressed == null) return "";
    var i, value, context_dictionary = {}, context_dictionaryToCreate = {}, context_c = "", context_wc = "", context_w = "", context_enlargeIn = 2, context_dictSize = 3, context_numBits = 2, context_data = [], context_data_val = 0, context_data_position = 0, ii;
    for (ii = 0; ii < uncompressed.length; ii += 1) {
      context_c = uncompressed.charAt(ii);
      if (!Object.prototype.hasOwnProperty.call(context_dictionary, context_c)) {
        context_dictionary[context_c] = context_dictSize++;
        context_dictionaryToCreate[context_c] = true;
      }
      context_wc = context_w + context_c;
      if (Object.prototype.hasOwnProperty.call(context_dictionary, context_wc)) {
        context_w = context_wc;
      } else {
        if (Object.prototype.hasOwnProperty.call(context_dictionaryToCreate, context_w)) {
          if (context_w.charCodeAt(0) < 256) {
            for (i = 0; i < context_numBits; i++) {
              context_data_val = context_data_val << 1;
              if (context_data_position == bitsPerChar - 1) {
                context_data_position = 0;
                context_data.push(getCharFromInt(context_data_val));
                context_data_val = 0;
              } else {
                context_data_position++;
              }
            }
            value = context_w.charCodeAt(0);
            for (i = 0; i < 8; i++) {
              context_data_val = context_data_val << 1 | value & 1;
              if (context_data_position == bitsPerChar - 1) {
                context_data_position = 0;
                context_data.push(getCharFromInt(context_data_val));
                context_data_val = 0;
              } else {
                context_data_position++;
              }
              value = value >> 1;
            }
          } else {
            value = 1;
            for (i = 0; i < context_numBits; i++) {
              context_data_val = context_data_val << 1 | value;
              if (context_data_position == bitsPerChar - 1) {
                context_data_position = 0;
                context_data.push(getCharFromInt(context_data_val));
                context_data_val = 0;
              } else {
                context_data_position++;
              }
              value = 0;
            }
            value = context_w.charCodeAt(0);
            for (i = 0; i < 16; i++) {
              context_data_val = context_data_val << 1 | value & 1;
              if (context_data_position == bitsPerChar - 1) {
                context_data_position = 0;
                context_data.push(getCharFromInt(context_data_val));
                context_data_val = 0;
              } else {
                context_data_position++;
              }
              value = value >> 1;
            }
          }
          context_enlargeIn--;
          if (context_enlargeIn == 0) {
            context_enlargeIn = Math.pow(2, context_numBits);
            context_numBits++;
          }
          delete context_dictionaryToCreate[context_w];
        } else {
          value = context_dictionary[context_w];
          for (i = 0; i < context_numBits; i++) {
            context_data_val = context_data_val << 1 | value & 1;
            if (context_data_position == bitsPerChar - 1) {
              context_data_position = 0;
              context_data.push(getCharFromInt(context_data_val));
              context_data_val = 0;
            } else {
              context_data_position++;
            }
            value = value >> 1;
          }
        }
        context_enlargeIn--;
        if (context_enlargeIn == 0) {
          context_enlargeIn = Math.pow(2, context_numBits);
          context_numBits++;
        }
        context_dictionary[context_wc] = context_dictSize++;
        context_w = String(context_c);
      }
    }
    if (context_w !== "") {
      if (Object.prototype.hasOwnProperty.call(context_dictionaryToCreate, context_w)) {
        if (context_w.charCodeAt(0) < 256) {
          for (i = 0; i < context_numBits; i++) {
            context_data_val = context_data_val << 1;
            if (context_data_position == bitsPerChar - 1) {
              context_data_position = 0;
              context_data.push(getCharFromInt(context_data_val));
              context_data_val = 0;
            } else {
              context_data_position++;
            }
          }
          value = context_w.charCodeAt(0);
          for (i = 0; i < 8; i++) {
            context_data_val = context_data_val << 1 | value & 1;
            if (context_data_position == bitsPerChar - 1) {
              context_data_position = 0;
              context_data.push(getCharFromInt(context_data_val));
              context_data_val = 0;
            } else {
              context_data_position++;
            }
            value = value >> 1;
          }
        } else {
          value = 1;
          for (i = 0; i < context_numBits; i++) {
            context_data_val = context_data_val << 1 | value;
            if (context_data_position == bitsPerChar - 1) {
              context_data_position = 0;
              context_data.push(getCharFromInt(context_data_val));
              context_data_val = 0;
            } else {
              context_data_position++;
            }
            value = 0;
          }
          value = context_w.charCodeAt(0);
          for (i = 0; i < 16; i++) {
            context_data_val = context_data_val << 1 | value & 1;
            if (context_data_position == bitsPerChar - 1) {
              context_data_position = 0;
              context_data.push(getCharFromInt(context_data_val));
              context_data_val = 0;
            } else {
              context_data_position++;
            }
            value = value >> 1;
          }
        }
        context_enlargeIn--;
        if (context_enlargeIn == 0) {
          context_enlargeIn = Math.pow(2, context_numBits);
          context_numBits++;
        }
        delete context_dictionaryToCreate[context_w];
      } else {
        value = context_dictionary[context_w];
        for (i = 0; i < context_numBits; i++) {
          context_data_val = context_data_val << 1 | value & 1;
          if (context_data_position == bitsPerChar - 1) {
            context_data_position = 0;
            context_data.push(getCharFromInt(context_data_val));
            context_data_val = 0;
          } else {
            context_data_position++;
          }
          value = value >> 1;
        }
      }
      context_enlargeIn--;
      if (context_enlargeIn == 0) {
        context_enlargeIn = Math.pow(2, context_numBits);
        context_numBits++;
      }
    }
    value = 2;
    for (i = 0; i < context_numBits; i++) {
      context_data_val = context_data_val << 1 | value & 1;
      if (context_data_position == bitsPerChar - 1) {
        context_data_position = 0;
        context_data.push(getCharFromInt(context_data_val));
        context_data_val = 0;
      } else {
        context_data_position++;
      }
      value = value >> 1;
    }
    while (true) {
      context_data_val = context_data_val << 1;
      if (context_data_position == bitsPerChar - 1) {
        context_data.push(getCharFromInt(context_data_val));
        break;
      } else context_data_position++;
    }
    return context_data.join("");
  }
  function buildHref(ex) {
    const documentText = ex.state === undefined ? "" : typeof ex.state === "string" ? ex.state : JSON.stringify(ex.state, null, 2);
    return "https://console.typesafe.ai/decode#share/" + compressToEncodedURIComponent(JSON.stringify({
      apiVersion: "v1",
      documentText,
      promptsText: JSON.stringify(ex.questions, null, 2),
      selectedModels: ex.selectedModels
    }));
  }
  const displayedExample = display === "questions" ? example.questions : example.state === undefined ? {
    questions: example.questions
  } : {
    state: example.state,
    questions: example.questions
  };
  const code = JSON.stringify(displayedExample, null, 2);
  const href = buildHref(example);
  return <div style={{
    margin: "1.25rem 0"
  }}>
      <CodeBlock language="json" filename={title ?? "request"}>
        {code}
      </CodeBlock>
      <div className="pb-8">
        <a href={href} target="_blank" rel="noreferrer" className="text-primary">
          Try it in the Playground →
        </a>
      </div>
    </div>;
}

Las primitivas de CosVec son los bloques de construcción pequeños y tipados que compones en código. Vienen en pares: una pregunta define un juicio que un [modelo System One](/es/concepts/system-one) debe hacer sobre un [estado](/es/concepts/state), y su respuesta es el valor tipado que regresa. Tú compones las respuestas en tu código para tomar decisiones. Hay tres tipos de pregunta, cada uno con una forma de respuesta distinta.

| Tipo                            | Qué responde             | Devuelve                                         |
| ------------------------------- | ------------------------ | ------------------------------------------------ |
| [Choice](/es/primitives/choice) | ¿Cuál de estas opciones? | `choice`, `probabilities`, `confidence`          |
| [Score](/es/primitives/score)   | ¿Qué nivel?              | `score`, `legend`, `probabilities`, `confidence` |
| [Noul](/es/primitives/noul)     | ¿Esto es verdadero?      | `noul` (0 a 1)                                   |

Puedes hacer una pregunta o enviar varias juntas. Cada pregunta de una solicitud ve el mismo estado, se evalúa de forma independiente y devuelve una respuesta tipada bajo el ID que elegiste.

## Pide un solo juicio rápido por pregunta

Los modelos System One están hechos para juicios rápidos y enfocados. Pide un juicio que una persona knowledgeable haría en un segundo con el contexto adecuado. "¿Este mensaje transmite urgencia?" es una buena pregunta. "Analiza este mensaje y determina el mejor curso de acción" no lo es. Eso requiere razonamiento lento, y es una señal para dividir la tarea en preguntas pequeñas y componer las respuestas en código.

Si el juicio que quieres depende de varios factores independientes, pregunta por cada factor por separado y combina las respuestas con tu propia lógica. En lugar de "califica este pitch de startup", pregunta por tamaño de mercado, factibilidad técnica y diferenciación, y luego ponles pesos en código según su importancia relativa. Cuando cambien las prioridades, cambia el valor de los pesos en lugar de reescribir un prompt. [Hacer varias preguntas juntas](#hacer-varias-preguntas-juntas) muestra cómo hacerlo.

## Definir una pregunta

Toda pregunta tiene un ID, un `type` e `instructions`. Las preguntas Choice y Score también aceptan `criteria`, que define las opciones para una pregunta Choice o los niveles para un Score. Las preguntas Noul aceptan `criteria` como una aclaración opcional de qué significan sí y no.

* ID. La clave que tú eliges, como `refund_requested`. Identifica la respuesta en la respuesta de la API.
* `type`. Uno de `choice`, `score` o `noul`.
* `instructions`. La pregunta que haces sobre el estado. Aquí va tu lógica de evaluación. Escríbela como una pregunta clara y específica, o como una afirmación para que el modelo la juzgue. Un string basta para la mayoría de las preguntas. También puede ser un objeto o un array, lo que pone la pregunta en un campo y los datos a los que se refiere en otros; consulta [Usar estructura en las preguntas](/es/concepts/how-to-build-with-system-one#usar-estructura-en-las-preguntas).
* `criteria`. Las respuestas posibles: un mapa de opciones para una pregunta Choice, una lista ordenada de niveles para un Score, y una descripción opcional de sí y no para un Noul. La página de cada tipo de pregunta cubre su forma.

Esta pregunta pide si un cliente solicitó un reembolso:

```python theme={null} theme={null}
from typesafe_sdk import Noul

questions = {
    "refund_requested": Noul(
        instructions="Does the customer request a refund?",
    ),
}
```

<Tip>
  Los IDs de pregunta son para tu código. No se envían al modelo. Escribe la pregunta completa en `instructions`, incluso cuando el ID parezca autoexplicativo.
</Tip>

## Elegir un tipo de pregunta

Elige el tipo que coincida con la forma de la respuesta que necesitas.

* **Choice** encaja cuando la respuesta es una de un conjunto conocido de opciones sin orden entre ellas: enrutar un ticket a un departamento, clasificar un tipo de documento, detectar un lenguaje de programación. Da la lista completa de opciones, y añade una opción `other` o `none of the above` cuando la lista podría no cubrir todas las entradas.

* **Score** encaja cuando la respuesta cae en un espectro y puedes describir qué significa cada punto de ese espectro: severidad de un bug, frustración del cliente, nivel de habilidad. Los niveles los defines tú, y el modelo devuelve una posición a lo largo de ellos.

* **Noul** encaja para una pregunta limpia de sí/no donde la probabilidad misma es la señal útil: ¿este mensaje contiene información de identificación personal?, ¿el cliente está solicitando un reembolso?, ¿el currículum menciona sistemas distribuidos?

<Note>
  Usa Noul para un juicio de sí/no y Score para medir una posición en un espectro. "¿Este candidato es fuerte en Python?" necesita una definición clara de "fuerte". Un valor de Noul de 0.5 significa que el modelo da igual probabilidad al sí y al no. No significa que el candidato tenga un nivel medio de habilidad. Una definición poco clara hace que esa probabilidad sea difícil de interpretar.

  Si quieres medir el nivel de habilidad, usa un Score con niveles definidos, como sin experiencia, cierta familiaridad, uso diario y experiencia profunda. Si necesitas una decisión de sí/no, define la condición con claridad, como "¿El currículum indica que el candidato ha usado Python en el trabajo?"
</Note>

Si dos tipos parecen encajar, prefiere aquel cuya respuesta tu código pueda usar directamente. Una Choice entre `refund`, `rebook` e `information` se mapea directo a tres rutas de código. Un Score de frustración del cliente se mapea a un umbral. Un Noul se mapea a un `if`.

## Qué devuelve

Las respuestas también son primitivas. Cada tipo de pregunta devuelve un valor tipado que tu código puede comparar, umbralizar, ordenar, pasar a más lógica o poner en el estado de una solicitud posterior (consulta [Cuándo una pregunta depende de otra](#cuando-una-pregunta-depende-de-otra)).

| Tipo   | Campos de la respuesta                           | Cómo leerla                                                                                                                                                                       |
| ------ | ------------------------------------------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Choice | `choice`, `probabilities`, `confidence`          | `choice` es la opción seleccionada. `probabilities` es la distribución sobre todas las opciones. `confidence` resume qué tan concentrada está esa distribución.                   |
| Score  | `score`, `legend`, `probabilities`, `confidence` | `score` es una posición a lo largo de tus niveles, y puede caer entre dos de ellos. `legend` repite los niveles por número. `probabilities` es la distribución sobre los niveles. |
| Noul   | `noul`                                           | La probabilidad de que la respuesta sea sí. Cerca de 1 es un sí fuerte, cerca de 0 un no fuerte, cerca de 0.5 incertidumbre. Noul no tiene un `confidence` separado.              |

Dos propiedades de estas respuestas las hacen componibles:

* **Toda respuesta está restringida a las opciones que suministraste.** El modelo devuelve una distribución de probabilidad sobre tus opciones o niveles, nunca un valor fuera de ellas. Tu código nunca tiene que recuperar un valor desde prosa generada.
* **Toda respuesta es independiente.** La respuesta de una pregunta no es contexto oculto para otra. Puedes añadir o quitar preguntas sin cambiar los resultados de las demás.

[Confianza](/es/confidence) explica cómo se deriva `confidence` a partir de `probabilities` y cómo usarla para decidir cuándo actuar automáticamente y cuándo derivar el caso a una persona.

## Referenciar campos específicos

El contenido que se evalúa, el [estado](/es/concepts/state), suele ser un objeto JSON con varias partes: una conversación, un registro, una política. Cuando una pregunta trata sobre una de esas partes, nómbrala en las `instructions` con una ruta de puntos e índices hasta su clave, incluyendo los backticks. Así el modelo sabe qué parte del estado juzgar.

Toma la conversación de soporte de la página de Estado:

```json theme={null} theme={null}
{
  "ticket": {
    "subject": "Duplicate charge",
    "messages": [
      {"from": "customer", "text": "I was charged twice for order A-104. Please refund the duplicate."},
      {"from": "support", "text": "We are checking the charges."}
    ]
  },
  "order": {
    "id": "A-104",
    "charges": [
      {"amount_usd": 49, "status": "captured"},
      {"amount_usd": 49, "status": "captured"}
    ]
  },
  "refund_policy": "Duplicate charges are eligible for a refund."
}
```

Estas dos preguntas apuntan por ruta al mensaje del cliente, la política y los cobros:

```python theme={null} theme={null}
questions = {
    "refund_requested": {
        "type": "noul",
        "instructions": "Does `ticket.messages[0].text` request a refund?",
    },
    "policy_supports_refund": {
        "type": "noul",
        "instructions": (
            "Does `refund_policy` support the refund requested "
            "in `ticket.messages[0].text`, given `order.charges`?"
        ),
    },
}
```

Las rutas explícitas dejan claro qué partes de un estado estructurado deben informar cada juicio. Consulta [Estado](/es/concepts/state) para saber cómo estructurar la entrada.

## Hacer varias preguntas juntas

Envía en una sola solicitud toda pregunta que use el mismo estado. Puedes mezclar tipos de pregunta libremente. Los modelos System One evalúan en paralelo toda pregunta de una solicitud. Añadir preguntas apenas cambia el tiempo de respuesta y solo cuesta los tokens de las preguntas extra, que son baratos. Preguntar algo que quizá no necesitas es casi gratis.

Esta solicitud clasifica un mensaje de cliente, verifica la urgencia y califica la frustración todo a la vez:

<TypesafeExample
  example={{
state:
"Our API integration started returning 500 errors on every request about 20 minutes ago, and we can't process any customer orders until this is fixed.",
questions: {
department: {
type: 'choice',
instructions: 'Which team should handle this',
criteria: {
  billing: 'Payment or subscription issues',
  technical: 'Bugs or integration problems',
  sales: 'Pricing or account questions',
},
},
is_urgent: {
type: 'noul',
instructions: 'The message conveys urgency or time-sensitivity',
},
frustration: {
type: 'score',
instructions: 'How frustrated the customer appears',
criteria: [
  'Calm, just stating facts',
  'Frustrated but civil',
  'Very angry, strong language',
],
},
},
}}
/>

Nuestros [SDKs de cliente](/es/sdk) proporcionan preguntas y respuestas tipadas. En Python, pasa un diccionario `questions` con objetos `Choice`, `Noul` y `Score` a `client.system_one(...)`. Esta solicitud envía un ticket y una política de reembolso una sola vez y obtiene una respuesta tipada por cada pregunta:

```python theme={null} theme={null}
from typesafe_sdk import Choice, Noul, Score, TypeSafeClient

state = {
    "ticket_message": "My flight was cancelled. Can I get a refund?",
    "refund_policy": "Cancelled flights are eligible for a full refund.",
}

with TypeSafeClient() as client:
    response = client.system_one(
        state=state,
        questions={
            "refund_requested": Noul(
                instructions="Does `ticket_message` request a refund?",
            ),
            "request_type": Choice(
                instructions="What is the main request in `ticket_message`?",
                criteria={
                    "refund": "The customer wants money returned.",
                    "rebooking": "The customer wants a replacement flight.",
                    "information": "The customer is asking for information only.",
                },
            ),
            "frustration": Score(
                instructions="How frustrated does the customer appear in `ticket_message`?",
                criteria=[
                    "Calm and neutral.",
                    "Concerned but civil.",
                    "Very angry or using strong language.",
                ],
            ),
        },
    )

print(response.answers["refund_requested"].noul)
print(response.answers["request_type"].choice)
print(response.answers["frustration"].score)
```

Consulta los [SDKs de cliente](/es/sdk) para la instalación y el uso en tu lenguaje.

### Hacer preguntas especulativas

Haz toda pregunta que tu código podría necesitar, incluidas aquellas cuya respuesta solo importa para algunas entradas, y deja que el código decida qué respuestas usar. Si un ticket resulta no ser un reporte de bug, ignora la respuesta de severidad. A esto lo llamamos el patrón [Speculative fan-out](/es/patterns/fan-out). El [cookbook de preguntas en paralelo](/es/cookbooks/parallel_questions) muestra cómo agrupar 13 preguntas en una sola llamada es 11.5 veces más barato y 9.6 veces más rápido que 13 llamadas separadas, sin cambios en las respuestas.

<Tip>
  Los agentes de código caen en el hábito de una pregunta por llamada más que las personas. La [skill de agente de CosVec](/es/agent-skill#installation) le dice a tu agente que ponga muchas preguntas en cada llamada, incluidas las que solo importan para algunas entradas.
</Tip>

### Dividir un juicio complejo en varias preguntas

Un juicio que depende de varias cosas se divide mejor en una pregunta por cosa. Combina las respuestas en tu código, dándole a cada una un peso según su importancia relativa. Los pesos son tuyos. Cuando el resultado combinado no coincida con lo que tu equipo decidiría, cámbialos en código y ejecuta de nuevo. Añadir preguntas apenas cambia el tiempo de respuesta porque se evalúan en paralelo dentro de una solicitud. La división cuesta unos pocos tokens de pregunta extra.

Por ejemplo, la prioridad de un ticket podría construirse con tres preguntas Score: qué tan severo es el bug, qué tan frustrado está el cliente y cuánto material de trabajo le da el reporte a un ingeniero. La página de Score recorre esta solicitud y el código que normaliza y pondera las respuestas en [Dividir un juicio complejo en varios Scores](/es/primitives/score#dividir-un-juicio-complejo-en-varios-scores). Esta técnica se llama el patrón [Composite scoring](/es/patterns/composite-scoring).

### Cuándo una pregunta depende de otra

Las preguntas de una misma solicitud son independientes: una respuesta no se convierte en contexto para otra pregunta. Si un juicio posterior depende de una respuesta anterior, haz una segunda solicitud en código. La dependencia es real solo cuando tu código no puede construir la segunda solicitud hasta tener la primera respuesta: necesita la respuesta para obtener más datos para el estado, para decidir de qué está hecho el estado o para elegir las opciones de la siguiente pregunta. De lo contrario, haz las preguntas juntas y combina sus respuestas en código.

Dos solicitudes son la excepción, no la regla. Si las preguntas de la segunda solicitud pudieron hacerse contra el estado original, házlas en la primera solicitud y deja que el código ignore las que no necesita. Tres cookbooks hacen una segunda solicitud por una razón real. [Skill suggestion](/es/cookbooks/skill_suggestion) rankea 182 skills en una solicitud, luego obtiene el texto completo de las tres primeras y las juzga de nuevo contra esa mejor evidencia. [Structure recovery](/es/cookbooks/autoformat) pregunta si cada salto de línea partió una oración, fusiona líneas en bloques a partir de esas respuestas, y luego clasifica los bloques, que no existían hasta que la primera solicitud respondió. [Hierarchical classification](/es/cookbooks/hierarchical_classification) usa cada respuesta Choice para decidir qué opciones ofrece la siguiente solicitud.

Consulta [Cómo construir con CosVec](/es/concepts/how-to-build-with-system-one) para orientación sobre cómo dividir un flujo de trabajo en juicios enfocados.

## Próximos pasos

<Columns cols={3}>
  <Card title="Choice" href="/es/primitives/choice" icon="list">
    Elige una opción de una lista fija.
  </Card>

  <Card title="Score" href="/es/primitives/score" icon="gauge">
    Califica el estado a lo largo de niveles ordenados.
  </Card>

  <Card title="Noul" href="/es/primitives/noul" icon="circle-check">
    Obtén la probabilidad de que una afirmación sea verdadera.
  </Card>
</Columns>

Para ver cómo esto se compone en arquitecturas de sistema, ve a [Patterns](/es/patterns).
