iT邦幫忙

2025 iThome 鐵人賽

DAY 15
1
AI & Data

Notion遇上LLM:30天打造我的AI知識管理系統系列 第 15

【Day 15】從API Key 到本地向量庫:設定 OpenAI 與 Chroma DB

  • 分享至 

  • xImage
  •  

Day 14,我們學會了如何將 Notion 筆記切分 (Chunking),並且估算了 Embedding 成本。
接下來,要讓我們的筆記進入「語意檢索」的世界,就必須具備兩大基礎設施:

  1. OpenAI API Key:連線到 OpenAI 的 Embedding 模型。
  2. Chroma DB:本地向量資料庫,負責儲存與檢索 Embedding 結果。

今天我們會一步步完成這兩件事,讓專案準備好進入「語意向量」的下一步。

1. 取得 & 設置 OpenAI API Key

Step1. 註冊/登入 OpenAI 帳戶

Step2. 建立新的 API Key

  • 進入「建立與管理 API Key」頁面 https://platform.openai.com/api-keys
  • 點擊 「+ Create new secret key」
    https://ithelp.ithome.com.tw/upload/images/20250929/20178104YsLrvwnAZT.png
  • 給 API Key 命名(例如 notion-project),方便之後管理。
    https://ithelp.ithome.com.tw/upload/images/20250929/20178104lf4AYErPCz.png
  • 系統會顯示一組 Secret Key(類似 sk-xxxxxx...)。
    ⚠️ 注意:這個 Key 只會顯示一次,請立刻複製並妥善保存。
    https://ithelp.ithome.com.tw/upload/images/20250929/20178104WHs7j3ERo0.png

Step3. 設定環境變數

  • 在專案資料夾根目錄的 .env 檔案加上OPENAI_API_KEY
    OPENAI_API_KEY=sk-xxxxxxx
    

Step4. 驗證 API Key

  • 我們先寫一支簡單的py來測試,使用我們的 API Key向 OpenAI 伺服器發送一個請求,取得帳號權限下所有可用的 AI 模型列表,因此,如果能成功列出模型清單,代表 API Key 已經正確設定。
  • 需先安裝 openai 套件,test_openai_key.py
    import os
    from openai import OpenAI
    from dotenv import load_dotenv
    
    # 載入 .env 檔案中的環境變數
    load_dotenv()
    
    try:
        print("正在連線至 OpenAI API 並取得模型列表...")
    
        # 初始化 OpenAI client,它會自動讀取環境變數
        client = OpenAI(api_key=os.getenv("OPENAI_API"))
    
        # 取得模型列表
        models = client.models.list()
    
        print("--- ✅ 連線成功!帳號可用的模型列表如下 ---")
    
        # 逐一印出模型
        for model in models:            
            print(f" • ID: {model.id:<30} | Created by: {model.owned_by}")
    
        print("--------------------------------------------------")
    
    except Exception as e:
        print(f"❌ 發生錯誤:{e}")
        print("請檢查 API Key 是否正確,以及帳戶是否有足夠的額度。")
    
    • 輸出結果:
    正在連線至 OpenAI API 並取得模型列表...
    --- ✅ 連線成功!帳號可用的模型列表如下 ---
     • ID: gpt-3.5-turbo                  | Created by: openai
     • ID: gpt-5-codex                    | Created by: system
     • ID: gpt-5-nano-2025-08-07          | Created by: system
     • ID: gpt-5-nano                     | Created by: system
     • ID: gpt-audio-2025-08-28           | Created by: system
     • ID: gpt-audio                      | Created by: system
     • ID: davinci-002                    | Created by: system
     • ID: babbage-002                    | Created by: system
     • ID: gpt-3.5-turbo-instruct         | Created by: system
     • ID: gpt-3.5-turbo-instruct-0914    | Created by: system
     • ID: dall-e-3                       | Created by: system
     ...
    

2. 安裝與初始化 Chroma DB(本地向量資料庫)

2.1 什麼是 Chroma DB?

【Day 12】向量化的準備:Embedding 與向量資料庫 中,我們介紹過 Chroma DB -- 一個開源、專為 AI 應用打造的向量資料庫:

  • 本地運行: 所有資料都儲存在自己的電腦上,無需雲端費用,隱私性最高。
  • Python 原生: 與 Python 整合極佳,API 設計對開發者非常友善。
  • 輕量快速: 非常適合中小型專案、快速原型開發與個人使用。

2.2 安裝 Chroma DB

pip install chromadb

2.3 ChromaDB 的階層架構

ChromaDB 以一個清晰、四層的階層架構來組織資料。在預設的單機模式下,所有這些資訊都被儲存在一個 SQLite 資料庫檔案中。

這個結構能有效地隔離與管理向量數據,從單一使用者到多租戶的應用都能應對。

