最新[AI] RAG 實作會踩到的雷與解法
前言這陣子 LLM 應用紅翻天,其中最實用也最常被拿來解決「幻覺」(Hallucination)問題的,大概就是 RAG(Retrieval Augmented Generation,檢索增強生成)了。白話來說,就是讓 LLM 在回答問題前,先去參考一些「課外讀物」,這樣它就比較不會憑空捏造,回答也能更精確。
RAG 聽起來很美好,架構圖看起來也好像很直觀,但實際下去做,你會發現裡面眉角超多,一不小心就踩到雷。我最近在玩 RAG 應用也遇到不少坑,今天就來跟大家分享一下,實作 RAG 會碰到哪些常見問題,以及一些我整理出來的實戰解法。
RAG 的基本流程,我們快速複習一下為了確保大家在同一個頻道上,我們先用一張圖快速回顧一下 RAG 的基本流程。其實就是三大塊:
資料準備(Ingestion):把你的原始文件(PDF、網頁、資料庫內容等等)切成小塊(Chunk),然後轉成向量(Embedding),存到向量資料庫裡。
檢索(Retrieval):使用者提問後,把問題轉成向量,去向量資料庫裡找出最相關的「小塊」(也就是前面切好的 Chunk)。
生成(Generation):把使用者問 ...
[後端] 向量資料庫是什麼?跟一般資料庫差在哪
前言這陣子,如果你有在關注 AI、尤其是大型語言模型(LLM)的應用,肯定會一直聽到一個名詞:「向量資料庫」(Vector Database)。什麼 RAG 要用向量資料庫、推薦系統要用向量資料庫、連圖片搜尋也跟向量資料庫有關……搞得好像它無所不能一樣。
欸,但是它到底是什麼?跟我們平常在用的 MySQL、PostgreSQL、MongoDB 這些傳統資料庫有什麼不同?難道這些老牌資料庫不能用嗎?為什麼突然間大家都跳出來說向量資料庫很屌?
今天,Hikari 我就來用最白話的方式,跟大家聊聊向量資料庫到底在幹嘛,還有它為什麼會在 AI 時代這麼重要。
所以,什麼是「向量」?要搞懂向量資料庫,首先要理解什麼是「向量」(Vector)。在數學上,向量就是一個有方向、有大小的量,通常用一串數字來表示。你高中物理可能學過位移、速度是向量對吧?
但在 AI 的世界裡,它更像是一種「特徵的數位化表示」。
想像一下,你想描述一個人。你可以說他「身高 175 公分、體重 70 公斤、年齡 30 歲」。如果把這些數字排成一串 [175, 70, 30],這就是一個很簡單的「向量」了。這個向量代表了這個人 ...
[後端] 資料庫交易與隔離等級白話講:為什麼你轉帳不能只做一半?
前言工程師們,大家午安!今天想跟大家聊一個看似老生常談,但其實超級重要、而且常常被誤解的概念:資料庫交易(Transaction) 跟 隔離等級(Isolation Level)。
欸,不要看到「交易」兩個字就想說跟錢有關就頭痛,它跟我們每天寫的程式、處理的資料息息相關。想想看,你平常在開發的時候,有沒有遇過這樣的狀況:
客戶回報說,他們的訂單狀態明明已經成功,但庫存卻沒有扣到?
或者使用者抱怨,他剛買完票,但重新整理頁面後,票又可以買了?
更嚴重一點,你轉帳給朋友,結果你的錢扣了,朋友卻沒收到?
這些問題的背後,常常都跟「資料庫交易」沒搞清楚,或者「隔離等級」設定不對有關係。今天,我們就來用最白話的方式,把這些概念拆解開來,讓你知道為什麼不能只做一半,以及怎麼在效能跟資料一致性之間做取捨。
什麼是「交易 (Transaction)」?為什麼你轉帳不能只做一半?想像一下你去銀行轉帳,整個流程通常是這樣:
從你的帳戶扣錢
把錢加到對方的帳戶
這兩個步驟必須「同時成功」或「同時失敗」,不能只完成其中一個。如果你的錢扣了,對方卻沒收到,那麻煩就大了。這個「要嘛全成功、要嘛全失敗」的原 ...
[AI] Prompt 的眉角:讓你的 LLM 不再雞同鴨講
前言自從大型語言模型(LLM)普及之後,大家是不是都開始想辦法把 AI 整合到自己的工作流程裡?從寫程式、除錯、文件整理到發想,LLM 真的超好用。但是,有沒有遇過你給它一個指令,它卻回覆得牛頭不對馬嘴,讓你覺得它根本聽不懂你在說什麼?
這種「雞同鴨講」的狀況,其實大部分時候不是模型不夠聰明,而是我們給的「說明書」不夠清楚。這個說明書,就是我們常說的 Prompt。
Prompt 不只是單純輸入問題,它是一種跟 LLM 溝通的藝術,也是一種工程。寫得好的 Prompt,能讓 LLM 成為你的神隊友;寫得不好,就變成一個只能給你模糊答案的黑箱。今天想跟大家分享一些我在實務上常用、而且很有效的 Prompt 技巧,希望能幫大家跟 LLM 合作得更順暢。
怎麼跟 LLM 溝通最有效?從角色設定開始想像一下,你要跟一個同事請教問題,你會直接丟一句「請解釋區塊鏈」嗎?通常不會對不對?你會先設定情境:「嘿,我是新來的,對區塊鏈有點好奇,可以請你用資深工程師的角度,跟我這個新手解釋一下嗎?」
對 LLM 也是一樣!給 LLM 一個明確的「角色(Role)」,它會更好地理解你的意圖,並以該角色應有的知 ...
[AI] 把 token 當成錢來算,context window 不是越大越好
前言每次看 API 帳單或看到 Token 耗盡的錯誤時,是不是都會有一種「這到底是什麼東西在計費」的懵懵懂懂?
LLM 的 Token 機制和 Context Window,聽起來很高深,但其實就是這兩個東西在決定你的程式會花多少錢、會不會卡。我今天不講大道理,只用最實際的方式拆解它們,還有我在實務上踩過的坑。
Token 到底在算什麼?最常見的迷思是:Token 等於一個英文字母,或等於一個中文字。
其實 Token 是模型底層的「碎塊」。英文大概 4 個字元等於 1 個 Token,中文因為每個字佔用空間較大,通常 1 個中文字會被拆成 1 到 2 個 Token(視語言模型而定)。
舉個例子,Prompt 寫這樣:
1請將以下文章翻譯成英文:今天天氣很好。
這句話大約會消耗 15-20 個 Token(Input token)。你會發現,中文的 Token 消耗速度比英文快很多,這也是為什麼台灣工程師特別需要注意的地方。
Context Window 不是越大越好Context Window 就是模型一次能記住的「工作記憶」容量。你可以想像成你開會時能同時記憶的紙張數量。
早 ...
[學習筆記] 技術筆記要寫給未來的自己看
前言學技術時,很容易一直收藏文章、影片和文件。
但收藏久了會發現,資料越來越多,真正用得到的時候卻常常找不到。
後來我覺得,技術筆記不一定要寫得很完整,但要能讓未來的自己快速想起來:「當時我到底怎麼解的?」
不要只貼連結只貼連結的筆記,短期看起來很快。
例如:
1Docker 教學:https://example.com/docker
但過一段時間後,可能會遇到幾個問題:
忘記這篇連結重點是什麼。
網站失效。
文章內容太長,不知道當初看的是哪一段。
當時的問題情境已經忘了。
所以我會至少補一句自己的摘要。
1這篇主要是在講 Docker volume,解決 container 重建後資料消失的問題。
這樣未來找回來時會快很多。
記錄問題情境技術筆記最有價值的部分,通常不是答案本身,而是問題情境。
例如:
123問題:本機可以連 DB,但部署到測試機後連線失敗。原因:測試機沒有設定正確的 connection string。解法:補上環境變數 Database__ConnectionString。
這種筆記下次遇到類似問題時,非常好用。
因為你不是只記得一個指令,而是記得完整判 ...
[後端] Log 不只是用來看錯誤
前言很多人一開始寫 log,都是在程式壞掉時才想到:
1Console.WriteLine("error");
或是:
1Console.WriteLine(ex.Message);
這當然比完全沒有 log 好,但如果系統真的在線上環境出問題,這種資訊通常還是不夠。
log 的價值不只是「看到錯誤」,更重要的是幫助我們還原當時發生了什麼事。
Log 要能串起流程假設使用者回報:「我按送出之後畫面一直失敗。」
如果 log 只有一行:
1System error
那幾乎沒有辦法判斷問題在哪。
比較有幫助的 log,至少要能讓我們串起流程:
12345Start creating order. userId=123Validate order request completed. userId=123Call payment service. userId=123, orderId=456Payment service timeout. userId=123, orderId=456Create order failed. userId=123, orderId ...
[工程分享] 重構不是看到不順眼就重寫
前言寫程式久了,總會看到一些讓人手癢的程式碼。
變數命名怪怪的、方法太長、邏輯繞來繞去,第一個反應可能是:「我想把它重寫掉。」
但重構不是單純把程式改成自己喜歡的樣子。
重構的目標應該是降低維護成本,而且不能改變原本行為。
重構前先確認目的我覺得重構前要先問:
這段程式現在造成什麼問題?
是讀不懂、難測試、容易出錯,還是擴充困難?
這次重構能解決哪個具體痛點?
有沒有測試可以保護行為不變?
如果答案只是「我覺得不漂亮」,那可能還不到需要重構的程度。
程式碼當然可以追求美感,但在工作專案裡,改動要有足夠理由。
小步調整比大爆改安全重構最怕一次改太多。
例如同時做:
改命名
拆方法
換設計模式
改資料結構
順便修 bug
這樣 review 很難看,出問題也很難定位。
比較安全的方式是小步調整:
1234先補測試再拆出方法再改善命名最後才調整結構
每一步都保持可執行、可驗證。
不要把修 bug 和重構混在一起修 bug 是改變錯誤行為。
重構是不改變行為,只改善內部結構。
如果兩件事混在同一個 commit 或 PR,未來追問題會比較麻煩。
比較好的做法是:
123commit ...
[後端] Cache 可以加速,也可能製造麻煩
前言Cache 是很常聽到的效能優化方式。
簡單來說,就是把常用的結果先存起來,下次需要時不用重新計算或重新查詢。
聽起來很美好,但 Cache 不是免費的。它可以讓系統變快,也可能讓資料變得難以理解。
Cache 解決的是重複成本假設某個 API 每次都要查很多資料、做很多計算,但結果短時間內不太會變。
這時候就可以考慮 Cache。
第一次請求:
1查資料庫 -> 計算 -> 回傳結果 -> 存入 Cache
下一次請求:
1從 Cache 取結果 -> 回傳
如果資料真的不常變,這樣可以省下很多成本。
最大問題是資料何時失效Cache 最麻煩的地方通常不是怎麼存,而是什麼時候要讓它失效。
例如商品資料被修改了,但 Cache 裡還留著舊資料。
使用者看到的就可能是:
12資料庫:新價格頁面:舊價格
這種問題常常比查詢慢更難排查。
所以加入 Cache 前,要先想清楚:
資料可以舊多久?
什麼情況要清掉 Cache?
Cache 清不掉時會造成多大影響?
使用者是否能接受短暫不一致?
TTL 是常見做法TTL 是 Time To Live,也就是 ...
[SQL] Index 是什麼?先用查書目錄的方式理解
前言剛開始接觸資料庫效能問題時,常常會聽到一句話:
「這個查詢很慢,可能要加 index。」
但 index 到底是什麼?為什麼加了它查詢就可能變快?
這篇先不鑽太深的資料結構,而是用比較直覺的方式整理 index 的基本概念。
Index 可以想成書的目錄假設你手上有一本很厚的書,想找「例外處理」這個主題。
如果沒有目錄,你只能從第一頁開始慢慢翻。
但如果有目錄,你可以先查目錄,找到相關章節在哪一頁,再直接翻過去。
資料庫的 index 概念也很像。
沒有 index 時,資料庫可能需要掃描整張表,逐筆檢查資料是否符合條件。
有 index 時,資料庫可以透過索引結構更快找到符合條件的資料。
最常見的使用情境假設有一張 Users 表:
123456CREATE TABLE Users ( Id INT PRIMARY KEY, Email VARCHAR(255), Name VARCHAR(100), CreatedAt DATETIME);
如果系統常常用 Email 查使用者:
123SELECT *FROM UsersWHERE Email = & ...
![[AI] RAG 實作會踩到的雷與解法](/img/covers/rag-pitfalls-and-solutions.jpg)
![[後端] 向量資料庫是什麼?跟一般資料庫差在哪](/img/covers/vector-database-vs-traditional-database.jpg)
![[後端] 資料庫交易與隔離等級白話講:為什麼你轉帳不能只做一半?](/img/covers/database-transaction-isolation-level-explained.jpg)
![[AI] Prompt 的眉角:讓你的 LLM 不再雞同鴨講](/img/covers/llm-prompt-techniques-practical-tips.jpg)
![[AI] 把 token 當成錢來算,context window 不是越大越好](/img/covers/token-cost-context-window.jpg)
![[學習筆記] 技術筆記要寫給未來的自己看](/img/covers/technical-note-habit.jpg)
![[後端] Log 不只是用來看錯誤](/img/covers/logging-basic.jpg)
![[工程分享] 重構不是看到不順眼就重寫](/img/covers/refactor-basic.jpg)
![[後端] Cache 可以加速,也可能製造麻煩](/img/covers/cache-basic.jpg)
![[SQL] Index 是什麼?先用查書目錄的方式理解](/img/covers/sql-index-basic.jpg)