Поделиться через


Руководство: Создание решения для генерации с дополнением извлечением

В этом руководстве объясняется, как создать решение для генерации с дополнением поиска (RAG) с помощью Azure AI для понимания контента. В ней рассматриваются основные шаги по созданию надежной системы RAG, советы по повышению релевантности и точности и показано, как подключиться к другим службам Azure. К концу вы можете использовать распознавание содержимого для обработки многомодальных данных, улучшения извлечения и поддержки моделей ИИ для получения точных и значимых ответов.

Упражнения, включенные в это руководство

Предпосылки

Чтобы приступить к работе, вам нужна активная подписка Azure. Если у вас нет учетной записи Azure, можно создать бесплатную подписку.

  • После получения подписки Azure создайте ресурс Azure AI Foundry на портале Azure.

    • Этот ресурс указан в разделе AI Foundry>"AI Foundry" на портале.

      Снимок экрана: страница ресурсов с несколькими службами в портал Azure.

  • Ресурс поиска ИИ Azure: Настройте ресурс поиска ИИ Azure , чтобы включить индексирование и получение многомодальных данных.

  • Развертывание модели чата Azure OpenAI: Разверните модель чата Azure OpenAI, которая позволяет вести разговорные взаимодействия.

  • Развертывание модели встраивания: Убедитесь, что у вас развернута модель встраивания для создания векторных представлений для семантического поиска.

  • Версия API: В этом руководстве используется последняя предварительная версия API.

  • Среда Python: Установите Python 3.11 для выполнения предоставленных примеров кода и скриптов.

  • В этом руководстве приведен пример кода, который можно найти в записной книжке Python. Следуйте инструкциям README , чтобы создать необходимые ресурсы, предоставьте нужные роли управления доступом (IAM) и установите все пакеты, необходимые для работы с этим руководством.

  • Многомодальные данные, используемые в этом руководстве, состоят из документов, изображений, аудио и видео. Они предназначены для того, чтобы направить вас через процесс создания надежного решения RAG с использованием функции понимания контента Azure AI.

Извлечение данных

Дополненное генеративное получение (RAG*) — это метод, который улучшает функциональные возможности крупных языковых моделей (LLM), интегрируя данные из внешних источников знаний. Создание надежного многомодального решения RAG начинается с извлечения и структурирования данных из различных типов контента. Azure AI Content Understanding предоставляет три ключевых компонента для упрощения этого процесса: извлечение содержимого, извлечение полей и анализаторов. Вместе эти компоненты формируют основу для создания унифицированного, повторного использования и расширенного конвейера данных для рабочих процессов RAG.

Этапы реализации

Чтобы реализовать извлечение данных в Content Understanding, выполните следующие действия.

  1. Создание анализатора: Определите анализатор с помощью REST API или примеров кода Python.

  2. Выполнение извлечения содержимого: Используйте анализатор для обработки файлов и извлечения структурированного содержимого.

  3. (Необязательно) Улучшение с помощью извлечения полей: При необходимости укажите поля, созданные ИИ, чтобы обогатить извлеченное содержимое с помощью добавленных метаданных.

Создание анализаторов

Анализаторы являются повторно используемыми компонентами в Content Understanding, которые упрощают процесс извлечения данных. После создания анализатора его можно многократно использовать для обработки файлов и извлечения содержимого или полей на основе предопределенных схем. Анализатор выступает в качестве схемы обработки данных, обеспечения согласованности и эффективности в нескольких файлах и типах контента.

В следующих примерах кода показано, как создавать анализаторы для каждого модальности, указывая структурированные данные для извлечения, такие как ключевые поля, сводки или классификации. Эти анализаторы служат основой для извлечения и обогащения содержимого в решении RAG.

Загрузка всех переменных среды и необходимых библиотек из Langchain


import os
from dotenv import load_dotenv
load_dotenv()

# Load and validate Azure AI Services configs
AZURE_AI_SERVICE_ENDPOINT = os.getenv("AZURE_AI_SERVICE_ENDPOINT")
AZURE_AI_SERVICE_API_VERSION = os.getenv("AZURE_AI_SERVICE_API_VERSION") or "2024-12-01-preview"
AZURE_DOCUMENT_INTELLIGENCE_API_VERSION = os.getenv("AZURE_DOCUMENT_INTELLIGENCE_API_VERSION") or "2024-11-30"

