WeHelp
Chroma 是一個輕量、開源的向量資料庫,專門為 AI 與大型語言模型(LLM)應用設計。
  1. 簡介、用途說明
  2. 下載、安裝、快速開始
  3. Chroma 運作模式
  4. 集合與資料管理
  5. 查詢相似資料
  6. RAG 檢索增強生成
查詢相似資料
以下以 Chroma 的 Python API 為例,說明查詢資料時最重要的觀念與常見選項。 --- ## 1. Chroma 查詢的核心概念 Chroma 是向量資料庫。每筆資料通常包含: - `id`:資料的唯一識別碼 - `document`:原始文字或文件內容 - `embedding`:文件轉換後的向量 - `metadata`:額外欄位,例如作者、日期、分類、權限等 - `uri`:外部資源位置,可選 查詢時,Chroma 會: 1. 將查詢文字轉成 embedding,或直接使用你提供的 embedding。 2. 計算查詢向量與資料庫中向量的距離。 3. 找出距離最近的前 `n_results` 筆資料。 4. 套用 metadata 或文件內容篩選條件。 5. 回傳符合條件的資料。 因此,Chroma 的典型用途是: > 「找出語意上最接近這段文字的資料,並可限制在某些分類、使用者或日期範圍內。」 --- ## 2. 基本查詢方式 ### 使用文字查詢 如果 collection 建立時有設定 embedding function,可以直接使用 `query_texts`: ```python results = collection.query( query_texts=["如何重設密碼?"], n_results=5 ) ``` Chroma 會使用 collection 的 embedding function 將文字轉為向量。 ### 使用既有 embedding 查詢 如果你已經自行產生 embedding,可以使用: ```python results = collection.query( query_embeddings=[[0.12, 0.34, 0.56, ...]], n_results=5 ) ``` 注意: - 查詢向量的維度必須和 collection 的 embedding 維度相同。 - 產生查詢向量時,應使用與建立資料時相同或相容的 embedding model。 - 不應用一個模型建立文件、另一個不相容的模型查詢。 ### 其他查詢輸入 依 Chroma 版本與設定,也可能支援: ```python collection.query( query_images=[...], query_uris=[...], ) ``` 不過最常見的是 `query_texts` 和 `query_embeddings`。 --- ## 3. `n_results`:要取幾筆結果 ```python results = collection.query( query_texts=["Chroma 是什麼?"], n_results=10 ) ``` `n_results` 表示每個查詢要回傳幾筆最近結果。 常見設定: ```python n_results=3 n_results=5 n_results=10 ``` 它不是「相似度門檻」,而是固定取前幾名。 如果你需要「只回傳距離小於某個值的資料」,通常要自行檢查回傳的 `distances`: ```python results = collection.query( query_texts=["如何登入?"], n_results=10 ) for doc, distance in zip( results["documents"][0], results["distances"][0] ): if distance < 0.8: print(doc, distance) ``` 距離門檻要根據 collection 使用的距離函數與實際資料測試後決定。 --- ## 4. `where`:依 metadata 篩選 如果資料具有 metadata,可以使用 `where` 做結構化條件過濾。 例如資料: ```python collection.add( ids=["a1", "a2"], documents=[ "這是一篇 Python 教學。", "這是一篇 JavaScript 教學。" ], metadatas=[ {"category": "programming", "language": "python", "year": 2024}, {"category": "programming", "language": "javascript", "year": 2023} ] ) ``` 查詢 Python 文件: ```python results = collection.query( query_texts=["程式設計教學"], where={"language": "python"}, n_results=5 ) ``` 也可以明確使用 `$eq`: ```python where={ "language": {"$eq": "python"} } ``` ### 常見 metadata 運算子 #### 等於 ```python {"category": {"$eq": "programming"}} ``` 或簡寫為: ```python {"category": "programming"} ``` #### 不等於 ```python {"language": {"$ne": "python"}} ``` #### 數值比較 ```python {"year": {"$gt": 2020}} {"year": {"$gte": 2020}} {"year": {"$lt": 2025}} {"year": {"$lte": 2025}} ``` #### 屬於某些值 ```python { "language": { "$in": ["python", "javascript"] } } ``` #### 不屬於某些值 ```python { "language": { "$nin": ["java", "c++"] } } ``` ### 多個條件 可以使用 `$and`: ```python results = collection.query( query_texts=["程式設計教學"], where={ "$and": [ {"category": "programming"}, {"year": {"$gte": 2023}} ] }, n_results=5 ) ``` 使用 `$or`: ```python where={ "$or": [ {"language": "python"}, {"language": "javascript"} ] } ``` 實際支援的運算子可能依 Chroma 版本而略有差異,使用前可確認目前版本的 filter schema。 --- ## 5. `where_document`:依文件文字內容篩選 `where` 是過濾 metadata;`where_document` 則是過濾原始文件文字。 例如查詢文件中包含某個字串的資料: ```python results = collection.query( query_texts=["資料庫教學"], where_document={ "$contains": "Python" }, n_results=5 ) ``` 排除包含某字串的文件: ```python where_document={ "$not_contains": "deprecated" } ``` 也可以搭配邏輯條件: ```python where_document={ "$and": [ {"$contains": "Python"}, {"$contains": "database"} ] } ``` ### `where` 與 `where_document` 的差異 | 選項 | 篩選對象 | 範例 | |---|---|---| | `where` | metadata | `{"category": "news"}` | | `where_document` | document 文字內容 | `{"$contains": "Python"}` | 一般而言: - 類別、使用者、日期、權限等條件,應放在 `metadata`。 - 需要搜尋文件中是否出現特定文字,可使用 `where_document`。 - 語意相似度搜尋仍然是由 embedding 負責,`where_document` 不是語意搜尋。 --- ## 6. `include`:指定回傳哪些欄位 查詢時可以指定要回傳的內容: ```python results = collection.query( query_texts=["向量資料庫"], n_results=3, include=[ "documents", "metadatas", "distances" ] ) ``` 常見選項包括: - `"documents"`:原始文件內容 - `"metadatas"`:metadata - `"distances"`:查詢向量與結果向量的距離 - `"embeddings"`:結果資料的 embedding - `"uris"`:資料 URI - `"data"`:部分資料型態使用的額外資料 `ids` 通常會直接回傳,不需放在 `include` 中。 例如: ```python results = collection.query( query_texts=["向量搜尋"], n_results=3, include=["documents", "metadatas", "distances"] ) print(results.keys()) print(results["ids"]) print(results["documents"]) print(results["metadatas"]) print(results["distances"]) ``` ### 為什麼不一定要回傳 embeddings? Embedding 通常維度很高,回傳會增加資料量。若只是要顯示搜尋結果,通常只需要: ```python include=["documents", "metadatas", "distances"] ``` 只有在要做: - 二次排序 - 自行計算相似度 - 向量分析 - 匯出 embedding 時,才需要: ```python include=["embeddings"] ``` --- ## 7. `distances` 的意義 結果通常會包含: ```python results["distances"] ``` 它代表查詢向量與每筆結果向量之間的距離。 重要的是: > 距離越小,通常代表越相似。 但距離的實際意義取決於 collection 使用的 distance metric,例如: - `l2` - `cosine` - `ip`,inner product 例如: ```python results = collection.query( query_texts=["Python"], n_results=3, include=["documents", "distances"] ) for document, distance in zip( results["documents"][0], results["distances"][0] ): print(f"距離:{distance}") print(document) ``` 不要直接把 distance 當成百分比,也不要在不知道 metric 的情況下直接套用: ```python score = 1 - distance ``` 因為不同距離函數的數值範圍與意義不同。 --- ## 8. 查詢結果的資料結構 即使只查一個 query,結果通常也是巢狀 list: ```python results = collection.query( query_texts=["如何備份資料?"], n_results=2 ) ``` 概念上會得到: ```python { "ids": [["doc1", "doc2"]], "documents": [["文件一", "文件二"]], "metadatas": [[{"type": "guide"}, {"type": "manual"}]], "distances": [[0.12, 0.35]] } ``` 外層代表「查詢句子」,內層代表該查詢的結果。 如果一次查詢多個問題: ```python results = collection.query( query_texts=[ "如何備份資料?", "如何重設密碼?" ], n_results=3 ) ``` 則: ```python results["documents"][0] ``` 是第一個問題的結果,而: ```python results["documents"][1] ``` 是第二個問題的結果。 --- ## 9. `query` 與 `get` 的差異 ### `query` 適合語意搜尋: ```python collection.query( query_texts=["找出關於退款的文件"], n_results=5 ) ``` 它會根據 embedding 相似度排序。 ### `get` 適合依 ID 或條件直接取得資料: ```python collection.get( ids=["doc1", "doc2"] ) ``` 也可以依 metadata 取得: ```python collection.get( where={"category": "faq"} ) ``` `get` 不會進行向量相似度搜尋。 簡單比較: | 方法 | 用途 | |---|---| | `query` | 語意相似度搜尋 | | `get` | 依 ID 或條件直接取資料 | | `peek` | 查看 collection 中少量資料 | | `count` | 取得資料筆數 | --- ## 10. 一個較完整的查詢範例 ```python results = collection.query( query_texts=["如何設定使用者權限?"], n_results=5, where={ "$and": [ {"category": "documentation"}, {"language": "zh-TW"} ] }, where_document={ "$not_contains": "deprecated" }, include=[ "documents", "metadatas", "distances" ] ) for i, doc_id in enumerate(results["ids"][0]): print("ID:", doc_id) print("文件:", results["documents"][0][i]) print("Metadata:", results["metadatas"][0][i]) print("Distance:", results["distances"][0][i]) print("---") ``` 這個查詢的意思是: 1. 將問題轉成向量。 2. 只在 `category= documentation` 且 `language= zh-TW` 的資料中搜尋。 3. 排除文件中含有 `deprecated` 的資料。 4. 取最相似的五筆。 5. 回傳文件、metadata 與距離。 --- ## 11. 實務上的重要注意事項 ### 查詢文字與建立資料時的語言要一致 如果文件是中文,embedding model 最好對中文有良好支援。否則即使 Chroma 查詢成功,語意排序品質也可能不佳。 ### `n_results` 不代表結果一定相關 即使指定: ```python n_results=5 ``` Chroma 仍可能回傳五筆相對較近、但實際上不太相關的資料。因此實務上常搭配: - distance threshold - reranking model - metadata filter - 關鍵字檢查 - LLM 後處理 ### Metadata 要事先設計好 常用的篩選欄位,例如: ```python { "tenant_id": "company_a", "document_type": "faq", "language": "zh-TW", "created_at": "2024-01-01", "access_level": "internal" } ``` 應在寫入資料時就保存,之後查詢才能有效過濾。 ### 權限過濾應在查詢階段處理 如果不同使用者只能看到不同資料,不應先取回所有結果再在應用程式中隨意過濾,而應將權限條件放進 `where`: ```python where={ "tenant_id": "company_a" } ``` 這樣可以避免不該暴露的資料出現在搜尋結果中。 --- ## 總結 Chroma 查詢最主要的選項可以記成: ```python collection.query( query_texts=[...], # 查詢文字 query_embeddings=[...], # 或直接提供 embedding n_results=5, # 取前幾筆 where={...}, # metadata 篩選 where_document={...}, # 文件文字篩選 include=[...], # 指定回傳欄位 ) ``` 其中最重要的觀念是: - `query` 是向量相似度搜尋。 - `n_results` 是取前幾名,不是相似度門檻。 - `where` 過濾 metadata。 - `where_document` 過濾文件內容。 - `distances` 通常是距離,越小通常越相似。 - 查詢與寫入資料應使用相容的 embedding model。 - `get` 是直接取資料,不是語意搜尋。
相關學習地圖、教學課程
Python 人工智慧
建議完成「Python 資料工程」教程後,繼續學習以下課程。