跳转至

02. LangChain 入门与 RAG 实战

一句话说明:LangChain 是一个 Python 框架,帮你把大语言模型(LLM)和你自己的数据连起来——最核心的用法就是 RAG(先搜后答),让 AI 回答问题时能查你的文档,而不是瞎编。


目录

  1. 为什么要学
  2. 核心概念详解
  3. 环境安装与配置
  4. 实操教程
  5. 用 RAG 搭建个人知识库问答
  6. 常见报错与解决方案
  7. LangChain vs LlamaIndex vs 直接调 API 对比
  8. 速查表
  9. 延伸学习资源

1. 为什么要学

RAG 解决了什么问题

大语言模型有两个致命缺陷:

缺陷白话举例
知识截止模型训练完就不更新了,不知道最新的事问它2026年最新的 MetaPhlAn 版本,它可能答错
幻觉不知道的东西它会瞎编,而且编得很像真的问它你论文里的数据,它会编一个看起来像真的结果

RAG(Retrieval-Augmented Generation,检索增强生成) 的思路很简单:先从你的文档里搜到相关内容,再把搜到的内容喂给 AI,让 AI 基于真实资料回答。

白话比方:你问一个学生问题,与其让他凭记忆瞎答,不如先让他翻书找到相关段落,再基于书上的内容回答——这就是 RAG。

LangChain 在 AI 生态中的地位

  • GitHub 135,000+ stars(截至2026年5月),Python AI 框架中 star 数最多
  • 官方定位:The Agent Engineering Platform(代理工程平台)
  • 生态完善:对接了几百种 LLM、向量数据库、文档加载器
  • 面试加分:许多生信+AI 岗会问"你有没有用 LangChain 搭过 RAG"

2. 核心概念详解

2.1 LangChain 是什么(白话比方)

白话:LangChain 就像一个"AI 应用搭建的乐高积木盒"。它不是一个 AI 模型,而是一套工具,帮你把各种组件(模型、数据库、文档、搜索引擎)像搭积木一样拼成一个完整的 AI 应用。

不用 LangChain 的话:你需要自己写代码调 API、自己处理文档切分、自己管理向量数据库……全部手动拼接。

用了 LangChain:每个步骤都有现成的模块,几行代码就能搭起来。

2.2 Chain(链)是什么

白话:Chain 就是"流水线"——把多个步骤串起来,前一步的输出自动传给下一步。

用户提问 → 组装 Prompt → 调用 LLM → 解析输出 → 返回结果

就像工厂的流水线:原料进去 → 加工 → 包装 → 出货,每一站做一件事,最后得到成品。

2.3 Agent(代理)是什么

白话:Agent 是一个"会自己决定下一步该做什么的 AI"。

Chain 是固定流水线(步骤提前定好),Agent 是灵活的——它会根据情况自己判断: - 需要搜索吗?→ 调用搜索工具 - 需要算数吗?→ 调用计算器 - 需要查数据库吗?→ 调用 SQL 工具

类似于:Chain 是按食谱做菜(步骤固定),Agent 是大厨随机应变(根据食材临场发挥)。

2.4 RAG 完整流程详解(重点)

RAG 一共 6 步,像一条加工流水线:

┌─────────┐    ┌─────────┐    ┌─────────┐    ┌─────────┐    ┌─────────┐    ┌─────────┐
│ ① 加载   │ →  │ ② 切分   │ →  │ ③ 向量化  │ →  │ ④ 存储   │ →  │ ⑤ 检索   │ →  │ ⑥ 生成   │
│ 文档     │    │ 文本     │    │ Embedding│    │ 向量库   │    │ 相似搜索  │    │ LLM回答  │
└─────────┘    └─────────┘    └─────────┘    └─────────┘    └─────────┘    └─────────┘
   离线准备阶段(只做一次)                                      在线问答阶段(每次提问都走)

每一步白话解释:

步骤做了什么白话比方
① 文档加载读取你的文件(PDF/Markdown/TXT/网页)把书从书架上拿下来
② 文本切分把长文档切成小段(chunk),一般 500-1000 字一段把整本书拆成一张张知识卡片
③ 向量化用 Embedding 模型把每段文字变成一组数字(向量)给每张卡片编一个"含义坐标"
④ 存储把所有向量存到向量数据库里把编好号的卡片整齐放进索引柜
⑤ 检索用户提问时,也把问题变成向量,去向量库里找最相似的几段用户问问题,从柜子里找出最相关的几张卡片
⑥ 生成把找到的段落 + 用户问题一起喂给 LLM,让它基于内容回答把卡片交给 AI,说"根据这些资料回答"