# Load and validate Azure OpenAI configs
AZURE_OPENAI_ENDPOINT = os.getenv("AZURE_OPENAI_ENDPOINT")
AZURE_OPENAI_CHAT_DEPLOYMENT_NAME = os.getenv("AZURE_OPENAI_CHAT_DEPLOYMENT_NAME")
AZURE_OPENAI_CHAT_API_VERSION = os.getenv("AZURE_OPENAI_CHAT_API_VERSION") or "2024-08-01-preview"
AZURE_OPENAI_EMBEDDING_DEPLOYMENT_NAME = os.getenv("AZURE_OPENAI_EMBEDDING_DEPLOYMENT_NAME")
AZURE_OPENAI_EMBEDDING_API_VERSION = os.getenv("AZURE_OPENAI_EMBEDDING_API_VERSION") or "2023-05-15"

# Load and validate Azure Search Services configs
AZURE_SEARCH_ENDPOINT = os.getenv("AZURE_SEARCH_ENDPOINT")
AZURE_SEARCH_INDEX_NAME = os.getenv("AZURE_SEARCH_INDEX_NAME") or "sample-doc-index"

# Import libraries from Langchain
from langchain import hub
from langchain_openai import AzureChatOpenAI
from langchain_openai import AzureOpenAIEmbeddings
from langchain.schema import StrOutputParser
from langchain.schema.runnable import RunnablePassthrough
from langchain.text_splitter import MarkdownHeaderTextSplitter
from langchain.vectorstores.azuresearch import AzureSearch
from langchain_core.prompts import ChatPromptTemplate
from langchain.schema import Document
import requests
import json
import sys
import uuid
from pathlib import Path
from dotenv import find_dotenv, load_dotenv
from azure.identity import DefaultAzureCredential, get_bearer_token_provider

# Add the parent directory to the path to use shared modules
parent_dir = Path(Path.cwd()).parent
sys.path.append(str(parent_dir))


Пример кода: создание анализатора

from pathlib import Path
from python.content_understanding_client import AzureContentUnderstandingClient
credential = DefaultAzureCredential()
token_provider = get_bearer_token_provider(credential, "https://cognitiveservices.azure.com/.default")

#set analyzer configs
analyzer_configs = [
    {
        "id": "doc-analyzer" + str(uuid.uuid4()),
        "template_path": "../analyzer_templates/content_document.json",
        "location": Path("../data/sample_layout.pdf"),
    },
    {
        "id": "image-analyzer" + str(uuid.uuid4()),
        "template_path": "../analyzer_templates/image_chart_diagram_understanding.json",
        "location": Path("../data/sample_report.pdf"),
    },
    {
        "id": "audio-analyzer" + str(uuid.uuid4()),
        "template_path": "../analyzer_templates/call_recording_analytics.json",
        "location": Path("../data/callCenterRecording.mp3"),
    },
    {
        "id": "video-analyzer" + str(uuid.uuid4()),
        "template_path": "../analyzer_templates/video_content_understanding.json",
        "location": Path("../data/FlightSimulator.mp4"),
    },
]

# Create Content Understanding client
content_understanding_client = AzureContentUnderstandingClient(
    endpoint=AZURE_AI_SERVICE_ENDPOINT,
    api_version=AZURE_AI_SERVICE_API_VERSION,
    token_provider=token_provider,
    x_ms_useragent="azure-ai-content-understanding-python/content_extraction", # This header is used for sample usage telemetry, please comment out this line if you want to opt out.
)

# Iterate through each config and create an analyzer
for analyzer in analyzer_configs:
    analyzer_id = analyzer["id"]
    template_path = analyzer["template_path"]

    try:

        # Create the analyzer using the content understanding client
        response = content_understanding_client.begin_create_analyzer(
            analyzer_id=analyzer_id,
            analyzer_template_path=template_path
        )
        result = content_understanding_client.poll_result(response)
        print(f"Successfully created analyzer: {analyzer_id}")

    except Exception as e:
        print(f"Failed to create analyzer: {analyzer_id}")
        print(f"Error: {e}")


Заметка: Схемы извлечения полей являются необязательными и не требуются для извлечения содержимого. Чтобы выполнить извлечение содержимого и создать анализаторы без определения схем полей, просто укажите идентификатор анализатора и файл для анализа.

Схемы использовались в этом руководстве. Ниже приведен пример определения схемы

В следующем примере мы определим схему извлечения основных сведений из документа счета.

