Tutorial: Uso de REST y AI para generar contenido en el que se pueden realizar búsquedas desde blobs de Azure
Si tiene imágenes o texto no estructurado en Azure Blob Storage, una canalización de enriquecimiento con IA puede extraer la información y crear contenido en escenarios de búsqueda de texto completo o minería de conocimientos.
En este tutorial de REST, aprenderá a:
- Configurar un entorno de desarrollo.
- Definir una canalización que use OCR, la detección de idioma, el reconocimiento de entidades y la extracción de frases clave.
- Ejecutar la canalización para invocar transformaciones y para crear y cargar un índice de búsqueda.
- Explore los resultados mediante la búsqueda de texto completo y una sintaxis de consulta enriquecida.
Si no tiene una suscripción a Azure, abra una cuenta gratuita antes de empezar.
Información general
En este tutorial se usa Postman y las API REST de Azure Cognitive Search para crear un origen de datos, un índice, un indexador y un conjunto de aptitudes.
El indexador se conecta a Azure Blob Storage y recupera el contenido, que se debe cargar de antemano. Luego, invoca el conjunto de aptitudes para el procesamiento especializado e ingiere el contenido enriquecido en un índice de búsqueda.
El conjunto de aptitudes se adjunta a un indizador. Usa aptitudes integradas de Microsoft para buscar y extraer información. Los pasos de la canalización incluyen el reconocimiento óptico de caracteres (OCR) en imágenes, la detección de idiomas, la extracción de frases clave y el reconocimiento de entidades (organizaciones, ubicaciones o personas). La nueva información creada por la canalización se almacena en nuevos campos en un índice. Una vez que se rellena el índice, esos campos se pueden usar en las consultas, facetas y filtros.
Requisitos previos
Nota
Puede usar un servicio gratuito para este tutorial. Un servicio de búsqueda gratuito tiene una limitación de tres índices, tres indexadores y tres orígenes de datos. En este tutorial se crea uno de cada uno. Antes de empezar, asegúrese de que haya espacio en el servicio para aceptar los nuevos recursos.
Descarga de archivos
Los datos de ejemplo constan de 14 archivos de tipo de contenido mixto que se cargarán en Azure Blob Storage en un paso posterior.
Obtenga los archivos de azure-search-sample-data/ai-enrichment-mixed-media/ y cópielos en el equipo local.
Luego, obtenga el código fuente, un archivo de colección de Postman, para este tutorial. El código fuente se puede encontrar en azure-search-postman-samples/tree/master/Tutorial.
1: Creación de servicios
En este tutorial se usa Azure Cognitive Search para la indexación y las consultas, Cognitive Services en el back-end para el enriquecimiento con IA y Azure Blob Storage para proporcionar los datos. Este tutorial permanece por debajo de la asignación gratuita de 20 transacciones por indexador al día en Cognitive Services, por lo que los únicos servicios que tiene que crear son la búsqueda y el almacenamiento.
Si es posible, cree los dos en la misma región y grupo de recursos para la proximidad y la capacidad de administración. En la práctica, la cuenta de Azure Storage puede estar en cualquier región.
Comienzo con Azure Storage
Inicie sesión en Azure Portal y seleccione + Crear un recurso.
Busque cuenta de almacenamiento y seleccione la oferta de Cuenta de almacenamiento de Microsoft.
En la pestaña Datos básicos, se necesitan los siguientes elementos. Acepte los valores predeterminados para todo lo demás.
Grupo de recursos. Seleccione un grupo existente o cree uno nuevo, pero use el mismo grupo para todos los servicios, con el fin de que pueda administrarlos colectivamente.
Nombre de cuenta de almacenamiento. Si cree que puede tener varios recursos del mismo tipo, use el nombre para diferenciarlos por tipo y región, por ejemplo blobstoragewestus.
Ubicación. Si es posible, elija la misma ubicación que se usa para Azure Cognitive Search y Cognitive Services. Una ubicación única anula los cargos de ancho de banda.
Tipo de cuenta. Elija el valor predeterminado, StorageV2 (uso general v2) .
Seleccione Revisar y crear para crear el servicio.
Una vez creado, seleccione Go to the resource (Ir al recurso) para abrir la página de información general.
Seleccione el servicio Blobs.
Seleccione + Contenedor para crear un contenedor y asígnele el nombre cog-search-demo.
Seleccione cog-search-demo y, después, Cargar para abrir la carpeta en la que guardó los archivos de descarga. Seleccione todos los archivos. Seleccione Cargar.
Antes de salir de Azure Storage, obtenga una cadena de conexión para poder formular una conexión en Azure Cognitive Search.
Vuelva a la página de información general de la cuenta de almacenamiento (hemos usado blobstragewestus como ejemplo).
En el panel de navegación izquierdo, seleccione Claves de acceso y copie una de las cadenas de conexión.
La cadena de conexión es una dirección URL parecida a la del ejemplo siguiente:
DefaultEndpointsProtocol=https;AccountName=cogsrchdemostorage;AccountKey=<your account key>;EndpointSuffix=core.windows.net
Guarde la cadena de conexión en el Bloc de notas. La necesitará más adelante, al configurar la conexión del origen de datos.
Cognitive Services
El enriquecimiento de la inteligencia artificial tiene el respaldo de Cognitive Services, lo que incluye el servicio de lenguaje y Computer Vision para el procesamiento de imágenes y del lenguaje natural. Si su objetivo fuera completar un prototipo o un proyecto reales, en este punto aprovisionaría Cognitive Services (en la misma región que Azure Cognitive Search) para poder conectarlo con un conjunto de aptitudes.
Sin embargo, en este ejercicio puede omitir el aprovisionamiento de recursos, porque Azure Cognitive Search puede conectarse a Cognitive Services y ejecutar 20 transacciones por cada ejecución del indexador sin cargo alguno. Dado que en este tutorial se usan 14 transacciones, la asignación gratuita es suficiente. En el caso de proyectos mayores, planee aprovisionamiento de Cognitive Services en el nivel S0 de pago por uso.
Azure Cognitive Search
El tercer componente es Azure Cognitive Search, que puede crear en el portal o buscar en un servicio de búsqueda existente en su suscripción.
Puede usar el nivel Gratis para completar este tutorial.
Copia de una clave de API de administración y una dirección URL para Azure Cognitive Search
Para interactuar con el servicio Azure Cognitive Search, necesita la dirección URL del servicio y una clave de acceso.
Inicie sesión en Azure Portal y, en la página Información general del servicio de búsqueda, obtenga el nombre del servicio de búsqueda. Para confirmar el nombre del servicio, revise la dirección URL del punto de conexión. Si la dirección URL del punto de conexión fuera
https://mydemo.search.windows.net
, el nombre del servicio seríamydemo
.En Configuración>Claves, obtenga una clave de administrador para tener derechos completos en el servicio. Puede copiar la clave principal o la secundaria.
Todas las solicitudes HTTP que se realicen a un servicio de búsqueda requieren una clave de API. Una clave válida genera la confianza, solicitud a solicitud, entre la aplicación que la envía y el servicio que se encarga de ella.
2: Configuración de Postman
Inicie Postman, importe la colección y configure las variables de entorno. Si no conoce esta herramienta, consulte Exploración de las API REST de Azure Cognitive Search.
Deberá especificar un nombre de servicio de búsqueda, una clave de API de administrador, un nombre de índice, una cadena de conexión a la cuenta de Azure Storage y el nombre del contenedor.
Los métodos de solicitud que se usan en esta colección son PUT y GET. Estos métodos se usarán para crear un origen de datos, un conjunto de aptitudes, un índice y un indexador.
3: Creación de la canalización
En Azure Cognitive Search, el enriquecimiento se produce durante la indexación (o la ingesta de datos). En esta parte del tutorial se crean cuatro objetos: origen de datos, definición de índice, conjunto de aptitudes, indexador.
Paso 1: Creación de un origen de datos
Llame a Create Data Source (creación de un origen de datos) para configurar la cadena de conexión al contenedor de blobs que contiene los archivos de datos de ejemplo.
Seleccione la solicitud "Crear un origen de datos".
El cuerpo de la solicitud es JSON e incluye las propiedades de un objeto de origen de datos del indexador. La cadena de conexión incluye credenciales para acceder al servicio.
{ "description" : "Demo files to demonstrate cognitive search capabilities.", "type" : "azureblob", "credentials" : { "connectionString": "{{azure_storage_connection_string}}" }, "container" : { "name" : "{{container_name}}" } }
Envíe la solicitud. Debería ver un código de estado 201 que confirme que la operación se ha realizado correctamente.
Si ha recibido un error 403 o 404, compruebe la clave de API del administrador de búsqueda y la cadena de cadena de conexión de Azure Storage.
Paso 2: Creación de un conjunto de aptitudes
Llame a Create Skillset (creación de un conjunto de aptitudes) para especificar qué pasos de enriquecimiento se aplican al contenido.
Seleccione la solicitud "Crear un conjunto de aptitudes".
El cuerpo de la solicitud especifica las siguientes aptitudes integradas:
Habilidad Descripción Reconocimiento óptico de caracteres Reconoce texto y números en archivos de imagen. Combinación de texto Crea "contenido combinado" que recombina contenido previamente separado, útil para documentos con imágenes insertadas (PDF, DOCX, etc.). Las imágenes y el texto se separan durante la fase de descifrado de documentos. La aptitud de fusión mediante combinación los vuelve a combinar mediante la inserción de cualquier texto reconocido, títulos de imagen o etiquetas creados durante el enriquecimiento en la misma ubicación en que se extrajo la imagen en el documento. Al trabajar con contenido combinado en un conjunto de aptitudes, este nodo contendrá todo el texto del documento, incluidos los documentos de solo texto que nunca se someten a OCR o análisis de imágenes. Detección de idioma Detecta el idioma y genera un nombre de idioma o un código. En los conjuntos de datos multilingües, un campo de idioma puede ser útil para los filtros. Reconocimiento de entidades Extrae los nombres de las personas, organizaciones y ubicaciones del contenido combinado. División de texto Divide el contenido combinado de gran tamaño en fragmentos más pequeños antes de llamar a la aptitud de extracción de frases clave. La extracción de frases clave acepta entradas de 50 000 caracteres o menos. Algunos de los archivos de ejemplo deben dividirse para no superar este límite. Extracción de frases clave Extrae las principales frases clave. Cada aptitud se ejecuta en el contenido del documento. Durante el procesamiento, Azure Cognitive Search extrae cada documento para leer el contenido de diferentes formatos de archivo. El texto encontrado procedente del archivo de origen se coloca en un campo
content
generado, uno para cada documento. Como tal, la entrada pasa a ser"/document/content"
.Para la extracción de las frases clave, al usar el separador de texto para dividir los archivos grandes en páginas, el contenido de la aptitud de la extracción de frases clave es
"document/pages/*"
(para cada página del documento) en lugar de"/document/content"
.{ "description": "Apply OCR, detect language, extract entities, and extract key-phrases.", "cognitiveServices": null, "skills": [ { "@odata.type": "#Microsoft.Skills.Vision.OcrSkill", "context": "/document/normalized_images/*", "defaultLanguageCode": "en", "detectOrientation": true, "inputs": [ { "name": "image", "source": "/document/normalized_images/*" } ], "outputs": [ { "name": "text" } ] }, { "@odata.type": "#Microsoft.Skills.Text.MergeSkill", "description": "Create merged_text, which includes all the textual representation of each image inserted at the right location in the content field. This is useful for PDF and other file formats that supported embedded images.", "context": "/document", "insertPreTag": " ", "insertPostTag": " ", "inputs": [ { "name":"text", "source": "/document/content" }, { "name": "itemsToInsert", "source": "/document/normalized_images/*/text" }, { "name":"offsets", "source": "/document/normalized_images/*/contentOffset" } ], "outputs": [ { "name": "mergedText", "targetName" : "merged_text" } ] }, { "@odata.type": "#Microsoft.Skills.Text.SplitSkill", "textSplitMode": "pages", "maximumPageLength": 4000, "defaultLanguageCode": "en", "context": "/document", "inputs": [ { "name": "text", "source": "/document/merged_text" } ], "outputs": [ { "name": "textItems", "targetName": "pages" } ] }, { "@odata.type": "#Microsoft.Skills.Text.LanguageDetectionSkill", "description": "If you have multilingual content, adding a language code is useful for filtering", "context": "/document", "inputs": [ { "name": "text", "source": "/document/merged_text" } ], "outputs": [ { "name": "languageName", "targetName": "language" } ] }, { "@odata.type": "#Microsoft.Skills.Text.KeyPhraseExtractionSkill", "context": "/document/pages/*", "inputs": [ { "name": "text", "source": "/document/pages/*" } ], "outputs": [ { "name": "keyPhrases", "targetName": "keyPhrases" } ] }, { "@odata.type": "#Microsoft.Skills.Text.V3.EntityRecognitionSkill", "categories": ["Organization"], "context": "/document", "inputs": [ { "name": "text", "source": "/document/merged_text" } ], "outputs": [ { "name": "organizations", "targetName": "organizations" } ] }, { "@odata.type": "#Microsoft.Skills.Text.V3.EntityRecognitionSkill", "categories": ["Location"], "context": "/document", "inputs": [ { "name": "text", "source": "/document/merged_text" } ], "outputs": [ { "name": "locations", "targetName": "locations" } ] }, { "@odata.type": "#Microsoft.Skills.Text.V3.EntityRecognitionSkill", "categories": ["Person"], "context": "/document", "inputs": [ { "name": "text", "source": "/document/merged_text" } ], "outputs": [ { "name": "persons", "targetName": "persons" } ] } ] }
A continuación se muestra una representación gráfica de una parte del conjunto de aptitudes.
Envíe la solicitud. Postman debe devolver un código de estado 201 que confirme que la operación se ha realizado correctamente.
Nota
Las salidas se pueden asignar a un índice, usar como entrada para una aptitud descendente, o ambas cosas como sucede con el código de idioma. En el índice, un código de idioma es útil para el filtrado. Para obtener más información sobre los conceptos básicos del conjunto de aptitudes, consulte el tema sobre la definición de un conjunto de aptitudes.
Paso 3: Creación de un índice
Llame a Create Index (creación de un índice) para proporcionar el esquema que se usa para crear índices invertidos y otras construcciones en Azure Cognitive Search. El componente mayor de un índice es la colección de campos, donde el tipo de datos y los atributos determinan tanto el contenido como el comportamiento en Azure Cognitive Search.
Seleccione la solicitud "Crear un índice".
El cuerpo de la solicitud define el esquema del índice de búsqueda. Una colección de campos requiere que se designe un campo como clave. En el caso del contenido del blob, este campo a menudo es el "metadata_storage_path" que identifica de forma única cada blob del contenedor.
En este esquema, el campo "text" recibe la salida del OCR, "content" recibe la salida combinada y "language" recibe la salida de detección de idioma. Las frases clave, las entidades y varios campos que se han restringido de Blob Storage componen las entradas restantes.
{ "fields": [ { "name": "text", "type": "Collection(Edm.String)", "searchable": true, "sortable": false, "filterable": true, "facetable": false }, { "name": "content", "type": "Edm.String", "searchable": true, "sortable": false, "filterable": false, "facetable": false }, { "name": "language", "type": "Edm.String", "searchable": false, "sortable": true, "filterable": true, "facetable": false }, { "name": "keyPhrases", "type": "Collection(Edm.String)", "searchable": true, "sortable": false, "filterable": true, "facetable": true }, { "name": "organizations", "type": "Collection(Edm.String)", "searchable": true, "sortable": false, "filterable": true, "facetable": true }, { "name": "persons", "type": "Collection(Edm.String)", "searchable": true, "sortable": false, "filterable": true, "facetable": true }, { "name": "locations", "type": "Collection(Edm.String)", "searchable": true, "sortable": false, "filterable": true, "facetable": true }, { "name": "metadata_storage_path", "type": "Edm.String", "key": true, "searchable": true, "sortable": false, "filterable": false, "facetable": false }, { "name": "metadata_storage_name", "type": "Edm.String", "searchable": true, "sortable": false, "filterable": false, "facetable": false } ] }
Envíe la solicitud. Postman debe devolver un código de estado 201 que confirme que la operación se ha realizado correctamente.
Paso 4: Creación y ejecución de un indexador
Llame a Create Indexer (creación de un indizador) para impulsar la canalización. Los tres componentes que ha creado hasta ahora (origen de datos, conjunto de aptitudes e índice) son entradas para un indexador. La creación del indexador en Azure Cognitive Search es el evento que pone toda la canalización en movimiento.
Seleccione la solicitud "Crear un indexador".
El cuerpo de la solicitud incluye referencias a los objetos anteriores, propiedades de configuración necesarias para el procesamiento de imágenes y dos tipos de asignaciones de campos.
"fieldMappings"
se procesan antes que el conjunto de aptitudes y envían el contenido del origen de datos a los campos de destino de un índice. Usará asignaciones de campos para enviar contenido existente sin modificar al índice. Si los tipos y nombres de campo son los mismos en ambos extremos, no se requiere ninguna asignación."outputFieldMappings"
son para los campos creados por aptitudes, después de la ejecución del conjunto de aptitudes. Las referencias asourceFieldName
enoutputFieldMappings
no existen hasta que el descifrado de documentos o el enriquecimiento las crean.targetFieldName
es un campo de un índice definido en el esquema del índice.{ "dataSourceName" : "{{index_name}}-datasource", "targetIndexName" : "{{index_name}}", "skillsetName" : "{{index_name}}-skillset", "fieldMappings" : [ { "sourceFieldName" : "metadata_storage_path", "targetFieldName" : "metadata_storage_path", "mappingFunction" : { "name" : "base64Encode" } }, { "sourceFieldName": "metadata_storage_name", "targetFieldName": "metadata_storage_name" } ], "outputFieldMappings" : [ { "sourceFieldName": "/document/merged_text", "targetFieldName": "content" }, { "sourceFieldName" : "/document/normalized_images/*/text", "targetFieldName" : "text" }, { "sourceFieldName" : "/document/organizations", "targetFieldName" : "organizations" }, { "sourceFieldName": "/document/language", "targetFieldName": "language" }, { "sourceFieldName" : "/document/persons", "targetFieldName" : "persons" }, { "sourceFieldName" : "/document/locations", "targetFieldName" : "locations" }, { "sourceFieldName" : "/document/pages/*/keyPhrases/*", "targetFieldName" : "keyPhrases" } ], "parameters": { "batchSize": 1, "maxFailedItems":-1, "maxFailedItemsPerBatch":-1, "configuration": { "dataToExtract": "contentAndMetadata", "imageAction": "generateNormalizedImages" } } }
Envíe la solicitud. Postman debe devolver un código de estado 201 que confirme el éxito del procesamiento.
Este paso puede tardar varios minutos en completarse. Aunque el conjunto de datos es pequeño, las aptitudes analíticas realiza un uso intensivo de los recursos.
Nota
La creación de un indexador invoca la canalización. Si hay problemas para conectar con los datos, las entradas y salidas de asignación o el orden de las operaciones, se muestran en esta fase. Para volver a ejecutar la canalización con los cambios de código o script, deberá quitar primero los objetos. Para más información, consulte Restablecer y volver a ejecutar.
Acerca de los parámetros de un indexador
El script establece "maxFailedItems"
en -1, lo que indica al motor de indexación que ignore los errores durante la importación de datos. Esto es aceptable porque hay muy pocos documentos en el origen de datos de demostración. Para un origen de datos mayor, debería establecer un valor mayor que 0.
La instrucción "dataToExtract":"contentAndMetadata"
le indica al indizador que extraiga automáticamente los valores de la propiedad de contenido del blob y los metadatos de cada objeto.
Una vez extraído el contenido, puede establecer imageAction
para que se extraiga el texto de las imágenes que se encuentran en el origen de datos. La configuración de "imageAction":"generateNormalizedImages"
, en combinación con OCR Skill y Text Merge Skill, le dice al indexador que extraiga texto de las imágenes (por ejemplo, la palabra "stop" de una señal de Stop de tráfico) y lo inserte como parte del campo de contenido. Este comportamiento se aplica tanto a las imágenes insertadas (por ejemplo, una imagen dentro de un PDF) como a los archivos de imagen independientes, como un archivo JPG.
4: Supervisión de la indexación
La indexación y el enriquecimiento comienzan en cuanto se envía la solicitud de creación de indexador. En función de las aptitudes cognitivas definidas, la indexación puede tardar un tiempo.
Para averiguar si el indexador todavía se está ejecutando, llame a Get Indexer Status (obtener estado de indizador) para comprobar el estado del indizador.
Seleccione y envíe la solicitud "Comprobar estado del indexador".
Revise la respuesta para saber si el indexador se está ejecutando o para ver la información de los errores y advertencias.
Las advertencias son comunes en algunos escenarios y no siempre indican un problema. Por ejemplo, si un contenedor de blobs incluye archivos de imagen y la canalización no controla imágenes, recibirá una advertencia que indica que no se procesaron las imágenes.
En este ejemplo, hay un archivo PNG que no contiene texto. Ninguna de las cinco aptitudes basadas en texto (detección de idioma, reconocimiento de entidades de ubicaciones, organizaciones, personas y extracción de frases clave) se pueden ejecutar en este archivo. La notificación resultante se muestra en el historial de ejecución.
5: Búsqueda
Ahora que ha creado un índice que contiene contenido generado por inteligencia artificial, llame a Search Documents (búsqueda de documentos) para ejecutar algunas consultas para ver los resultados.
Recuerde que comenzamos con el contenido del blob, donde todo el documento se empaqueta en un solo campo content
. Puede buscar en este campo elementos que coincidan con sus consultas.
Abra la solicitud "Buscar" y ejecútela para ver el contenido del índice. Esta solicitud es una búsqueda vacía ("search=*") por lo que devolverá contenido para cada uno de los 14 documentos. El parámetro $select limita los resultados al nombre de archivo, el nombre de idioma y una de las entidades reconocidas.
GET /indexes//{{index_name}}/docs?search=*&$select=metadata_storage_name,language,organizations&$count=true&api-version=2020-06-30
Revise la consulta anterior para buscar "crear oportunidades sin límites". Esta frase se obtuvo mediante OCR de un archivo de imagen insertada en un documento PDF. Incluya "highlight" para aplicar formato a los términos que coincidan en campos densamente rellenados.
GET /indexes//{{index_name}}/docs?search=creating boundaryless opportunities&$select=content&highlight=content&$count=true&api-version=2020-06-30
Para la siguiente consulta, aplique un filtro. Recuerde que se pueden crear filtros tanto en el campo de idioma como en todos los campos de la entidad.
GET /indexes/{{index_name}}/docs?search=*&$filter=organizations/any(organizations: organizations eq 'Microsoft')&$select=metadata_storage_name,organizations&$count=true&api-version=2020-06-30
Estas consultas muestran algunas de las formas en que puede trabajar con sintaxis de consulta y filtros en nuevos campos creados por la búsqueda cognitiva. Para más ejemplos de consultas, vea Ejemplos de la API REST de búsqueda de documentos, Ejemplos de consulta de sintaxis simple y Ejemplos de consultas que usan la sintaxis de búsqueda de Lucene "completa".
Restablecer y volver a ejecutar
Durante las primeras fases del desarrollo, es habitual la iteración sobre el diseño. Lo más probable es que elimine y vuelva a compilar los mismos objetos con frecuencia.
Si usa el portal para su eliminación y elimina primero el indexador, el portal le pedirá que elimine los objetos asociados.
Como alternativa, puede usar DELETE y especificar direcciones URL para cada objeto. El siguiente comando elimina un indexador.
DELETE https://[YOUR-SERVICE-NAME].search.windows.net/indexers/cog-search-demo-idxr?api-version=2020-06-30
Se devuelve el código de estado 204 si la eliminación se realiza correctamente.
Puntos clave
Este tutorial muestra los pasos básicos para la creación de una canalización de indexación enriquecida a través de la creación de componentes: un origen de datos, un conjunto de aptitudes, un índice y un indexador.
Se presentaron las aptitudes integradas, junto con la definición del conjunto de aptitudes y los mecanismos de encadenamiento de aptitudes, mediante entradas y salidas. También aprendió que outputFieldMappings
en la definición del indexador es necesario para enrutar los valores enriquecidos de la canalización a un índice que permita búsquedas en un servicio Azure Cognitive Search.
Por último, ha aprendido cómo probar los resultados y restablecer el sistema para otras iteraciones. Ha aprendido que emitir consultas en el índice devuelve la salida creada por la canalización de indexación enriquecida.
Limpieza de recursos
Cuando trabaje con su propia suscripción, al final de un proyecto, es recomendable eliminar los recursos que ya no necesite. Los recursos que se dejan en ejecución pueden costarle mucho dinero. Puede eliminar los recursos de forma individual o eliminar el grupo de recursos para eliminar todo el conjunto de recursos.
Puede buscar y administrar los recursos en el portal, mediante el vínculo Todos los recursos o Grupos de recursos en el panel de navegación izquierdo.
Pasos siguientes
Ahora que está familiarizado con todos los objetos de una canalización de enriquecimiento de AI, echemos un vistazo más de cerca a las definiciones de actitudes y a los conocimientos individuales.