一、前置准备(依赖库+环境配置)

上次分享了LangChain入门指南后,很多朋友私信我:“入门案例已经跑通了,接下来该学什么?”“怎么用LangChain做更实用的AI应用?”

其实LangChain的入门不难,难的是从“会用”到“活用”——摆脱简单的对话、文本问答,掌握进阶组件和实战技巧,才能真正把它用到工作和项目中。

今天这篇进阶文,就衔接上一篇入门内容,避开冗余理论,直接实战:

先梳理入门到进阶的核心跃迁点,再拆解3个高频进阶案例(含完整可运行代码,适配阿里千问,复制就能跑),帮你吃透LangChain的进阶能力,从初学者快速成长为能独立搭建实战应用的开发者。

(全文干货+代码,建议收藏,搭配上一篇入门文食用,效果翻倍;代码已规避版本兼容问题,新手也能零踩坑)

1.1 依赖库安装(终端执行)

核心作用:安装进阶案例所需的所有依赖库,固定版本以避免兼容问题,包含环境管理、向量库、文档解析、模型依赖等,终端复制对应命令执行即可。

pip install python-dotenv==1.0.0 faiss-cpu==1.7.4 python-docx==1.1.0 tiktoken==0.5.2 langchain==0.1.10 dashscope==1.14.0

1.2 .env文件配置(同级目录新建.env文件,无后缀)

核心作用:工程化管理阿里千问API密钥,避免明文泄露,需在新建的.env文件中,填写个人的AccessKey ID和AccessKey Secret(替换占位符)。

DASHSCOPE_ACCESS_KEY_ID=你的AccessKey ID
DASHSCOPE_ACCESS_KEY_SECRET=你的AccessKey Secret

二、通用函数(所有案例均可复用)

核心作用:封装所有案例共用的基础操作,无需重复编写,对应代码位置包含5个核心部分,分别是:

  • 导入所需核心依赖包(环境、模型、文本分割、向量库相关);

  • 读取.env文件中的阿里千问API密钥,初始化密钥变量;

  • init_llm函数:初始化阿里千问模型,可调整温度、最大输出token数等参数;

  • init_text_splitter函数:初始化文本分割工具,适配中文文本,可调整分割块大小和重叠长度;

  • init_vector_store函数:初始化向量库,将文本块转为向量并保存到本地,方便后续复用;

  • load_local_vector_store函数:加载本地已保存的向量库,避免重复生成,提升效率。

import os
from dotenv import load_dotenv
from langchain_community.llms import DashScope
from langchain_community.embeddings import DashScopeEmbeddings
from langchain.text_splitter import RecursiveCharacterTextSplitter
from langchain.vectorstores import FAISS

load_dotenv()
access_key_id = os.getenv("DASHSCOPE_ACCESS_KEY_ID")
access_key_secret = os.getenv("DASHSCOPE_ACCESS_KEY_SECRET")

def init_llm(temperature=0.5, max_tokens=1000):
    llm = DashScope(
        model_name="qwen-turbo",
        temperature=temperature,
        max_tokens=max_tokens,
        dashscope_api_key=access_key_secret
    )
    return llm

def init_text_splitter(chunk_size=500, chunk_overlap=50):
    text_splitter = RecursiveCharacterTextSplitter(
        chunk_size=chunk_size,
        chunk_overlap=chunk_overlap,
        length_function=len,
        separators=["\n\n", "\n", "。", ",", ";"]
    )
    return text_splitter

def init_vector_store(text_chunks, embeddings=None):
    if embeddings is None:
        embeddings = DashScopeEmbeddings(
            model="text-embedding-v2",
            dashscope_api_key=access_key_secret
        )
    vector_store = FAISS.from_documents(text_chunks, embeddings)
    vector_store.save_local("faiss_vector_store")
    return vector_store

def load_local_vector_store(embeddings=None):
    if embeddings is None:
        embeddings = DashScopeEmbeddings(
            model="text-embedding-v2",
            dashscope_api_key=access_key_secret
        )
    vector_store = FAISS.load_local("faiss_vector_store", embeddings, allow_dangerous_deserialization=True)
    return vector_store

三、案例1:进阶版多文档问答

这3个案例,是进阶阶段最高频、最实用的实战场景,循序渐进,从“多文档问答”(基础进阶),到“结构化输出批量生成”(实战常用),再到“AI智能体入门”(高阶能力),每个案例都衔接上一篇入门内容,且包含代码注释、运行说明和避坑要点。

所有代码都适配阿里千问,无需科学上网,替换.env文件中的密钥即可直接运行。

