LangChain + RAG + Agent + 多模态 完整实战教程


🚀 从零到一:LangChain 完整实战教程

前言

本教程将带你从零开始,使用 LangChain 框架和阿里云百炼平台,构建一个完整的 AI 智能助手,支持:

· 📄 RAG 检索增强生成(基于 PDF/TXT 文档问答)

· 🤖 Agent 智能代理(自动调用工具)

· 🎨 多模态生成(文生图、图生图)

· 💬 对话记忆(多轮对话)

· 🌐 Web 界面(Streamlit)


一、环境搭建

1.1 安装 Python 依赖

bash 复制代码
# 创建项目目录
mkdir ai_blog_demo
cd ai_blog_demo

# 安装依赖包
pip3 install langchain langchain-openai langchain-community -i https://pypi.tuna.tsinghua.edu.cn/simple
pip3 install streamlit chromadb pypdf python-dotenv -i https://pypi.tuna.tsinghua.edu.cn/simple
pip3 install sentence-transformers langchain-chroma -i https://pypi.tuna.tsinghua.edu.cn/simple
pip3 install openai pillow requests -i https://pypi.tuna.tsinghua.edu.cn/simple

1.2 配置 API Key

创建 .env 文件:

bash 复制代码
DASHSCOPE_API_KEY="你的阿里云百炼API Key"
DASHSCOPE_BASE_URL="https://dashscope.aliyuncs.com/compatible-mode/v1"

💡 获取 API Key:访问 阿里云百炼控制台 注册并创建

1.3 准备测试文档

创建 sample.txt:

text 复制代码
人工智能(AI)是计算机科学的一个分支,致力于创建能够执行通常需要人类智能的任务的系统。
这些任务包括视觉感知、语音识别、决策制定和语言翻译等。

机器学习是人工智能的一个子集,它使系统能够从数据中学习并改进,而无需明确编程。
深度学习是机器学习的一个子集,使用多层神经网络来处理复杂的数据模式。

大语言模型(LLM)如GPT、通义千问等,是基于深度学习技术的模型,能够理解和生成人类语言。
LangChain 是一个用于开发由大语言模型驱动的应用程序的框架。

检索增强生成(RAG)是一种结合信息检索和文本生成的技术,可以让大模型基于外部知识库回答问题,
有效解决大模型知识陈旧和幻觉问题。

二、核心功能实现

2.1 基础 LLM 调用

python 复制代码
# 01_basic_llm.py
import os
from dotenv import load_dotenv
from langchain_openai import ChatOpenAI
from langchain_core.messages import SystemMessage, HumanMessage

load_dotenv()

llm = ChatOpenAI(
    model="qwen3-max",
    temperature=0.7,
    openai_api_key=os.getenv("DASHSCOPE_API_KEY"),
    openai_api_base=os.getenv("DASHSCOPE_BASE_URL"),
)

messages = [
    SystemMessage(content="你是一个专业的Python编程助手,回答要简洁。"),
    HumanMessage(content="请用一句话介绍什么是装饰器")
]

response = llm.invoke(messages)
print(response.content)

2.2 提示词模板

python 复制代码
# 02_prompt_template.py
from langchain_core.prompts import ChatPromptTemplate
from langchain_core.output_parsers import StrOutputParser

prompt = ChatPromptTemplate.from_messages([
    ("system", "你是一个{role}专家,回答要{style}。"),
    ("user", "{question}")
])

chain = prompt | llm | StrOutputParser()

result = chain.invoke({
    "role": "Python编程",
    "style": "简洁,不超过30字",
    "question": "什么是列表推导式?"
})
print(result)

2.3 输出解析器(JSON 格式)

python 复制代码
# 03_output_parser.py
from langchain_core.output_parsers import JsonOutputParser
from pydantic import BaseModel, Field

class Person(BaseModel):
    name: str = Field(description="人物姓名")
    age: int = Field(description="人物年龄")
    hobby: str = Field(description="人物爱好")

parser = JsonOutputParser(pydantic_object=Person)