2.5 Embedding 是什么

白话:把文字变成数字坐标,让计算机能算"两段文字有多像"。

举例: - "糖尿病肠道菌群" → [0.23, -0.15, 0.87, ...](一组几百维的数字) - "T2D gut microbiome" → [0.21, -0.13, 0.85, ...](坐标很接近!) - "今天天气不错" → [0.91, 0.44, -0.32, ...](坐标差很远)

意思越接近的文字,生成的坐标就越接近。这样计算机就能用数学方法(余弦相似度)算出哪些文字跟你的问题最相关。

2.6 向量数据库是什么

白话:一个按"含义相似度"搜索的仓库。

普通数据库搜索是精确匹配(搜"苹果"只能找到包含"苹果"两个字的记录),向量数据库是语义搜索(搜"苹果"也能找到"iPhone""水果"相关的内容)。

常用的向量数据库:

名称特点适合场景
ChromaDB轻量、纯 Python、开箱即用学习、个人项目(我们用这个)
FAISSMeta 出品、速度极快大规模向量搜索
Milvus分布式、生产级企业级部署
Pinecone云托管、免运维不想自己维护数据库的情况

2.7 Prompt Template 是什么

白话:一个"填空题模板",把固定格式的指令和动态内容拼在一起。

# 不用模板(硬拼接,容易出错)
prompt = "请根据以下内容回答:" + context + "\n问题:" + question

# 用模板(清晰、可复用)
template = """请根据以下内容回答用户的问题。
如果内容中没有答案,请说"我不确定"。

参考内容:{context}
用户问题:{question}
"""

好处:统一管理提示词,改一处就行,不用到处改字符串。


3. 环境安装与配置

# 建议在独立的 conda 环境中安装
conda create -n langchain python=3.11 -y
conda activate langchain

# 安装核心包
pip install langchain langchain-community langchain-openai chromadb

每个包是干什么的:

包名作用
langchain核心框架,提供 Chain、Prompt Template 等基础组件
langchain-community社区贡献的集成(文档加载器、向量数据库连接器等)
langchain-openaiOpenAI/兼容 API 的封装(也支持连 Ollama 等本地模型)
chromadb轻量级向量数据库,存储和检索向量

可选安装:

# 如果要用本地 Ollama 模型(免费方案)
pip install langchain-ollama

# 如果要加载 PDF 文件
pip install pypdf

# 如果要用 HuggingFace 的 Embedding 模型(免费)
pip install langchain-huggingface sentence-transformers

4. 实操教程

4.1 入门:第一个 LangChain 程序

用 LangChain 调用 LLM 回答一个问题:

# === 第一个 LangChain 程序 ===
# 功能:调用 LLM 回答一个简单问题

# 导入 ChatOpenAI 类(支持 OpenAI 及兼容 API)
from langchain_openai import ChatOpenAI

# 初始化模型
# 如果你用 OpenAI 官方 API:
# llm = ChatOpenAI(model="gpt-4o-mini", api_key="你的key")

# 如果你用本地 Ollama(免费,推荐):
llm = ChatOpenAI(
    model="qwen2.5:7b",               # Ollama 里下载的模型名
    base_url="http://localhost:11434/v1",  # Ollama 的 API 地址
    api_key="ollama",                  # Ollama 不需要真实 key,随便填
    temperature=0                      # 0 = 回答更稳定,不随机
)

# 调用模型回答问题
response = llm.invoke("什么是宏基因组学?用一句话解释。")

# 打印结果
print(response.content)
# 输出示例:宏基因组学是直接从环境样本中提取所有微生物的DNA进行测序分析的学科。

4.2 搭建一个完整的 RAG 系统(重点)

这是本教程的核心。我们从零搭建一个完整的 RAG 系统:加载文档 → 切分 → 向量化 → 存储到 ChromaDB → 检索问答。

# === 完整 RAG 系统 ===
# 功能:加载 Markdown 文件 → 切分 → 向量化 → 存储 → 检索问答

