我有一個 GPTs,裡面塞了兩千多個 token 的「系統提示」。
它幫我回答所有關於我自己的問題——我的作品、我的技術棧、我在做的專案。每一次有人問我「你現在在做什麼」,它都能給出一個得體的回答。
這個 GPTs 運作得很好。只要我記得定期手動更新那些 token。
我不記得。
——所以我想做一個真正的 RAG 系統。讓文件自己爬、自己更新、自己進向量資料庫。我只要負責問問題就好。
選工具:為什麼是 Apify
要做 RAG,第一步永遠是:資料從哪裡來?
我可以自己寫爬蟲。Python 的 requests + BeautifulSoup,再補上 Playwright 處理 JS 渲染——這些我都會。但我不想維護。
我是獨立開發者。我的時間應該花在產品的核心邏輯上,不是在半夜被 site structure 改版吵醒。
Apify 的 Store 上有五萬多個 Actor,每一個都是打包好的 scraping 工具。最接近我需求的,是官方維護的 apify/website-content-crawler。
它的賣點很直接:
- 輸入一個網址,它就能深層爬取整個網站
- 輸出是乾淨的 Markdown(不是 raw HTML)
- 內建 LangChain 整合
- 超過 14 萬人用過,月活 8K
對於一個不想寫爬蟲的人來說,這幾乎是最優解。
實戰:爬取技術文件
我第一個想餵給 LLM 的,是我的 side project VerifyAI 的網站。
在 Apify Console 建立一個 Actor task,輸入 URL,調整一些參數——maxCrawlPages 設 50,removeLinkFromText 設 true——然後按 Run。
跑了大概兩分鐘。結果是一個 JSON array,每個 entry 包含網站的某個 page,以 Markdown 格式呈現。
輸出長這樣:
`
{
"url": "https://verifyai.app/docs",
"markdown": "# VerifyAI Documentation\n\nVerifyAI is a reverse image search tool...",
"metadata": {
"title": "Docs | VerifyAI",
"description": "..."
}
}
`
直接可以吃。
串進向量資料庫
拿到 Markdown 之後,下一步是 chunking + embedding + 進 vector store。
我用的是最簡單的 stack:
- langchain 做 pipeline 串接
- RecursiveCharacterTextSplitter 做 chunking(chunk size 1000,overlap 200)
- OpenAI text-embedding-3-small 做 embedding
- Chroma 做本地 vector store(先跑通再考慮升級)
程式碼其實不多:
`python
from langchain_community.document_loaders import TextLoader
from langchain.text_splitter import RecursiveCharacterTextSplitter
from langchain_openai import OpenAIEmbeddings
from langchain_community.vectorstores import Chroma
讀取 Apify 輸出的 Markdown
loader = TextLoader("crawl_output.md")
docs = loader.load()
Chunking
splitter = RecursiveCharacterTextSplitter(
chunk_size=1000, chunk_overlap=200
)
chunks = splitter.split_documents(docs)
Embedding → Chroma
embeddings = OpenAIEmbeddings(model="text-embedding-3-small")
vectorstore = Chroma.from_documents(
chunks, embeddings, persist_directory="./chroma_db"
)
`
整段不到 30 行。從 crawler output 到可以查詢的 vector store,大概就是這個量級的工作。
查詢驗證
寫一個簡單的 query loop:
`python
retriever = vectorstore.as_retriever(search_kwargs={"k": 3})
query = "VerifyAI 支援哪些圖片來源?"
results = retriever.invoke(query)
for r in results:
print(f"[{r.metadata.get('source', '?')}] {r.page_content[:200]}")
`
第一次跑的時候,回來的 chunk 確實包含了「支援 Google Images、Bing Images、TinEye」這段文字。資料管線通了。
那一刻的感覺,老實說,比預期平淡。不是因為不興奮——是因為它本來就應該這麼簡單。
排程更新
單純一次性的 import 沒有意義。文件的價值在於它會自動更新。
Apify 的 Actor 可以設定 schedule。我在 Apify Console 開了每週排程,讓 website-content-crawler 每七天重新爬一次 VerifyAI 的網站。
然後寫了一個 CRON job,每週跑一次:
1. 觸發 Apify API 執行爬蟲
2. 下載最新的 Markdown output
3. 重新 chunking + embedding
4. 更新 Chroma 資料庫
整個流程不需要任何人介入。
這套管線目前跑了三週。我已經習慣每天問 GPTs 關於 VerifyAI 的問題,而它永遠回答最新的內容——因為資料每週更新一次。
下一步的計畫是擴展到更多來源:競品的 docs、相關的論壇討論、甚至 GitHub Issues。
但我可以慢慢來。因為爬蟲不是我寫的,維護也不是我的事——Apify 幫我扛了。
如果你想自己做一套類似的 RAG 管線,從 apify/website-content-crawler 開始,大概兩個小時內就能跑通。