prompt = ChatPromptTemplate.from_messages([
    ("system", "提取信息,按格式输出:{format_instructions}"),
    ("user", "小明今年18岁,喜欢打篮球")
])

chain = prompt | llm | parser
result = chain.invoke({"format_instructions": parser.get_format_instructions()})
print(f"姓名: {result['name']}, 年龄: {result['age']}, 爱好: {result['hobby']}")

2.4 对话记忆

python 复制代码
# 04_memory.py
from langchain.memory import ConversationBufferMemory
from langchain.chains import LLMChain

memory = ConversationBufferMemory(return_messages=True)
prompt = ChatPromptTemplate.from_messages([
    ("system", "你是一个友好的AI助手"),
    ("placeholder", "{history}"),
    ("human", "{input}")
])

chain = LLMChain(llm=llm, prompt=prompt, memory=memory)

chain.invoke({"input": "我叫小明,我喜欢吃披萨"})
response = chain.invoke({"input": "我叫什么名字?我喜欢吃什么?"})
print(response['text'])

2.5 RAG 检索增强生成

python 复制代码
# 05_rag.py
from langchain_community.document_loaders import TextLoader
from langchain.text_splitter import RecursiveCharacterTextSplitter
from langchain_huggingface import HuggingFaceEmbeddings
from langchain_chroma import Chroma
from langchain.chains import create_retrieval_chain
from langchain.chains.combine_documents import create_stuff_documents_chain

# 加载文档
loader = TextLoader("sample.txt", encoding="utf-8")
docs = loader.load()

# 分割文档
text_splitter = RecursiveCharacterTextSplitter(chunk_size=300, chunk_overlap=50)
chunks = text_splitter.split_documents(docs)

# 向量化
embeddings = HuggingFaceEmbeddings(
    model_name="sentence-transformers/paraphrase-multilingual-MiniLM-L12-v2"
)
vectorstore = Chroma.from_documents(chunks, embeddings)
retriever = vectorstore.as_retriever(search_kwargs={"k": 3})

# RAG 链
system_prompt = "基于以下内容回答问题:{context}"
prompt = ChatPromptTemplate.from_messages([
    ("system", system_prompt),
    ("human", "{input}")
])

document_chain = create_stuff_documents_chain(llm, prompt)
rag_chain = create_retrieval_chain(retriever, document_chain)

response = rag_chain.invoke({"input": "什么是RAG?"})
print(response['answer'])

2.6 Agent 智能代理

python 复制代码
# 06_agent.py
from langchain.agents import AgentExecutor, create_tool_calling_agent
from langchain.tools import tool
from datetime import datetime

@tool
def calculator(expression: str) -> str:
    """计算数学表达式"""
    try:
        return f"结果: {eval(expression)}"
    except:
        return "计算错误"

@tool  
def get_current_time() -> str:
    """获取当前时间"""
    return datetime.now().strftime("%Y-%m-%d %H:%M:%S")

tools = [calculator, get_current_time]

prompt = ChatPromptTemplate.from_messages([
    ("system", "你是智能助手,可使用工具:{tools}"),
    ("placeholder", "{chat_history}"),
    ("human", "{input}"),
    ("placeholder", "{agent_scratchpad}")
])

agent = create_tool_calling_agent(llm, tools, prompt)
agent_executor = AgentExecutor(agent=agent, tools=tools, verbose=True)

response = agent_executor.invoke({"input": "现在几点?计算 123*456"})
print(response['output'])

2.7 多模态(文生图)

python 复制代码
# 07_multimodal.py
from openai import OpenAI
import requests

client = OpenAI(
    api_key=os.getenv("DASHSCOPE_API_KEY"),
    base_url="https://dashscope.aliyuncs.com/compatible-mode/v1",
)

response = client.images.generate(
    model="wanx-v1",
    prompt="一只穿着宇航服的橘猫,漂浮在星云中,写实风格",
    n=1,
    size="1024*1024",
)

image_url = response.data[0].url
print(f"生成的图片: {image_url}")