# ============ 第1步:导入所有需要的模块 ============
from langchain_community.document_loaders import DirectoryLoader, TextLoader
from langchain.text_splitter import RecursiveCharacterTextSplitter
from langchain_community.vectorstores import Chroma
from langchain_openai import ChatOpenAI, OpenAIEmbeddings
from langchain.chains import RetrievalQA
from langchain.prompts import PromptTemplate

# ============ 第2步:加载文档 ============
# 从指定目录加载所有 .md 文件
loader = DirectoryLoader(
    path="./knowledge_base",       # 你的知识库目录
    glob="**/*.md",                # 匹配所有 .md 文件(** 表示递归子目录)
    loader_cls=TextLoader,         # 用纯文本加载器
    loader_kwargs={"encoding": "utf-8"}  # 指定编码,避免中文乱码
)
# 执行加载,返回 Document 对象列表
documents = loader.load()
print(f"✓ 加载了 {len(documents)} 个文档")

# ============ 第3步:文本切分 ============
# 把长文档切成小段(chunk)
text_splitter = RecursiveCharacterTextSplitter(
    chunk_size=500,       # 每段最多 500 个字符
    chunk_overlap=50,     # 相邻段之间重叠 50 个字符(避免切断句子丢失上下文)
    separators=["\n## ", "\n### ", "\n\n", "\n", "。", ";", " "]
    # 切分优先级:优先在标题处切 → 空行处切 → 句号处切
    # 这样能保证每段内容是完整的意思
)
# 执行切分
chunks = text_splitter.split_documents(documents)
print(f"✓ 切分成 {len(chunks)} 个文本块")

# ============ 第4步:向量化 + 存储到 ChromaDB ============
# 初始化 Embedding 模型(把文字变成数字向量)
# 方案A:用 OpenAI 的 Embedding(付费但效果好)
# embeddings = OpenAIEmbeddings(api_key="你的key")

# 方案B:用 Ollama 本地 Embedding(免费,推荐)
from langchain_ollama import OllamaEmbeddings
embeddings = OllamaEmbeddings(
    model="nomic-embed-text",  # Ollama 里的 Embedding 模型
    base_url="http://localhost:11434"
)

# 把所有文本块向量化并存入 ChromaDB
vectorstore = Chroma.from_documents(
    documents=chunks,                # 要存储的文本块
    embedding=embeddings,            # 用什么模型做向量化
    persist_directory="./chroma_db"  # 数据存在磁盘的位置(下次不用重新建)
)
print(f"✓ 向量数据库构建完成,共 {vectorstore._collection.count()} 条记录")

# ============ 第5步:构建检索问答链 ============
# 初始化 LLM(用 Ollama 本地模型)
llm = ChatOpenAI(
    model="qwen2.5:7b",
    base_url="http://localhost:11434/v1",
    api_key="ollama",
    temperature=0
)

# 自定义 Prompt Template(告诉 AI 怎么回答)
prompt_template = PromptTemplate(
    input_variables=["context", "question"],
    template="""你是一个生物信息学知识助手。请根据以下参考内容回答问题。
要求:
1. 只根据参考内容回答,不要编造
2. 如果参考内容中没有答案,请说"根据已有资料无法回答"
3. 用中文回答,术语附英文原文

参考内容:
{context}

问题:{question}

回答:"""
)

# 创建检索问答链(把检索器 + LLM + Prompt 组装起来)
qa_chain = RetrievalQA.from_chain_type(
    llm=llm,                                         # 用哪个语言模型
    chain_type="stuff",                               # stuff = 把所有检索到的内容塞进一个 prompt
    retriever=vectorstore.as_retriever(
        search_kwargs={"k": 3}                        # 每次检索返回最相关的 3 段
    ),
    chain_type_kwargs={"prompt": prompt_template},    # 使用自定义 Prompt
    return_source_documents=True                      # 同时返回来源文档(方便溯源)
)

# ============ 第6步:提问! ============
question = "宏基因组分析的主要流程有哪些步骤?"
result = qa_chain.invoke({"query": question})

# 打印回答
print("=" * 50)
print(f"问题:{question}")
print(f"回答:{result['result']}")
print("=" * 50)