核心作用:实现多文档(PDF、Word、TXT)问答,支持批量加载、向量库复用、来源标注,对应代码位置包含7个核心部分,分别是:

  • 导入多文档问答所需依赖(文档加载、检索链、提示词模板、异常捕获相关);

  • 调用通用函数,初始化千问模型(调整温度适配结构化问答)和文本分割工具(调整参数适配多文档);

  • load_multiple_documents函数:批量加载多格式文档(PDF、Word、TXT),标注文档来源,增加异常捕获避免单个文件加载失败;

  • 设置多文档路径(替换占位符为个人文档路径),加载文档并分割为文本块,打印分割结果;

  • 尝试加载本地已保存的向量库,无本地向量库则初始化并保存,提升复用效率;

  • 定义多文档问答提示词模板(明确回答要求、来源标注规则),初始化检索式问答链(调整参数提升检索精度);

  • 搭建循环交互逻辑,支持用户连续提问,输出问答结果及来源详情,输入“退出”可结束交互。

from langchain.document_loaders import PyPDFLoader, Docx2txtLoader, TextLoader
from langchain.chains import RetrievalQA
from langchain.prompts import PromptTemplate
import traceback

llm = init_llm(temperature=0.3)
text_splitter = init_text_splitter(chunk_size=600, chunk_overlap=60)

def load_multiple_documents(file_paths):
    documents = []
    for file_path in file_paths:
        try:
            if file_path.endswith(".pdf"):
                loader = PyPDFLoader(file_path)
            elif file_path.endswith(".docx"):
                loader = Docx2txtLoader(file_path)
            elif file_path.endswith(".txt"):
                loader = TextLoader(file_path, encoding="utf-8")
            else:
                print(f"不支持的文件格式:{file_path}")
                continue
            doc = loader.load()
            for d in doc:
                d.metadata["source"] = file_path
            documents.extend(doc)
            print(f"成功加载文件:{file_path},共{len(doc)}页")
        except Exception as e:
            print(f"加载文件{file_path}失败:{str(e)}")
            traceback.print_exc()
    return documents

file_paths = [
    "文档1.pdf",
    "文档2.docx",
    "文档3.txt"
]
documents = load_multiple_documents(file_paths)
text_chunks = text_splitter.split_documents(documents)
print(f"多文档分割完成,共生成{len(text_chunks)}个文本块")

try:
    vector_store = load_local_vector_store()
    print("成功加载本地向量库")
except:
    print("本地无向量库,开始初始化向量库...")
    vector_store = init_vector_store(text_chunks)
    print("向量库初始化并保存完成")

prompt_template = """
你是一个专业的多文档问答助手,严格按照以下要求回答:
1. 仅基于提供的多文档内容回答问题,不编造任何信息;
2. 回答时,先给出核心答案,再标注回答来源(格式:来源:XXX文件,页码:XXX);
3. 若多个文件包含相关内容,全部标注来源;若文档中无相关内容,直接回复“文档中未找到相关信息”;
4. 回答简洁明了,分点清晰(复杂问题可分点,简单问题一句话概括)。

多文档相关内容:
{context}

用户问题:{question}

回答:
"""
prompt = PromptTemplate(
    template=prompt_template,
    input_variables=["context", "question"]
)

qa_chain = RetrievalQA.from_chain_type(
    llm=llm,
    chain_type="map_reduce",
    retriever=vector_store.as_retriever(
        k=3,
        search_kwargs={"score_threshold": 0.7}
    ),
    chain_type_kwargs={"prompt": prompt},
    return_source_documents=True
)

print("\n=== 多文档问答演示(输入'退出'结束)===")
while True:
    user_input = input("你:")
    if user_input.lower() == "退出":
        print("对话结束")
        break
    result = qa_chain({"query": user_input})
    print(f"\nAI:{result['result']}")
    print("\n回答来源详情:")
    for idx, doc in enumerate(result["source_documents"], 1):
        source = doc.metadata.get("source", "未知来源")
        page = doc.metadata.get("page", "未知页码")
        content = doc.page_content[:150] + "..."
        print(f"{idx}. 来源:{source},页码:{page},相关内容:{content}")
    print("\n" + "-"*50)

四、案例2:结构化输出进阶(批量生成+格式校验)