# 下载保存
img_data = requests.get(image_url).content
with open("generated_image.png", "wb") as f:
    f.write(img_data)
print("图片已保存到 generated_image.png")

三、完整的 Streamlit Web 应用

这是本教程的核心,整合了以上所有功能:

python 复制代码
# app.py - 完整的 Streamlit 应用
import os
import tempfile
import streamlit as st
from dotenv import load_dotenv
from langchain_openai import ChatOpenAI
from langchain_core.prompts import ChatPromptTemplate
from langchain_core.output_parsers import StrOutputParser
from langchain.memory import ConversationBufferMemory
from langchain.chains import LLMChain
from langchain_community.document_loaders import TextLoader, PyPDFLoader
from langchain.text_splitter import RecursiveCharacterTextSplitter
from langchain_huggingface import HuggingFaceEmbeddings
from langchain_chroma import Chroma
from langchain.chains import create_retrieval_chain
from langchain.chains.combine_documents import create_stuff_documents_chain
from langchain.agents import AgentExecutor, create_tool_calling_agent
from langchain.tools import tool
from datetime import datetime
from openai import OpenAI
import requests

load_dotenv()

# 页面配置
st.set_page_config(
    page_title="AI 智能助手",
    page_icon="🤖",
    layout="wide"
)

st.title("🤖 AI 智能助手 - LangChain 完整实战")
st.markdown("支持 RAG 文档问答、Agent 智能代理、多模态生图")

# 初始化 session_state
if "messages" not in st.session_state:
    st.session_state.messages = []
if "memory" not in st.session_state:
    st.session_state.memory = ConversationBufferMemory(return_messages=True)
if "retriever" not in st.session_state:
    st.session_state.retriever = None
if "vectorstore" not in st.session_state:
    st.session_state.vectorstore = None

# 初始化 LLM
@st.cache_resource
def init_llm():
    return ChatOpenAI(
        model="qwen3-max",
        temperature=0.7,
        openai_api_key=os.getenv("DASHSCOPE_API_KEY"),
        openai_api_base=os.getenv("DASHSCOPE_BASE_URL"),
    )

llm = init_llm()

# 初始化多模态客户端
@st.cache_resource
def init_multimodal_client():
    return OpenAI(
        api_key=os.getenv("DASHSCOPE_API_KEY"),
        base_url="https://dashscope.aliyuncs.com/compatible-mode/v1",
    )

multimodal_client = init_multimodal_client()

# ========== 侧边栏 ==========
with st.sidebar:
    st.header("⚙️ 功能配置")
    
    # 功能选择
    mode = st.radio(
        "选择模式",
        ["💬 普通对话", "📚 RAG 文档问答", "🤖 Agent 智能代理", "🎨 文生图"]
    )
    
    st.divider()
    
    # RAG 文档上传
    if mode == "📚 RAG 文档问答":
        st.subheader("📄 上传文档")
        uploaded_file = st.file_uploader(
            "支持 TXT/PDF",
            type=["txt", "pdf"]
        )
        
        if uploaded_file and st.button("处理文档"):
            with st.spinner("处理中..."):
                # 保存临时文件
                suffix = f".{uploaded_file.name.split('.')[-1]}"
                with tempfile.NamedTemporaryFile(delete=False, suffix=suffix) as tmp:
                    tmp.write(uploaded_file.getvalue())
                    tmp_path = tmp.name
                
                # 加载文档
                if uploaded_file.name.endswith('.txt'):
                    loader = TextLoader(tmp_path, encoding="utf-8")
                else:
                    loader = PyPDFLoader(tmp_path)
                
                docs = loader.load()
                
                # 分割
                text_splitter = RecursiveCharacterTextSplitter(
                    chunk_size=500, chunk_overlap=100
                )
                chunks = text_splitter.split_documents(docs)
                
                # 向量化
                embeddings = HuggingFaceEmbeddings(
                    model_name="sentence-transformers/paraphrase-multilingual-MiniLM-L12-v2"
                )
                st.session_state.vectorstore = Chroma.from_documents(chunks, embeddings)
                st.session_state.retriever = st.session_state.vectorstore.as_retriever(
                    search_kwargs={"k": 3}
                )
                
                os.unlink(tmp_path)
                st.success(f"✅ 已加载 {len(chunks)} 个文档块")
    
    # Agent 工具说明
    if mode == "🤖 Agent 智能代理":
        st.subheader("🛠️ 可用工具")
        st.info("""
        - 📅 获取当前时间
        - 🧮 数学计算
        - 📝 文本长度统计
        """)
    
    # 文生图配置
    if mode == "🎨 文生图":
        st.subheader("🎨 生成配置")
        img_size = st.selectbox("图片尺寸", ["1024*1024", "768*1024", "1024*768"])
        img_style = st.selectbox("风格", ["<auto>", "写实", "插画", "水墨"])
    
    # 清空对话
    if st.button("🗑️ 清空对话"):
        st.session_state.messages = []
        st.session_state.memory.clear()
        st.rerun()