# 打印来源(可以看到 AI 参考了哪些文档片段)
print("\n参考来源:")
for i, doc in enumerate(result["source_documents"]):
    print(f"  [{i+1}] {doc.metadata.get('source', '未知')} ")
    print(f"      内容片段:{doc.page_content[:80]}...")

4.3 使用本地 Ollama 模型搭建免费 RAG

上面的代码已经用 Ollama 作为默认方案了。这里补充完整的 Ollama 配置流程:

# ====== 第1步:安装 Ollama ======
# Linux:
curl -fsSL https://ollama.com/install.sh | sh

# ====== 第2步:下载模型 ======
# 下载对话模型(选一个,推荐 qwen2.5:7b,中文好)
ollama pull qwen2.5:7b       # 4.7GB,中文效果好
# 或者
ollama pull llama3.1:8b      # 4.7GB,英文强

# 下载 Embedding 模型(必须下,用于向量化)
ollama pull nomic-embed-text  # 274MB,小巧够用

# ====== 第3步:验证模型可用 ======
ollama list   # 查看已下载的模型
ollama run qwen2.5:7b "你好"  # 测试对话
# ====== 免费 RAG 完整配置(不花一分钱) ======

from langchain_openai import ChatOpenAI
from langchain_ollama import OllamaEmbeddings

# LLM:用 Ollama 本地模型(免费)
llm = ChatOpenAI(
    model="qwen2.5:7b",
    base_url="http://localhost:11434/v1",
    api_key="ollama"
)

# Embedding:用 Ollama 本地 Embedding 模型(免费)
embeddings = OllamaEmbeddings(
    model="nomic-embed-text",
    base_url="http://localhost:11434"
)

# 向量数据库:ChromaDB(免费,本地存储)
# 加上上面4.2节的代码就是一个完整的免费 RAG 系统
# 总花费:0元

4.4 自定义 Prompt Template

# === 不同场景的 Prompt Template ===

from langchain.prompts import PromptTemplate

# 场景1:严格问答(不让 AI 编造)
strict_qa_prompt = PromptTemplate(
    input_variables=["context", "question"],
    template="""请严格根据以下参考内容回答问题。
如果参考内容中找不到答案,请回答"无法确定"。

参考内容:{context}
问题:{question}
回答:"""
)

# 场景2:生信面试模拟
interview_prompt = PromptTemplate(
    input_variables=["context", "question"],
    template="""你是一位生信面试教练。
根据参考资料,用面试回答的格式回答问题:
1. 先用一句话总结核心要点
2. 再分点展开(2-3个要点)
3. 最后举一个实际应用的例子

参考资料:{context}
面试问题:{question}
回答:"""
)

# 场景3:多语言术语对照
bilingual_prompt = PromptTemplate(
    input_variables=["context", "question"],
    template="""根据以下内容回答问题。
要求:所有专业术语同时给出中文和英文,格式为"中文(English)"。

内容:{context}
问题:{question}
回答:"""
)

4.5 Chain 的串联用法

# === 用 LCEL(LangChain Expression Language)串联 Chain ===
# LCEL 是 LangChain 推荐的新写法,用 | 符号串联步骤

from langchain_openai import ChatOpenAI
from langchain.prompts import ChatPromptTemplate
from langchain_core.output_parsers import StrOutputParser

# 初始化模型
llm = ChatOpenAI(
    model="qwen2.5:7b",
    base_url="http://localhost:11434/v1",
    api_key="ollama"
)

# 定义一个翻译 + 总结的串联 Chain
# 第一步:翻译
translate_prompt = ChatPromptTemplate.from_template(
    "把以下英文生信术语翻译成中文并解释:{term}"
)

# 第二步:简化
simplify_prompt = ChatPromptTemplate.from_template(
    "把以下解释用更通俗的白话重新说一遍,让完全没基础的人也能听懂:\n{text}"
)

# 用 | 串联:输入 → 翻译prompt → LLM → 解析文本 → 简化prompt → LLM → 输出
chain = translate_prompt | llm | StrOutputParser() | simplify_prompt | llm | StrOutputParser()

# 运行
result = chain.invoke({"term": "Metagenomic binning"})
print(result)

5. 用 RAG 搭建个人知识库问答

把你 knowledge_base 目录里的文档变成一个可以问答的系统:

