从可视化到代码
LangChain 实战进阶
学习路径总览
三个阶段,从基础调用到工程化部署,每课对标已学平台操作。
| 阶段 | 课程 | 对标已学 | 核心能力 |
|---|---|---|---|
| P0 | 01-06 | FastGPT / Coze / Dify | RAG 全链路 + Agent 工具调用 |
| P1 | 07-09 | FastGPT API / Coze 工作流 | API 服务化 + Web 界面 + 多步 Agent |
| P2 | 10-12 | 框架对比 + 文档处理 | LlamaIndex + Unstructured + Flask |
LangChain 的本质就是管道语法:prompt | llm | parser —— 前一个的输出自动流入后一个的输入,就像 Unix 管道。
P0 基础课程(01-06)
从调用 LLM 到完整 RAG + Agent,6 课打通用代码实现 AI 应用的全部基础。
学习目标
- 用
ChatOllama连接本地 Ollama 模型 - 掌握
invoke(一次性返回)和stream(流式输出)两种调用方式 - 理解
SystemMessage/HumanMessage/AIMessage消息角色
核心代码
from langchain_ollama import ChatOllama # 连接本地模型 llm = ChatOllama(model="qwen2.5:7b", base_url="http://localhost:11434") # 方式1:一次性返回 response = llm.invoke("什么是网站备案?") print(response.content) # 方式2:流式输出(逐字返回) for chunk in llm.stream("网站备案需要什么材料?"): print(chunk.content, end="", flush=True)
对标已学
| FastGPT 操作 | LangChain 代码 |
|---|---|
| 配置模型渠道(选 qwen2.5:7b) | ChatOllama(model=...) |
| 配置 Ollama 地址 | base_url="http://localhost:11434" |
| 温度参数 | temperature=0.1 |
三个测试全部通过:invoke 返回一句话解释、stream 逐字输出材料清单、多轮对话正确记住上文。
学习目标
- 用
ChatPromptTemplate创建带变量的提示词模板 - 用代码实现 CREATE 框架(Context/Role/Example/ACTION/Tone/Extra)
- 掌握 Few-shot 给 AI 看示例学习格式
- 理解 LCEL 链式语法
prompt | llm | parser
核心代码
from langchain_core.prompts import ChatPromptTemplate from langchain_core.output_parsers import StrOutputParser # CREATE 框架代码版 prompt = ChatPromptTemplate.from_messages([ ("system", """你是{role}。 领域:{domain} 职责:{responsibility} 语气:{tone} 最多{max_words}字"""), ("human", "{question}"), ]) # LCEL 链式语法 chain = prompt | llm | StrOutputParser() result = chain.invoke({ "role": "网站备案专家", "domain": "工信部网站备案", "question": "备案被退回怎么办?", ... })
LCEL 分步调试
step1 = prompt.invoke({...}) # → ChatPromptValue
step2 = llm.invoke(step1) # → AIMessage
step3 = parser.invoke(step2) # → 纯文本字符串
# 等价于一步到位:
chain = prompt | llm | parser
result = chain.invoke({...})
你在 FastGPT 中配置的"开场白"和"知识库回答提示词",在代码里就是 ChatPromptTemplate。CREATE 框架从文档概念变成了可运行的代码。
学习目标
- 用
PyPDFLoader加载 PDF 文档 - 用
RecursiveCharacterTextSplitter切分文档为知识块 - 理解
chunk_size和chunk_overlap参数的作用 - 管理元数据(来源、页码等)
核心代码
from langchain_community.document_loaders import PyPDFLoader from langchain_text_splitters import RecursiveCharacterTextSplitter # 加载 PDF pages = PyPDFLoader("网站备案办事指南.pdf").load() # 递归切分 splitter = RecursiveCharacterTextSplitter( chunk_size=200, # 每块约200字 chunk_overlap=30, # 相邻块重叠30字(防截断) separators=["\n\n", "\n", "。", ";", ",", " ", ""], ) splits = splitter.split_documents(pages) # 结果:1页PDF → 5个知识块
overlap 对比实验
overlap=0:4 个知识块,在句子中间截断
overlap=50:5 个知识块,相邻块有重叠内容,语义连续
等价于你在 FastGPT 知识库中上传文档并配置"分块长度 512、重叠 0"的操作。区别是现在能看到每个知识块的具体内容。
学习目标
- 用
OllamaEmbeddings把文本转成 1024 维向量 - 用
FAISS存储向量并做相似度检索 - 理解相似度分数(越低越相关)
- 掌握 MMR 多样性检索(避免重复结果)
核心代码
from langchain_ollama import OllamaEmbeddings from langchain_community.vectorstores import FAISS # 嵌入模型 embeddings = OllamaEmbeddings(model="bge-m3") # 存入 FAISS 向量数据库 vectorstore = FAISS.from_documents(splits, embeddings) # 相似度检索 results = vectorstore.similarity_search("备案需要什么材料?", k=3) # 带分数检索(越低越相关) results = vectorstore.similarity_search_with_score("备案被退回", k=3) # 结果:score 0.76 → 0.80 → 0.85 # MMR 多样性检索 results = vectorstore.max_marginal_relevance_search("备案流程", k=3)
带分数检索是 FastGPT 界面里看不到的——你能看到每个结果的相似度分数,精确控制检索质量。
学习目标
- 组装完整 RAG 链:检索 → 格式化 → 提示词 → LLM → 输出
- 实现防幻觉提示词:"只用检索内容回答,不编造"
- 流式 RAG 输出
- 接入重排模型(硅基流动 API)
核心代码
# RAG 提示词(防幻觉核心) rag_prompt = ChatPromptTemplate.from_template("""你是网站备案专家。根据以下资料回答问题。 【资料】{context} 【规范】只根据资料回答,不编造。无相关信息时说明"根据现有资料无法回答"。 【问题】{question}""") # 组装 RAG 链 rag_chain = ( {"context": retriever | format_docs, "question": RunnablePassthrough()} | rag_prompt | llm | StrOutputParser() )
三个问题测试结果
Q: 网站备案需要什么材料?
A: 列出6项材料(负责人证件、域名证书等)
Q: 备案被退回原因?
A: "根据现有资料无法回答"——防幻觉生效
Q: 备案需要多长时间?
A: "根据现有资料无法回答"——诚实拒绝
对比问题 1(有答案→精准回答)和问题 2/3(无答案→拒绝编造),这就是 RAG 的核心价值。你用代码实现了和 FastGPT 完全等价的系统能力。
学习目标
- 用
@tool装饰器定义工具函数 - 用
bind_tools把工具绑定到 LLM - 实现 ReAct 循环:思考 → 调用工具 → 观察 → 生成回答
- LLM 自主判断何时调用工具、何时不调用
核心代码
from langchain_core.tools import tool # 定义工具 @tool def search_filing_info(question: str) -> str: """搜索网站备案相关信息""" return retriever.invoke(question) # 绑定工具到 LLM llm_with_tools = llm.bind_tools([search_filing_info, calculate_days]) # Agent 执行循环 def run_agent(question): messages = [HumanMessage(content=question)] while True: response = llm_with_tools.invoke(messages) if response.tool_calls: # LLM 要调工具 → 执行工具 → 结果加入对话 ... else: return response.content # 不需要工具 → 直接回答
三个测试结果
Q: 备案需要什么材料? → 调用 search_filing_info → 生成回答
Q: 广东备案需要多久? → 调用 calculate_days → 生成回答
Q: 你好,你是做什么的? → 不调用任何工具 → 直接回答
等价于你在 Coze 中创建 Agent 并添加插件,或在 Dify 中配置 Agent 节点。第 3 个测试最关键——LLM 自己判断了"这个问题不需要工具"。
P1 工程化实战(07-09)
把 RAG 封装成 API 服务、加上 Web 界面、构建多步复杂 Agent 工作流。
学习目标
- 把 Lesson 05 的 RAG 链封装成 HTTP API
POST /ask接口:接收问题 JSON,返回回答POST /ask/stream:SSE 流式返回(打字效果)- FastAPI 自动生成 API 文档(Swagger UI)
核心代码
from fastapi import FastAPI from fastapi.responses import StreamingResponse from pydantic import BaseModel app = FastAPI(title="网站备案 RAG API", version="1.0.0") class AskRequest(BaseModel): question: str @app.post("/ask") async def ask(request: AskRequest): answer = rag_chain.invoke(request.question) return {"answer": answer, "question": request.question} @app.post("/ask/stream") async def ask_stream(request: AskRequest): def generate(): for chunk in rag_chain.stream(request.question): yield f"data: {chunk}\n\n" return StreamingResponse(generate(), media_type="text/event-stream")
你之前调用 FastGPT 的 POST https://cloud.fastgpt.cn/api(带 Bearer 令牌)。现在你是 API 的提供者——别人调用你的 http://localhost:8000/ask。
POST /ask {"question":"网站备案需要什么材料?"}
→ 返回6项材料清单
GET /docs → 浏览器打开自动生成的 Swagger API 文档
学习目标
- 用 Streamlit 搭建聊天界面(不到 200 行代码)
- 侧边栏上传 PDF/TXT 动态构建知识库
- 多轮对话 + 流式输出
- 和 FastGPT/Coze/Dify 前端界面的对比
核心代码
import streamlit as st # 侧边栏:上传文件 uploaded_files = st.sidebar.file_uploader("上传PDF/TXT", type=["pdf", "txt"]) # 聊天界面 if prompt := st.chat_input("输入你的问题..."): with st.chat_message("user"): st.write(prompt) with st.chat_message("assistant"): # 流式输出 for chunk in rag_chain.stream(prompt): st.write(chunk, end="")
python -m streamlit run lesson08_streamlit.py → 浏览器自动打开 http://localhost:8501 → 和 ChatGPT 一样的聊天界面。
学习目标
- LangGraph 核心概念:图(Graph)、节点(Node)、边(Edge)、状态(State)
- 条件路由:根据检索结果决定走"生成"还是"搜索"路径
- 多步 Agent:检索 → 判断相关性 → 生成/联网搜索
- 和 Coze/Dify 工作流编排的对比
Agent 工作流程图
核心代码
from langgraph.graph import StateGraph, END # 定义状态 class AgentState(TypedDict): question: str documents: list answer: str # 构建图 workflow = StateGraph(AgentState) workflow.add_node("retrieve", retrieve_node) workflow.add_node("grade", grade_documents_node) workflow.add_node("generate", generate_node) workflow.add_node("search", search_tool_node) workflow.set_entry_point("retrieve") workflow.add_edge("retrieve", "grade") workflow.add_conditional_edges("grade", route_after_grading, { "generate": "generate", # 有文档 → 生成 "search": "search", # 无文档 → 搜索 }) workflow.add_edge("generate", END) workflow.add_edge("search", END) app_graph = workflow.compile()
Coze 拖拽连线 = LangGraph 的 add_edge;Coze 的 if-else 节点 = LangGraph 的 conditional_edges。代码版更灵活,支持循环、并行、人工介入。
P2 框架进阶(10-12)
学习 LlamaIndex 框架、专业文档解析工具 Unstructured、经典 Web 框架 Flask。
学习目标
- LlamaIndex 核心概念:Document → Node → Index → QueryEngine
- 3 行代码搭建 RAG(对比 LangChain 的 3 步组装)
- ChatEngine 多轮对话
- 两个框架的选型建议
框架对比
| 概念 | LangChain | LlamaIndex |
|---|---|---|
| 知识块 | split_documents | Node |
| 存储 | FAISS / Chroma | VectorStoreIndex |
| 检索 | retriever.invoke | index.as_retriever |
| 问答 | RAG Chain | QueryEngine |
| 链式语法 | LCEL (a | b | c) | Workflow |
| 核心优势 | 通用、灵活 | 数据处理、索引管理 |
核心代码
# LlamaIndex:1步搞定索引(自动切分+向量化) index = VectorStoreIndex.from_documents(documents) query_engine = index.as_query_engine(similarity_top_k=3) response = query_engine.query("网站备案需要什么材料?") # 对比 LangChain:需要3步 # splits = splitter.split_documents(pages) # vectorstore = FAISS.from_documents(splits, embeddings) # retriever = vectorstore.as_retriever()
LangChain = 万能瑞士军刀(Agent、多步推理、高度自定义)
LlamaIndex = 文档处理专家(多种索引、LlamaHub 数据源、增量更新)
实际项目中两个可以组合使用。
学习目标
- 理解 PyPDFLoader 的局限:表格乱码、图片丢失、版面混乱
- Unstructured 的版面分析:标题/正文/表格/列表分类
- 元素级智能分块(对比字符级分块)
- OCR 方案选型:Tesseract / PaddleOCR / 多模态 LLM
版面分析示意图
┌──────────────────────────┐ │ [Title] 网站备案办事指南 │ ← 识别为标题 ├──────────────────────────┤ │ [NarrativeText] │ ← 识别为正文 │ 第一步:备案单位... │ ├──────────────────────────┤ │ [Table] │ ← 识别为表格(不切断) │ 材料名称 | 材料形式 │ ├──────────────────────────┤ │ [ListItem] │ ← 识别为列表项 │ 1. 登录系统 │ └──────────────────────────┘
选型决策树
纯文本 PDF + 简单版面 → PyPDFLoader(够用)
纯文本 PDF + 复杂版面/表格 → Unstructured hi_res
扫描件 PDF + 中文 → PaddleOCR
扫描件 PDF + 高精度 → 多模态 LLM (Qwen-VL)
学习目标
- Flask 基础:路由
@app.route、请求request.get_json()、响应jsonify() - 用 Flask 封装 RAG API(和 FastAPI 实现同样的功能)
- 实现 Bearer Token 认证(和你调用 FastGPT API 时一样)
- Flask vs FastAPI 选型
Flask vs FastAPI 对比
| 特性 | Flask | FastAPI |
|---|---|---|
| 路由定义 | @app.route | @app.get/post |
| 请求体验证 | 手动 get_json() | Pydantic 自动验证 |
| 异步支持 | 需要扩展 | 原生 async/await |
| API 文档 | 需要扩展 | 自动生成 Swagger |
| 性能 | 中 | 高(ASGI) |
| 生态成熟度 | 非常成熟 | 快速成长中 |
快速原型/学习 → 都可以,Flask 更简单;新项目/高性能 → FastAPI(异步+自动文档);岗位要求 Flask → 必须会,但也了解 FastAPI。
岗位要求覆盖对照
基于 AI 工程师岗位要求的技能覆盖情况。
LLM/Agent 方向岗位要求覆盖率约 80%。主要差距在 vLLM 部署和 CV/传统 ML,可按需补充。
学习路径总结
从"点页面"到"写代码"的完整进阶路径。
已完成的学习路径
下一步
你用代码实现了之前在 FastGPT、Coze、Dify 三个平台上做的全部事情。区别是:以前是"点页面",现在是"写代码"——你能控制每一个细节,看到每一步的中间结果。这就是从"AI 应用使用者"到"AI 工程师"的转变。
12 课代码文件位于 langchain-learning/lessons/ 目录,每课都有详细中文注释,可随时回看复习。