https://ithelp.ithome.com.tw/upload/images/20250929/20178104MWSUqqNjv7.png

  1. Tenant (租戶) 🏢
    • 最高層級的群組,主要用於多租戶情境,以隔離不同組織或個人的資料。
    • 想像它代表整間公司的檔案櫃系統。
  2. Database (資料庫) 🗄️
    • 在 Tenant 之下,Database 是 Collection 的容器,通常對應到一個特定的專案或應用程式。
    • 這就像檔案櫃中一個標示著「Q3 專案」的抽屜。
  3. Collection (集合) 📂
    • 這會是我們最常互動的層級,用來存放一組相關的 Documents、向量 (Embeddings) 與元數據 (Metadata)。
    • 就像抽屜裡的一個文件夾,例如「會議記錄」或「使用者回饋」。
    • 一個關鍵特性是 Collection 屬於無綱要 (schema-less),這讓我們不需預先定義嚴格的資料結構,即可彈性地新增資料。
  4. Document (文件) 📄
    • 這是儲存與搜尋的最小資料單元。
    • 就是實際的那張紙——也就是文字區塊 (text chunk) 及其對應的向量 (embedding)。

2.4 實際操作:一個完整的「存入」與「查詢」範例

import chromadb

# --- 1. 初始化 Chroma DB Client ---
# 我們使用 PersistentClient 來將資料儲存到硬碟上的指定路徑
# 這可以確保我們的向量資料庫在程式重啟後依然存在
db_path = "db/chroma_db"
client = chromadb.PersistentClient(path=db_path)

# --- 2. 建立或載入一個 Collection ---
# get_or_create_collection 會嘗試取得同名的 collection,
# 如果不存在,它會自動建立一個新的。避免重複建立。
collection_name = "my_notes_collection"
collection = client.get_or_create_collection(name=collection_name)

print(f"✅ Collection '{collection_name}' 準備就緒。")
print(f"目前 Collection 中有 {collection.count()} 筆資料。")

# --- 3. 新增資料到 Collection ---
# documents: 原始的文字內容
# metadatas: 與每段文字相關的「元數據」,例如來源、頁面ID等,這在RAG中極其重要!
# ids: 每段文字的唯一標識符
collection.add(
    documents=[
        "物件導向是一種程式設計方法,它將資料與行為包裝在一起。",
        "類別就像是物件的設計藍圖,定義了物件的屬性與方法。",
        "SQL 是一種用於管理關聯式資料庫的標準化查詢語言。",
        "NoSQL 資料庫提供了比 SQL 資料庫更靈活的資料模型。"
    ],
    metadatas=[
        {"source": "cs101_notes", "page_id": "page_001"},
        {"source": "cs101_notes", "page_id": "page_001"},
        {"source": "db_notes", "page_id": "page_002"},
        {"source": "db_notes", "page_id": "page_002"}
    ],
    ids=["doc_001", "doc_002", "doc_003", "doc_004"]
)

print(f"✅ 新增了 4 筆資料。")
print(f"現在 Collection 中有 {collection.count()} 筆資料。")


# --- 4. 查詢 (Query) 資料 ---
# 這是 RAG 流程的核心,我們用自然語言來「查詢」最相關的筆記
results = collection.query(
    query_texts=["什麼是物件導向?"],
    n_results=2 # 指定回傳最相關的 2 筆結果
)

print("\n--- 查詢結果 ---")
print("問題:什麼是物件導向?")

# --- 5. 解析並印出結果 ---
for i, doc in enumerate(results['documents'][0]):
    distance = results['distances'][0][i]
    metadata = results['metadatas'][0][i]
    print(f"\n結果 {i+1}:")
    print(f"  - 相似度 (距離): {distance:.4f}")
    print(f"  - 內容: {doc}")
    print(f"  - 元數據: {metadata}")

執行後,會看到類似以下的輸出:

✅ Collection 'my_notes_collection' 準備就緒。
目前 Collection 中有 0 筆資料。
✅ 新增了 4 筆資料。
現在 Collection 中有 4 筆資料。

--- 查詢結果 ---
問題:什麼是物件導向?

結果 1:
  - 相似度 (距離): 0.3512
  - 內容: 物件導向是一種程式設計方法,它將資料與行為包裝在一起。
  - 元數據: {'source': 'cs101_notes', 'page_id': 'page_001'}

結果 2:
  - 相似度 (距離): 0.4890
  - 內容: 類別就像是物件的設計藍圖,定義了物件的屬性與方法。
  - 元數據: {'source': 'cs101_notes', 'page_id': 'page_001'}

3. 小結與下篇預告

今天我們完成了兩個重要基礎建設:

  1. 取得並設定 OpenAI API Key,成功連線模型。
  2. 安裝並初始化 Chroma DB,能存放與檢索 Embedding 向量。

在 Day 16,我們就可以把「Notion 筆記 → Embedding → 向量資料庫」的流程串接起來,將 Notion 筆記 chunks 送進 text-embedding-3-small 轉換成向量,並寫入 Chroma DB。


上一篇
【Day 14】資料 Chunking 與 Embedding 成本評估
下一篇
【Day 16】從 Chunk 到向量:將 Notion 筆記寫入 Chroma DB
系列文
Notion遇上LLM:30天打造我的AI知識管理系統21
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言