# === 个人知识库问答系统(完整版) ===
# 把你面试准备的知识库目录变成 AI 可问答的系统

import os
from langchain_community.document_loaders import DirectoryLoader, TextLoader
from langchain.text_splitter import RecursiveCharacterTextSplitter
from langchain_community.vectorstores import Chroma
from langchain_openai import ChatOpenAI
from langchain_ollama import OllamaEmbeddings
from langchain.chains import RetrievalQA
from langchain.prompts import PromptTemplate

# ======== 配置区(根据你的实际情况修改) ========
KNOWLEDGE_DIR = "/home/user/面试/knowledge_base  知识库"  # 你的知识库路径
CHROMA_DIR = "/home/user/面试/my_vectordb"                # 向量库存储位置
OLLAMA_URL = "http://localhost:11434"                      # Ollama 地址

def build_knowledge_base():
    """构建向量知识库(只需运行一次)"""

    # 1. 加载所有 Markdown 文件
    loader = DirectoryLoader(
        path=KNOWLEDGE_DIR,
        glob="**/*.md",
        loader_cls=TextLoader,
        loader_kwargs={"encoding": "utf-8"},
        show_progress=True    # 显示加载进度条
    )
    docs = loader.load()
    print(f"加载了 {len(docs)} 个文档")

    # 2. 切分
    splitter = RecursiveCharacterTextSplitter(
        chunk_size=500,
        chunk_overlap=50,
        separators=["\n## ", "\n### ", "\n\n", "\n", "。", " "]
    )
    chunks = splitter.split_documents(docs)
    print(f"切分成 {len(chunks)} 个文本块")

    # 3. 向量化 + 存储
    embeddings = OllamaEmbeddings(
        model="nomic-embed-text",
        base_url=OLLAMA_URL
    )
    vectorstore = Chroma.from_documents(
        documents=chunks,
        embedding=embeddings,
        persist_directory=CHROMA_DIR
    )
    print(f"知识库构建完成!共 {vectorstore._collection.count()} 条记录")
    return vectorstore

def ask(question, vectorstore=None):
    """向知识库提问"""

    # 如果没传入 vectorstore,就从磁盘加载已有的
    if vectorstore is None:
        embeddings = OllamaEmbeddings(
            model="nomic-embed-text",
            base_url=OLLAMA_URL
        )
        vectorstore = Chroma(
            persist_directory=CHROMA_DIR,
            embedding_function=embeddings
        )

    # 初始化 LLM
    llm = ChatOpenAI(
        model="qwen2.5:7b",
        base_url=f"{OLLAMA_URL}/v1",
        api_key="ollama",
        temperature=0
    )

    # 自定义 Prompt
    prompt = PromptTemplate(
        input_variables=["context", "question"],
        template="""你是[用户]的面试备考助手。请根据知识库中的内容回答问题。
要求:
1. 只基于提供的内容回答,不要编造
2. 如果涉及面试,给出面试回答模板
3. 术语给出英文原文

参考内容:
{context}

问题:{question}

回答:"""
    )

    # 构建 QA Chain
    qa = RetrievalQA.from_chain_type(
        llm=llm,
        retriever=vectorstore.as_retriever(search_kwargs={"k": 4}),
        chain_type_kwargs={"prompt": prompt},
        return_source_documents=True
    )

    result = qa.invoke({"query": question})
    print(f"\n问:{question}")
    print(f"答:{result['result']}")
    print(f"\n来源:")
    for doc in result["source_documents"]:
        src = os.path.basename(doc.metadata.get("source", ""))
        print(f"  - {src}")
    return result

# ======== 使用方式 ========
if __name__ == "__main__":
    # 第一次运行:构建知识库(约需几分钟)
    # vs = build_knowledge_base()

    # 之后每次运行:直接提问(秒级响应)
    ask("宏基因组分析流程有哪些步骤?")
    ask("Shannon 指数和 Simpson 指数有什么区别?")
    ask("如果面试官问我随机森林的原理,我该怎么回答?")

6. 常见报错与解决方案