# ========== 主界面 ==========
st.header("💬 对话")

# 显示历史消息
for message in st.session_state.messages:
    with st.chat_message(message["role"]):
        st.markdown(message["content"])

# ========== 模式处理函数 ==========
def normal_chat(prompt: str) -> str:
    """普通对话模式"""
    chain = LLMChain(llm=llm, prompt=ChatPromptTemplate.from_messages([
        ("system", "你是友好的AI助手"),
        ("placeholder", "{history}"),
        ("human", "{input}")
    ]), memory=st.session_state.memory)
    
    response = chain.invoke({"input": prompt})
    return response['text']

def rag_chat(prompt: str) -> str:
    """RAG 文档问答模式"""
    if not st.session_state.retriever:
        return "⚠️ 请先在侧边栏上传文档"
    
    system_prompt = "基于以下文档内容回答问题,如果文档中没有相关信息,请明确说明:\n{context}"
    chat_prompt = ChatPromptTemplate.from_messages([
        ("system", system_prompt),
        ("human", "{input}")
    ])
    
    document_chain = create_stuff_documents_chain(llm, chat_prompt)
    rag_chain = create_retrieval_chain(st.session_state.retriever, document_chain)
    
    response = rag_chain.invoke({"input": prompt})
    return response['answer']

def agent_chat(prompt: str) -> str:
    """Agent 智能代理模式"""
    @tool
    def get_time() -> str:
        """获取当前时间"""
        return datetime.now().strftime("%Y-%m-%d %H:%M:%S")
    
    @tool
    def calculate(expr: str) -> str:
        """计算数学表达式"""
        try:
            return str(eval(expr))
        except:
            return "计算错误"
    
    @tool
    def text_len(text: str) -> str:
        """计算文本长度"""
        return str(len(text))
    
    tools = [get_time, calculate, text_len]
    
    prompt_template = ChatPromptTemplate.from_messages([
        ("system", "你是智能助手,可使用工具"),
        ("placeholder", "{chat_history}"),
        ("human", "{input}"),
        ("placeholder", "{agent_scratchpad}")
    ])
    
    agent = create_tool_calling_agent(llm, tools, prompt_template)
    executor = AgentExecutor(agent=agent, tools=tools, verbose=False)
    
    response = executor.invoke({"input": prompt})
    return response['output']

def image_gen(prompt: str) -> str:
    """文生图模式"""
    try:
        response = multimodal_client.images.generate(
            model="wanx-v1",
            prompt=prompt,
            n=1,
            size=img_size,
            parameters={"style": img_style}
        )
        
        image_url = response.data[0].url
        
        # 下载并显示
        img_data = requests.get(image_url).content
        timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
        filename = f"generated_{timestamp}.png"
        
        with open(filename, "wb") as f:
            f.write(img_data)
        
        # 在聊天中显示图片
        st.image(image_url, caption=f"生成: {prompt[:50]}...")
        
        return f"✅ 图片已生成!\n\n![图片]({image_url})"
    except Exception as e:
        return f"❌ 生成失败: {str(e)}"

