问答
怎么用 YouTube 视频字幕做一个 RAG 问答机器人?
简短回答
先用 YouTube 视频搜索找到要收录的视频(每页约 20 条,$0.004),再逐个拉取带时间戳的字幕(每个视频 $0.004),按时间窗口切块后存进任意向量库。收录 200 个视频大约花 $0.84,每个回答都能链接到出处的那一秒。
一家做健身教练培训的公司,自己有 200 个长视频,都是教练在回答学员问题,另外还想收进同行里讲得最好的一批演讲。他们要的机器人是这样的:有人问大重量深蹲前怎么热身,它用两句话回答,再给一个链接,点开直接跳到某个视频的 14:32。这就是一条 RAG 流水线,只多一个讲究:时间戳要从头保留到尾,因为一个能跳到那一刻的链接,比一段总结更有用。
整体流程
- 收集视频 ID。 用 YouTube 视频搜索按主题关键词搜,或者用频道名加主题词搜。目前没有列出某个频道全部视频的接口,自己的频道可以直接从 YouTube Studio 里复制视频 ID。
- 拉字幕。 YouTube 视频字幕接收 11 位视频 ID 和可选的
lang,返回segments(开始时间、结束时间、文字)和完整的text。 - 按时间切块。 把相邻片段合并成 60 到 90 秒的窗口,每块都带上
video_id、标题和窗口的起始秒数。 - 向量化入库。 用你现成的工具就行:LlamaIndex、LangChain、pgvector、Qdrant 都可以。
- 回答带出处。 用块里的元数据拼出
https://youtu.be/<id>?t=<起始秒>,要求模型在回答里引用。
第 1 到 3 步的 Python 代码
import json, os, requests
API = "https://api.okdata.online"
H = {"Authorization": f"Bearer {os.environ['OKDATA_API_KEY']}"}
def get(path, **params):
body = requests.get(API + path, headers=H, params=params, timeout=90).json()
if body["code"] != "ok":
raise RuntimeError(f"{body['code']}: {body['message']}")
return body["data"]
videos = get("/v1/youtube/videos/search", query="squat warm up coaching",
fields="id,title,url")["items"]
with open("chunks.jsonl", "w", encoding="utf-8") as out:
for v in videos:
try:
tr = get("/v1/youtube/videos/transcript/get", id=v["id"], lang="en")["item"]
except RuntimeError as err: # 没字幕、私密、已删除:都不扣费
print("跳过", v["id"], err)
continue
window, start = [], None
for seg in tr["segments"]:
start = seg["start"] if start is None else start
window.append(seg["text"])
if seg["end"] - start >= 75:
out.write(json.dumps({"video_id": v["id"], "title": v["title"], "start": int(start),
"text": " ".join(window)}, ensure_ascii=False) + "\n")
window, start = [], None
if window:
out.write(json.dumps({"video_id": v["id"], "title": v["title"], "start": int(start),
"text": " ".join(window)}, ensure_ascii=False) + "\n")
chunks.jsonl 里的每一行都可以直接拿去做向量化。
收录要花多少
| 知识库规模 | 调用次数 | 费用 |
|---|---|---|
| 50 个视频 | 搜 3 次 + 50 份字幕 | {{cost:youtube.videos.search3+youtube.videos.transcript.get50}} |
| 200 个视频 | 搜 10 次 + 200 份字幕 | {{cost:youtube.videos.search10+youtube.videos.transcript.get200}} |
| 1,000 个视频 | 搜 50 次 + 1,000 份字幕 | {{cost:youtube.videos.search50+youtube.videos.transcript.get1000}} |
更新比新建便宜得多:每月跑一次,只给还没入库的视频 ID 拉字幕。
容易出问题的地方
- 自动生成的字幕常把人名和术语听错。在回答的提示词里放一份术语表,或者入库前先替换掉。
- 没有字幕的视频会调用失败,不扣费。这些视频如果重要,要另外对音频做转写。
- 用
lang指定你入库的语言,一个索引里混着几种语言会拖累检索效果。 - 字幕的版权属于创作者。内部用来答疑问题不大,原样转载发布就是另一回事了。
其他做法
LlamaIndex 的 YoutubeTranscriptReader 和 LangChain 的 YoutubeLoader 免费,底层都是 youtube-transcript-api。在自己电脑上跑效果不错,但在云服务器和 Serverless 环境里,它们的 issue 里有很多被封 IP、拿不到字幕的反馈。如果是你自己的频道,YouTube Studio 和 YouTube Data API 能拿到你上传过的字幕。完全没有字幕的视频,可以下载音频用 Whisper 转写,代价是下载和算力。这类需求的更多做法见视频转文字方案。
更新于