{
  "description": "Sample invoice analyzer",
  "scenario": "document",
  "config": {
    "returnDetails": true
  },
  "fieldSchema": {
    "fields": {
      "VendorName": {
        "type": "string",
        "method": "extract",
        "description": "Vendor issuing the invoice"
      },
      "Items": {
        "type": "array",
        "method": "extract",
        "items": {
          "type": "object",
          "properties": {
            "Description": {
              "type": "string",
              "method": "extract",
              "description": "Description of the item"
            },
            "Amount": {
              "type": "number",
              "method": "extract",
              "description": "Amount of the item"
            }
          }
        }
      }
    }
  }
}

Извлечение содержимого и полей

Извлечение содержимого — это первый шаг в процессе реализации RAG. Он преобразует необработанные многомодальные данные в структурированные и доступные для поиска форматы. Этот базовый шаг гарантирует, что содержимое организовано и готово к индексации и извлечению. Хотя извлечение содержимого предоставляет основу для индексирования и извлечения, оно может не полностью решать специфические для области потребности или предоставлять более глубокие контекстуальные понимания. Дополнительные сведения о возможностях извлечения содержимого для каждой модальности.

Извлечение полей основывается на извлечении содержимого с помощью ИИ для создания дополнительных метаданных, которые обогащают базу знаний. Этот шаг позволяет определить настраиваемые поля, адаптированные к конкретному варианту использования, обеспечивая более точное получение и повышенную релевантность поиска. Извлечение полей дополняет извлечение содержимого путем добавления глубины и контекста, что делает данные более интерактивными для сценариев RAG. Узнать больше о возможностях извлечения данных для каждой модальности.

С помощью анализаторов, созданных для каждого модальности, теперь можно обрабатывать файлы для извлечения структурированного содержимого и метаданных, созданных ИИ, на основе определенных схем. В этом разделе показано, как использовать анализаторы для анализа многомодальных данных и предоставляет пример результатов, возвращаемых API. Эти результаты демонстрируют преобразование необработанных данных в полезные аналитические сведения, формируя основу для индексирования, извлечения и рабочих процессов RAG.


Анализ файлов


#Iterate through each analyzer created and analyze content for each modality

analyzer_results =[]
extracted_markdown = []
analyzer_content = []
for analyzer in analyzer_configs:
    analyzer_id = analyzer["id"]
    template_path = analyzer["template_path"]
    file_location = analyzer["location"]
    try:
           # Analyze content
            response = content_understanding_client.begin_analyze(analyzer_id, file_location)
            result = content_understanding_client.poll_result(response)
            analyzer_results.append({"id":analyzer_id, "result": result["result"]})
            analyzer_content.append({"id": analyzer_id, "content": result["result"]["contents"]})

    except Exception as e:
            print(e)
            print("Error in creating analyzer. Please double-check your analysis settings.\nIf there is a conflict, you can delete the analyzer and then recreate it, or move to the next cell and use the existing analyzer.")

print("Analyzer Results:")
for analyzer_result in analyzer_results:
    print(f"Analyzer ID: {analyzer_result['id']}")
    print(json.dumps(analyzer_result["result"], indent=2))

# Delete the analyzer if it is no longer needed
#content_understanding_client.delete_analyzer(ANALYZER_ID)

Результаты извлечения

В следующих примерах кода показаны выходные данные содержимого и извлечения полей с помощью Azure AI Content Understanding. Ответ JSON содержит несколько полей, каждый из которых обслуживает определенную цель в представлении извлеченных данных.

  • Поле Markdown: поле markdown предоставляет упрощенное, доступное для чтения представление извлеченного содержимого. Особенно полезно для быстрого просмотра или интеграции извлеченных данных в приложения, для которых требуется структурированный текст, например базы знаний или интерфейсы поиска. Например, в документе markdown поле может содержать заголовки, абзацы и другие структурные элементы, отформатированные для удобства чтения.

  • Выходные данные JSON: полные выходные данные JSON предоставляют комплексное представление извлеченных данных, включая содержимое и метаданные, созданные во время процесса извлечения, включая следующие свойства:

    • Поля: Метаданные, созданные ИИ, такие как сводки, ключевые разделы или классификации, адаптированные к определенной схеме, определенной в анализаторе.
    • Оценки достоверности: Индикаторы надежности извлеченных данных.
    • Охватывает: Сведения о расположении извлеченного содержимого в исходном файле.
    • Дополнительные метаданные: Сведения, такие как номера страниц, измерения и другие контекстные сведения.

В результате показано извлечение заголовков, абзацев, таблиц и других структурных элементов при сохранении логической организации содержимого. Кроме того, он демонстрирует возможность извлечения ключевых полей, обеспечивая краткие извлечения длинных материалов.