核心作用:批量生成复杂结构化数据,实现格式严格校验、异常重试、数据持久化,对应代码位置包含8个核心部分,分别是:

  • 导入结构化输出所需依赖(输出解析、提示词模板、链、格式校验、时间、JSON处理相关);

  • 调用通用函数,初始化千问模型(调整温度和最大token数,适配结构化生成);

  • 定义结构化格式模型(Author嵌套模型、Book核心模型),明确字段类型、约束条件和示例,实现严格校验;

  • 初始化JSON输出解析器,基于定义的结构化模型,实现格式校验和解析;

  • 定义提示词模板,明确结构化生成要求、格式约束,避免格式错误;

  • 初始化生成链,串联提示词、模型、输出解析器,实现“提示→生成→校验”一体化;

  • batch_generate_books函数:实现批量生成逻辑,支持设置生成数量和重试次数,格式错误时自动重试;

  • 调用批量生成函数,生成指定数量的结构化数据,格式化输出生成结果,清晰展示每一条数据的核心信息;

  • 将批量生成的结构化数据保存到JSON文件,实现数据持久化,方便后续复用(如填充表格、生成报告)。

from langchain_core.output_parsers import JsonOutputParser, OutputParserException
from langchain_core.prompts import ChatPromptTemplate
from langchain.chains import LLMChain
from pydantic import BaseModel, Field
import time
import json

llm = init_llm(temperature=0.3, max_tokens=1500)

class Author(BaseModel):
    name: str = Field(description="书籍作者姓名,必须是中文", examples=["张三"])
    gender: str = Field(description="作者性别,只能是'男'或'女'或'未知'", examples=["男"])
    introduction: str = Field(description="作者简介,50-100字,简洁明了", examples=["张三,资深AI工程师,从事LLM应用开发5年,出版多本AI相关书籍"])

class Book(BaseModel):
    book_name: str = Field(description="书籍名称,必须是中文,不能包含英文", examples=["LangChain实战指南"])
    author: Author = Field(description="作者信息,嵌套结构,严格按照Author模型格式填写")
    publish_year: int = Field(description="出版年份,必须是整数,范围在2000-2026之间", examples=[2025])
    category: str = Field(description="书籍分类,只能是'人工智能'、'历史'、'科幻'、'文学'、'编程'中的一种", examples=["人工智能"])
    introduction: str = Field(description="书籍简介,100-200字,详细说明书籍核心内容", examples=["本书从初学者视角出发,拆解LangChain的核心组件和实战案例,包含完整代码,帮助新手快速上手LLM应用开发,适配阿里千问等国产模型。"])
    price: float = Field(description="书籍价格,必须是浮点数,范围在20.0-100.0之间", examples=[69.9])

parser = JsonOutputParser(pydantic_object=Book)

prompt_template = ChatPromptTemplate.from_messages([
    (
        "system",
        """你是一个专业的书籍信息结构化生成助手,严格按照以下要求执行:
1. 严格按照指定的JSON格式生成书籍信息,字段类型、约束必须符合要求(比如出版年份是整数,价格是浮点数);
2. 批量生成时,每本书的信息必须独立、不重复,分类均匀分布在指定分类中;
3. 作者简介、书籍简介必须符合字数要求,语言流畅,符合中文表达习惯;
4. 若生成的格式不符合要求,会被强制重试,直到符合要求为止;
5. 只输出JSON格式,不包含任何额外文字、注释,否则会报错。

输出格式要求(严格遵守):
{format_instructions}
"""
    ),
    (
        "human",
        "请批量生成{num}本中文书籍的信息,要求覆盖不同分类,每本书的信息完整、真实可信,符合上述要求。"
    )
])

chain = prompt_template | llm | parser

def batch_generate_books(num=5, retry=3):
    books_list = []
    print(f"开始批量生成{num}本中文书籍信息...")
    for i in range(num):
        print(f"\n生成第{i+1}本书信息:")
        for attempt in range(retry):
            try:
                result = chain.invoke({
                    "num": 1,
                    "format_instructions": parser.get_format_instructions()
                })
                books_list.append(result)
                print(f"生成成功:{result['book_name']}")
                break
            except OutputParserException as e:
                print(f"第{attempt+1}次生成失败,格式错误:{str(e)},正在重试...")
                time.sleep(1)
            except Exception as e:
                print(f"第{attempt+1}次生成失败,错误:{str(e)},正在重试...")
                time.sleep(1)
        else:
            print(f"第{i+1}本书生成失败,已达到最大重试次数")
    return books_list

batch_books = batch_generate_books(num=5, retry=3)

print("\n=== 批量生成书籍信息完成 ===")
for idx, book in enumerate(batch_books, 1):
    print(f"\n{idx}. 书籍名称:{book['book_name']}")
    print(f"   作者:{book['author']['name']}({book['author']['gender']})")
    print(f"   出版年份:{book['publish_year']}年")
    print(f"   分类:{book['category']}")
    print(f"   价格:{book['price']}元")
    print(f"   作者简介:{book['author']['introduction']}")
    print(f"   书籍简介:{book['introduction']}")

