共用方式為


教學課程:在 Azure AI 搜尋服務中設計 RAG 的索引

索引包含可搜尋的文字和向量內容以及設定。 在使用聊天模型的RAG模式中,您想要針對查詢時間傳遞至LLM的內容區塊所設計的索引。

在本教學課程中,您已:

  • 了解針對 RAG 建置的索引結構描述特性
  • 建立索引以容納向量和混合式查詢
  • 新增向量設定檔和設定
  • 新增結構化資料
  • 新增篩選

必要條件

具有 Python 延伸模組Jupyter 套件Visual Studio Code。 如需詳細資訊,請參閱 Visual Studio Code 中的 Python

此練習的輸出是 JSON 格式的索引定義。 此時不會將輸出上傳至 Azure AI 搜尋服務,因此此練習中無需雲端服務或權限。

檢閱 RAG 的結構描述考量

在交談式搜尋中,LLM 會撰寫使用者看到的回應,而不是搜尋引擎,因此您不需要考慮搜尋結果中要顯示哪些欄位,以及個別搜尋文件的表示方式是否與使用者一致。 視問題而定,LLM 可能會從您的索引傳回逐字呈現的內容,或更可能的是,重新封裝內容以提供更好的答案。

圍繞著區塊組織

LLM 會在產生回應時處理訊息輸入的內容區塊,當其需要知道區塊來源以用於引文目的時,最重要的是訊息輸入的品質,以及其與使用者問題的相關性。 不論區塊來自一份或一千份文件,LLM 都會擷取資訊或「基礎資料」,並使用系統提示中提供的指示來制定回應。

區塊是結構描述的焦點,而每個區塊都是 RAG 模式中搜尋文件的定義元素。 您可以將索引視為大型區塊集合,而不是可能有更多結構的傳統搜尋文件,例如包含名稱、描述、類別和位址等統一內容的欄位。

使用產生的資料增強

在本教學課程中,樣本資料是由 NASA Earth Book 的 PDF 和內容所組成。 此內容具有描述性和資訊性,包含世界各地地理位置、國家/地區的許多參考。 所有文字內容都會以區塊擷取,但地名的週期性實例會建立將結構新增至索引的機會。 使用技能,可以辨識文字中的實體,並將其擷取在索引中,以用於查詢和篩選。 在本教學課程中,我們會包含可辨識和擷取位置實體的實體辨識技能、將它載入可搜尋且可篩選的 locations 欄位。 將結構化內容新增至您的索引可為您提供更多的篩選選項、提高相關性和更有針對性的答案。

一或兩個索引中的父子欄位?

區塊內容通常衍生自較大的文件。 雖然結構描述是圍繞著區塊來組織,但您也可以在父層級上擷取屬性和內容。 這些屬性的範例可能包括父檔案路徑、標題、作者、發行日期或摘要。

結構描述設計中的轉捩折是,是否針對父子/區塊化內容使用兩個索引,或是使用針對每個區塊重複父元素的單一索引。

在本教學課程中,由於所有文字區塊都源自單一父系 (NASA Earth Book),因此您不需要專門的個別索引來升級父系欄位。 不過,如果您要從多個父系 PDF 編製索引,您可能會想使用父子索引組來擷取層級專屬的欄位,然後將查閱查詢傳送至父索引,以擷取與每個區塊相關的欄位。

結構描述考量的檢查清單

在 Azure AI 搜尋服務中,最適合 RAG 工作負載的索引具有下列品質:

  • 傳回與查詢相關且 LLM 可讀取的區塊。 LLM 可以處理區塊中特定層級的雜亂資料 (dirty data),例如標記、冗餘和不完整的字串。 雖然區塊需要可讀取且與問題相關,但不需要是原始的。

  • 維護文件區塊與父文件屬性之間的父子關聯性,例如檔案名稱、檔類類型、標題、作者等等。 為了回答查詢,可以從索引中的任何位置提取區塊。 與提供區塊的父文件建立關聯對於內容、引文和後續查詢很有用。

  • 滿足您想要建立的查詢。 您應該具有向量和混合式內容的欄位,而且這些欄位應歸咎於支援特定查詢行為,例如可搜尋或可篩選。 您一次只能查詢一個索引 (沒有聯結),因此您的欄位集合應該定義所有可搜尋的內容。

  • 您的架構應該是平面的(沒有複雜類型或結構),或者您應該 先將 complext 類型輸出格式化為 JSON ,再將它傳送至 LLM。 此需求專屬於 Azure AI 搜尋服務中的 RAG 模式。

注意

架構設計會影響記憶體和成本。 此練習著重於架構基本概念。 在最小化 記憶體和成本 教學課程中,您會重新瀏覽架構,以瞭解縮小數據類型、壓縮和儲存選項如何大幅減少向量所使用的記憶體數量。

建立 RAG 工作負載的索引

