---
title: Agente de atención al cliente
url: https://platform.claude.com/docs/es/about-claude/use-case-guides/customer-support-chat
description: Crea un chatbot de atención al cliente con Claude que responda preguntas sobre productos, se mantenga en el tema y genere cotizaciones mediante el uso de herramientas.
---

## Requisitos previos

Para seguir esta guía, necesitas:

* Una clave de API de Claude (configurada como la variable de entorno `ANTHROPIC_API_KEY`)
* Python 3.10 o posterior

Instala los paquetes requeridos:

```bash
pip install anthropic streamlit python-dotenv
```

## Antes de construir con Claude

### Decide si usar Claude para el chat de soporte

Estos son algunos indicadores clave de que deberías emplear un "large language model" (modelo de lenguaje grande), o LLM, como Claude para automatizar partes de tu proceso de atención al cliente:

<AccordionGroup>
  <Accordion title="Alto volumen de consultas repetitivas">
    Claude se destaca en manejar una gran cantidad de preguntas similares de manera eficiente, liberando a los agentes humanos para problemas más complejos.
  </Accordion>

  <Accordion title="Necesidad de síntesis rápida de información">
    Claude puede recuperar, procesar y combinar rápidamente información de amplias bases de conocimiento, mientras que los agentes humanos pueden necesitar tiempo para investigar o consultar múltiples fuentes.
  </Accordion>

  <Accordion title="Requisito de disponibilidad 24/7">
    Claude puede brindar soporte las 24 horas sin fatiga, mientras que dotar de personal humano para una cobertura continua puede ser costoso y desafiante.
  </Accordion>

  <Accordion title="Escalamiento rápido durante períodos de alta demanda">
    Claude puede manejar aumentos repentinos en el volumen de consultas sin necesidad de contratar y capacitar personal adicional.
  </Accordion>

  <Accordion title="Voz de marca consistente">
    Puedes indicarle a Claude que represente de manera consistente el tono y los valores de tu marca, mientras que los agentes humanos pueden variar en sus estilos de comunicación.
  </Accordion>
</AccordionGroup>

Algunas consideraciones para elegir Claude sobre otros LLMs:

* Priorizas una conversación natural y matizada: la sofisticada comprensión del lenguaje de Claude permite conversaciones más naturales y conscientes del contexto, que se sienten más humanas que los chats con otros LLMs.
* Recibes con frecuencia consultas complejas y abiertas: Claude puede manejar una amplia gama de temas y consultas sin generar respuestas prefabricadas ni requerir una programación extensa de permutaciones de expresiones del usuario.
* Necesitas soporte multilingüe escalable: las capacidades multilingües de Claude le permiten mantener conversaciones en más de 200 idiomas sin necesidad de chatbots separados ni procesos de traducción extensos para cada idioma admitido.

### Define tu interacción de chat ideal

Esboza una interacción ideal con el cliente para definir cómo y cuándo esperas que el cliente interactúe con Claude. Este esquema ayudará a determinar los requisitos técnicos de tu solución.

Este es un ejemplo de interacción de chat para atención al cliente de seguros de automóviles:

* **Cliente:** Inicia la experiencia de chat de soporte
  * **Claude:** Saluda cálidamente al cliente e inicia la conversación

* **Cliente:** Pregunta sobre el seguro para su nuevo automóvil eléctrico
  * **Claude:** Proporciona información relevante sobre la cobertura de vehículos eléctricos

* **Cliente:** Hace preguntas relacionadas con las necesidades particulares de los seguros para vehículos eléctricos
  * **Claude:** Responde con respuestas precisas e informativas y proporciona enlaces a las fuentes

* **Cliente:** Hace preguntas fuera de tema no relacionadas con seguros o automóviles
  * **Claude:** Aclara que no trata temas no relacionados y redirige al usuario de vuelta al seguro de automóviles

* **Cliente:** Expresa interés en una cotización de seguro

  * **Claude:** Hace una serie de preguntas para determinar la cotización adecuada, adaptándose a sus respuestas
  * **Claude:** Envía una solicitud para usar la herramienta de API de generación de cotizaciones junto con la información necesaria recopilada del usuario
  * **Claude:** Recibe la información de respuesta del uso de la herramienta de API, sintetiza la información en una respuesta natural y presenta la cotización proporcionada al usuario

* **Cliente:** Hace preguntas de seguimiento

  * **Claude:** Responde las preguntas de seguimiento según sea necesario
  * **Claude:** Guía al cliente hacia los siguientes pasos en el proceso del seguro y cierra la conversación

<Tip>
  En el ejemplo real que escribas para tu propio caso de uso, puede resultarte útil escribir las palabras reales de esta interacción para que también puedas tener una idea del tono ideal, la longitud de respuesta y el nivel de detalle que quieres que tenga Claude.
</Tip>

### Divide la interacción en tareas únicas

El chat de atención al cliente es una colección de múltiples tareas diferentes, desde responder preguntas hasta recuperar información y tomar acciones sobre solicitudes, todo envuelto en una sola interacción con el cliente. Antes de empezar a construir, desglosa tu interacción ideal con el cliente en cada tarea que quieres que Claude pueda realizar. Esto garantiza que puedas dar indicaciones y evaluar a Claude para cada tarea, y te da una buena idea del rango de interacciones que debes tener en cuenta al escribir casos de prueba.

<Tip>
  A los clientes a veces les resulta útil visualizar esto como un diagrama de flujo de interacción con los posibles puntos de inflexión de la conversación según las solicitudes del usuario.
</Tip>

Estas son las tareas clave asociadas con la interacción de seguros del ejemplo:

1. Saludo y orientación general

   * Saludar cálidamente al cliente e iniciar la conversación
   * Proporcionar información general sobre la empresa y la interacción

