<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>RAG on kenji.blog</title><link>http://kenji.blog/zh-tw/categories/rag/</link><description>Recent content in RAG on kenji.blog</description><generator>Hugo -- gohugo.io</generator><language>zh-tw</language><copyright>kenjinote</copyright><lastBuildDate>Fri, 11 Sep 2026 13:00:00 +0900</lastBuildDate><atom:link href="http://kenji.blog/zh-tw/categories/rag/index.xml" rel="self" type="application/rss+xml"/><item><title>【RAG 實作入門】讓本機 AI 讀取自己文件的教學</title><link>http://kenji.blog/zh-tw/p/rag-local-ai-implementation-guide/</link><pubDate>Fri, 11 Sep 2026 13:00:00 +0900</pubDate><guid>http://kenji.blog/zh-tw/p/rag-local-ai-implementation-guide/</guid><description>&lt;img src="http://kenji.blog/p/rag-local-ai-implementation-guide/img/eyecatch.jpg" alt="Featured image of post 【RAG 實作入門】讓本機 AI 讀取自己文件的教學" />&lt;h1 id="前言">前言
&lt;/h1>&lt;p>近年來，大型語言模型（LLM）的進化令人矚目，以 ChatGPT 和 Claude 為首的許多 AI 已經滲透到我們的生活和業務中。然而，一般的 LLM 存在著明顯的弱點。那就是它們只知道「訓練時的公開資訊」。對於公司內部規定、個人筆記、未公開的專案資料等「私有文件」相關的提問，它們自然無法回答。如果硬要它們回答，就會增加產生與事實不符、似是而非的謊言（幻覺，Hallucination）的風險。&lt;/p>
&lt;p>因此，目前在世界各地爆發性普及的技術架構就是 &lt;strong>RAG（Retrieval-Augmented Generation，檢索增強生成）&lt;/strong>。透過使用 RAG，可以從外部資料庫動態地提供專有知識給 LLM，讓它能基於這些知識產生準確且有根據的回答。&lt;/p>
&lt;p>此外，在處理企業領域或個人機密資訊時，將資料傳送到 OpenAI 等雲端 API 在資安政策上通常是不被允許的。這時就需要結合&lt;strong>本機 AI&lt;/strong>（在自己的電腦或地端伺服器上獨立運作的 LLM）來建構「本機 RAG（Local RAG）」。&lt;/p>
&lt;p>本文將從 RAG 的基礎理論開始，徹底解說使用 Python 實作本機 RAG 的具體方法、數學背景（向量檢索的原理），以及讓系統上線運作的進階技巧。&lt;/p>
&lt;hr>
&lt;h1 id="1-rag-的整體架構">1. RAG 的整體架構
&lt;/h1>&lt;p>RAG 並非單一的 AI 模型，而是多個元件協同運作的系統架構。大致可分為「攝取（資料匯入）階段」與「檢索與生成階段」兩個部分。&lt;/p>
&lt;p>以下的 Mermaid 圖表展示了 RAG 系統的整體樣貌。&lt;/p>
&lt;div class="mermaid">graph TD
subgraph "攝取階段 (事前準備)"
Doc["專屬文件 (PDF, TXT 等)"] --> Loader["文件載入器"]
Loader --> Splitter["文字分割 (分塊)"]
Splitter --> EmbedModel1["嵌入模型 (Embedding)"]
EmbedModel1 --> VectorDB["向量資料庫"]
end
subgraph "推論階段 (使用者提問時)"
User["使用者的問題 (查詢)"] --> EmbedModel2["嵌入模型 (Embedding)"]
EmbedModel2 --> QueryVector["查詢向量"]
QueryVector --> Search["相似度檢索 (向量檢索)"]
VectorDB --> Search
Search --> Context["相關分塊擷取 (上下文)"]
User --> PromptBuilder["提示詞建構"]
Context --> PromptBuilder
PromptBuilder --> LocalLLM["本機 LLM"]
LocalLLM --> Answer["最終回答生成"]
end&lt;/div>
&lt;h2 id="攝取階段事前準備">攝取階段（事前準備）
&lt;/h2>&lt;ol>
&lt;li>&lt;strong>讀取文件&lt;/strong>：讀取 PDF、Word、純文字檔等非結構化資料。&lt;/li>
&lt;li>&lt;strong>分塊（文字分割）&lt;/strong>：為了符合 LLM 的輸入限制（上下文視窗大小）並提高檢索精準度，將長篇文章分割成有意義的區塊（Chunk）。&lt;/li>
&lt;li>&lt;strong>嵌入（向量化）&lt;/strong>：將分割後的區塊輸入至嵌入模型（Embedding Model），轉換成數百到數千維的數值陣列（向量）。&lt;/li>
&lt;li>&lt;strong>儲存至資料庫&lt;/strong>：將轉換後的向量與原始文字資料關聯起來，儲存到向量資料庫（Vector DB）中。&lt;/li>
&lt;/ol>
&lt;h2 id="推論階段執行時">推論階段（執行時）
&lt;/h2>&lt;ol>
&lt;li>&lt;strong>查詢向量化&lt;/strong>：使用與事前準備相同的嵌入模型，將使用者提出的問題進行向量化。&lt;/li>
&lt;li>&lt;strong>相似度檢索&lt;/strong>：在查詢向量與資料庫中的文件向量之間進行相似度計算，取得在語意上最接近（關聯性最高）的前幾筆文字區塊。&lt;/li>
&lt;li>&lt;strong>建構提示詞&lt;/strong>：將取得的相關文字作為「上下文（背景知識）」與使用者的問題結合，建立提供給 LLM 的輸入提示詞。&lt;/li>
&lt;li>&lt;strong>生成回答&lt;/strong>：接收到擴充提示詞的 LLM，根據附加的上下文資訊生成回答。&lt;/li>
&lt;/ol>
&lt;hr>
&lt;h1 id="2-深入理解向量檢索與嵌入embeddings">2. 深入理解向量檢索與嵌入（Embeddings）
&lt;/h1>&lt;p>RAG 的核心在於「向量檢索（語意檢索）」。傳統的關鍵字檢索（如 BM25）是基於單詞的完全比對或出現頻率，而向量檢索則是基於「語意的相似性」。例如，「狗」與「小狗」、「PC」與「個人電腦」，即使單字不同，只要語意相近就能被檢索出來。&lt;/p>
&lt;h2 id="什麼是嵌入模型embedding-model">什麼是嵌入模型（Embedding Model）？
&lt;/h2>&lt;p>嵌入模型是一種神經網路，它接收自然語言的文字作為輸入，並輸出固定長度的密集向量（Dense Vector）。常見的模型（例如 &lt;code>text-embedding-3-small&lt;/code> 或開源的 &lt;code>multilingual-e5-large&lt;/code>）會將文字對映到 384 維或 1024 維的實數向量。&lt;/p>
&lt;p>在這個多維空間（潛在空間）中，語意越相似的句子，在座標空間上的距離就越近。&lt;/p>
&lt;h2 id="相似度計算的數學背景餘弦相似度">相似度計算的數學背景：餘弦相似度
&lt;/h2>&lt;p>當向量資料庫在檢索相關文件時，最常使用的距離指標是&lt;strong>餘弦相似度（Cosine Similarity）&lt;/strong>。與歐幾里得距離（空間上的絕對距離）不同，餘弦相似度關注的是「兩個向量之間的夾角」。因為它較不易受文章長度（向量的範數）影響，所以非常適合用於文字的相似度計算。&lt;/p>
&lt;p>用數學公式表示的話，向量 $\mathbf{A}$ 和 $\mathbf{B}$ 的餘弦相似度如下：&lt;/p>
$$ \text{Cosine Similarity}(\mathbf{A}, \mathbf{B}) = \cos(\theta) = \frac{\mathbf{A} \cdot \mathbf{B}}{\|\mathbf{A}\| \|\mathbf{B}\|} = \frac{\sum_{i=1}^{n} A_i B_i}{\sqrt{\sum_{i=1}^{n} A_i^2} \sqrt{\sum_{i=1}^{n} B_i^2}} $$
&lt;ul>
&lt;li>$\mathbf{A} \cdot \mathbf{B}$ 代表內積（Dot Product）。&lt;/li>
&lt;li>$\|\mathbf{A}\|$ 代表向量 $\mathbf{A}$ 的 L2 範數（長度）。&lt;/li>
&lt;li>$n$ 是向量的維度數。&lt;/li>
&lt;/ul>
&lt;p>餘弦相似度的值介於 -1 到 1 之間。&lt;/p>
&lt;ul>
&lt;li>&lt;strong>接近 1&lt;/strong>：兩個向量的方向幾乎相同（語意非常相似）。&lt;/li>
&lt;li>&lt;strong>接近 0&lt;/strong>：兩個向量互相垂直（毫無關聯）。&lt;/li>
&lt;li>&lt;strong>接近 -1&lt;/strong>：兩個向量的方向完全相反（語意相反）。&lt;/li>
&lt;/ul>
&lt;p>最近的向量資料庫（Chroma、FAISS、Qdrant 等）採用了被稱為 HNSW（Hierarchical Navigable Small World）的近似最近鄰搜尋（ANN）演算法，經過最佳化後，即使從數百萬筆向量資料中，也能在毫秒級別內檢索出餘弦相似度高的文件。&lt;/p>
&lt;hr>
&lt;h1 id="3-建構本機-rag-的技術堆疊">3. 建構本機 RAG 的技術堆疊
&lt;/h1>&lt;p>為了建構完全不依賴雲端的本機 RAG，我們將活用開源生態系統。以下介紹推薦的技術堆疊。&lt;/p>
&lt;ol>
&lt;li>&lt;strong>語言模型 (LLM)&lt;/strong>
&lt;ul>
&lt;li>工具：&lt;code>Ollama&lt;/code> 或 &lt;code>Llama.cpp&lt;/code>&lt;/li>
&lt;li>模型：&lt;code>Llama-3-8B-Instruct&lt;/code>、&lt;code>Gemma-2-9B-It&lt;/code>、&lt;code>Qwen2-7B-Instruct&lt;/code> 等輕量且高效能的開源模型。針對日文任務，適合使用經過日文微調的 &lt;code>Llama-3-ELYZA-JP-8B&lt;/code> 等。&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>&lt;strong>嵌入模型 (Embedding)&lt;/strong>
&lt;ul>
&lt;li>模型：&lt;code>intfloat/multilingual-e5-large&lt;/code> 或 &lt;code>BAAI/bge-m3&lt;/code>。若要在本機執行，通常會從 Hugging Face 下載並透過 Sentence-Transformers 執行。&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>&lt;strong>向量資料庫 (Vector DB)&lt;/strong>
&lt;ul>
&lt;li>&lt;code>ChromaDB&lt;/code>：基於 Python，設定極為簡單。最適合用於本機開發。&lt;/li>
&lt;li>&lt;code>FAISS&lt;/code>：Meta 開發的高速向量檢索函式庫。&lt;/li>
&lt;li>&lt;code>Qdrant&lt;/code> / &lt;code>Milvus&lt;/code>：適用於更大規模且正式的生產環境。&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>&lt;strong>編排框架 (Orchestration Framework)&lt;/strong>
&lt;ul>
&lt;li>&lt;code>LangChain&lt;/code>：用於串聯各個元件（Chain）的業界標準。&lt;/li>
&lt;li>&lt;code>LlamaIndex&lt;/code>：特別專注於 RAG 的資料連接框架。&lt;/li>
&lt;/ul>
&lt;/li>
&lt;/ol>
&lt;p>這次我們將使用最容易導入的組合：&lt;strong>LangChain + ChromaDB + Ollama + HuggingFaceEmbeddings&lt;/strong> 來進行實作。&lt;/p>
&lt;hr>
&lt;h1 id="4-實作教學使用-python-建構完整的本機-rag">4. 實作教學：使用 Python 建構完整的本機 RAG
&lt;/h1>&lt;p>接下來，我們將實際撰寫 Python 程式碼來建構本機 RAG。請先在電腦上安裝 Ollama 並讓它在背景執行。同時，請先在 Ollama 上拉取（pull）好模型（例如：&lt;code>ollama run llama3&lt;/code>）。&lt;/p>
&lt;h2 id="step-1-安裝必要的函式庫">Step 1: 安裝必要的函式庫
&lt;/h2>&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;span class="lnt">2
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">pip install langchain langchain-community langchain-huggingface
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">pip install chromadb sentence-transformers pypdf
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;h2 id="step-2-實作程式碼全貌">Step 2: 實作程式碼全貌
&lt;/h2>&lt;p>以下是讀取 PDF 檔案、將其向量化並讓本機 LLM 進行問答的完整 Python 腳本。&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt"> 1
&lt;/span>&lt;span class="lnt"> 2
&lt;/span>&lt;span class="lnt"> 3
&lt;/span>&lt;span class="lnt"> 4
&lt;/span>&lt;span class="lnt"> 5
&lt;/span>&lt;span class="lnt"> 6
&lt;/span>&lt;span class="lnt"> 7
&lt;/span>&lt;span class="lnt"> 8
&lt;/span>&lt;span class="lnt"> 9
&lt;/span>&lt;span class="lnt">10
&lt;/span>&lt;span class="lnt">11
&lt;/span>&lt;span class="lnt">12
&lt;/span>&lt;span class="lnt">13
&lt;/span>&lt;span class="lnt">14
&lt;/span>&lt;span class="lnt">15
&lt;/span>&lt;span class="lnt">16
&lt;/span>&lt;span class="lnt">17
&lt;/span>&lt;span class="lnt">18
&lt;/span>&lt;span class="lnt">19
&lt;/span>&lt;span class="lnt">20
&lt;/span>&lt;span class="lnt">21
&lt;/span>&lt;span class="lnt">22
&lt;/span>&lt;span class="lnt">23
&lt;/span>&lt;span class="lnt">24
&lt;/span>&lt;span class="lnt">25
&lt;/span>&lt;span class="lnt">26
&lt;/span>&lt;span class="lnt">27
&lt;/span>&lt;span class="lnt">28
&lt;/span>&lt;span class="lnt">29
&lt;/span>&lt;span class="lnt">30
&lt;/span>&lt;span class="lnt">31
&lt;/span>&lt;span class="lnt">32
&lt;/span>&lt;span class="lnt">33
&lt;/span>&lt;span class="lnt">34
&lt;/span>&lt;span class="lnt">35
&lt;/span>&lt;span class="lnt">36
&lt;/span>&lt;span class="lnt">37
&lt;/span>&lt;span class="lnt">38
&lt;/span>&lt;span class="lnt">39
&lt;/span>&lt;span class="lnt">40
&lt;/span>&lt;span class="lnt">41
&lt;/span>&lt;span class="lnt">42
&lt;/span>&lt;span class="lnt">43
&lt;/span>&lt;span class="lnt">44
&lt;/span>&lt;span class="lnt">45
&lt;/span>&lt;span class="lnt">46
&lt;/span>&lt;span class="lnt">47
&lt;/span>&lt;span class="lnt">48
&lt;/span>&lt;span class="lnt">49
&lt;/span>&lt;span class="lnt">50
&lt;/span>&lt;span class="lnt">51
&lt;/span>&lt;span class="lnt">52
&lt;/span>&lt;span class="lnt">53
&lt;/span>&lt;span class="lnt">54
&lt;/span>&lt;span class="lnt">55
&lt;/span>&lt;span class="lnt">56
&lt;/span>&lt;span class="lnt">57
&lt;/span>&lt;span class="lnt">58
&lt;/span>&lt;span class="lnt">59
&lt;/span>&lt;span class="lnt">60
&lt;/span>&lt;span class="lnt">61
&lt;/span>&lt;span class="lnt">62
&lt;/span>&lt;span class="lnt">63
&lt;/span>&lt;span class="lnt">64
&lt;/span>&lt;span class="lnt">65
&lt;/span>&lt;span class="lnt">66
&lt;/span>&lt;span class="lnt">67
&lt;/span>&lt;span class="lnt">68
&lt;/span>&lt;span class="lnt">69
&lt;/span>&lt;span class="lnt">70
&lt;/span>&lt;span class="lnt">71
&lt;/span>&lt;span class="lnt">72
&lt;/span>&lt;span class="lnt">73
&lt;/span>&lt;span class="lnt">74
&lt;/span>&lt;span class="lnt">75
&lt;/span>&lt;span class="lnt">76
&lt;/span>&lt;span class="lnt">77
&lt;/span>&lt;span class="lnt">78
&lt;/span>&lt;span class="lnt">79
&lt;/span>&lt;span class="lnt">80
&lt;/span>&lt;span class="lnt">81
&lt;/span>&lt;span class="lnt">82
&lt;/span>&lt;span class="lnt">83
&lt;/span>&lt;span class="lnt">84
&lt;/span>&lt;span class="lnt">85
&lt;/span>&lt;span class="lnt">86
&lt;/span>&lt;span class="lnt">87
&lt;/span>&lt;span class="lnt">88
&lt;/span>&lt;span class="lnt">89
&lt;/span>&lt;span class="lnt">90
&lt;/span>&lt;span class="lnt">91
&lt;/span>&lt;span class="lnt">92
&lt;/span>&lt;span class="lnt">93
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-python" data-lang="python">&lt;span class="line">&lt;span class="cl">&lt;span class="kn">import&lt;/span> &lt;span class="nn">os&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kn">from&lt;/span> &lt;span class="nn">langchain_community.document_loaders&lt;/span> &lt;span class="kn">import&lt;/span> &lt;span class="n">PyPDFLoader&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kn">from&lt;/span> &lt;span class="nn">langchain_text_splitters&lt;/span> &lt;span class="kn">import&lt;/span> &lt;span class="n">RecursiveCharacterTextSplitter&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kn">from&lt;/span> &lt;span class="nn">langchain_huggingface&lt;/span> &lt;span class="kn">import&lt;/span> &lt;span class="n">HuggingFaceEmbeddings&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kn">from&lt;/span> &lt;span class="nn">langchain_community.vectorstores&lt;/span> &lt;span class="kn">import&lt;/span> &lt;span class="n">Chroma&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kn">from&lt;/span> &lt;span class="nn">langchain_community.llms&lt;/span> &lt;span class="kn">import&lt;/span> &lt;span class="n">Ollama&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kn">from&lt;/span> &lt;span class="nn">langchain_core.prompts&lt;/span> &lt;span class="kn">import&lt;/span> &lt;span class="n">PromptTemplate&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kn">from&lt;/span> &lt;span class="nn">langchain.chains&lt;/span> &lt;span class="kn">import&lt;/span> &lt;span class="n">RetrievalQA&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">def&lt;/span> &lt;span class="nf">main&lt;/span>&lt;span class="p">():&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># 1. 讀取文件&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">print&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;正在讀取文件...&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># 指定要讀取的 PDF 路徑&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">file_path&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;sample_company_policy.pdf&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">loader&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">PyPDFLoader&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">file_path&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">documents&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">loader&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">load&lt;/span>&lt;span class="p">()&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># 2. 文字分割（Text Splitting）&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># 為了不破壞文章語意，分割成適當的大小&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">text_splitter&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">RecursiveCharacterTextSplitter&lt;/span>&lt;span class="p">(&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">chunk_size&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="mi">500&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="c1"># 每個分塊的最大字元數&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">chunk_overlap&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="mi">50&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="c1"># 前後分塊的重疊字元數（防止上下文斷層）&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">separators&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="se">\n\n&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="se">\n&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s2">&amp;#34;。&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s2">&amp;#34;、&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s2">&amp;#34; &amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s2">&amp;#34;&amp;#34;&lt;/span>&lt;span class="p">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">chunks&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">text_splitter&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">split_documents&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">documents&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">print&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="sa">f&lt;/span>&lt;span class="s2">&amp;#34;已分割成 &lt;/span>&lt;span class="si">{&lt;/span>&lt;span class="nb">len&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">chunks&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="si">}&lt;/span>&lt;span class="s2"> 個分塊。&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># 3. 初始化嵌入模型 (Local HuggingFace Model)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># 使用對日文等支援度高的多語系模型&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">print&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;正在載入嵌入模型...&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">embeddings&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">HuggingFaceEmbeddings&lt;/span>&lt;span class="p">(&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">model_name&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s2">&amp;#34;intfloat/multilingual-e5-large&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">model_kwargs&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="p">{&lt;/span>&lt;span class="s1">&amp;#39;device&amp;#39;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="s1">&amp;#39;cpu&amp;#39;&lt;/span>&lt;span class="p">}&lt;/span> &lt;span class="c1"># 若有 GPU 可改為 &amp;#39;cuda&amp;#39; 或 &amp;#39;mps&amp;#39;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># 4. 建構向量資料庫 (Chroma)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">print&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;正在建構向量資料庫...&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">persist_directory&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;./chroma_db&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">vectorstore&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">Chroma&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">from_documents&lt;/span>&lt;span class="p">(&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">documents&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="n">chunks&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">embedding&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="n">embeddings&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">persist_directory&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="n">persist_directory&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># 建立檢索器（Retriever）。設定為取得前 3 筆關聯文件&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">retriever&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">vectorstore&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">as_retriever&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">search_kwargs&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="p">{&lt;/span>&lt;span class="s2">&amp;#34;k&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="mi">3&lt;/span>&lt;span class="p">})&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># 5. 初始化本機 LLM (Ollama)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">print&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;正在連接至本機 LLM...&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># 請先透過 &amp;#39;ollama pull llama3&amp;#39; 等指令取得模型&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">llm&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">Ollama&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">model&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s2">&amp;#34;llama3&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># 6. 定義提示詞模板&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">prompt_template&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;&amp;#34;&amp;#34;你是一位精通公司規定與內部資訊的優秀助理。
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s2">請「僅」使用以下的上下文（背景資訊），詳細回答使用者的問題。
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s2">如果從上下文中找不到答案，請誠實地回答「從提供的資訊中無法得知」，不要隨意猜測。
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s2">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s2">【上下文】
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s2">&lt;/span>&lt;span class="si">{context}&lt;/span>&lt;span class="s2">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s2">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s2">【問題】
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s2">&lt;/span>&lt;span class="si">{question}&lt;/span>&lt;span class="s2">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s2">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s2">【回答】:
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s2">&amp;#34;&amp;#34;&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">PROMPT&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">PromptTemplate&lt;/span>&lt;span class="p">(&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">template&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="n">prompt_template&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">input_variables&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="s2">&amp;#34;context&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s2">&amp;#34;question&amp;#34;&lt;/span>&lt;span class="p">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># 7. 建構 RAG Chain&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">qa_chain&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">RetrievalQA&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">from_chain_type&lt;/span>&lt;span class="p">(&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">llm&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="n">llm&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">chain_type&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s2">&amp;#34;stuff&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">retriever&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="n">retriever&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">return_source_documents&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="kc">True&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="c1"># 設定是否回傳資訊來源&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">chain_type_kwargs&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="p">{&lt;/span>&lt;span class="s2">&amp;#34;prompt&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">PROMPT&lt;/span>&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># 8. 執行提問&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">query&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;請告訴我關於遠端工作時的交通費補助條件。&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">print&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="sa">f&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="se">\n&lt;/span>&lt;span class="s2">問題: &lt;/span>&lt;span class="si">{&lt;/span>&lt;span class="n">query&lt;/span>&lt;span class="si">}&lt;/span>&lt;span class="se">\n&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">result&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">qa_chain&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">invoke&lt;/span>&lt;span class="p">({&lt;/span>&lt;span class="s2">&amp;#34;query&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">query&lt;/span>&lt;span class="p">})&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">print&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;【回答】&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">print&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">result&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="s1">&amp;#39;result&amp;#39;&lt;/span>&lt;span class="p">])&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">print&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="se">\n&lt;/span>&lt;span class="s2">---&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">print&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;【參考的資訊來源】&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">for&lt;/span> &lt;span class="n">doc&lt;/span> &lt;span class="ow">in&lt;/span> &lt;span class="n">result&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="s1">&amp;#39;source_documents&amp;#39;&lt;/span>&lt;span class="p">]:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">print&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="sa">f&lt;/span>&lt;span class="s2">&amp;#34;- 第 &lt;/span>&lt;span class="si">{&lt;/span>&lt;span class="n">doc&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">metadata&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">get&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s1">&amp;#39;page&amp;#39;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s1">&amp;#39;未知&amp;#39;&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="si">}&lt;/span>&lt;span class="s2"> 頁: &lt;/span>&lt;span class="si">{&lt;/span>&lt;span class="n">doc&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">page_content&lt;/span>&lt;span class="p">[:&lt;/span>&lt;span class="mi">50&lt;/span>&lt;span class="p">]&lt;/span>&lt;span class="si">}&lt;/span>&lt;span class="s2">...&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">if&lt;/span> &lt;span class="vm">__name__&lt;/span> &lt;span class="o">==&lt;/span> &lt;span class="s2">&amp;#34;__main__&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">main&lt;/span>&lt;span class="p">()&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;h2 id="程式碼重點解說">程式碼重點解說
&lt;/h2>&lt;ol>
&lt;li>&lt;strong>RecursiveCharacterTextSplitter&lt;/strong>:
這是處理自然語言分割時最被推薦的分割器。它會依序嘗試段落 (&lt;code>\n\n&lt;/code>)、換行 (&lt;code>\n&lt;/code>)、句號 (&lt;code>。&lt;/code>) 進行分割，盡可能在維持語意完整性的情況下，將文字分割至指定的 &lt;code>chunk_size&lt;/code> 內。透過設定 &lt;code>chunk_overlap&lt;/code>，可以防止上下文的交界處被截斷而流失資訊。&lt;/li>
&lt;li>&lt;strong>HuggingFaceEmbeddings&lt;/strong>:
&lt;code>intfloat/multilingual-e5-large&lt;/code> 是一個支援多國語言、非常強大的開源嵌入模型。不需要使用雲端 API（如 OpenAI 的 &lt;code>text-embedding-ada-002&lt;/code> 等），即可在離線狀態下於本機記憶體中將文字向量化。&lt;/li>
&lt;li>&lt;strong>ChromaDB&lt;/strong>:
因為它是在記憶體內或本機儲存空間（基於 SQLite）中運作，所以不需要架設複雜的資料庫伺服器。透過指定 &lt;code>persist_directory&lt;/code>，可以在下次執行時跳過向量化的過程，直接從磁碟讀取資料庫。&lt;/li>
&lt;/ol>
&lt;hr>
&lt;h1 id="5-進階-rag-技巧advanced-rag-techniques">5. 進階 RAG 技巧（Advanced RAG Techniques）
&lt;/h1>&lt;p>雖然上述教學中建構的基礎 RAG 系統（Naive RAG）也能運作，但若在生產環境中要求較高的回答準確度，就需要導入以下進階技巧。&lt;/p>
&lt;h2 id="51-混合檢索-hybrid-search">5.1 混合檢索 (Hybrid Search)
&lt;/h2>&lt;p>向量檢索雖然擅長捕捉「語意」，但有時卻不擅長處理「特定的專有名詞」、「產品型號」、「員工 ID」等精確的關鍵字檢索。
因此，可以將基於向量檢索的&lt;strong>語意檢索&lt;/strong>與使用 BM25 演算法的&lt;strong>關鍵字檢索&lt;/strong>平行執行，再將兩者的結果進行評分與整合（例如使用 Reciprocal Rank Fusion; RRF 等技術），如此一來能大幅減少漏檢的情況。&lt;/p>
&lt;h2 id="52-重新排序-re-ranking">5.2 重新排序 (Re-ranking)
&lt;/h2>&lt;p>向量檢索速度很快，但它並不一定能準確評估上下文的語意適合度。為了提升檢索準確度，一般的流程如下：&lt;/p>
&lt;ol>
&lt;li>&lt;strong>初步檢索 (First-stage Retrieval)&lt;/strong>：從向量資料庫中，廣泛且初步地取得約 20 到 30 筆相關分塊。&lt;/li>
&lt;li>&lt;strong>重新評估 (Re-ranking)&lt;/strong>：使用另一個較為笨重、被稱為 Cross-Encoder 的機器學習模型（例如：&lt;code>bge-reranker&lt;/code> 等），輸入使用者查詢與取得的分塊配對，重新計算語意適合度的分數。&lt;/li>
&lt;li>&lt;strong>篩選&lt;/strong>：僅挑選分數最高的前 3 到 5 筆作為最終的上下文，傳遞給 LLM 的提示詞。&lt;/li>
&lt;/ol>
&lt;p>透過這種方法，可以防止無關的雜訊資訊傳入 LLM，大幅提升回答的精準度（Precision）。&lt;/p>
&lt;div class="mermaid">graph LR
Query["查詢"] --> VSearch["向量檢索 (前 20 筆)"]
VSearch --> Reranker["重排模型 (Cross-Encoder)"]
Query --> Reranker
Reranker --> TopK["高精準度的前 3 筆"]
TopK --> LLM["LLM 生成"]&lt;/div>
&lt;h2 id="53-語意分塊與父文件檢索">5.3 語意分塊與父文件檢索
&lt;/h2>&lt;p>還有一種被稱為「語意分塊 (Semantic Chunking)」的技術，不是根據固定的字元數死板地分割文字，而是由 AI 偵測文章語意的轉折點來進行分割。
此外，「父文件檢索 (Parent Document Retriever)」技術則是為了檢索而將文字切割成非常小的單位（如句子等）以實現高精準度的檢索，但在提供給 LLM 時，則是將包含該句子的「原始大段落（父文件）」交給 LLM，藉此提供充足的上下文背景。&lt;/p>
&lt;hr>
&lt;h1 id="6-運作本機-rag-時的挑戰與對策">6. 運作本機 RAG 時的挑戰與對策
&lt;/h1>&lt;p>在本地環境建構並維運 RAG 時，會面臨一些特有的挑戰。&lt;/p>
&lt;ul>
&lt;li>&lt;strong>VRAM（顯示卡記憶體）耗盡&lt;/strong>：
若要讓本機 LLM 以實用的速度（每秒數十個 Token）運作，必須將模型載入 GPU 的 VRAM 中。要以 fp16（16 位元浮點數）執行 8B 等級的模型大約需要 16GB 的 VRAM。但透過**量化（Quantization）**技術（例如 GGUF 或 AWQ 格式，將其壓縮至 4bit 或 8bit 等），即使是 8GB 的 VRAM（如一般的電競電腦等）也能以足夠快的速度運作。Llama.cpp 或 Ollama 預設都有支援這些量化格式。&lt;/li>
&lt;li>&lt;strong>上下文視窗的限制&lt;/strong>：
如果檢索後取得的上下文數量過多，可能會超過 LLM 的輸入上限（Token 限制），或者模型會忘記資訊中間部分的內容（Lost in the middle 現象）。因此，調整提取的分塊數量，以及導入前述的重新排序（Re-ranking）技術進行嚴格篩選是不可或缺的。&lt;/li>
&lt;li>&lt;strong>資料的新鮮度管理&lt;/strong>：
當來源文件被更新時，必須同步更新或刪除（CRUD 操作）向量資料庫中相對應的向量資料。因為 ChromaDB 支援基於文件 ID 的更新操作，所以管理檔案的雜湊值（Hash），並撰寫批次處理程式來僅同步差異部分是比較實用的做法。&lt;/li>
&lt;/ul>
&lt;hr>
&lt;h1 id="總結">總結
&lt;/h1>&lt;p>RAG（檢索增強生成）是一個強大的典範轉移，它能將 AI 從一般的通用助理進化為「你的專屬專家」或「專精於公司內部業務的達人」。&lt;/p>
&lt;p>我們了解到，即使在無法使用雲端服務、具有高度機密性要求的情況下，透過組合 Ollama、LangChain、ChromaDB 等開源生態系統，也能相對容易地建構出完整的「本機 RAG」環境。&lt;/p>
&lt;p>請務必以上述解說的向量空間數學基礎，以及文字分割、重新排序等進階方法為基礎，嘗試使用您擁有的資料來開發專屬的 AI 系統。本機 AI 的進化速度非常驚人，您今天所建構的系統，只需在明天換上更聰明的輕量級模型，就能在瞬間提升效能。&lt;/p>
&lt;hr>
&lt;p>&lt;em>本部落格未來也會繼續發布關於 AI 技術與 RAG 的深入探討文章。如果您有任何問題或回饋，歡迎在留言區告訴我們。&lt;/em>&lt;/p></description></item></channel></rss>