:從知識庫問答到智能體工作流)
這次我們來看一套 LangChain RAG AI Agent 的完整實戰(zhàn)路徑知識庫問答、工具調用、狀態(tài)化工作流、接口服務化一條主線串到底?,F(xiàn)在網(wǎng)上講 LangChain 的教程非常多但真正動手時會發(fā)現(xiàn)幾個問題版本更新太快、示例代碼抄下來就跑不通、檢索結果和預期差很遠、一到 Agent 多輪調用就報錯。所以這篇文章不做概念堆砌直接給出一條可運行、可驗證、可擴展的技術主線。文章會覆蓋 RAG 知識庫的完整構建流程、Agent 工具調用實戰(zhàn)、LangGraph 狀態(tài)化工作流、效果評估指標、接口服務化與批量任務設計以及最常見的 8 個排查場景。不管你是想給公司內部資料做知識庫問答還是想把大模型接進現(xiàn)有業(yè)務工具鏈這套流程的通用思路都可以直接復用。1. 核心能力速覽能力項說明技術棧LangChain、LangGraph、Chroma、FastAPI可選 Ollama 本地模型核心功能文檔加載、文本切分、向量化、檢索生成、Agent 工具調用、工作流管理模型接入OpenAI 風格 API / 本地 Ollama 雙通道可切換接口能力FastAPI 暴露 HTTP 接口支持單條問答和批量任務硬件門檻云端 API 模式普通開發(fā)機即可本地模型按參數(shù)量匹配合適內存或顯存學習成本有 Python 基礎一天內可跑通主鏈路適合場景知識庫問答、制度文檔檢索、數(shù)據(jù)分析助手、業(yè)務工具編排注意邊界需按實際情況驗證模型授權、數(shù)據(jù)合規(guī)與內容準確性整體判斷這套技術棧的入門門檻不算高真正容易出問題的是版本兼容、檢索質量和工具調用編排。后面每一節(jié)都會圍繞這幾個痛點展開。2. LangChain、RAG、Agent 與 LangGraph 的關系很多初學者會把 LangChain、RAG、Agent 混為一談其實它們是四個不同層次的東西。2.1 LangChain 是編排框架LangChain 本身不提供大模型也不負責訓練模型。它是一個應用開發(fā)框架幫開發(fā)者把大模型、提示詞、文檔、向量庫、外部工具串聯(lián)起來。你可以把它理解為一條流水線模板定義好之后數(shù)據(jù)從一端進入經過處理從另一端輸出。框架的價值在于規(guī)范化了常用組件模型封裝ChatOpenAI、Ollama 等統(tǒng)一的聊天模型接口提示詞管理ChatPromptTemplate、FewShotPromptTemplate文檔處理各種 DocumentLoader、TextSplitter記憶管理對話歷史、窗口記憶、摘要記憶工具調用Tool、Agent、AgentExecutor組件之間用標準接口連接所以你可以隨時替換某個環(huán)節(jié)。比如今天用 OpenAI明天換成 Ollama 的 Qwen代碼改動很小。2.2 RAG 是解決“模型不知道”的路徑RAG全稱 Retrieval-Augmented Generation檢索增強生成。核心思路是模型回答之前先從知識庫或文檔庫中檢索相關內容再把檢索結果作為上下文送給生成模型。為什么要這么做因為大模型的知識截止時間有限也不掌握你的私有業(yè)務資料。讓它直接回答公司制度問題它只會瞎編。RAG 的做法是先用檢索把答案的“候選材料”找出來模型只需要做閱讀理解幻覺概率會明顯下降。RAG 的典型鏈路文檔加載 - 文本切分 - 向量化 - 向量庫存儲 用戶提問 - 向量檢索 - 拼接上下文 - 模型生成中間有一個關鍵點檢索質量直接決定生成質量。檢索不到正確答案模型怎么生成都是錯的。2.3 Agent 是“讓模型自己決定下一步”Agent 可以理解為一個智能體。它不僅僅是回答問題而是能根據(jù)任務目標編排步驟、調用工具、查看結果再決定下一步動作。例如用戶提問“查詢最近三天的訂單金額并生成匯總報告”這串任務不能靠一次模型調用解決。Agent 需要先調用訂單查詢工具拿到原始數(shù)據(jù)再調用計算工具或報表工具最后整理成報告。LangChain 的 Agent 體系里關鍵組件包括Tool一個可以執(zhí)行具體功能的函數(shù)比如查詢數(shù)據(jù)庫、調用接口Prompt告訴模型有哪些工具、什么情況下用哪個Agent根據(jù)用戶輸入和工具列表規(guī)劃下一步動作AgentExecutor負責循環(huán)執(zhí)行“思考→調用工具→觀察結果→再規(guī)劃”的過程2.4 LangGraph 是狀態(tài)化工作流LangGraph 是 LangChain 團隊推出的低層編排框架用來構建狀態(tài)化的 Agent 應用。它和 LangChain 的關系不是替代而是向下延伸。LangChain 的 AgentExecutor 適合簡單的循環(huán)任務。一旦業(yè)務流程復雜比如需要條件分支、人工審核節(jié)點、多 Agent 協(xié)作就需要更精確的控制。LangGraph 用圖的方式定義工作流節(jié)點就是處理邏輯邊就是流轉條件每個節(jié)點都能讀寫共享狀態(tài)。簡單對比對比項LangChain AgentExecutorLangGraph定位高層封裝開箱即用底層編排靈活可控狀態(tài)管理簡單適合單輪循環(huán)顯式狀態(tài)支持復雜分支使用場景快速驗證、輕量 Agent生產級工作流、多 Agent 協(xié)作學習成本低中等我的建議是先跑通 LangChain 的 AgentExecutor理解工具調用邏輯再遷移到 LangGraph。3. 環(huán)境準備與前置條件第 3 節(jié)開始進入實操。先準備一套干凈的基礎環(huán)境。3.1 Python 與虛擬環(huán)境建議使用 Python 3.10 或 3.11兼容性更穩(wěn)定。正式項目務必使用虛擬環(huán)境避免把依賴裝進系統(tǒng)環(huán)境。python -m venv .venv source .venv/bin/activate # Windows 用戶執(zhí)行 .venv\Scripts\activate安裝核心依賴pip install langchain langchain-openai langchain-community langchain-chroma chromadb pypdf fastapi uvicorn python-dotenv如果后面要測試本地模型再補裝pip install ollama注意LangChain 的包拆分比較細老教程里的from langchain.llms import OpenAI在 0.3 之后已經變更。新版本統(tǒng)一從langchain_openai導入模型類這一點很關鍵。3.2 模型接入云端 API 與本地模型模型接入是第一個分叉口。如果你有 OpenAI 兼容的 API Key直接配置環(huán)境變量即可。在項目根目錄創(chuàng)建.env文件OPENAI_API_KEY你的API_KEY OPENAI_BASE_URLhttps://api.openai.com/v1使用國內可直連的大模型服務時把OPENAI_BASE_URL換成對應的兼容地址即可代碼不用改。如果想在本地跑模型可以先安裝 Ollama然后拉取一個支持工具調用的模型比如 Qwen 系列ollama pull qwen2.5:7b ollama serve本地模型的好處是數(shù)據(jù)不出內網(wǎng)壞處是效果和速度取決于硬件。具體拉取哪個 tag以 Ollama 官方倉庫當前支持的模型列表為準。4. 從 0 構建 RAG 知識庫這一節(jié)用一個真實可運行的示例打通 RAG 全流程。示例默認使用云端 API本地模型接入方式在同一節(jié)末尾說明。4.1 文檔加載先看文檔加載。LangChain 社區(qū)提供了多種加載器常見的有TextLoader加載純文本文件PyPDFLoader加載 PDFCSVLoader加載 CSVDirectoryLoader批量加載目錄下的文檔from langchain_community.document_loaders import TextLoader loader TextLoader(./data/kb.txt, encodingutf-8) docs loader.load() print(docs[0].page_content[:500])加載完成后文檔變成Document對象包含page_content和metadata。如果后續(xù)要做多文檔來源追蹤可以在加載時給metadata添加來源字段。4.2 文本切分文檔加載完成后不能直接整篇向量化。模型對輸入長度有限制而且整篇文檔向量化之后檢索粒度太粗。常見做法是使用RecursiveCharacterTextSplitter。from langchain.text_splitter import RecursiveCharacterTextSplitter splitter RecursiveCharacterTextSplitter( chunk_size512, chunk_overlap64, separators[\n\n, \n, 。, , , , , ] ) chunks splitter.split_documents(docs) print(f切分后文檔塊數(shù)量: {len(chunks)})參數(shù)解釋chunk_size每塊最大字符數(shù)中文場景建議 300 到 800 之間chunk_overlap相鄰塊之間的重疊字符數(shù)用來緩解切分截斷導致的語義斷裂separators優(yōu)先在段落、句號、分號處切分最后才按空格或字符切切分策略是 RAG 調優(yōu)的第一步。塊太大檢索定位不準塊太小上下文信息不完整。后面評估章節(jié)會專門說。4.3 向量化與向量庫入庫文本切分之后調用 Embedding 模型把每塊文本變成向量。這里用 OpenAI 的text-embedding-3-small做演示。from langchain_openai import OpenAIEmbeddings from langchain_chroma import Chroma embeddings OpenAIEmbeddings(modeltext-embedding-3-small) vectorstore Chroma.from_documents( documentschunks, embeddingembeddings, persist_directory./db/chroma )persist_directory指定向量庫的持久化目錄第一次運行后向量數(shù)據(jù)會寫入本地磁盤。下次啟動時不需要重新加載文檔直接加載向量庫即可vectorstore Chroma( persist_directory./db/chroma, embedding_functionembeddings )Chroma 是一個輕量級開源向量數(shù)據(jù)庫適合本地開發(fā)。生產環(huán)境如果需要更高并發(fā)可以遷移到 Elasticsearch、Milvus 或者 Qdrant接口設計理念類似。4.4 檢索與生成向量庫準備好之后把檢索器和生成鏈拼起來。from langchain_core.prompts import ChatPromptTemplate from langchain_openai import ChatOpenAI from langchain_core.output_parsers import StrOutputParser retriever vectorstore.as_retriever(search_kwargs{k: 4}) prompt ChatPromptTemplate.from_messages([ (system, 你是知識庫問答助手。請嚴格基于以下資料回答問題資料中沒有的信息不要編造\n\n{context}), (human, {question}) ]) llm ChatOpenAI(modelgpt-4o-mini, temperature0) def ask(question: str) - str: docs retriever.invoke(question) context \n\n.join([doc.page_content for doc in docs]) chain prompt | llm | StrOutputParser() return chain.invoke({context: context, question: question}) if __name__ __main__: answer ask(這篇知識庫里提到了哪些關鍵概念) print(answer)流程拆開看retriever.invoke(question)返回 TopK 相關文檔所有文檔拼接成一個context提示詞要求模型只基于context回答chain.invoke完成生成這是最基礎的 RAG 鏈路。跑通之后再考慮重排序、混合檢索、記憶等增強能力。如果使用 Ollama 本地模型只需要替換兩處from langchain_ollama import ChatOllama, OllamaEmbeddings embeddings OllamaEmbeddings(modelqwen2.5:7b) llm ChatOllama(modelqwen2.5:7b, temperature0)代碼結構不用改。5. Agent 實戰(zhàn)讓模型學會調用工具RAG 解決的是“知識來源”問題Agent 解決的是“執(zhí)行動作”問題。這一節(jié)用一個帶兩個工具的 Agent 示例說明原理。先定義兩個工具一個查詢當前時間一個做乘法計算。from datetime import datetime from langchain.tools import tool from langchain.agents import create_tool_calling_agent, AgentExecutor from langchain_core.prompts import ChatPromptTemplate from langchain_openai import ChatOpenAI tool def get_current_time() - str: 返回當前日期時間。 return datetime.now().isoformat() tool def multiply(a: int, b: int) - int: 計算兩個整數(shù)的乘積。 return a * b tools [get_current_time, multiply]初始化 Agent 時提示詞里需要包含input和agent_scratchpad兩個變量。agent_scratchpad用來記錄模型已經思考過什么、調用過哪些工具是循環(huán)執(zhí)行的關鍵。prompt ChatPromptTemplate.from_messages([ (system, 你是一個智能助手可以在需要時調用工具解決問題。), (human, {input}), (placeholder, {agent_scratchpad}), ]) llm ChatOpenAI(modelgpt-4o-mini, temperature0) agent create_tool_calling_agent(llm, tools, prompt) executor AgentExecutor(agentagent, toolstools, verboseTrue) if __name__ __main__: result executor.invoke({ input: 現(xiàn)在北京時間是多少順便計算 23 乘以 17。 }) print(result[output])執(zhí)行時打開verboseTrue可以看到完整的思考軌跡模型決定先調用get_current_time工具返回時間結果模型接著調用multiply工具返回 391模型整理最終答案這里的關鍵認知是工具只是普通函數(shù)tool裝飾器負責把函數(shù)包裝成模型可識別的工具描述。工具名、參數(shù)說明、函數(shù) docstring 都會傳給模型作為模型選擇工具的依據(jù)。所以工具說明必須寫清楚否則模型可能不會調用。需要注意工具調用能力是模型側支持的。OpenAI 的 GPT 系列原生支持Ollama 本地模型需要看模型是否支持 Function Calling。跑之前確認模型版本。6. RAG 效果評估與調優(yōu)RAG 鏈路跑通后下一步是評估效果。很多初學者只關注“能不能生成答案”忽略“檢索質量”這個真正的瓶頸。知識庫問答的失敗案例大部分問題出在檢索環(huán)節(jié)。6.1 核心評估指標指標觀察環(huán)節(jié)說明評估方式命中率 Hit Rate檢索正確答案所需的文檔是否出現(xiàn)在 TopK 結果中人工標注或按標準答案片段判斷MRR檢索排序第一個正確答案排得越靠前越好自動化計算上下文相關性檢索生成檢索出的內容是否與問題主題相關LLM 輔助評分忠實度 Faithfulness生成答案是否忠于檢索上下文不編造信息LLM 輔助對比答案與上下文答案相關性生成答案是否直接回答用戶問題而非答非所問LLM 輔助評分工程上最常用的兩個指標是 Hit Rate 和 MRR。它們只考察檢索結果不涉及生成方便快速迭代??梢詫懸粋€簡易命中率評估腳本def hit_rate(questions, golden_docs, retriever): hits 0 for question, gold in zip(questions, golden_docs): docs retriever.invoke(question) context .join([doc.page_content for doc in docs]) if gold in context: hits 1 return hits / len(questions)更完整的評估可以借助 RAGAS 這類開源框架做 LLM 輔助評分也可以自己寫一個“LLM 裁判”腳本。核心是先把問題集和標準答案準備好再跑指標避免憑感覺判斷效果。6.2 重排序與混合檢索基礎向量檢索有兩個常見問題語義相近但關鍵詞不匹配的文本召回不穩(wěn)定TopK 結果里混入無關片段重排序Rerank可以在向量檢索之后用 Cross-Encoder 模型對候選文檔逐條打分把最相關的內容排到前面。# 偽代碼先向量檢索得到候選再用重排序模型精排 candidates retriever.invoke(question, k10) reranked reranker.rerank(question, candidates) final_docs reranked[:4]混合檢索則是“向量檢索 關鍵詞檢索”并行再把結果合并去重。Elasticsearch 同時支持 BM25 和向量檢索生產場景常用它做統(tǒng)一檢索層。如果你們系統(tǒng)已經在用 Elasticsearch接入 RAG 時優(yōu)先考慮它而不是另起一套向量庫。6.3 切分與提示詞調優(yōu)RAG 調優(yōu)的大方向按優(yōu)先級排列切分策略調整chunk_size、chunk_overlap實測 300 到 800 之間最常用檢索召回數(shù)k太小可能漏答案太大可能引入噪聲常見取值 4 到 10重排序候選集擴到 10 到 20精排后取前 4 到 5提示詞明確要求“只基于資料回答”“資料不足時直接說明”查詢改寫用戶問題太口語化時先讓模型改寫為檢索表達調優(yōu)時一次只改一個變量跑完評估指標再改下一個。7. 接口服務化與批量任務設計純腳本演示只能驗證邏輯真正接入業(yè)務需要把 RAG 和 Agent 封裝成接口服務。7.1 FastAPI 包裝 RAG用 FastAPI 包裝一個/rag/query接口from fastapi import FastAPI from pydantic import BaseModel app FastAPI() class QueryBody(BaseModel): question: str k: int 4 temperature: float 0.0 app.post(/rag/query) def rag_query(body: QueryBody): docs retriever.invoke(body.question) context \n\n.join([doc.page_content for doc in docs]) chain prompt | llm | StrOutputParser() answer chain.invoke({context: context, question: body.question}) return { answer: answer, source_count: len(docs), sources: [doc.metadata.get(source, ) for doc in docs] }啟動服務uvicorn main:app --host 127.0.0.1 --port 8000用 curl 驗證curl -X POST http://127.0.0.1:8000/rag/query \ -H Content-Type: application/json \ -d {question: 什么是RAG, k: 4}返回結果里帶上sources方便調用方核對答案來源。這個信息在調試階段非常有用。7.2 批量任務設計接口服務適合在線問答。如果業(yè)務有批量需求比如一次性處理上百個問題不應該在上百個請求里直接并發(fā)調用接口更穩(wěn)妥的做法是任務隊列模式。簡單實現(xiàn)可以用concurrent.futures控制并發(fā)import time from concurrent.futures import ThreadPoolExecutor, as_completed questions [問題1, 問題2, 問題3] def process(question): return ask(question) with ThreadPoolExecutor(max_workers4) as pool: futures {pool.submit(process, q): q for q in questions} for future in as_completed(futures): question futures[future] try: answer future.result() print(f{question}: {answer}) except Exception as e: print(f{question}: FAILED - {e})生產環(huán)境建議使用 Celery 或消息隊列做異步任務任務狀態(tài)、失敗重試、結果落庫都更完善。無論哪種方案都要注意記錄每個任務的狀態(tài)和日志失敗任務要有重試機制建議設置重試上限控制并發(fā)數(shù)避免打爆模型服務或向量庫接口服務要加訪問限制避免內部接口被外部調用7.3 并發(fā)與重試策略大模型接口的延遲通常以秒計在線接口超時設置建議 60 秒以上。批量任務重試時要注意冪等性同一個問題重復處理不應該產生兩份不一致的結果。簡單做法是任務表里記錄處理狀態(tài)處理成功后標記完成。8. 資源占用與性能觀察如果你的開發(fā)機性能一般需要關心整個 RAG 鏈路的資源占用。8.1 各環(huán)節(jié)資源消耗特征環(huán)節(jié)資源消耗類型說明文檔加載與切分CPU、內存一次性操作PDF 解析較慢向量化嵌入CPU/GPU、內存批量文本越多耗時越長向量庫檢索內存、磁盤文本塊數(shù)量越大索引占用越高LLM 生成內存/顯存或云端 API本地模型時資源占用最明顯重排序CPU/GPU推理耗時比向量檢索高通常只對候選集執(zhí)行本地嵌入模型的參數(shù)量通常在幾百 MB 到幾 GB 之間CPU 可以推理只是大批量嵌入時速度慢。本地 7B 量級模型通過 Ollama 運行通常需要 4GB 以上內存或顯存具體取決于模型量化精度。實際占用需以本機測試為準。8.2 顯存與內存觀察方法Linux 下觀察顯存使用nvidia-smi觀察內存使用free -hAPI 模式下本地資源壓力主要來自向量庫和文檔預處理模型推理在云端。如果感覺響應變慢優(yōu)先檢查向量庫磁盤 IO 和 API 調用頻率。8.3 降低資源占用的通用手段文本塊數(shù)量較大時先做嵌入緩存重復文本不重復向量化向量庫索引大小影響檢索耗時按業(yè)務范圍拆分多個集合本地模型中優(yōu)先選擇 4bit 量化版本減少內存占用批量任務控制并發(fā)數(shù)避免內存暴漲定時清理日志和臨時文件還有一個常見問題服務啟動后端口被占用。啟動前先檢查端口lsof -i :8000如果有進程殘留殺掉舊進程再啟動新服務。9. 常見問題與排查方法實戰(zhàn)中報錯不可怕關鍵要知道往哪個方向查。把最常見的問題整理成一張表問題現(xiàn)象可能原因排查方式解決方案pip 安裝依賴失敗Python 版本過低或依賴沖突查看報錯日志確認 Python 版本使用 Python 3.10/3.11創(chuàng)建新虛擬環(huán)境找不到langchain.llms模塊使用了舊版導入路徑檢查 LangChain 版本改用langchain_openai等新包模型返回空內容或報錯API Key 未配置或 Base URL 不對檢查.env文件和日志確認環(huán)境變量已加載Chroma 向量庫打開失敗持久化目錄損壞或版本不一致查看啟動日志備份后刪除./db/chroma重建檢索結果不相關切分策略不合理或 embedding 不適配打印檢索到的文檔內容調整 chunk_size、k 值加重排序Agent 不調用工具工具描述不清晰或模型不支持工具調用打開 verbose 查看規(guī)劃過程改寫工具 docstring換支持工具調用的模型接口超時模型推理耗時較長或并發(fā)過高查看 API 日志和耗時記錄加長超時時間降低并發(fā)數(shù)批量任務卡住某個任務出現(xiàn)異常未捕獲檢查任務日志和異常處理單任務 try/except設置重試上限實際排查時先看報錯信息再縮小到具體環(huán)節(jié)。RAG 鏈路按“文檔加載→切分→向量化→檢索→生成”分段打日志很快能定位問題。有一個非常有用的調試技巧在檢索之后打印檢索到的文檔內容。如果文檔內容本身就不對那問題一定在檢索前面的環(huán)節(jié)而不是生成模型的問題。10. 最佳實踐與學習路徑建議最后聊幾條工程落地建議都是容易被忽視但很影響結果的事情。10.1 先小參數(shù)跑通再擴大規(guī)模第一次搭建時不要準備幾百 MB 的文檔先拿 3 到 5 篇文章跑通全鏈路。確認檢索和生成都正常后再逐步擴充知識庫。這樣可以快速區(qū)分“代碼問題”和“數(shù)據(jù)問題”。10.2 建立一套最小可運行配置把環(huán)境依賴、.env模板、啟動命令記錄成文檔或者在項目里保留一個README.md和requirements.txt。團隊協(xié)作時新成員十幾分鐘就能把環(huán)境跑起來而不是反復踩安裝坑。10.3 評估優(yōu)先于調參沒有評估指標的 RAG 調優(yōu)都是憑感覺。先準備一份至少覆蓋常見問題的測試集再用命中率和忠實度指標做基線每次改動跑一遍結果對比。比直接調整參數(shù)更有效。10.4 合規(guī)與邊界意識如果知識庫涉及公司內部資料或用戶隱私需要特別注意確認文檔來源合法不放入未授權的版權內容系統(tǒng)內部接口要限制訪問范圍避免數(shù)據(jù)泄露涉及人臉、聲音等敏感數(shù)據(jù)時必須確保有明確授權重要場景生成結果要人工復核不能直接對外發(fā)布10.5 下一步學習方向跑通基礎鏈路后可以按這幾個方向繼續(xù)深入把 Agent 接進業(yè)務系統(tǒng)接入數(shù)據(jù)庫查詢、日志分析、工單處理等真實工具學習 LangGraph把多步驟流程做成帶狀態(tài)管理的工作流研究多路召回策略結合關鍵詞檢索、向量檢索和知識圖譜針對垂直領域數(shù)據(jù)做切分策略和提示詞優(yōu)化用 Elasticsearch 等企業(yè)級檢索組件替換單機向量庫支撐更高并發(fā)這套 LangChain、RAG、AI Agent 的組合在任何大模型應用項目里基本都是基礎設施。把這一條主線跑通后面再學多 Agent 協(xié)作、記憶管理、工具調用增強都有清晰的地圖可以參照。建議先照著文中的示例代碼把 RAG 鏈路跑通再嘗試加上一個簡單工具Ag ent 和 LangGraph 的部分很快就能上手。