{
  "id": "bcf8c7c7-03ab-4204-b22c-2b34203ef5db",
  "status": "Succeeded",
  "result": {
    "analyzerId": "training_document_analyzer",
    "apiVersion": "2024-12-01-preview",
    "createdAt": "2024-11-13T07:15:46Z",
    "warnings": [],
    "contents": [
      {
        "markdown": "CONTOSO LTD.\n\n\n# Contoso Training Topics\n\nContoso Headquarters...",
        "fields": {
          "ChapterTitle": {
            "type": "string",
            "valueString": "Risks and Compliance regulations",
            "spans": [ { "offset": 0, "length": 12 } ],
            "confidence": 0.941,
            "source": "D(1,0.5729,0.6582,2.3353,0.6582,2.3353,0.8957,0.5729,0.8957)"
          },
          "ChapterAuthor": {
            "type": "string",
            "valueString": "John Smith",
            "spans": [ { "offset": 0, "length": 12 } ],
            "confidence": 0.941,
            "source": "D(1,0.5729,0.6582,2.3353,0.6582,2.3353,0.8957,0.5729,0.8957)"
          },
          "ChapterPublishDate": {
            "type": "Date",
            "valueString": "04-11-2017",
            "spans": [ { "offset": 0, "length": 12 } ],
            "confidence": 0.941,
            "source": "D(1,0.5729,0.6582,2.3353,0.6582,2.3353,0.8957,0.5729,0.8957)"
          },
        },
        "kind": "document",
        "startPageNumber": 1,
        "endPageNumber": 1,
        "unit": "inch",
        "pages": [
          {
            "pageNumber": 1,
            "angle": -0.0039,
            "width": 8.5,
            "height": 11,
            "spans": [ { "offset": 0, "length": 1650 } ],
            "words": [
              {
               ....
              },
            ],
            "lines": [
              {
                ...
              },
            ]
          }
        ],

      }
    ]
  }
}

Предварительная обработка выходных данных из службы "Понимание содержимого"

После извлечения данных с помощью Azure AI Content Understanding необходимо подготовить выходные данные анализа для внедрения в систему поиска. Предварительная обработка выходных данных гарантирует, что извлеченный контент преобразуется в формат, подходящий для индексирования и извлечения. Этот шаг включает преобразование выходных данных JSON из анализаторов в структурированные строки, сохраняя содержимое и метаданные для простой интеграции в подчиненные рабочие процессы.

В следующем примере показано, как предварительно обработать выходные данные из анализаторов, включая документы, изображения, аудио и видео. Процесс преобразования каждого выходных данных JSON в структурированную строку является основой внедрения данных в систему поиска на основе векторов, обеспечивая эффективное извлечение и усовершенствованные рабочие процессы RAG.



def convert_values_to_strings(json_obj):
    return [str(value) for value in json_obj]

#process all content and convert to string
def process_allJSON_content(all_content):

    # Initialize empty list to store string of all content
    output = []

    document_splits = [
        "This is a json string representing a document with text and metadata for the file located in "+str(analyzer_configs[0]["location"])+" "
        + v
        + "```"
        for v in convert_values_to_strings(all_content[0]["content"])
    ]
    docs = [Document(page_content=v) for v in document_splits]
    output += docs

    #convert image json object to string and append file metadata to the string
    image_splits = [
       "This is a json string representing an image verbalization and OCR extraction for the file located in "+str(analyzer_configs[1]["location"])+" "
       + v
       + "```"
       for v in convert_values_to_strings(all_content[1]["content"])
    ]
    image = [Document(page_content=v) for v in image_splits]
    output+=image

    #convert audio json object to string and append file metadata to the string
    audio_splits = [
        "This is a json string representing an audio segment with transcription for the file located in "+str(analyzer_configs[2]["location"])+" "
       + v
       + "```"
       for v in convert_values_to_strings(all_content[2]["content"])
    ]
    audio = [Document(page_content=v) for v in audio_splits]
    output += audio

    #convert video json object to string and append file metadata to the string
    video_splits = [
        "The following is a json string representing a video segment with scene description and transcript for the file located in "+str(analyzer_configs[3]["location"])+" "
        + v
        + "```"
        for v in convert_values_to_strings(all_content[3]["content"])
    ]
    video = [Document(page_content=v) for v in video_splits]
    output+=video

    return output

all_splits = process_allJSON_content(analyzer_content)

print("There are " + str(len(all_splits)) + " documents.")
# Print the content of all doc splits
for doc in all_splits:
    print(f"doc content", doc.page_content)