LLM 的最小索引是設計來儲存內容的區塊。 如果您想要對高度相關的結果進行相似度搜尋,其通常會包含向量欄位。 也會針對 LLM 的人類可讀取輸入包含非向量欄位,以用於對話式搜尋。 搜尋結果中的非向量區塊化內容會變成傳送至 LLM 的基礎資料。

  1. 開啟 Visual Studio Code 並建立新的檔案。 在此練習中,其不一定是 Python 檔案類型。

  2. 以下是支援向量和混合式搜尋之 RAG 解決方案的最小索引定義。 請加以檢閱,以取得必要元素的簡介:向量欄位的索引名稱、欄位和設定區段。

    {
      "name": "example-minimal-index",
      "fields": [
        { "name": "id", "type": "Edm.String", "key": true },
        { "name": "chunked_content", "type": "Edm.String", "searchable": true, "retrievable": true },
        { "name": "chunked_content_vectorized", "type": "Edm.Single", "dimensions": 1536, "vectorSearchProfile": "my-vector-profile", "searchable": true, "retrievable": false, "stored": false },
        { "name": "metadata", "type": "Edm.String", "retrievable": true, "searchable": true, "filterable": true }
      ],
      "vectorSearch": {
          "algorithms": [
              { "name": "my-algo-config", "kind": "hnsw", "hnswParameters": { }  }
          ],
          "profiles": [ 
            { "name": "my-vector-profile", "algorithm": "my-algo-config" }
          ]
      }
    }
    

    欄位必須包含索引鍵欄位 (此範例為 "id"),且應該包含用於相似度搜尋的向量區塊,以及用於 LLM 輸入的非向量區塊。

    向量欄位會與在查詢時判斷搜尋路徑的演算法相關聯。 索引具有 vectorSearch 區段,用於指定多個演算法設定。 向量欄位也具有用於內嵌模型維度的特定類型和額外屬性。 Edm.Single 是適用於常用 LLM 的資料類型。 如需向量欄位的詳細資訊,請參閱建立向量索引

    中繼資料欄位可能是父檔案路徑、建立日期或內容類型,而且適用於篩選

  3. 以下是教學課程原始程式碼Earth Book 內容的索引結構描述。

    就像基本結構描述一樣,這會圍繞著區塊進行組織。 chunk_id 會識別每個獨特區塊。 text_vector 欄位是區塊的內嵌項目。 非向量 chunk 欄位是可讀取的字串。 title 會對應至 Blob 的唯一中繼資料儲存體路徑。 parent_id 是唯一的父層級欄位,也是父檔案 URI 的 base64 編碼版本。

    結構描述也包含 locations 欄位,用於儲存索引管線所建立的已產生內容。

     from azure.identity import DefaultAzureCredential
     from azure.identity import get_bearer_token_provider
     from azure.search.documents.indexes import SearchIndexClient
     from azure.search.documents.indexes.models import (
         SearchField,
         SearchFieldDataType,
         VectorSearch,
         HnswAlgorithmConfiguration,
         VectorSearchProfile,
         AzureOpenAIVectorizer,
         AzureOpenAIVectorizerParameters,
         SearchIndex
     )
    
     credential = DefaultAzureCredential()
    
     # Create a search index  
     index_name = "py-rag-tutorial-idx"
     index_client = SearchIndexClient(endpoint=AZURE_SEARCH_SERVICE, credential=credential)  
     fields = [
         SearchField(name="parent_id", type=SearchFieldDataType.String),  
         SearchField(name="title", type=SearchFieldDataType.String),
         SearchField(name="locations", type=SearchFieldDataType.Collection(SearchFieldDataType.String), filterable=True),
         SearchField(name="chunk_id", type=SearchFieldDataType.String, key=True, sortable=True, filterable=True, facetable=True, analyzer_name="keyword"),  
         SearchField(name="chunk", type=SearchFieldDataType.String, sortable=False, filterable=False, facetable=False),  
         SearchField(name="text_vector", type=SearchFieldDataType.Collection(SearchFieldDataType.Single), vector_search_dimensions=1024, vector_search_profile_name="myHnswProfile")
         ]  
    
     # Configure the vector search configuration  
     vector_search = VectorSearch(  
         algorithms=[  
             HnswAlgorithmConfiguration(name="myHnsw"),
         ],  
         profiles=[  
             VectorSearchProfile(  
                 name="myHnswProfile",  
                 algorithm_configuration_name="myHnsw",  
                 vectorizer_name="myOpenAI",  
             )
         ],  
         vectorizers=[  
             AzureOpenAIVectorizer(  
                 vectorizer_name="myOpenAI",  
                 kind="azureOpenAI",  
                 parameters=AzureOpenAIVectorizerParameters(  
                     resource_url=AZURE_OPENAI_ACCOUNT,  
                     deployment_name="text-embedding-3-large",
                     model_name="text-embedding-3-large"
                 ),
             ),  
         ], 
     )  
    
     # Create the search index
     index = SearchIndex(name=index_name, fields=fields, vector_search=vector_search)  
     result = index_client.create_or_update_index(index)  
     print(f"{result.name} created")  
    
  4. 對於更接近模擬結構化內容的索引結構描述,您會有用於父欄位和子 (區塊化) 欄位的個別索引。 您需要索引投影,才能同時協調兩個索引的索引編製。 查詢會針對子索引執行。 查詢邏輯包含查閱查詢,使用parent_idt從父索引擷取內容。

    子索引中的欄位:

    • 識別碼
    • chunk
    • chunkVectcor
    • parent_id

    父索引中的欄位 (您想要「其中一個」的所有項目):

    • parent_id
    • 父層級欄位 (名稱、標題、類別)

後續步驟