# ========== 输入处理 ==========
user_input = st.chat_input("输入你的问题...")

if user_input:
    # 添加用户消息
    st.session_state.messages.append({"role": "user", "content": user_input})
    with st.chat_message("user"):
        st.markdown(user_input)
    
    # 生成回复
    with st.chat_message("assistant"):
        with st.spinner("思考中..."):
            if mode == "💬 普通对话":
                response = normal_chat(user_input)
            elif mode == "📚 RAG 文档问答":
                response = rag_chat(user_input)
            elif mode == "🤖 Agent 智能代理":
                response = agent_chat(user_input)
            elif mode == "🎨 文生图":
                response = image_gen(user_input)
            else:
                response = normal_chat(user_input)
            
            st.markdown(response)
    
    # 添加助手消息
    st.session_state.messages.append({"role": "assistant", "content": response})

# ========== 页脚 ==========
st.divider()
st.caption("💡 使用说明:")
st.caption("1. 选择模式:普通对话 / RAG文档问答 / Agent代理 / 文生图")
st.caption("2. RAG模式需先在侧边栏上传文档并点击「处理文档」")
st.caption("3. Agent模式支持:时间查询、数学计算、文本统计")

四、运行与部署

4.1 本地运行

bash 复制代码
# 确保所有文件在同一目录
ls -la
# 应包含:.env, sample.txt, app.py

# 启动 Streamlit
streamlit run app.py

4.2 项目文件结构

复制代码
ai_blog_demo/
├── .env                 # API Key 配置
├── sample.txt           # 测试文档
├── app.py               # 主应用(Streamlit)
├── 01_basic_llm.py      # 基础调用
├── 02_prompt_template.py
├── 03_output_parser.py
├── 04_memory.py
├── 05_rag.py
├── 06_agent.py
├── 07_multimodal.py
└── generated_images/    # 生成的图片(自动创建)

4.3 部署到云端

bash 复制代码
# 安装依赖
pip3 install streamlit

# 后台运行(Linux 服务器)
nohup streamlit run app.py --server.port 8501 --server.address 0.0.0.0 > streamlit.log 2>&1 &

五、总结

通过本教程,你学会了:

功能 状态

✅ LangChain 环境搭建 完成

✅ 基础 LLM 调用 完成

✅ 提示词模板 完成

✅ 输出解析器(JSON) 完成

✅ 对话记忆 完成

✅ RAG 检索增强生成 完成

✅ Agent 智能代理 完成

✅ 多模态文生图 完成

✅ Streamlit Web 界面 完成


相关推荐
我是无敌小恐龙2 小时前
Java SE 零基础入门Day06 方法重载+Debug调试+String字符串全套API详解(超全干货)
java·开发语言·人工智能·python·transformer·无人机·量子计算
aidesignplus2 小时前
从平方到线性:Mamba如何挑战Transformer的长序列效率瓶颈?
人工智能·python·深度学习·vim·transformer
2301_773553622 小时前
Redis怎样优化复制缓冲池大小_调大repl-backlog-size减少频繁的全量同步触发
jvm·数据库·python
三维频道2 小时前
工业级三维扫描实测:汽车灯具复杂结构件的全尺寸 3D 测量方案分析
java·人工智能·python·数码相机·3d·汽车·汽车轻量化制造
weixin_381288182 小时前
HTML lang 属性的正确取值规范:BCP 47 格式详解与最佳实践
jvm·数据库·python
阿荻在肝了2 小时前
Agent学习七:LangGraph学习-持久化与记忆二
python·学习·agent
u0109147602 小时前
如何正确对 JavaScript 对象的键进行字母序排序
jvm·数据库·python
maqr_1102 小时前
MySQL在事务中如何实现串行化_使用select lock in share mode查询
jvm·数据库·python
TechWayfarer2 小时前
离线IP数据库内网部署:场景选型与热更新落地实践
网络·数据库·python·网络协议·tcp/ip