报错信息原因解决方法
Connection refused localhost:11434Ollama 没有启动终端运行 ollama serve,或检查 Ollama 是否安装
model 'xxx' not found模型没下载运行 ollama pull qwen2.5:7b 下载对应模型
UnicodeDecodeError: 'utf-8' codec can't decode文件编码不是 UTF-8loader_kwargs={"encoding": "utf-8"} 或转换文件编码
chromadb.errors.InvalidCollectionExceptionChromaDB 版本不兼容或数据损坏删除 ./chroma_db 目录重新构建
openai.AuthenticationError: invalid api_key用 OpenAI API 但 key 无效/过期检查 OPENAI_API_KEY 环境变量;或改用 Ollama 免费方案
ImportError: cannot import name 'xxx'LangChain 版本更新,API 变了pip install --upgrade langchain langchain-community;查看迁移文档
RuntimeError: CUDA out of memory本地 GPU 显存不够跑模型换小模型如 qwen2.5:1.5b,或用 CPU 模式(慢但能跑)
RecursionError: maximum recursion depthChain 套了死循环检查 Chain 定义,确保没有循环引用

7. LangChain vs LlamaIndex vs 直接调 API 对比

维度LangChainLlamaIndex直接调 API
定位通用 AI 应用框架专注数据索引和 RAG最底层调用
上手难度中等,概念多较低,RAG 开箱即用最低,但什么都要自己写
RAG 搭建灵活但需要手动组装各步骤几行代码就能搭好 RAG需要自己实现切分、向量化、检索
Agent 支持强(核心功能之一)弱(不是主要方向)需要自己实现
生态集成极广(几百种工具/模型)主要围绕数据索引取决于你自己写多少代码
灵活性高,可自定义每个环节中等,封装较重最高,完全自由
适合场景复杂 AI 应用、Agent纯 RAG / 知识库问答简单调用、追求极致控制
推荐想系统学 AI 应用开发只想快速搭 RAG只需要简单调用 LLM

对于你(生信面试)的建议:先学 LangChain(覆盖面广,面试加分),等熟悉后再看 LlamaIndex 作为补充。


8. 速查表

常用文档加载器

from langchain_community.document_loaders import (
    TextLoader,           # 纯文本文件(.txt, .md)
    PyPDFLoader,          # PDF 文件(需要 pip install pypdf)
    CSVLoader,            # CSV 表格
    DirectoryLoader,      # 批量加载整个目录
    WebBaseLoader,        # 从网页加载(需要 pip install beautifulsoup4)
    UnstructuredFileLoader # 通用加载器(自动识别格式)
)

常用文本切分器

from langchain.text_splitter import (
    RecursiveCharacterTextSplitter,  # 最常用,递归按分隔符切
    CharacterTextSplitter,           # 简单按字符数切
    MarkdownTextSplitter,            # 按 Markdown 标题切
    TokenTextSplitter                # 按 Token 数切
)

常用向量数据库

from langchain_community.vectorstores import (
    Chroma,    # ChromaDB(轻量,推荐入门用)
    FAISS,     # Facebook AI 相似度搜索
)

常用 Chain 类型

Chain 类型用途
RetrievalQA检索 + 问答(RAG 核心)
ConversationalRetrievalChain带对话历史的 RAG
LLMChain最基础的 Prompt → LLM 调用
SequentialChain串联多个 Chain

LCEL 常用写法

# 基础调用
chain = prompt | llm | StrOutputParser()
result = chain.invoke({"question": "..."})

# 带检索的 RAG
from langchain_core.runnables import RunnablePassthrough
chain = (
    {"context": retriever, "question": RunnablePassthrough()}
    | prompt
    | llm
    | StrOutputParser()
)

9. 延伸学习资源

资源说明
LangChain 官方文档最权威的参考,API 变动时以此为准
LangChain GitHub135k+ stars,源码和示例
LangSmithLangChain 官方的调试和监控平台
Ollama 官网本地模型下载和管理
ChromaDB 文档向量数据库使用指南
本知识库:21_大语言模型入门.mdLLM 基础概念(先读这个再来看本文)
本知识库:22_Prompt工程技巧.mdPrompt 写法技巧,搭配 RAG 的 Prompt Template 使用

学习路线建议: 1. 先确保 Ollama 本地模型跑通(参考知识库2的 01_Ollama本地大模型部署与使用.md) 2. 跑通 4.1 节的第一个程序 3. 跑通 4.2 节的完整 RAG 4. 用第 5 节的代码把自己的知识库接上去 5. 面试前能讲清楚 RAG 的 6 步流程,加分