
如果您曾經嘗試將 Jupyter Notebook 中的 LLM 原型部署到實際環境中,那麼您一定知道這並非點選“執行”按鈕那麼簡單。我還記得第一次嘗試部署 LLM 端點時的情景:簡直一團糟。模型在本地執行良好,但一旦使用者開始傳送大量請求……一切都崩潰了。
那時我才意識到,我缺少的不是機器學習知識,而是 LLMOps。
本指南旨在幫助您從零基礎成為 LLMOps 高手,完整講解如何使用 LangChain、FastAPI 和 Docker 在生產環境中執行 LLM,並提供 AWS 部署的概念概述。
我們將構建一個小型但實用的 RAG 聊天機器人,作為理解 LLMOps 生命週期的完美切入點。
LLMOps究竟是什麼?
簡而言之,LLMOps 是 MLOps 的擴充套件,用於大型語言模型。
它涵蓋了模型訓練或選擇之後的所有環節,包括推理最佳化、監控、提示編排、資料管道、部署、擴充套件和治理。
您可以將其視為模型與現實世界之間的橋樑,確保可靠性、可擴充套件性、可觀測性和合規性。
以下是我們將要介紹的 LLMOps 流水線概覽:
- 資料攝取與向量化
- 理解資料集
- 構建向量儲存
- 構建並執行 RAG 聊天機器人
- 使用 LangChain 進行提示編排
- 透過 FastAPI 提供服務
- 使用 Streamlit 構建聊天 UI
- 透過 Ngrok 實現公共訪問
- 使用 Docker 進行容器化
- AWS 部署概念
- 監控、版本控制、評估和治理
基本設定
在開始實現之前,讓我們先進行基本設定,安裝必要的庫。本專案使用 Google Colab 作為程式設計環境。請複製以下程式碼以設定庫:
!mkdir llmops-demo !cd llmops-demo !python3 -m venv venv !source venv/bin/activate !pip install langchain openai faiss-cpu fastapi uvicorn python-dotenv langchain-community !pip install nest_asyncio pyngrok streamlit
本專案還將使用 OpenAI 和 NGROK。您可以從以下連結獲取它們的 API 訪問令牌/金鑰:
- OpenAI: https://platform.openai.com/api-keys
- NGROK: https://dashboard.ngrok.com/get-started/your-authtoken
請注意,本部落格使用免費版本的 API/身份驗證令牌即可。請在 Colab 中編寫以下程式碼來設定這些令牌:
import os
from getpass import getpass
os.environ['OPENAI_API_KEY'] = getpass("Enter OPENAI KEY:")
os.environ['NGROK_AUTHTOKEN'] = getpass("ENTER NGROK TOKEN:")
資料攝取和向量化
瞭解資料集
在構建任何模型之前,讓我們先從資料入手,因為資料才是 RAG 系統的核心。我使用了一個名為 Sample RAG Knowledge Item Dataset 的小型 Kaggle 資料集。它簡潔明瞭,非常適合學習。每一行都像一條迷你版的“IT 服務檯”筆記,是特定主題下的簡短知識點。
你會看到兩列:
- ki_text → 實際內容(例如“VPN 連線故障排除步驟”)
- ki_topic → 主題標籤,例如“網路”、“硬體”或“安全”
這個資料集特意設計得比較小,我很喜歡這一點,因為它可以讓你快速測試不同的 RAG 概念,例如分塊大小、嵌入模型和檢索策略,而無需等待數小時的索引。它提取自一個更大的 IT 知識庫資料集(約 100 篇文章),但這個精簡版非常適合實驗,因為它速度快、重點突出,而且非常適合演示。
現在我們瞭解了資料的結構,接下來讓我們開始教模型如何“記住”它:將文字轉換為嵌入向量,並將其儲存在向量資料庫中。
構建向量儲存
資料集準備就緒後,下一個目標是讓模型理解它,而不僅僅是讀取它。為此,我們需要將文字轉換為嵌入向量,即表示含義的數值向量。
以下是實現此操作的程式碼:
import os
import pandas as pd
from langchain.text_splitter import RecursiveCharacterTextSplitter
from langchain.embeddings import OpenAIEmbeddings
from langchain.vectorstores import FAISS
from langchain.docstore.document import Document
# Load dataset
df = pd.read_csv("/content/rag_sample_qas_from_kis.csv")
# Use ki_text as main text and ki_topic as metadata
docs = [
Document(page_content=row["ki_text"], metadata={"topic": row["ki_topic"]})
for _, row in df.iterrows()
]
# Split into chunks for embedding
splitter = RecursiveCharacterTextSplitter(chunk_size=800, chunk_overlap=100)
chunks = splitter.split_documents(docs)
# Embed and store in FAISS
embeddings = OpenAIEmbeddings(openai_api_key=os.getenv("OPENAI_API_KEY"))
db = FAISS.from_documents(chunks, embeddings)
db.save_local("vectorstore")
print("Vectorstore created successfully using ki_text as content!")
哇,程式碼好多啊,我們來看看這裡面到底發生了什麼!
設定好資料集之後,下一步是幫助模型“理解”它,方法是將文字轉換為詞嵌入。我們首先載入 CSV 檔案,並將每條記錄封裝成 LangChain Document 物件,將“ki_text”儲存為內容,“ki_topic”儲存為後設資料。這些後設資料之後可以幫助進行過濾或特定主題的檢索。
接下來,我們將每個文件分割成更小的重疊塊(800 個字元,100 個字元重疊),這樣分割過程中就不會丟失任何資訊。然後,我們使用 OpenAIEmbeddings 將每個塊轉換為向量:語義含義的密集數值表示。
最後,所有詞嵌入都儲存在 FAISS 向量儲存中,這是一個高效的相似性搜尋索引,可以在查詢期間快速檢索最相關的塊。
完成此步驟後,向量儲存/資料夾將作為模型的本地“記憶體”,準備在下一階段進行查詢。
構建和執行RAG聊天機器人
以下是部署後的最終聊天機器人:
現在,讓我們介紹實現此功能所需的所有庫/工具,並瞭解它們如何協同工作。
使用LangChain進行提示編排
在這裡,我們使用 LangChain 的 RetrievalQA 鏈將向量儲存、檢索器和 LLM 連線起來。
之前建立的 FAISS 向量儲存將被重新載入到記憶體中,並連線到 OpenAI 嵌入。然後,檢索器充當智慧查詢引擎,僅從資料集中獲取最相關的資料塊。
現在,每個查詢都將流經此管道:檢索 → 增強 → 生成。
透過FastAPI提供服務
為了模擬生產環境,我們新增了一個輕量級的 FastAPI 後端。雖然在 Colab 中此步驟是可選的,但它模擬了您的 RAG 模型在真實環境中的暴露方式,並提供可用於外部整合或 API 請求的端點。
目前,“/”路由僅返回健康訊息,但此結構可以輕鬆擴充套件,以處理來自您的 UI、Slack 機器人或 Web 客戶端的查詢。
使用Streamlit構建聊天UI
在後端之上,我們使用 Streamlit 構建了一個互動式聊天介面。這提供了一個簡潔的、基於瀏覽器的體驗,用於與您的 RAG 管道進行互動。使用者可以輸入問題,點選“傳送”,然後看到由 LangChain 的檢索和推理鏈支援的、具有上下文感知和文件感知的回覆。
每次交流都儲存在 st.session_state 中,從而在您和模型之間建立持久的對話流。
透過Ngrok進行公開訪問
由於 Colab 不支援直接 Web 託管,我們使用 ngrok 安全地公開 Streamlit 應用。Ngrok 會將您的本地埠隧道連線到一個臨時的公共 URL,允許任何人(或僅限您)在真實的瀏覽器標籤頁中訪問聊天機器人 UI。
一旦 ngrok 生成公共連結,聊天機器人即可立即訪問。
整合所有元件
- LangChain 負責編排嵌入、檢索和生成
- FastAPI 提供可選的後端層
- Streamlit 作為互動式 UI
- Ngrok 將 Colab 與外部世界連線起來
這樣,您就可以在筆記型電腦上即時執行一個功能齊全、端到端的 RAG 聊天機器人。
以下是結合了上述所有工具的 RAG 聊天機器人的完整程式碼:
from langchain.chains import RetrievalQA
from langchain.vectorstores import FAISS
from langchain.embeddings import OpenAIEmbeddings
from langchain.llms import OpenAI
from pyngrok import ngrok
import nest_asyncio
import threading
import streamlit as st
import uvicorn
from fastapi import FastAPI
# --- Create FastAPI backend (optional) ---
app = FastAPI(title="RAG Chatbot – Backend")
embeddings = OpenAIEmbeddings(openai_api_key=os.getenv("OPENAI_API_KEY"))
db = FAISS.load_local("vectorstore", embeddings, allow_dangerous_deserialization=True)
retriever = db.as_retriever()
qa_chain = RetrievalQA.from_chain_type(
llm=OpenAI(openai_api_key=os.getenv("OPENAI_API_KEY"), temperature=0),
chain_type="stuff",
retriever=retriever,
)
@app.get("/")
def home():
return {"message": "Backend ready"}
# --- Streamlit Chat UI ---
def run_streamlit():
st.set_page_config(page_title="💬 RAG Chatbot", layout="centered")
st.title("💬 Chat with your RAG-Powered LLM")
if "history" not in st.session_state:
st.session_state.history = []
query = st.text_input("Ask me something:")
if st.button("Send") and query:
with st.spinner("Thinking..."):
answer = qa_chain.run(query)
st.session_state.history.append((query, answer))
for q, a in reversed(st.session_state.history):
st.markdown(f"**You:** {q}")
st.markdown(f"**Bot:** {a}")
st.markdown("---")
# --- Launch ngrok and Streamlit ---
ngrok.kill()
public_url = ngrok.connect(8501)
print(f"Chat UI available at: {public_url}")
# Run Streamlit app in background
nest_asyncio.apply()
def start_streamlit():
!streamlit run app.py &>/dev/null&
# Save UI to file
with open("app.py", "w") as f:
f.write('''
import streamlit as st
from langchain.chains import RetrievalQA
from langchain.vectorstores import FAISS
from langchain.embeddings import OpenAIEmbeddings
from langchain.llms import OpenAI
import os
os.environ["OPENAI_API_KEY"] = "''' + os.environ["OPENAI_API_KEY"] + '''"
st.set_page_config(page_title="💬 RAG Chatbot", layout="centered")
st.title("💬 Chat with your RAG-Powered LLM")
embeddings = OpenAIEmbeddings(openai_api_key=os.getenv("OPENAI_API_KEY"))
db = FAISS.load_local("vectorstore", embeddings, allow_dangerous_deserialization=True)
retriever = db.as_retriever()
qa_chain = RetrievalQA.from_chain_type(
llm=OpenAI(openai_api_key=os.getenv("OPENAI_API_KEY"), temperature=0),
chain_type="stuff",
retriever=retriever,
)
if "history" not in st.session_state:
st.session_state.history = []
query = st.text_input("Ask me something:")
if st.button("Send") and query:
with st.spinner("Thinking..."):
answer = qa_chain.run(query)
st.session_state.history.append((query, answer))
for q, a in reversed(st.session_state.history):
st.markdown(f"**You:** {q}")
st.markdown(f"**Bot:** {a}")
st.markdown("---")
''')
# Start Streamlit
get_ipython().system_raw('streamlit run app.py --server.port 8501 &')
print("Chatbot is running. Open the ngrok URL above")
執行上述程式碼後,您將看到如下輸出:
聊天介面位於:NgrokTunnel: “https://22f6c6d1ef68.ngrok-free.app” -> “http://localhost:8501” 。聊天機器人正在執行。開啟上面的 ngrok URL。
這是您的聊天機器人部署的 URL:https://22f6c6d1ef68.ngrok-free.app/
此連結可從世界任何地方透過網際網路訪問。您可以與朋友分享,或親自使用它來測試您的機器人。是不是很棒?
透過使用 Streamlit、FastAPI、NGrok 和 LangChain 等工具,我們僅用幾行程式碼就成功部署了一個基於 RAG 的端到端聊天機器人。想象一下它為您帶來的無限可能;您的成就將無可限量。
使用Docker進行容器化
至此,我們已經擁有一個功能齊全的 RAG 聊天機器人:後端、使用者介面等等。但如果您曾經嘗試過跨環境部署該配置,您就會明白其中的痛苦:缺少依賴項、版本不匹配、路徑損壞等等,都是常見的混亂情況。
而 Docker 正是解決這一問題的利器。Docker 提供了一種簡潔、可移植的方式,將整個環境以及所有工具(例如 FastAPI、Streamlit、LangChain、FAISS,甚至您的向量儲存)打包成一個統一的單元,可以在任何地方執行。
如果您想部署與上述完全相同的 RAG 聊天機器人,但希望透過 Docker 來實現,那麼以下是更新後的程式碼:
import os
import subprocess
from pyngrok import ngrok
# --- Create Streamlit UI ---
streamlit_code = """
import streamlit as st
import requests
st.set_page_config(page_title="RAG Chatbot", page_icon="", layout="centered")
st.title("RAG Chatbot – LLMOps Demo")
st.write("Ask questions from your knowledge base. Backend powered by FastAPI, deployed in Docker.")
query = st.text_input("💬 Your question:")
if query:
with st.spinner("Thinking..."):
try:
response = requests.get(f"http://localhost:8000/ask", params={"query": query})
if response.status_code == 200:
st.success(response.json()["answer"])
else:
st.error("Something went wrong with the backend.")
except Exception as e:
st.error(f"Error: {e}")
"""
with open("streamlit_app.py", "w") as f:
f.write(streamlit_code.strip())
# --- Create requirements.txt ---
with open("requirements.txt", "w") as f:
f.write("fastapi\nuvicorn\nstreamlit\nlangchain\nopenai\nfaiss-cpu\npyngrok\nrequests\n")
# --- Create Dockerfile ---
dockerfile = f"""
FROM python:3.10-slim
WORKDIR /app
COPY . .
RUN pip install --no-cache-dir -r requirements.txt
EXPOSE 8000 8501
ENV OPENAI_API_KEY=${{OPENAI_API_KEY}}
CMD bash -c "uvicorn from_zero_to_llmops_hero_your_101_guide_to_running_llms_in_production:app --host 0.0.0.0 --port 8000 & streamlit run streamlit_app.py --server.port 8501 --server.address 0.0.0.0"
"""
with open("Dockerfile", "w") as f:
f.write(dockerfile.strip())
# --- Install Docker if needed ---
try:
subprocess.run(["docker", "--version"], check=True)
except Exception:
print("Installing Docker...")
subprocess.run(["apt-get", "update", "-qq"], check=True)
subprocess.run(["apt-get", "install", "-qq", "-y", "docker.io"], check=True)
# --- Check if Docker daemon available ---
try:
subprocess.run(["docker", "build", "--version"], check=True)
docker_available = True
except Exception:
docker_available = False
if docker_available:
print("Building Docker image...")
subprocess.run(["docker", "build", "-t", "rag-chatbot-ui", "."], check=True)
print("Running container (FastAPI + Streamlit)...")
subprocess.run(["docker", "run", "-d", "-p", "8000:8000", "-p", "8501:8501",
"-e", f"OPENAI_API_KEY={os.getenv('OPENAI_API_KEY')}",
"rag-chatbot-ui"], check=True)
else:
print("Docker not supported in Colab — running natively instead.")
print("Starting FastAPI + Streamlit locally...")
# Run both apps directly
import threading
def run_fastapi():
os.system("uvicorn from_zero_to_llmops_hero_your_101_guide_to_running_llms_in_production:app --host 0.0.0.0 --port 8000")
def run_streamlit():
os.system("streamlit run streamlit_app.py --server.port 8501 --server.address 0.0.0.0")
threading.Thread(target=run_fastapi).start()
threading.Thread(target=run_streamlit).start()
# --- Expose via ngrok ---
ngrok.kill()
public_url = ngrok.connect(8501)
print(f"Your RAG Chatbot UI is live at: {public_url}")
print("API (FastAPI docs) at: <ngrok_url_for_8000>/docs")
程式碼的實際變化
仔細檢視新的程式碼塊,你會發現以下幾個主要變化:
1. 建立Dockerfile
這就像應用程式的配方。我們從一個輕量級的 python:3.10-slim 映象開始,複製所有專案檔案,根據 requirements.txt 安裝依賴項,並暴露兩個埠:
- 8000 用於 FastAPI 後端,
- 8501 用於 Streamlit UI。
最後,使用一條命令即可在同一個容器中啟動這兩個伺服器:
CMD bash -c "uvicorn ... & streamlit run ..."
只需一行程式碼,Docker 就能同時執行 FastAPI 和 Streamlit,一個提供 API 服務,另一個提供介面服務。
2. 自動化需求處理
在構建 Docker 映象之前,我們會以程式設計方式生成一個乾淨的 requirements.txt 檔案,其中包含我們使用的所有庫:fastapi、uvicorn、streamlit、langchain、openai、faiss-cpu、pyngrok 和 requests。
這確保了 Docker 映象始終安裝筆記本中使用的確切軟體包,無需手動複製貼上。
3. 構建和執行容器
Docker 準備就緒後,我們執行以下命令:
subprocess.run(["docker", "build", "-t", "rag-chatbot-ui", "."]) subprocess.run(["docker", "run", "-d", "-p", "8000:8000", "-p", "8501:8501", ...])
這會構建一個名為 rag-chatbot-ui 的映象,並啟動一個執行後端和前端的容器。如果您在本地計算機上,這將立即為您提供兩個可用的端點:
- http://localhost:8000/docs → FastAPI
- http://localhost:8501 → Streamlit UI
4. Colab的備用方案
由於 Google Colab 不直接支援 Docker 守護程序,我們採取了優雅的處理方式。如果 Docker 不可用,指令碼會自動在兩個後臺執行緒中啟動 FastAPI 和 Streamlit,從而確保使用者體驗與本地環境一致。
為什麼這很重要?
從 notebook 程式碼到容器化設定的這種小小的轉變,是真正意義上從“玩轉 LLM”到“像運營產品一樣運營 LLM”的轉折點。
現在您擁有:
- 可復現性 → 隨時隨地執行相同的環境
- 可移植性 → 可部署在 AWS、GCP 甚至您的筆記型電腦上
- 可擴充套件性 → 稍後可在負載均衡器後部署多個容器
沒錯,它就是同一個應用程式,只是被巧妙地封裝在了 Docker 容器中。
AWS部署概念
在 AWS 上部署 LLM 系統可以實現生產級的可擴充套件性,但這本身就是一個值得深入探討的話題。從在 EC2 或 ECS 上託管 FastAPI 應用程式,到在 S3 上儲存向量資料庫,再到使用 AWS Lambda 進行事件驅動觸發,各種可能性層出不窮。您甚至可以整合 CloudFront + API Gateway,以實現安全、全球分散式的推理端點。
目前,您只需知道 AWS 為您提供了從本地 Docker 容器遷移到完全託管、自動擴充套件設定所需的所有構建模組。我們有機會將會探討整個工作流程,包括基礎設施即程式碼、CI/CD 流水線和部署指令碼。
監控、版本控制、評估和治理
系統部署完成後,真正的工作才剛剛開始:監控和維護。跟蹤延遲、檢索準確率、故障率和版本漂移對於確保聊天機器人的可靠性和可解釋性至關重要。再加上版本控制、評估和治理,就構成了生產級 LLMOps 的基礎。
這些領域值得單獨探討。在下一篇文章中,我們將深入研究日誌記錄、評估儀表板和模型治理,所有這些都直接整合到您的 RAG 流水線中。
小結
我們從零開始,搭建了一個簡單的聊天機器人使用者介面,並逐步構建了一個完整的 LLMOps 工作流程:
- 資料攝取、建立向量儲存、嵌入、提示編排、透過 FastAPI 提供服務、使用 Docker 容器化,以及準備在 AWS 上部署。
- 每一層都增加了結構、可擴充套件性和可靠性,最終將實驗轉化為可部署、可維護的產品。
- 但這僅僅是開始。真正的 LLMOps 始於部署之後,那時您需要監控行為、最佳化檢索、對嵌入進行版本控制,並確保模型的安全性和合規性。
在本系列的下一部分中,我們將超越設定,深入探討 AWS 部署、可觀測性、版本控制和治理——這些才是真正讓您的 LLM 達到生產就緒狀態的關鍵所在。
請在下方留言分享您的想法/問題!

評論留言