2. Información del producto

   * Proporcionar información sobre la cobertura de vehículos eléctricos
     <Note>
       Esto requerirá que Claude tenga la información necesaria en su contexto, y podría implicar que sea necesaria una 

       [integración RAG](https://platform.claude.com/cookbook/capabilities-retrieval-augmented-generation-guide)

       .
     </Note>
   * Responder preguntas relacionadas con las necesidades particulares de los seguros para vehículos eléctricos
   * Responder preguntas de seguimiento sobre la cotización o los detalles del seguro
   * Ofrecer enlaces a fuentes cuando sea apropiado

3. Gestión de la conversación

   * Mantenerse en el tema (seguro de automóviles)
   * Redirigir las preguntas fuera de tema hacia temas relevantes

4. Generación de cotizaciones

   * Hacer las preguntas apropiadas para determinar la elegibilidad para la cotización
   * Adaptar las preguntas según las respuestas del cliente
   * Enviar la información recopilada a la API de generación de cotizaciones
   * Presentar la cotización proporcionada al cliente

### Establece criterios de éxito

Trabaja con tu equipo de soporte para [definir criterios de éxito y escribir evaluaciones detalladas](https://platform.claude.com/docs/es/test-and-evaluate/develop-tests) con puntos de referencia y objetivos medibles.

Estos son criterios y puntos de referencia que pueden usarse para evaluar con qué éxito Claude realiza las tareas definidas:

<AccordionGroup>
  <Accordion title="Precisión en la comprensión de consultas">
    Esta métrica evalúa con qué precisión Claude entiende las consultas de los clientes en diversos temas. Mídela revisando una muestra de conversaciones y evaluando si Claude tiene la interpretación correcta de la intención del cliente, los siguientes pasos críticos, cómo se ve una resolución exitosa y más. Apunta a una precisión de comprensión del 95% o superior.
  </Accordion>

  <Accordion title="Relevancia de la respuesta">
    Esto evalúa qué tan bien la respuesta de Claude aborda la pregunta o el problema específico del cliente. Evalúa un conjunto de conversaciones y califica la relevancia de cada respuesta (usando calificación basada en LLM para escalar). Apunta a una puntuación de relevancia del 90% o superior.
  </Accordion>

  <Accordion title="Precisión de la respuesta">
    Evalúa la exactitud de la información general de la empresa y del producto proporcionada al usuario, con base en la información proporcionada a Claude en el contexto. Apunta a un 100% de precisión en esta información introductoria.
  </Accordion>

  <Accordion title="Relevancia en la provisión de citas">
    Haz seguimiento de la frecuencia y relevancia de los enlaces o fuentes ofrecidos. Apunta a proporcionar fuentes relevantes en el 80% de las interacciones donde la información adicional podría ser beneficiosa.
  </Accordion>

  <Accordion title="Adherencia al tema">
    Mide qué tan bien Claude se mantiene en el tema, como el tema del seguro de automóviles en la implementación de ejemplo. Apunta a que el 95% de las respuestas estén directamente relacionadas con el seguro de automóviles o la consulta específica del cliente.
  </Accordion>

  <Accordion title="Efectividad en la generación de contenido">
    Mide qué tan exitoso es Claude al determinar cuándo generar contenido informativo y qué tan relevante es ese contenido. Por ejemplo, en esta implementación, estarías determinando qué tan bien Claude entiende cuándo generar una cotización y qué tan precisa es esa cotización. Apunta a un 100% de precisión, ya que esta es información vital para una interacción exitosa con el cliente.
  </Accordion>

  <Accordion title="Eficiencia de escalamiento">
    Esto mide la capacidad de Claude para reconocer cuándo una consulta necesita intervención humana y escalarla adecuadamente. Haz seguimiento del porcentaje de conversaciones escaladas correctamente frente a aquellas que deberían haberse escalado pero no lo fueron. Apunta a una precisión de escalamiento del 95% o superior.
  </Accordion>
</AccordionGroup>

Estos son criterios y puntos de referencia que pueden usarse para evaluar el impacto comercial de emplear Claude para soporte:

<AccordionGroup>
  <Accordion title="Mantenimiento del sentimiento">
    Esto evalúa la capacidad de Claude para mantener o mejorar el sentimiento del cliente a lo largo de la conversación. Usa herramientas de análisis de sentimiento para medir el sentimiento al inicio y al final de cada conversación. Apunta a un sentimiento mantenido o mejorado en el 90% de las interacciones.
  </Accordion>

  <Accordion title="Tasa de deflexión">
    El porcentaje de consultas de clientes manejadas exitosamente por el chatbot sin intervención humana. Normalmente apunta a una tasa de deflexión del 70-80%, dependiendo de la complejidad de las consultas.
  </Accordion>

  <Accordion title="Puntuación de satisfacción del cliente">
    Una medida de qué tan satisfechos están los clientes con su interacción con el chatbot. Generalmente se realiza mediante encuestas posteriores a la interacción. Apunta a una puntuación CSAT de 4 de 5 o superior.
  </Accordion>

  <Accordion title="Tiempo promedio de atención">
    El tiempo promedio que tarda el chatbot en resolver una consulta. Esto varía ampliamente según la complejidad de los problemas, pero en general, apunta a un AHT más bajo en comparación con los agentes humanos.
  </Accordion>
</AccordionGroup>

## Cómo implementar Claude como agente de servicio al cliente

### Elige el modelo de Claude adecuado

La elección del modelo depende de las compensaciones entre costo, precisión y tiempo de respuesta.

Para el chat de atención al cliente, Claude Opus 5.5 es muy adecuado para equilibrar inteligencia, "latency" (latencia) y costo, incluidos los escenarios de soporte más complejos que requieren un razonamiento profundo a lo largo de conversaciones largas y de varios pasos. Sin embargo, en los casos en que tengas un flujo de conversación con múltiples prompts que incluyan RAG, uso de herramientas o prompts de contexto largo, Claude Haiku 5.5 puede ser más adecuado para optimizar la latencia. El [esfuerzo](https://platform.claude.com/docs/es/build-with-claude/effort) es su principal control de velocidad: `low` es el nivel más rápido, adecuado para chat y tareas cortas con herramientas.

### Construye un prompt sólido

Usar Claude para atención al cliente requiere que Claude tenga suficiente dirección y contexto para responder adecuadamente, y al mismo tiempo suficiente flexibilidad para manejar una amplia gama de consultas de clientes.

Comienza escribiendo los elementos de un prompt sólido, empezando por un "system prompt" (indicación del sistema). Crea un archivo llamado `config.py` y agrega cada uno de los siguientes bloques:

```python
IDENTITY = """You are Eva, a friendly and knowledgeable AI assistant for Acme Insurance
Company. Your role is to warmly welcome customers and provide information on
Acme's insurance offerings, which include car insurance and electric car
insurance. You can also help customers get quotes for their insurance needs."""
```

<Tip>
  Aunque puedas sentirte tentado a poner toda tu información dentro de una indicación del sistema como forma de separar las instrucciones de la conversación del usuario, Claude en realidad funciona mejor con la mayor parte del contenido de su prompt escrito dentro del primer turno de 

  `User`

   (con la única excepción del prompting de rol). Lee más en 

  [Darle un rol a Claude con una indicación del sistema](https://platform.claude.com/docs/es/build-with-claude/prompt-engineering/claude-prompting-best-practices#give-claude-a-role)

  .
</Tip>

Es mejor dividir los prompts complejos en subsecciones y escribir una parte a la vez. Para cada tarea, podrías tener más éxito siguiendo un proceso paso a paso para definir las partes del prompt que Claude necesitaría para realizar bien la tarea. Para este ejemplo de atención al cliente de seguros de automóviles, escribirás por partes todos los componentes de un prompt, comenzando con la tarea "Saludo y orientación general". Esto también facilita la depuración de tu prompt, ya que puedes ajustar más rápidamente las partes individuales del prompt general.

```python
STATIC_GREETINGS_AND_GENERAL = """
<static_context>
Acme Auto Insurance: Your Trusted Companion on the Road

About:
At Acme Insurance, we understand that your vehicle is more than just a mode of transportation—it's your ticket to life's adventures.
Since 1985, we've been crafting auto insurance policies that give drivers the confidence to explore, commute, and travel with peace of mind.
Whether you're navigating city streets or embarking on cross-country road trips, Acme is there to protect you and your vehicle.
Our innovative auto insurance policies are designed to adapt to your unique needs, covering everything from fender benders to major collisions.
With Acme's award-winning customer service and swift claim resolution, you can focus on the joy of driving while we handle the rest.
We're not just an insurance provider—we're your co-pilot in life's journeys.
Choose Acme Auto Insurance and experience the assurance that comes with superior coverage and genuine care. Because at Acme, we don't just
insure your car—we fuel your adventures on the open road.

Note: We also offer specialized coverage for electric vehicles, ensuring that drivers of all car types can benefit from our protection.

Acme Insurance offers the following products:
- Car insurance
- Electric car insurance
- Two-wheeler insurance

Business hours: Monday-Friday, 9 AM - 5 PM EST
Customer service number: 1-800-123-4567
</static_context>
"""
```

Luego haz lo mismo con la información sobre seguros de automóviles y seguros de automóviles eléctricos.

```python
STATIC_CAR_INSURANCE = """
<static_context>
Car Insurance Coverage:
Acme's car insurance policies typically cover:
1. Liability coverage: Pays for bodily injury and property damage you cause to others.
2. Collision coverage: Pays for damage to your car in an accident.
3. Comprehensive coverage: Pays for damage to your car from non-collision incidents.
4. Medical payments coverage: Pays for medical expenses after an accident.
5. Uninsured/underinsured motorist coverage: Protects you if you're hit by a driver with insufficient insurance.

Optional coverages include:
- Rental car reimbursement
- Roadside assistance
- New car replacement
</static_context>
"""

STATIC_ELECTRIC_CAR_INSURANCE = """
<static_context>
Electric Car Insurance:
Our specialized electric car insurance goes beyond traditional auto coverage,
offering tailored protection for your high-tech investment. In addition to standard coverages, we offer:
- Safeguarding expensive battery systems
- Covering home charging equipment
- Adapting to the rapidly evolving world of electric vehicles

Whether you're driving a Rivian, Nissan Leaf, Chevrolet Bolt,
or any other electric vehicle, our knowledgeable agents are ready to craft a policy
that gives you the confidence to enjoy every electron-powered mile.
</static_context>
"""
```

Ahora que tienes tu contenido estático, agrega al menos 4-5 interacciones "buenas" de ejemplo para guiar las respuestas de Claude. Estos ejemplos deben ser representativos de tu interacción ideal con el cliente y pueden incluir elementos como barreras de protección y llamadas a herramientas.

```python
EXAMPLES = """
Here are a few examples of how you can interact with customers:

<example 1>
H: Hi, do you offer commercial insurance for small businesses?

A: Ah! Unfortunately, we don't offer commercial insurance at this time.
However, we do provide a range of personal insurance products including car insurance and electric car insurance.
Would you like to know more about these offerings?
</example 1>

<example 2>
H: Hi, what are your business hours?

A: Our business hours are Monday to Friday, 9 AM to 5 PM EST.
If you have any questions or need assistance, feel free to reach out during those times.
How else can I assist you today?
</example 2>

<example 3>
H: I'm shopping for car insurance. What does Acme offer?

A: Great choice! Acme's car insurance policies typically include:
- Liability coverage: Protects you if you're at fault in an accident
- Collision coverage: Pays for damage to your car in an accident
- Comprehensive coverage: Covers non-collision incidents like theft or vandalism
- Medical payments coverage: Pays for medical expenses after an accident
- Uninsured/underinsured motorist coverage: Protects you from drivers with insufficient insurance

We also offer optional coverages like rental car reimbursement, roadside assistance, and new car replacement.
Would you like more details on any of these coverages, or do you have specific questions about insuring your vehicle?
</example 3>

<example 4>
H: I'd like to hear about your electric car insurance.

A: Certainly! Our electric car insurance is specially designed to meet the unique needs of electric vehicle owners.
In addition to all the standard coverages we offer for regular cars, our electric car policies include:

- Battery coverage: Protection against damage or degradation of your vehicle's expensive battery system
- Tech package: Covers repairs or replacement of advanced electronics and onboard computer systems
- Charging station coverage: Protects both home and portable charging equipment
- Cybersecurity protection: Coverage against hacking or digital threats
- Specialized roadside assistance: Includes flatbed towing to protect the vehicle's undercarriage

We cover a wide range of electric vehicles, including popular models from Tesla, Rivian, Nissan, Chevrolet, and more.
Is there a specific electric vehicle you're looking to insure, or would you like more details on any of these coverages?
</example 4>

<example 5>
H: I'd like to get a quote for my car insurance.

A: Certainly! I'd be happy to help you get a quote for your car insurance.
To provide you with an accurate quote, I'll need to collect some information about your vehicle and the primary driver.
Let's start with the basics:

1. What is the make and model of your vehicle?
2. What year was it manufactured?
3. Approximately how many miles have you driven?
4. What is the age of the primary driver?

Once you provide this information, I'll use our quoting tool to generate a personalized insurance quote for you.
</example 5>
"""
```

También querrás incluir cualquier instrucción importante que describa lo que Claude debe y no debe hacer al interactuar con el cliente. Esto puede basarse en las barreras de protección de la marca o en las políticas de soporte.

```python
ADDITIONAL_GUARDRAILS = """Please adhere to the following guardrails:
1. Only provide information about insurance types listed in our offerings.
2. If asked about an insurance type we don't offer, politely state
that we don't provide that service.
3. Do not speculate about future product offerings or company plans.
4. Don't make promises or enter into agreements it's not authorized to make.
You only provide information and guidance.
5. Do not mention any competitor's products or services.
"""
```

Ahora combina todas estas secciones en una sola cadena para usarla como tu prompt.

```python
TASK_SPECIFIC_INSTRUCTIONS = " ".join(
    [
        STATIC_GREETINGS_AND_GENERAL,
        STATIC_CAR_INSURANCE,
        STATIC_ELECTRIC_CAR_INSURANCE,
        EXAMPLES,
        ADDITIONAL_GUARDRAILS,
    ]
)
```

### Agrega capacidades dinámicas y agénticas con el uso de herramientas

Claude es capaz de realizar acciones y recuperar información dinámicamente usando la funcionalidad de "tool use" (uso de herramientas) del lado del cliente. Comienza enumerando las herramientas externas o APIs que el prompt debería usar.

Para este ejemplo, comienza con una herramienta para calcular la cotización.

<Tip>
  Como recordatorio, esta herramienta no realizará el cálculo real; solo le indicará a la aplicación que se debe usar una herramienta con los argumentos especificados.
</Tip>

Agrega el nombre del modelo, la definición de la herramienta y una implementación provisional (stub) a `config.py`:

```python
import time

MODEL = "claude-opus-5-5"

TOOLS = [
    {
        "name": "get_quote",
        "description": "Calculate the insurance quote based on user input. Returned value is per month premium.",
        "input_schema": {
            "type": "object",
            "properties": {
                "make": {"type": "string", "description": "The make of the vehicle."},
                "model": {"type": "string", "description": "The model of the vehicle."},
                "year": {
                    "type": "integer",
                    "description": "The year the vehicle was manufactured.",
                },
                "mileage": {
                    "type": "integer",
                    "description": "The mileage on the vehicle.",
                },
                "driver_age": {
                    "type": "integer",
                    "description": "The age of the primary driver.",
                },
            },
            "required": ["make", "model", "year", "mileage", "driver_age"],
        },
    }
]


def get_quote(make, model, year, mileage, driver_age):
    """Returns the premium per month in USD"""
    # Puedes llamar a un endpoint HTTP o a una base de datos para obtener la cotización.
    # Aquí simulamos un retraso de 1 segundo y devolvemos una cotización fija de 100.
    time.sleep(1)
    return 100
```

### Despliega tus prompts

Es difícil saber qué tan bien funciona tu prompt sin desplegarlo en un entorno de producción de prueba y [ejecutar evaluaciones](https://platform.claude.com/docs/es/test-and-evaluate/develop-tests). Construye una pequeña aplicación usando el prompt, el SDK de Anthropic y Streamlit para la interfaz de usuario.

En un archivo llamado `chatbot.py` (o el módulo equivalente en tu lenguaje), configura la clase ChatBot, que encapsulará las interacciones con el SDK de Anthropic.

La clase debe tener dos métodos principales: uno que llama a la API para generar un mensaje y otro que procesa cada entrada del usuario.

<CodeGroup exclude="shell">
  ```python Python
  # En tu chatbot.py, importa esto desde el config.py que escribiste arriba:
  # from config import IDENTITY, TOOLS, MODEL, get_quote
  from anthropic import Anthropic
  from dotenv import load_dotenv

  load_dotenv()


  class ChatBot:
      def __init__(self, session_state):
          self.anthropic = Anthropic()
          self.session_state = session_state

      def generate_message(
          self,
          messages,
          max_tokens,
      ):
          try:
              response = self.anthropic.messages.create(
                  model=MODEL,
                  system=IDENTITY,
                  max_tokens=max_tokens,
                  messages=messages,
                  tools=TOOLS,
              )
              return response
          except Exception as e:
              return {"error": str(e)}

      def process_user_input(self, user_input):
          self.session_state.messages.append({"role": "user", "content": user_input})

          response_message = self.generate_message(
              messages=self.session_state.messages,
              max_tokens=2048,
          )

          if "error" in response_message:
              return f"An error occurred: {response_message['error']}"

          if response_message.content[-1].type == "tool_use":
              tool_use = response_message.content[-1]
              func_name = tool_use.name
              func_params = tool_use.input
              tool_use_id = tool_use.id

              result = self.handle_tool_use(func_name, func_params)
              self.session_state.messages.append(
                  {"role": "assistant", "content": response_message.content}
              )
              self.session_state.messages.append(
                  {
                      "role": "user",
                      "content": [
                          {
                              "type": "tool_result",
                              "tool_use_id": tool_use_id,
                              "content": f"{result}",
                          }
                      ],
                  }
              )

              follow_up_response = self.generate_message(
                  messages=self.session_state.messages,
                  max_tokens=2048,
              )

              if "error" in follow_up_response:
                  return f"An error occurred: {follow_up_response['error']}"

              response_text = next(
                  (
                      block.text
                      for block in follow_up_response.content
                      if block.type == "text"
                  ),
                  None,
              )
              if response_text is None:
                  raise Exception("An error occurred: Unexpected response type")
              self.session_state.messages.append(
                  {"role": "assistant", "content": response_text}
              )
              return response_text

          text_block = next(
              (block for block in response_message.content if block.type == "text"), None
          )
          if text_block is not None:
              response_text = text_block.text
              self.session_state.messages.append(
                  {"role": "assistant", "content": response_text}
              )
              return response_text

          raise Exception("An error occurred: Unexpected response type")

      def handle_tool_use(self, func_name, func_params):
          if func_name == "get_quote":
              premium = get_quote(**func_params)
              return f"Quote generated: ${premium:.2f} per month"

          raise Exception("An unexpected tool was used")
  ```

  ```typescript TypeScript
  import Anthropic from "@anthropic-ai/sdk";

  class ChatBot {
    // IDENTITY, MODEL, TOOLS y getQuote replican los valores de config.py definidos
    // anteriormente en esta guía (mostrados en Python).
    readonly anthropic = new Anthropic();
    readonly messages: Anthropic.MessageParam[] = [];

    async generateMessage(
      messages: Anthropic.MessageParam[],
      maxTokens: number
    ): Promise<Anthropic.Message> {
      return this.anthropic.messages.create({
        model: MODEL,
        system: IDENTITY,
        max_tokens: maxTokens,
        messages,
        tools: TOOLS
      });
    }

    async processUserInput(userInput: string): Promise<string> {
      this.messages.push({ role: "user", content: userInput });

      const responseMessage = await this.generateMessage(this.messages, 2048);

      const lastBlock = responseMessage.content.at(-1);
      if (lastBlock?.type === "tool_use") {
        const toolResult = this.handleToolUse(lastBlock.name, lastBlock.input);

        this.messages.push({ role: "assistant", content: responseMessage.content });
        this.messages.push({
          role: "user",
          content: [{ type: "tool_result", tool_use_id: lastBlock.id, content: toolResult }]
        });

        const followUpResponse = await this.generateMessage(this.messages, 2048);

        const followUpBlock = followUpResponse.content.find((block) => block.type === "text");
        if (!followUpBlock) {
          throw new Error("An error occurred: Unexpected response type");
        }
        this.messages.push({ role: "assistant", content: followUpBlock.text });
        return followUpBlock.text;
      }

      const firstBlock = responseMessage.content.find((block) => block.type === "text");
      if (firstBlock) {
        this.messages.push({ role: "assistant", content: firstBlock.text });
        return firstBlock.text;
      }

      throw new Error("An error occurred: Unexpected response type");
    }

    handleToolUse(toolName: string, toolInput: unknown): string {
      if (toolName === "get_quote") {
        // El SDK tipa tool_use.input como unknown; redúcelo al esquema de get_quote.
        if (
          toolInput === null ||
          typeof toolInput !== "object" ||
          !("make" in toolInput) ||
          typeof toolInput.make !== "string" ||
          !("model" in toolInput) ||
          typeof toolInput.model !== "string" ||
          !("year" in toolInput) ||
          typeof toolInput.year !== "number" ||
          !("mileage" in toolInput) ||
          typeof toolInput.mileage !== "number" ||
          !("driver_age" in toolInput) ||
          typeof toolInput.driver_age !== "number"
        ) {
          throw new Error("An error occurred: Unexpected tool input");
        }
        const { make, model: vehicleModel, year, mileage, driver_age: driverAge } = toolInput;

        const premium = getQuote(make, vehicleModel, year, mileage, driverAge);
        return `Quote generated: $${premium.toFixed(2)} per month`;
      }

      throw new Error("An unexpected tool was used");
    }
  }
  ```

  ```csharp C#
  using System.Text.Json;
  using Anthropic;
  using Anthropic.Models.Messages;

  // Config.Model, Config.Identity, Config.Tools y Config.GetQuote reflejan
  // los valores de config.py definidos antes en esta guía (mostrados en Python).
  public class ChatBot
  {
      private readonly AnthropicClient _anthropic = new();

      public List<MessageParam> Messages { get; } = [];

      public async Task<Message> GenerateMessage(List<MessageParam> messages, long maxTokens) =>
          await _anthropic.Messages.Create(
              new MessageCreateParams
              {
                  Model = Config.Model,
                  System = Config.Identity,
                  MaxTokens = maxTokens,
                  Messages = messages,
                  Tools = Config.Tools,
              }
          );

      public async Task<string> ProcessUserInput(string userInput)
      {
          Messages.Add(new() { Role = Role.User, Content = userInput });

          var responseMessage = await GenerateMessage(Messages, maxTokens: 2048);

          if (responseMessage.Content[^1].TryPickToolUse(out var toolUse))
          {
              var toolResult = HandleToolUse(toolUse.Name, toolUse.Input);

              Messages.Add(new()
              {
                  Role = Role.Assistant,
                  Content = responseMessage.Content
                      .Select(contentBlock => new ContentBlockParam(contentBlock.Json))
                      .ToList(),
              });
              Messages.Add(new()
              {
                  Role = Role.User,
                  Content = new List<ContentBlockParam>
                  {
                      new ToolResultBlockParam { ToolUseID = toolUse.ID, Content = toolResult },
                  },
              });

              var followUpResponse = await GenerateMessage(Messages, maxTokens: 2048);

              foreach (var block in followUpResponse.Content)
              {
                  if (block.TryPickText(out var followUpText))
                  {
                      Messages.Add(new() { Role = Role.Assistant, Content = followUpText.Text });
                      return followUpText.Text;
                  }
              }

              throw new InvalidOperationException("An error occurred: Unexpected response type");
          }

          foreach (var block in responseMessage.Content)
          {
              if (block.TryPickText(out var textBlock))
              {
                  Messages.Add(new() { Role = Role.Assistant, Content = textBlock.Text });
                  return textBlock.Text;
              }
          }

          throw new InvalidOperationException("An error occurred: Unexpected response type");
      }

      public string HandleToolUse(string funcName, IReadOnlyDictionary<string, JsonElement> funcParams)
      {
          if (funcName == "get_quote")
          {
              var premium = Config.GetQuote(
                  funcParams["make"].GetString()!,
                  funcParams["model"].GetString()!,
                  funcParams["year"].GetInt64(),
                  funcParams["mileage"].GetInt64(),
                  funcParams["driver_age"].GetInt64()
              );
              return $"Quote generated: ${premium:F2} per month";
          }

          throw new ArgumentException("An unexpected tool was used");
      }
  }
  ```

  ```go Go
  import (
  	"context"
  	"encoding/json"
  	"fmt"

  	"github.com/anthropics/anthropic-sdk-go"
  )

  // ChatBot envuelve el cliente de Anthropic y el historial de conversación. Los
  // valores de identity, model, tools y getQuote que usa reflejan las definiciones
  // de config.py mostradas antes en esta guía (en Python).
  type ChatBot struct {
  	client   anthropic.Client
  	messages []anthropic.MessageParam
  }

  func NewChatBot() *ChatBot {
  	return &ChatBot{client: anthropic.NewClient()}
  }

  func (bot *ChatBot) GenerateMessage(ctx context.Context, messages []anthropic.MessageParam, maxTokens int64) (*anthropic.Message, error) {
  	return bot.client.Messages.New(ctx, anthropic.MessageNewParams{
  		Model:     model,
  		System:    []anthropic.TextBlockParam{{Text: identity}},
  		MaxTokens: maxTokens,
  		Messages:  messages,
  		Tools:     tools,
  	})
  }

  func (bot *ChatBot) ProcessUserInput(ctx context.Context, userInput string) (string, error) {
  	bot.messages = append(bot.messages, anthropic.NewUserMessage(anthropic.NewTextBlock(userInput)))

  	response, err := bot.GenerateMessage(ctx, bot.messages, 2048)
  	if err != nil {
  		return "", err
  	}

  	lastBlock := response.Content[len(response.Content)-1]
  	if toolUse, ok := lastBlock.AsAny().(anthropic.ToolUseBlock); ok {
  		result, err := bot.HandleToolUse(toolUse.Name, toolUse.Input)
  		if err != nil {
  			return "", err
  		}

  		bot.messages = append(bot.messages,
  			response.ToParam(),
  			anthropic.NewUserMessage(anthropic.NewToolResultBlock(toolUse.ID, result, false)),
  		)

  		followUp, err := bot.GenerateMessage(ctx, bot.messages, 2048)
  		if err != nil {
  			return "", err
  		}

  		for _, block := range followUp.Content {
  			if textBlock, ok := block.AsAny().(anthropic.TextBlock); ok {
  				bot.messages = append(bot.messages, anthropic.NewAssistantMessage(anthropic.NewTextBlock(textBlock.Text)))
  				return textBlock.Text, nil
  			}
  		}
  		return "", fmt.Errorf("an error occurred: unexpected response type")
  	}

  	for _, block := range response.Content {
  		if textBlock, ok := block.AsAny().(anthropic.TextBlock); ok {
  			bot.messages = append(bot.messages, anthropic.NewAssistantMessage(anthropic.NewTextBlock(textBlock.Text)))
  			return textBlock.Text, nil
  		}
  	}

  	return "", fmt.Errorf("an error occurred: unexpected response type")
  }

  func (bot *ChatBot) HandleToolUse(toolName string, toolInput json.RawMessage) (string, error) {
  	if toolName != "get_quote" {
  		return "", fmt.Errorf("an unexpected tool was used: %s", toolName)
  	}

  	var input struct {
  		Make      string `json:"make"`
  		Model     string `json:"model"`
  		Year      int    `json:"year"`
  		Mileage   int    `json:"mileage"`
  		DriverAge int    `json:"driver_age"`
  	}
  	if err := json.Unmarshal(toolInput, &input); err != nil {
  		return "", err
  	}
  	premium := getQuote(input.Make, input.Model, input.Year, input.Mileage, input.DriverAge)
  	return fmt.Sprintf("Quote generated: $%.2f per month", premium), nil
  }
  ```

  ```java Java
  import com.anthropic.client.AnthropicClient;
  import com.anthropic.client.okhttp.AnthropicOkHttpClient;
  import com.anthropic.core.JsonValue;
  import com.anthropic.models.messages.ContentBlock;
  import com.anthropic.models.messages.ContentBlockParam;
  import com.anthropic.models.messages.Message;
  import com.anthropic.models.messages.MessageCreateParams;
  import com.anthropic.models.messages.MessageParam;
  import com.anthropic.models.messages.ToolResultBlockParam;
  import com.anthropic.models.messages.ToolUseBlock;

  // IDENTITY, MODEL, TOOLS y getQuote reflejan los valores de config.py definidos
  // anteriormente en esta guía (mostrados en Python).
  class ChatBot {
      final AnthropicClient anthropic;
      final List<MessageParam> messages;

      ChatBot() {
          // Lee la clave de API de la variable de entorno ANTHROPIC_API_KEY
          this.anthropic = AnthropicOkHttpClient.fromEnv();
          this.messages = new ArrayList<>();
      }

      Message generateMessage(List<MessageParam> messages, long maxTokens) {
          return anthropic.messages().create(MessageCreateParams.builder()
                  .model(MODEL)
                  .system(IDENTITY)
                  .maxTokens(maxTokens)
                  .messages(messages)
                  .tools(TOOLS)
                  .build());
      }

      String processUserInput(String userInput) {
          messages.add(MessageParam.builder()
                  .role(MessageParam.Role.USER)
                  .content(userInput)
                  .build());

          Message responseMessage = generateMessage(messages, 2048);

          List<ContentBlock> content = responseMessage.content();
          ContentBlock lastBlock = content.getLast();
          if (lastBlock.isToolUse()) {
              ToolUseBlock toolUse = lastBlock.asToolUse();
              Map<String, JsonValue> toolInput =
                      (Map<String, JsonValue>) toolUse._input().asObject().orElseThrow();
              String result = handleToolUse(toolUse.name(), toolInput);

              messages.add(MessageParam.builder()
                      .role(MessageParam.Role.ASSISTANT)
                      .contentOfBlockParams(content.stream().map(ContentBlock::toParam).toList())
                      .build());
              messages.add(MessageParam.builder()
                      .role(MessageParam.Role.USER)
                      .contentOfBlockParams(List.of(ContentBlockParam.ofToolResult(
                              ToolResultBlockParam.builder()
                                      .toolUseId(toolUse.id())
                                      .content(result)
                                      .build())))
                      .build());

              Message followUpResponse = generateMessage(messages, 2048);

              ContentBlock followUpBlock = followUpResponse.content().stream()
                      .filter(ContentBlock::isText)
                      .findFirst()
                      .orElseThrow(() -> new IllegalStateException("An error occurred: Unexpected response type"));
              String responseText = followUpBlock.asText().text();
              messages.add(MessageParam.builder()
                      .role(MessageParam.Role.ASSISTANT)
                      .content(responseText)
                      .build());
              return responseText;
          } else {
              ContentBlock textBlock = content.stream()
                      .filter(ContentBlock::isText)
                      .findFirst()
                      .orElseThrow(() -> new IllegalStateException("An error occurred: Unexpected response type"));
              String responseText = textBlock.asText().text();
              messages.add(MessageParam.builder()
                      .role(MessageParam.Role.ASSISTANT)
                      .content(responseText)
                      .build());
              return responseText;
          }
      }

      String handleToolUse(String funcName, Map<String, JsonValue> funcParams) {
          return switch (funcName) {
              case "get_quote" -> {
                  double premium = getQuote(
                          funcParams.get("make").asStringOrThrow(),
                          funcParams.get("model").asStringOrThrow(),
                          ((Number) funcParams.get("year").asNumber().orElseThrow()).longValue(),
                          ((Number) funcParams.get("mileage").asNumber().orElseThrow()).longValue(),
                          ((Number) funcParams.get("driver_age").asNumber().orElseThrow()).longValue());
                  yield "Quote generated: $%.2f per month".formatted(premium);
              }
              default -> throw new IllegalArgumentException("An unexpected tool was used");
          };
      }
  }
  ```

  ```php PHP
  use Anthropic\Client;
  use Anthropic\Messages\Message;
  use Anthropic\Messages\MessageParam;
  use Anthropic\Messages\TextBlock;
  use Anthropic\Messages\ToolResultBlockParam;
  use Anthropic\Messages\ToolUseBlock;

  class ChatBot
  {
      // MODEL, IDENTITY, TOOLS y get_quote() reflejan los valores de config.py
      // definidos anteriormente en esta guía (mostrados en Python).

      /** @var list<MessageParam> */
      public private(set) array $messages = [];

      public function __construct(
          private readonly Client $anthropic = new Client(),
      ) {}

      /**
       * @param list<MessageParam> $messages
       */
      public function generateMessage(array $messages, int $maxTokens): Message
      {
          return $this->anthropic->messages->create(
              model: MODEL,
              system: IDENTITY,
              maxTokens: $maxTokens,
              messages: $messages,
              tools: TOOLS,
          );
      }

      public function processUserInput(string $userInput): string
      {
          $this->messages[] = MessageParam::with(role: 'user', content: $userInput);

          $responseMessage = $this->generateMessage($this->messages, maxTokens: 2048);

          $content = $responseMessage->content;
          $lastBlock = array_last($content);

          if ($lastBlock instanceof ToolUseBlock) {
              $toolResult = $this->handleToolUse($lastBlock->name, $lastBlock->input);

              $this->messages[] = MessageParam::with(role: 'assistant', content: $content);
              $this->messages[] = MessageParam::with(
                  role: 'user',
                  content: [
                      ToolResultBlockParam::with(toolUseID: $lastBlock->id, content: $toolResult),
                  ],
              );

              $followUpResponse = $this->generateMessage($this->messages, maxTokens: 2048);

              $firstBlock = array_find(
                  $followUpResponse->content,
                  static fn ($block): bool => $block instanceof TextBlock,
              );
              if (!$firstBlock instanceof TextBlock) {
                  throw new \RuntimeException('An error occurred: Unexpected response type');
              }

              $this->messages[] = MessageParam::with(role: 'assistant', content: $firstBlock->text);

              return $firstBlock->text;
          }

          $firstBlock = array_find($content, static fn ($block): bool => $block instanceof TextBlock);
          if ($firstBlock instanceof TextBlock) {
              $this->messages[] = MessageParam::with(role: 'assistant', content: $firstBlock->text);

              return $firstBlock->text;
          }

          throw new \RuntimeException('An error occurred: Unexpected response type');
      }

      /**
       * @param array<string, mixed> $funcParams
       */
      private function handleToolUse(string $funcName, array $funcParams): string
      {
          if ($funcName === 'get_quote') {
              $premium = get_quote(...$funcParams);

              return sprintf('Quote generated: $%.2f per month', $premium);
          }

          throw new \RuntimeException('An unexpected tool was used');
      }
  }
  ```

  ```ruby Ruby
  # IDENTITY, MODEL, TOOLS y get_quote reflejan los valores de config.py definidos
  # anteriormente en esta guía (mostrados en Python).
  require "anthropic"

  class ChatBot
    attr_reader :messages

    def initialize
      @anthropic = Anthropic::Client.new
      @messages = []
    end

    def generate_message(messages, max_tokens)
      @anthropic.messages.create(
        model: MODEL,
        system_: IDENTITY,
        max_tokens:,
        messages:,
        tools: TOOLS
      )
    end

    def process_user_input(user_input)
      @messages << {role: "user", content: user_input}

      response_message = generate_message(@messages, 2048)

      case response_message.content
      in [*, Anthropic::ToolUseBlock => tool_use]
        result = handle_tool_use(tool_use.name, tool_use.input)
        @messages << {role: "assistant", content: response_message.content}
        @messages << {
          role: "user",
          content: [{type: "tool_result", tool_use_id: tool_use.id, content: result}]
        }

        follow_up_response = generate_message(@messages, 2048)

        case follow_up_response.content
        in [*, Anthropic::TextBlock => text_block, *]
          @messages << {role: "assistant", content: text_block.text}
          text_block.text
        else
          raise "An error occurred: Unexpected response type"
        end
      in [*, Anthropic::TextBlock => text_block, *]
        @messages << {role: "assistant", content: text_block.text}
        text_block.text
      else
        raise "An error occurred: Unexpected response type"
      end
    end

    def handle_tool_use(tool_name, tool_input)
      raise "An unexpected tool was used" unless tool_name == "get_quote"

      premium = get_quote(**tool_input)
      format("Quote generated: $%.2f per month", premium)
    end
  end
  ```
</CodeGroup>

### Construye tu interfaz de usuario

Prueba desplegar este código con Streamlit usando un método principal. Esta función `main()` configura una interfaz de chat basada en Streamlit. Streamlit es un framework de Python, por lo que esta parte del recorrido se muestra solo en Python; la clase ChatBot anterior es la pieza que puedes portar a cualquier lenguaje.

Haz esto en un archivo llamado `app.py`

```python
import streamlit as st
from chatbot import ChatBot
from config import TASK_SPECIFIC_INSTRUCTIONS


def main():
    st.title("Chat with Eva, Acme Insurance Company's Assistant🤖")

    if "messages" not in st.session_state:
        st.session_state.messages = [
            {"role": "user", "content": TASK_SPECIFIC_INSTRUCTIONS},
            {"role": "assistant", "content": "Understood"},
        ]

    chatbot = ChatBot(st.session_state)

    # Muestra los mensajes del usuario y del asistente omitiendo los dos primeros
    for message in st.session_state.messages[2:]:
        # ignora los bloques de uso de herramientas
        if isinstance(message["content"], str):
            with st.chat_message(message["role"]):
                st.markdown(message["content"])

    if user_msg := st.chat_input("Type your message here..."):
        st.chat_message("user").markdown(user_msg)

        with st.chat_message("assistant"):
            with st.spinner("Eva is thinking..."):
                response_placeholder = st.empty()
                full_response = chatbot.process_user_input(user_msg)
                response_placeholder.markdown(full_response)


if __name__ == "__main__":
    main()
```

Ejecuta el programa con:

```bash
streamlit run app.py
```

### Evalúa tus prompts

El prompting a menudo requiere pruebas y optimización para estar listo para producción. Para determinar la preparación de tu solución, evalúa el rendimiento del chatbot usando un proceso sistemático que combine métodos cuantitativos y cualitativos. Crear una [evaluación empírica sólida](https://platform.claude.com/docs/es/test-and-evaluate/develop-tests#build-evaluations) basada en tus criterios de éxito definidos te permitirá optimizar tus prompts.

### Mejora el rendimiento

En escenarios complejos, puede ser útil considerar estrategias adicionales para mejorar el rendimiento más allá de las [técnicas de ingeniería de prompts](https://platform.claude.com/docs/es/build-with-claude/prompt-engineering/overview) estándar y las [estrategias de implementación de barreras de protección](https://platform.claude.com/docs/es/test-and-evaluate/strengthen-guardrails/reduce-hallucinations). Estos son algunos escenarios comunes:

#### Reduce la latencia de contexto largo con RAG

Cuando se trabaja con grandes cantidades de contexto estático y dinámico, incluir toda la información en el prompt puede generar costos elevados, tiempos de respuesta más lentos y alcanzar los límites de la "context window" (ventana de contexto). En este escenario, implementar técnicas de "Retrieval Augmented Generation" (generación aumentada por recuperación), o RAG, puede mejorar el rendimiento y la eficiencia.

Puedes crear un sistema más escalable y con mejor capacidad de respuesta convirtiendo la información en representaciones vectoriales con [modelos de embeddings](https://platform.claude.com/docs/es/build-with-claude/embeddings), como los de Voyage AI by MongoDB. Este enfoque permite la recuperación dinámica de información relevante según la consulta actual, en lugar de incluir todo el contexto posible en cada prompt.

Se ha demostrado que implementar RAG para casos de uso de soporte aumenta la precisión, reduce los tiempos de respuesta y reduce los costos de API en sistemas con requisitos de contexto extensos. Consulta la [receta de RAG](https://platform.claude.com/cookbook/capabilities-retrieval-augmented-generation-guide) para ver un ejemplo desarrollado.

#### Integra datos en tiempo real con el uso de herramientas

Cuando se trata de consultas que requieren información en tiempo real, como saldos de cuentas o detalles de pólizas, los enfoques de RAG basados en embeddings no son suficientes. En su lugar, el uso de herramientas puede mejorar la capacidad de tu chatbot para proporcionar respuestas precisas en tiempo real. Por ejemplo, puedes usar el uso de herramientas para buscar información del cliente, recuperar detalles de pedidos y cancelar pedidos en nombre del cliente.

Este enfoque, [descrito en la receta de uso de herramientas: agente de servicio al cliente](https://platform.claude.com/cookbook/tool-use-customer-service-agent), te permite integrar datos en vivo en las respuestas de Claude y brindar una experiencia al cliente más personalizada y eficiente.

#### Refuerza las barreras de protección de entrada y salida

Al desplegar un chatbot, especialmente en escenarios de servicio al cliente, es importante prevenir los riesgos asociados con el uso indebido, las consultas fuera de alcance y las respuestas inapropiadas. Aunque Claude es inherentemente resistente a estos escenarios, estos son pasos adicionales para reforzar las barreras de protección de tu chatbot:

* [Reducir las alucinaciones](https://platform.claude.com/docs/es/test-and-evaluate/strengthen-guardrails/reduce-hallucinations): Implementa mecanismos de verificación de hechos y [citas](https://platform.claude.com/cookbook/misc-using-citations) para fundamentar las respuestas en la información proporcionada.
* Verificar la información de forma cruzada: Verifica que las respuestas del agente se alineen con las políticas de tu empresa y los hechos conocidos.
* Evitar compromisos contractuales: Asegúrate de que el agente no haga promesas ni celebre acuerdos que no esté autorizado a hacer.
* [Mitigar jailbreaks](https://platform.claude.com/docs/es/test-and-evaluate/strengthen-guardrails/mitigate-jailbreaks): Usa métodos como filtros de inocuidad y validación de entradas para evitar que los usuarios exploten vulnerabilidades del modelo con el objetivo de generar contenido inapropiado.
* Evitar mencionar a la competencia: Implementa un filtro de menciones de competidores para mantener el enfoque en la marca y no mencionar los productos o servicios de ningún competidor.
* [Aumentar la consistencia de las salidas](https://platform.claude.com/docs/es/test-and-evaluate/strengthen-guardrails/increase-consistency): Evita que Claude cambie de estilo o se salga de su personaje, incluso durante interacciones largas y complejas.
* Eliminar la información de identificación personal (PII): A menos que se requiera y autorice explícitamente, elimina cualquier PII de las respuestas.

#### Reduce el tiempo de respuesta percibido con streaming

Cuando se trata de respuestas potencialmente largas, implementar "streaming" (streaming) puede mejorar la participación y la satisfacción del usuario. En este escenario, los usuarios reciben la respuesta progresivamente en lugar de esperar a que se genere la respuesta completa.

Así es como se implementa el streaming:

1. Usa la [API de Streaming de Anthropic](https://platform.claude.com/docs/es/build-with-claude/streaming) para admitir respuestas en streaming.
2. Configura tu frontend para manejar los fragmentos de texto entrantes.
3. Muestra cada fragmento a medida que llega, simulando la escritura en tiempo real.
4. Implementa un mecanismo para guardar la respuesta completa, permitiendo que los usuarios la vean si salen de la página y regresan.

En algunos casos, el streaming permite el uso de modelos más avanzados con latencias base más altas, ya que la visualización progresiva mitiga el impacto de los tiempos de procesamiento más largos.

#### Escala tu chatbot

A medida que crece la complejidad de tu chatbot, la arquitectura de tu aplicación puede evolucionar para adaptarse. Antes de agregar más capas a tu arquitectura, considera las siguientes opciones menos exhaustivas:

* Asegúrate de estar aprovechando al máximo tus prompts y optimizando mediante la ingeniería de prompts. Usa las [guías de ingeniería de prompts](https://platform.claude.com/docs/es/build-with-claude/prompt-engineering/overview) para escribir los prompts más efectivos.
* Agrega [herramientas](https://platform.claude.com/docs/es/agents-and-tools/tool-use/overview) adicionales al prompt (que pueden incluir [cadenas de prompts](https://platform.claude.com/docs/es/build-with-claude/prompt-engineering/claude-prompting-best-practices#chain-complex-prompts)) y comprueba si puedes lograr la funcionalidad requerida.

Si tu chatbot maneja tareas increíblemente variadas, quizás quieras considerar agregar un [clasificador de intenciones separado](https://platform.claude.com/cookbook/capabilities-classification-guide) para enrutar la consulta inicial del cliente. Para la aplicación existente, esto implicaría crear un árbol de decisiones que enrutaría las consultas de los clientes a través del clasificador y luego hacia conversaciones especializadas (con su propio conjunto de herramientas e indicaciones del sistema). Ten en cuenta que este método requiere una llamada adicional a Claude que puede aumentar la latencia.

### Integra Claude en tu flujo de trabajo de soporte

Aunque estos ejemplos se han centrado en funciones de Python que se pueden llamar dentro de un entorno de Streamlit, desplegar Claude para un chatbot de soporte en tiempo real requiere un servicio de API.

Así es como puedes abordarlo:

1. Crea un wrapper de API: Desarrolla un wrapper de API simple alrededor de tu función de clasificación. Por ejemplo, puedes usar Flask API o Fast API para envolver tu código en un servicio HTTP. Tu servicio HTTP podría aceptar la entrada del usuario y devolver la respuesta del asistente en su totalidad. Así, tu servicio podría tener las siguientes características:

   * Server-Sent Events (SSE): SSE permite el streaming en tiempo real de las respuestas del servidor al cliente. Esto proporciona una experiencia fluida e interactiva al trabajar con LLMs.
   * Almacenamiento en caché: Implementar almacenamiento en caché puede mejorar los tiempos de respuesta y reducir las llamadas innecesarias a la API.
   * Retención de contexto: Mantener el contexto cuando un usuario sale de la página y regresa es importante para la continuidad de las conversaciones.

2. Construye una interfaz web: Implementa una interfaz web fácil de usar para interactuar con el agente impulsado por Claude.

## Próximos pasos

<CardGroup cols={2}>
  <Card title="Uso de herramientas" icon="wrench" href="https://platform.claude.com/docs/es/agents-and-tools/tool-use/overview">
    Dale a Claude acceso a tus APIs para que pueda actuar en nombre de los clientes.
  </Card>

  <Card title="Desarrolla pruebas" icon="check" href="https://platform.claude.com/docs/es/test-and-evaluate/develop-tests">
    Crea evaluaciones para medir tu agente de soporte según los criterios de éxito que definiste.
  </Card>

  <Card title="Streaming" icon="bolt" href="https://platform.claude.com/docs/es/build-with-claude/streaming">
    Transmite las respuestas en streaming para que los clientes vean las respuestas a medida que se generan.
  </Card>

  <Card title="Ingeniería de prompts" icon="lightbulb" href="https://platform.claude.com/docs/es/build-with-claude/prompt-engineering/overview">
    Refina tu indicación del sistema y tus ejemplos para un mejor rendimiento en las tareas.
  </Card>
</CardGroup>