with open("batch_books.json", "w", encoding="utf-8") as f:
    json.dump(batch_books, f, ensure_ascii=False, indent=4)
print("\n批量生成的书籍信息已保存到 batch_books.json 文件中")

五、案例3:AI智能体入门(自主工具调用)

核心作用:实现AI自主判断需求、调用合适工具完成复杂任务,支持多轮对话记忆,对应代码位置包含8个核心部分,分别是:

  • 导入AI智能体所需依赖(智能体、工具、记忆组件、检索链、网络请求相关);

  • 调用通用函数,初始化千问模型(调整温度,平衡决策理性和灵活性);

  • get_weather函数:自定义天气查询工具,调用免费天气API,根据城市名称返回格式化天气信息,增加异常处理;

  • 加载本地向量库(需先运行案例1生成),初始化多文档检索链,作为第二个自定义工具;

  • 注册工具列表,将天气查询工具和多文档检索工具注册到LangChain,明确每个工具的名称、对应函数和适用场景描述(供AI判断调用);

  • 初始化总结式记忆组件,压缩对话上下文,节省token,支持多轮对话上下文关联;

  • 初始化AI智能体,绑定工具和记忆,设置智能体类型(适配多轮对话+工具调用),开启详细日志便于调试;

  • 搭建循环交互逻辑,支持用户连续提问,AI自主判断需求并调用对应工具,输入“退出”可结束交互,附带提问示例供参考。

from langchain.agents import AgentType, initialize_agent, Tool
from langchain.memory import ConversationSummaryMemory
from langchain.chains import RetrievalQA
import requests

llm = init_llm(temperature=0.5)

def get_weather(city: str) -> str:
    try:
        url = f"https://v0.yiketianqi.com/api?unescape=1&version=v61&appid=43656176&appsecret=I42og6Lm&city={city}"
        response = requests.get(url, timeout=10)
        response.raise_for_status()
        weather_data = response.json()
        weather_info = f"""
{city}当天天气信息:
1. 天气状况:{weather_data['wea']}
2. 温度范围:{weather_data['tem1']}℃ ~ {weather_data['tem2']}℃
3. 风向风力:{weather_data['win']} {weather_data['win_speed']}
4. 湿度:{weather_data['humidity']}%
5. 空气质量:{weather_data['air_quality']}(AQI:{weather_data['air']})
6. 穿衣建议:{weather_data['air_tips']}
        """
        return weather_info.strip()
    except Exception as e:
        return f"天气查询失败:{str(e)},请检查城市名称是否正确,或稍后重试。"

try:
    vector_store = load_local_vector_store()
    qa_chain = RetrievalQA.from_chain_type(
        llm=llm,
        chain_type="map_reduce",
        retriever=vector_store.as_retriever(k=3, search_kwargs={"score_threshold": 0.7}),
        return_source_documents=False
    )
except:
    print("本地无向量库,请先运行案例1,生成多文档向量库后再运行本案例")
    exit()

tools = [
    Tool(
        name="WeatherQuery",
        func=get_weather,
        description="""用于查询中国城市的当天天气信息,当用户的问题包含“天气”“温度”“穿衣建议”等关键词,且明确提到城市名称时,调用此工具。
        注意:必须传入中文城市名称(如“北京”),不能传入英文或拼音。"""
    ),
    Tool(
        name="DocumentRetrieval",
        func=qa_chain.run,
        description="""用于回答用户关于多文档内容的问题,当用户的问题是询问文档中的信息、知识点,且不涉及天气时,调用此工具。
        注意:只能基于已加载的多文档内容回答,不能编造信息;若文档中无相关内容,直接回复“文档中未找到相关信息”。"""
    )
]

memory = ConversationSummaryMemory(
    llm=llm,
    memory_key="chat_history",
    return_messages=True
)

agent = initialize_agent(
    tools=tools,
    llm=llm,
    agent=AgentType.CHAT_CONVERSATIONAL_REACT_DESCRIPTION,
    memory=memory,
    verbose=True,
    handle_parsing_errors="检查你的回答格式,确保符合要求,不要包含任何额外文字,只输出最终回答。"
)

print("\n=== AI智能体演示(输入'退出'结束)===")
print("提示:可尝试提问:'北京今天天气怎么样?'、'文档中提到的LangChain核心组件有哪些?'、'上海今天适合穿什么?'")
while True:
    user_input = input("你:")
    if user_input.lower() == "退出":
        print("对话结束")
        break
    response = agent.run(input=user_input)
    print(f"\nAI:{response}\n")
    print("-"*60)

Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