LangChain YouTube 转录文本加载器,在生产中存活

每个 LangChain YouTube 转录文本教程都显示相同的三行:YoutubeLoader.from_youtube_url()、加载、完成。然后你部署到云盒子,它无声地返回什么都没有。下面是一个从托管 API 返回适当 Document 对象的加载器——大约 20 行,加上一个摘要链来证明它逐端工作。
为什么内置 YoutubeLoader 在服务器上死亡
YoutubeLoader 不调用官方 API。它从你的代码运行的任何机器爬取 YouTube 的内部字幕端点。从住宅 IP 大多数情况下有效。从 AWS、GCP 或 Hetzner IP 它被阻止或提供空响应,因为 YouTube 将数据中心流量视为机器人流量。我在为什么 YouTube 转录文本爬取在云 IP 上破裂中写了详细细节——简版是失败是环境的,所以它通过每个本地测试并在它最重要的地方死亡。
youtube2text.org 在其一侧进行获取并给你 JSON,这将你的加载器变成一个普通的 HTTP 调用。
加载器
import requests
from langchain_core.documents import Document
API_KEY = "yt_your_key_here"
def load_youtube_transcript(url: str, max_chars: int = 150000) -> Document:
resp = requests.get(
"https://youtube2text.org/api/transcribe",
params={"url": url, "maxChars": max_chars},
headers={"x-api-key": API_KEY},
timeout=90,
)
resp.raise_for_status()
r = resp.json()["result"]
return Document(
page_content=r["content"],
metadata={
"videoId": r["videoId"],
"title": r["title"],
"pubDate": r["pubDate"],
"source": url,
},
)
API 返回 videoId、title、pubDate、content、contentSize 和一个 truncated 标志。转录文本文本进入 page_content,所有其他进入元数据——恰好是下游链和向量存储期望的形状。
还没密钥?获取共享演示密钥:
curl https://youtube2text.org/api/demo-key
它限制于每个 IP 每月 5 个视频,足够测试加载器。
一个摘要链
from langchain_openai import ChatOpenAI
from langchain_core.prompts import ChatPromptTemplate
from langchain.chains.combine_documents import create_stuff_documents_chain
llm = ChatOpenAI(model="gpt-4o-mini")
prompt = ChatPromptTemplate.from_template(
"Summarize this video transcript in five bullet points:\n\n{context}"
)
chain = create_stuff_documents_chain(llm, prompt)
doc = load_youtube_transcript("https://www.youtube.com/watch?v=dQw4w9WgXcQ")
print(chain.invoke({"context": [doc]}))
create_stuff_documents_chain 把整个转录文本塞到一个提示中,这有效因为 maxChars 默认情况下将有效载荷限制在 150,000 个字符。对于小上下文模型上的长小时播客,向加载器传递更低的 maxChars 或切换到 map-reduce 模式。
在实际代码中要处理的
两个失败模式值得显式捕获。禁用字幕的视频返回 HTTP 404,错误代码 TRANSCRIPT_UNAVAILABLE——没有重试或库交换修复那个,文本根本不存在。和 RATE_LIMIT_EXCEEDED(429)在错误 JSON 中包括 retryAfterSeconds,所以读它并退避而不是敲打:
if resp.status_code == 429:
wait = resp.json()["error"].get("retryAfterSeconds", 60)
一个诚实的限制:content 是没有时间戳的纯文本。那对摘要和检索很好,但如果你需要"跳到 12:34"深链接,你必须满足于通过元数据中的 videoId 的视频级别归因。
从这里去哪里
相同的 Document 对象直接进入向量存储——我在对整个 YouTube 频道的 RAG中走过完整管道。如果你的栈是 LlamaIndex 而不是 LangChain,等价设置一样短。
当演示密钥的 5 个视频停止足够时,获得你自己的密钥——包括免费层、付费计划从 5.99 美元月 50 个视频起。