Встраивание и индексирование извлечённого содержимого

После предварительной обработки извлеченных данных из Azure AI Content Understanding необходимо внедрить и индексировать содержимое для эффективного извлечения. Этот шаг включает преобразование структурированных строк в векторные внедрения с помощью модели внедрения и их хранения в системе поиска ИИ Azure. Внедряя содержимое, вы можете включить возможности семантического поиска, позволяя системе получать наиболее релевантную информацию на основе смысла, а не точных совпадений ключевых слов. Этот шаг очень важен для создания надежного решения RAG, так как он гарантирует, что извлеченное содержимое оптимизировано для расширенных рабочих процессов поиска и извлечения.

# Embed the splitted documents and insert into Azure Search vector store
def embed_and_index_chunks(docs):
    aoai_embeddings = AzureOpenAIEmbeddings(
        azure_deployment=AZURE_OPENAI_EMBEDDING_DEPLOYMENT_NAME,
        openai_api_version=AZURE_OPENAI_EMBEDDING_API_VERSION,  # e.g., "2023-12-01-preview"
        azure_endpoint=AZURE_OPENAI_ENDPOINT,
        azure_ad_token_provider=token_provider
    )

    vector_store: AzureSearch = AzureSearch(
        azure_search_endpoint=AZURE_SEARCH_ENDPOINT,
        azure_search_key=None,
        index_name=AZURE_SEARCH_INDEX_NAME,
        embedding_function=aoai_embeddings.embed_query
    )
    vector_store.add_documents(documents=docs)
    return vector_store


# embed and index the docs:
vector_store = embed_and_index_chunks(all_splits)

Получение семантического фрагмента

При использовании извлеченного содержимого, внедренного и индексированного, следующий шаг — использовать возможности сходства и векторного поиска для получения наиболее релевантных фрагментов информации. В этом разделе показано, как выполнять аналогичные и гибридные поиски, что позволяет системе отображать содержимое на основе семантического значения, а не точного совпадения ключевых слов. Извлекая контекстно релевантные блоки, вы можете повысить точность рабочих процессов RAG и обеспечить более точные, значимые ответы на запросы пользователей.

# Set your query
query = "japan"

# Perform a similarity search
docs = vector_store.similarity_search(
    query=query,
    k=3,
    search_type="similarity",
)
for doc in docs:
    print(doc.page_content)

# Perform a hybrid search using the search_type parameter
docs = vector_store.hybrid_search(query=query, k=3)
for doc in docs:
    print(doc.page_content)


Использование OpenAI для взаимодействия с данными

После встраивания и индексирования извлеченного содержимого, завершающий этап создания надежного решения RAG заключается в обеспечении возможности взаимодействия в форме бесед с помощью чат-моделей OpenAI. В этом разделе показано, как запрашивать индексированные данные и применять модели чата OpenAI для предоставления кратких и контекстно богатых ответов. Интегрируя диалоговый ИИ, вы можете преобразовать решение RAG в интерактивную систему, которая обеспечивает значимые аналитические сведения и улучшает взаимодействие пользователей. В следующих примерах описано, как настроить поток беседы, дополненный извлечением данных, гарантируя бесшовную интеграцию между вашими данными и моделями чата OpenAI.


# Setup rag chain
prompt_str = """You are an assistant for question-answering tasks. Use the following pieces of retrieved context to answer the question. If you don't know the answer, just say that you don't know. Use three sentences maximum and keep the answer concise.
Question: {question}
Context: {context}
Answer:"""


def setup_rag_chain(vector_store):
    retriever = vector_store.as_retriever(search_type="similarity", k=3)

    prompt = ChatPromptTemplate.from_template(prompt_str)
    llm = AzureChatOpenAI(
        openai_api_version=AZURE_OPENAI_CHAT_API_VERSION,
        azure_deployment=AZURE_OPENAI_CHAT_DEPLOYMENT_NAME,
        azure_ad_token_provider=token_provider,
        temperature=0.7,
    )

    def format_docs(docs):
        return "\n\n".join(doc.page_content for doc in docs)

    rag_chain = (
        {"context": retriever | format_docs, "question": RunnablePassthrough()}
        | prompt
        | llm
        | StrOutputParser()
    )
    return rag_chain


# Setup conversational search
def conversational_search(rag_chain, query):
    print(rag_chain.invoke(query))


rag_chain = setup_rag_chain(vector_store)
while True:
    query = input("Enter your query: ")
    if query=="":
        break
    conversational_search(rag_chain, query)

Дальнейшие шаги