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