LangChain 入门笔记:AI 视频生成实战
- 约 14 分钟读完 - 全文 5588 字LangChain 入门笔记:AI 视频生成实战
最近重新刷了吴恩达和 Harrison Chase 主讲的《LangChain for LLM Application Development》。这门课不长,但把 LangChain 的"为什么存在"讲得很透:它不是让你写更多胶水代码,而是把 LLM 调用、提示工程、上下文管理、工具调用这些重复模式抽象成可组合的组件。这篇文章整理课程里的核心原理,并落到我们最熟悉的 AI 视频生成场景,给出可直接跑的 Demo。
一、LangChain 解决什么问题?
在直接调用 OpenAI / Claude / 国产大模型 API 时,我们通常会写出这样的代码:
import openai
messages = [
{"role": "system", "content": "你是一位短视频脚本专家。"},
{"role": "user", "content": "主题是'如何用 LangChain 生成视频脚本',风格轻松,30 秒左右。"}
]
resp = openai.chat.completions.create(model="gpt-4o", messages=messages)
script = resp.choices[0].message.content这段代码能跑,但问题很明显:
- 提示词散落在各处,难以复用和版本管理;
- 输出是字符串,需要手写解析逻辑;
- 多轮对话、上下文记忆要自己拼 messages;
- 一旦涉及"检索素材 → 生成脚本 → 检查合规 → 输出结构化数据",代码就会迅速膨胀成面条。
LangChain 的核心思想:把 LLM 应用里的常见模式抽象成标准组件,让你像搭积木一样拼装工作流。
可以把它理解成:
LangChain = 模型接口统一层 + 提示模板 + 输出解析 + 记忆 + 链式调用 + 工具/Agent 编排
二、课程核心内容回顾
吴恩达这门课围绕 6 个模块展开,也是 LangChain 最基础的 6 个能力:
| 模块 | 作用 | 视频生成场景映射 |
|---|---|---|
| Models | 统一不同 LLM 的调用接口 | 切换 GPT-4o / Claude / 国产模型时无需改业务代码 |
| Prompts | 模板化管理提示词 | 脚本生成、分镜描述、标题优化的模板复用 |
| Output Parsers | 把自然语言输出转成结构化数据 | 解析 JSON 分镜、时间轴、素材清单 |
| Memory | 维护多轮对话状态 | 用户反复修改脚本时保留上下文 |
| Chains | 把多个 LLM/工具步骤串成链 | “主题 → 大纲 → 脚本 → 分镜 → 渲染参数"流水线 |
| Agents | 让 LLM 决定调用哪些工具 | Agent 自主判断需要检索素材还是生成画面描述 |
下面逐一看原理和代码。
三、核心组件原理与示例
3.1 Models & Prompts:统一接口与模板复用
LangChain 用 ChatOpenAI、ChatAnthropic 等类封装模型,并用 ChatPromptTemplate 管理提示词模板。
from langchain_openai import ChatOpenAI
from langchain_core.prompts import ChatPromptTemplate
llm = ChatOpenAI(model="gpt-4o", temperature=0.7)
prompt = ChatPromptTemplate.from_messages([
("system", "你是一位短视频脚本专家,擅长把技术概念写成{style}风格的口播脚本。"),
("human", "主题是:{topic},时长控制在{duration}秒,需要{scene_count}个分镜。")
])
messages = prompt.invoke({
"style": "轻松幽默",
"topic": "LangChain 如何自动生成视频脚本",
"duration": 30,
"scene_count": 3
})
response = llm.invoke(messages)
print(response.content)好处:
- 提示词与业务数据解耦,模板可复用、可版本化;
- 切换模型只需改一行
ChatOpenAI→ChatAnthropic; - 支持批量
batch、流式stream、异步ainvoke等高级调用方式。
3.2 Output Parsers:从文本到结构化数据
视频生成流程需要结构化输出,例如:
{
"scenes": [
{"time": "0-10s", "narration": "...", "visual": "...", "bgm": "..."}
],
"title": "...",
"tags": ["..."]
}LangChain 提供 PydanticOutputParser,让模型按指定 Schema 输出。
from pydantic import BaseModel, Field
from langchain_core.output_parsers import PydanticOutputParser
from langchain_core.prompts import PromptTemplate
class Scene(BaseModel):
time_range: str = Field(description="时间区间,如 0-10s")
narration: str = Field(description="口播文案")
visual: str = Field(description="画面描述,用于后续生成图片/视频")
bgm_mood: str = Field(description="背景音乐情绪")
class VideoScript(BaseModel):
title: str
scenes: list[Scene]
tags: list[str]
parser = PydanticOutputParser(pydantic_object=VideoScript)
prompt = PromptTemplate(
template="根据主题生成短视频脚本。\n{format_instructions}\n主题:{topic}\n时长:{duration}秒\n",
input_variables=["topic", "duration"],
partial_variables={"format_instructions": parser.get_format_instructions()},
)
chain = prompt | llm | parser
result = chain.invoke({"topic": "LangChain 自动生成短视频", "duration": 30})
print(result.model_dump_json(indent=2))注意:LLM 不一定 100% 返回合法 JSON,生产环境建议加 RetryOutputParser 或兜底解析。
3.3 Memory:多轮修改不再"失忆”
做视频脚本时,用户常会说:“前面不错,但把第二段改得更口语化一点”。没有记忆,LLM 会从头生成,丢失已确认的片段。
from langchain.memory import ConversationBufferMemory
from langchain.chains import ConversationChain
memory = ConversationBufferMemory()
conversation = ConversationChain(llm=llm, memory=memory)
conversation.predict(input="帮我写一个 30 秒的 LangChain 短视频脚本")
conversation.predict(input="第二段太正式了,改成口语化一些")
print(memory.load_memory_variables({}))LangChain 还提供 ConversationBufferWindowMemory(只保留最近 N 轮)、ConversationSummaryMemory(摘要历史)等,适用于长会话场景。
3.4 Chains:把多个步骤串成流水线
视频生成的一个典型链:
主题 → 生成标题 → 生成脚本 → 生成分镜 → 输出结构化渲染参数
用 LCEL(LangChain Expression Language)可以非常直观地表达:
from langchain_core.runnables import RunnablePassthrough
from langchain_core.output_parsers import StrOutputParser
# 子链 1:生成标题
title_prompt = ChatPromptTemplate.from_template("为'{topic}'写一个 20 字以内的爆款标题")
title_chain = title_prompt | llm | StrOutputParser()
# 子链 2:根据标题和主题生成脚本
script_prompt = ChatPromptTemplate.from_template(
"标题:{title}\n主题:{topic}\n时长:{duration}秒\n请生成 3 个分镜的脚本。"
)
script_chain = script_prompt | llm | StrOutputParser()
# 组合
full_chain = (
{"topic": RunnablePassthrough(), "duration": RunnablePassthrough()}
| RunnablePassthrough.assign(title=title_chain)
| RunnablePassthrough.assign(script=script_chain)
)
result = full_chain.invoke({"topic": "LangChain 视频生成", "duration": 30})
print(result)LCEL 的 | 运算符让数据流像 Unix 管道一样清晰,这也是 LangChain 从 0.1 到 0.2/0.3 版本最重要的设计演进。
3.5 RAG:用本地素材库增强脚本生成
做批量短视频时,通常有沉淀的素材库(文案库、分镜库、音乐库)。LangChain 的 RAG 组件可以让模型先检索再生成:
from langchain_community.vectorstores import FAISS
from langchain_openai import OpenAIEmbeddings
from langchain_core.prompts import ChatPromptTemplate
from langchain.chains.combine_documents import create_stuff_documents_chain
# 1. 构建向量库
embeddings = OpenAIEmbeddings()
vectorstore = FAISS.from_texts(
["分镜案例 1:开头用悬念钩子...", "爆款标题公式:数字+痛点+解决方案..."],
embedding=embeddings
)
retriever = vectorstore.as_retriever(search_kwargs={"k": 2})
# 2. 构建 RAG Chain
prompt = ChatPromptTemplate.from_messages([
("system", "参考以下素材生成脚本:\n\n{context}"),
("human", "主题:{topic},时长:{duration}秒")
])
rag_chain = create_stuff_documents_chain(llm, prompt) | {
"topic": lambda x: x["topic"],
"context": retriever
}
# 实际调用时先检索文档,再塞入 prompt在方糖猫 AI 短视频平台的工程实现中,我们会把 RAG 检索结果和 LangGraph 状态机结合,实现"检索 → 生成 → 人工审核 → 渲染"的完整闭环。
3.6 Agents:让 LLM 自己决定下一步
当流程不是固定流水线,而是需要动态决策时,Agent 更有优势。例如:
- 判断用户输入是否需要检索素材库;
- 根据脚本内容决定调用文生图还是文生视频工具;
- 调用外部 API 查询热点话题。
from langchain.agents import AgentExecutor, create_openai_tools_agent
from langchain_core.tools import tool
@tool
def generate_image(description: str) -> str:
"""根据画面描述生成一张图片,返回图片 URL。"""
# 实际接入 DALL·E / Midjourney / Stable Diffusion
return f"https://fake-img.example.com?prompt={description}"
@tool
def generate_video_clip(description: str, duration: int) -> str:
"""根据画面描述生成一段视频片段,返回视频 URL。"""
return f"https://fake-video.example.com?prompt={description}&duration={duration}"
tools = [generate_image, generate_video_clip]
agent_prompt = ChatPromptTemplate.from_messages([
("system", "你是一位 AI 视频导演,能调用工具生成图片或视频。"),
("human", "{input}"),
("placeholder", "{agent_scratchpad}")
])
agent = create_openai_tools_agent(llm, tools, agent_prompt)
agent_executor = AgentExecutor(agent=agent, tools=tools, verbose=True)
agent_executor.invoke({
"input": "我要一个 30 秒关于 LangChain 的短视频,先出 3 张分镜图,再合成视频。"
})四、Demo:一个可扩展的"AI 视频脚本生成器"
下面把上面所有组件串起来,做一个最小的可运行 Demo。它的输出是一份结构化脚本,后续可以无缝接到 Remotion、FFmpeg 或视频生成 API。
import os
from langchain_openai import ChatOpenAI
from langchain_core.prompts import ChatPromptTemplate
from langchain_core.output_parsers import PydanticOutputParser
from langchain_core.runnables import RunnablePassthrough
from pydantic import BaseModel, Field
os.environ["OPENAI_API_KEY"] = "your-api-key"
llm = ChatOpenAI(model="gpt-4o-mini", temperature=0.7)
class Scene(BaseModel):
time_range: str
narration: str
visual: str
tool: str = Field(description="生成该分镜所需工具:image 或 video")
class VideoProject(BaseModel):
title: str
target_platform: str
scenes: list[Scene]
parser = PydanticOutputParser(pydantic_object=VideoProject)
title_chain = (
ChatPromptTemplate.from_template("为'{topic}'写一个适合{platform}的爆款标题")
| llm
| StrOutputParser()
)
script_prompt = ChatPromptTemplate.from_template(
"""为平台"{target_platform}"生成短视频脚本。
{format_instructions}
标题:{title}
主题:{topic}
时长:{duration}秒
要求:每个分镜标注用 image(图片)还是 video(视频片段)生成。
"""
)
script_chain = (
RunnablePassthrough.assign(title=title_chain)
| script_prompt.partial(format_instructions=parser.get_format_instructions())
| llm
| parser
)
project = script_chain.invoke({
"topic": "LangChain 如何帮助 AI 视频创作",
"platform": "抖音",
"target_platform": "抖音",
"duration": 30
})
print(project.model_dump_json(indent=2, ensure_ascii=False))下一步可以扩展的方向:
- 把
Scene.visual传给 DALL·E / Stable Diffusion / 可灵 / Pika 生成画面; - 用
pydub+gTTS合成配音,或用 CosyVoice 克隆音色; - 用 Remotion 或 MoviePy 把图片、视频、字幕、BGM 合成为成片;
- 接入 LangGraph 做状态持久化和人工审核节点(参考我之前写的 LangGraph 入门笔记)。
五、分布式场景下的运行方案
当 LangChain 应用从本地脚本走向生产环境,单进程运行肯定不够。AI 视频生成是典型的长链路任务:脚本生成、素材检索、文生图、文生视频、配音、渲染,每一步都可能耗时数秒到数分钟。分布式架构的关键是:让 LangChain 推理层保持无状态,把状态交给任务队列和持久化存储。
推荐架构
flowchart TD
A["用户请求"] --> B["FastAPI 网关"]
B --> C["Redis/RocketMQ<br/>(任务队列)"]
C --> D["Worker 集群(LangChain 链/Agent 执行)<br/>- Python<br/>- LangChain<br/>- GPU 节点"]
D --> E["结果存储<br/>(MySQL/PostgreSQL + OSS/S3)"]
关键设计点
-
LangChain 服务无状态化 不保存用户会话到本地内存,所有上下文通过
state参数或 Redis 传入。这样任意 Worker 都可以处理任意任务,方便水平扩展。 -
任务队列解耦 用 Celery、RQ 或自研 Worker 消费 RocketMQ/Redis Stream。一个任务对应一次视频生成链路,失败可以重试,不会阻塞 API 网关。
-
持久化中间状态 把每个阶段的结果(脚本 JSON、分镜图 URL、视频片段 URL)写入数据库。如果 Worker 崩溃,可以从上一个阶段恢复,而不是从头执行。
-
LangGraph 的分布式友好性 LangGraph 的
State天然适合持久化。可以配置checkpointer把状态快照到 Redis/Postgres,实现断点续跑:
from langgraph.checkpoint.memory import MemorySaver
from langgraph.graph import StateGraph
builder = StateGraph(VideoGenState)
# ... 添加节点和边 ...
graph = builder.compile(checkpointer=MemorySaver())生产环境建议把 MemorySaver 替换为 PostgresSaver 或 RedisSaver,让不同 Worker 共享状态。
六、服务器异常恢复方案
AI 视频生成链路长、依赖多(LLM API、素材库、视频生成服务、对象存储),任何一环抖动都会导致失败。异常恢复不是简单 try/except,而是要从架构层面保证可观测、可重试、可续跑。
1. 分级重试策略
| 异常类型 | 处理方式 | 示例 |
|---|---|---|
| LLM API 限流 / 超时 | 指数退避重试 3 次 | tenacity 或 LangChain 内置 max_retries |
| 第三方服务不可用 | 降级或转人工审核 | 视频生成失败时返回占位图 + 提示 |
| Worker 进程崩溃 | 队列自动重发,幂等消费 | Celery acks_late=True |
| 数据格式错误 | 进入死信队列,人工处理 | JSON 解析失败 |
LangChain 调用模型时建议统一封装:
from tenacity import retry, stop_after_attempt, wait_exponential
@retry(stop=stop_after_attempt(3), wait=wait_exponential(multiplier=1, min=2, max=10))
def invoke_with_retry(chain, inputs):
return chain.invoke(inputs)2. 幂等性设计
同一个视频生成任务可能因为网络超时被重复投递。给每个任务分配唯一 task_id,在数据库里记录 PENDING → PROCESSING → SUCCESS/FAILURE 状态。Worker 消费前先看状态,避免重复执行。
def process_video_task(task_id: str, inputs: dict):
if db.get_status(task_id) in ("SUCCESS", "PROCESSING"):
return db.get_result(task_id)
db.set_status(task_id, "PROCESSING")
try:
result = video_chain.invoke(inputs)
db.set_status(task_id, "SUCCESS", result=result)
return result
except Exception as e:
db.set_status(task_id, "FAILURE", error=str(e))
raise3. 死信队列(DLQ)
重试仍然失败的任务进入死信队列,由告警系统通知运维或产品人员处理。DLQ 里的任务可以手动重跑、补数据或退款。
4. 状态快照与断点续跑
结合 LangGraph 的 checkpointer,每个节点执行完后自动保存状态。Worker 重启后,可以根据 thread_id 恢复到最近的 checkpoint:
config = {"configurable": {"thread_id": task_id}}
# 首次执行
graph.invoke(initial_state, config=config)
# Worker 重启后继续执行
state = graph.get_state(config)
graph.invoke(None, config=config) # 从 checkpoint 继续七、如何实现高并发
AI 视频生成场景的高并发,核心矛盾是:LLM API 调用有速率限制,但用户请求可能突增。不能简单堆机器,需要把 IO 等待和计算分离。
1. 异步调用释放线程
LangChain 支持 ainvoke、abatch、astream,配合 asyncio 可以大幅提升吞吐:
import asyncio
async def batch_generate(tasks):
results = await script_chain.abatch(tasks)
return results
# 并发处理 20 个脚本生成请求
tasks = [{"topic": t, "duration": 30} for t in topic_list]
results = asyncio.run(batch_generate(tasks))注意:底层 HTTP 客户端(如 httpx)需要配置连接池,避免每次请求新建连接。
2. 流式响应降低首字节延迟
对于长文本生成,使用 astream 把结果逐步返回给用户,避免长时间阻塞:
async for chunk in chain.astream({"topic": "LangChain 高并发"}):
print(chunk, end="", flush=True)3. 限流与背压
- 模型侧限流:根据 OpenAI/Claude 的 RPM/TPM 限制,用令牌桶算法控制请求速率。
- 队列侧背压:当队列堆积超过阈值时,API 网关返回
429 Too Many Requests,保护下游 Worker。
import asyncio
from asyncio import Semaphore
sem = Semaphore(10) # 同时最多 10 个 LLM 调用
async def limited_invoke(inputs):
async with sem:
return await chain.ainvoke(inputs)4. 缓存常用结果
很多提示词是重复的(比如热门模板、常见分镜描述)。可以用 Redis 缓存 prompt_hash → result,命中时直接返回,不走 LLM:
import hashlib
def get_cache_key(inputs: dict) -> str:
return hashlib.sha256(json.dumps(inputs, sort_keys=True).encode()).hexdigest()
key = get_cache_key(inputs)
if cached := redis.get(key):
return json.loads(cached)
result = chain.invoke(inputs)
redis.setex(key, 3600, json.dumps(result))5. 水平扩展与资源隔离
- CPU 密集型步骤(如 FFmpeg 渲染、图片后处理)放到独立 Worker 池,避免阻塞 LLM 推理线程。
- GPU 密集型步骤(如文生视频)单独部署 GPU 节点,通过队列按需调度。
- API 网关层用 Nginx/Envoy 做负载均衡,无状态 LangChain 服务可以快速扩容。
八、学完这门课的几点体会
- 不要神化 LangChain:它本质是高阶胶水,帮你少写重复代码,但不会让模型变得更聪明。复杂的业务逻辑仍然需要自己设计。
- 优先用 LCEL:新项目中尽量用
Runnable+|组合链,比旧的LLMChain、SequentialChain更灵活、更易调试。 - 结构化输出是工程关键:视频、电商、客服等场景都需要把 LLM 输出转成 JSON,PydanticOutputParser 是必备技能。
- Agent 不是银弹:固定流程用 Chain,动态决策才用 Agent。Agent 调试成本高,要配合观察日志和工具描述优化。
九、参考资源
- 吴恩达 & Harrison Chase 官方课程:LangChain for LLM Application Development
- 中文笔记与代码:awesome-LangChain-for-LLM-Application-Development
- 我之前的相关笔记:LangGraph 入门:给传统工程师的 Agent 状态与编排指南
这篇文章把吴恩达课程的核心内容和我自己在 AI 视频生成项目里的经验做了结合。如果你也在用 LangChain 做视频、口播剪辑或 Agent 工作流,欢迎留言交流。