Crawl4AI 自适应爬虫实战:统计与嵌入双策略、参数调优与知识库持久化
本文基于 Crawl4AI 仓库中 docs/examples/adaptive_crawling/ 目录下的完整示例集,系统讲解 Adaptive Crawling(自适应抓取)的两种核心策略(statistical / embedding)的使用方法、全部可调参数与默认值、策略选型依据、状态持久化与断点续爬、自定义评分策略,以及知识库的 JSONL 导出/导入/合并,并结合 crawl4ai/adaptive_crawler.py 源码印证各参数的底层实现,帮助读者从“会调用 digest()”进阶到“会调参、会定制、会复用知识库”。
一、什么是自适应抓取
Crawl4AI 的自适应爬虫(AdaptiveCrawler)解决的核心问题是:抓取多少页面才算“够”,以及如何用最少的页面拿到最相关的信息。它不是一次性的单页抓取,也不是无边界的深度爬虫,而是一个带“信息觅食(information foraging)”机制的循环:
- 从起始 URL 出发,抓取页面并沉淀到内部知识库(knowledge base);
- 对每个候选链接按“预期信息增益”打分排序,每页只跟进 Top-K 链接;
- 每爬一批页面就重算一个 0~1 的置信度(confidence),融合覆盖率、一致性与饱和曲线;
- 置信度达到阈值、增益低于最小阈值或触发不相关判定后立即停止。
这套机制的数学框架见仓库根目录的 PROGRESSIVE_CRAWLING.md,官方核心文档见 docs/md_v2/core/adaptive-crawling.md,API 参考见 docs/md_v2/api/digest.md。
从源码结构看(crawl4ai/adaptive_crawler.py),整个模块由四部分构成:
| 组件 | 位置 | 职责 |
|---|---|---|
CrawlState |
crawl4ai/adaptive_crawler.py#L27-L150 | 追踪已爬 URL、知识库、待爬链接、词频/文档频率、嵌入向量与语义缺口,并支持 save()/load() 持久化 |
AdaptiveConfig |
crawl4ai/adaptive_crawler.py#L153-L274 | 所有可调参数的 dataclass,内置 validate() 校验权重和等约束 |
CrawlStrategy(ABC) |
crawl4ai/adaptive_crawler.py#L277-L298 | 抽象策略基类,定义 calculate_confidence / rank_links / should_stop / update_state 四个钩子 |
StatisticalStrategy / EmbeddingStrategy |
crawl4ai/adaptive_crawler.py#L301、#L615 | 两套内置策略的具体实现 |
AdaptiveCrawler |
crawl4ai/adaptive_crawler.py#L1292 | 对外入口:digest() 主循环、print_stats()、export/import_knowledge_base()、get_relevant_content() |
示例目录(docs/examples/adaptive_crawling/)共覆盖 7 个官方示例加 1 个补充示例:
| 示例文件 | 演示内容 |
|---|---|
| basic_usage.py | 最简单的自适应抓取:默认统计策略、查看统计、获取最相关内容 |
| embedding_strategy.py | 嵌入策略:查询扩展、无关查询检测、语义缺口分析 |
| embedding_vs_statistical.py | 两种策略在同一组查询上的正面对比(页数、耗时、置信度) |
| embedding_configuration.py | 嵌入策略的 6 种典型调参方案 + 参数调整指南 |
| advanced_configuration.py | 置信度阈值调优、状态持久化/断点续爬、链接选择策略、进度监控 |
| custom_strategies.py | 自定义评分策略(API 文档、学术论文、混合策略、性能优化) |
| export_import_kb.py | 知识库 JSONL 导出、分析、导入续爬、跨项目合并 |
| llm_config_example.py | 用 LLMConfig 对象(而非 dict)配置 OpenAI 嵌入 |
二、快速上手:统计策略(默认)
安装 Crawl4AI 后,最小可用示例如下(完整代码见 basic_usage.py):
python docs/examples/adaptive_crawling/basic_usage.py
import asyncio
from crawl4ai import AsyncWebCrawler, AdaptiveCrawler
async def main():
# 初始化底层爬虫
async with AsyncWebCrawler(verbose=True) as crawler:
# 默认使用 statistical 策略,无需传 config
adaptive = AdaptiveCrawler(crawler)
# 可选:改用嵌入策略
# from crawl4ai import AdaptiveConfig
# config = AdaptiveConfig(strategy="embedding")
# adaptive = AdaptiveCrawler(crawler, config)
# 开始自适应抓取
result = await adaptive.digest(
start_url="https://docs.python.org/3/library/asyncio.html",
query="async await context managers coroutines"
)
# 1) 打印抓取统计
adaptive.print_stats(detailed=False)
# 2) 获取最相关页面(top_k 控制数量)
for i, page in enumerate(adaptive.get_relevant_content(top_k=5), 1):
print(f"{i}. {page['url']} score={page['score']:.2%}")
# 3) 信息充分性判断
print(f"Final Confidence: {adaptive.confidence:.2%}")
print(f"Total Pages Crawled: {len(result.crawled_urls)}")
print(f"Knowledge Base Size: {len(adaptive.state.knowledge_base)} documents")
if adaptive.confidence >= 0.8:
print("High confidence - can answer detailed questions")
elif adaptive.confidence >= 0.6:
print("Moderate confidence - can answer basic questions")
else:
print("Low confidence - need more information")
asyncio.run(main())
关键 API 与源码对应关系:
AdaptiveCrawler(crawler, config=None):第二参数可选,不传即用源码中的默认AdaptiveConfig;await adaptive.digest(start_url, query):主入口(crawl4ai/adaptive_crawler.py#L1330),内部按“预取起始页 → 链接预览打分 → 批量抓取 → 更新状态 → 判断停止”循环推进,返回携带crawled_urls、expanded_queries、semantic_gaps、kb_embeddings、metrics等字段的结果对象;adaptive.confidence/adaptive.is_sufficient/adaptive.coverage_stats:均为属性(#L1531-L1570),分别返回当前置信度、是否达到confidence_threshold、以及覆盖/一致/饱和三项明细;adaptive.state:即CrawlState,可直接读取knowledge_base、crawled_urls等内部状态。
统计策略的置信度公式。源码中 StatisticalStrategy.calculate_confidence 将置信度定义为三项加权(crawl4ai/adaptive_crawler.py#L309-L326):
confidence = 0.4 × coverage + 0.3 × consistency + 0.3 × saturation
其中 coverage 衡量查询词在知识库中的覆盖程度,consistency 衡量跨文档一致性,saturation 基于 new_terms_history 判断“新词发现速度是否衰减”(即信息增益趋于饱和)。链接排序则使用 BM25 相关实现(bm25_k1=1.2、bm25_b=0.75,见 #L304-L307),相关性/新颖性/权威性权重默认 0.5/0.3/0.2。整个策略不依赖 LLM 与嵌入模型,因此快且零外部依赖——这也是 README 把它作为默认策略的原因。
三、嵌入策略:语义理解、查询扩展与无关查询检测
当查询是概念性、模糊性表述(如 “concurrent programming patterns”)而非精确 API 名时,统计策略的关键词匹配会失准。嵌入策略把查询和页面都映射到向量空间,用相似度而非词面命中来判断相关性。完整示例见 embedding_strategy.py:
import asyncio, os
from crawl4ai import AsyncWebCrawler, AdaptiveCrawler, AdaptiveConfig
async def main():
config = AdaptiveConfig(
strategy="embedding", # 切换到嵌入策略
embedding_model="sentence-transformers/all-MiniLM-L6-v2", # 默认本地模型
n_query_variations=10, # 查询语义扩展数量
max_pages=15,
top_k_links=3,
min_gain_threshold=0.05,
embedding_k_exp=3.0, # 越高要求相似度越严
embedding_min_confidence_threshold=0.1, # 低于该值判定“完全不相关”即停
embedding_validation_min_score=0.4, # 验证收敛的最低分数
)
# 可选:改用 OpenAI 嵌入(需要环境变量)
if os.getenv('OPENAI_API_KEY'):
config.embedding_llm_config = {
'provider': 'openai/text-embedding-3-small',
'api_token': os.getenv('OPENAI_API_KEY')
}
async with AsyncWebCrawler(verbose=True) as crawler:
adaptive = AdaptiveCrawler(crawler, config)
# TEST 1: 语义查询理解(查询被扩展成 n_query_variations 个变体)
result = await adaptive.digest(
start_url="https://docs.python.org/3/library/asyncio.html",
query="concurrent programming event-driven architecture"
)
print(f"Original query expanded to {len(result.expanded_queries)} variations")
# TEST 2: 无关查询检测——在 asyncio 文档上问“怎么做巧克力曲奇”
adaptive = AdaptiveCrawler(crawler, config) # 每个查询用全新实例
result = await adaptive.digest(
start_url="https://docs.python.org/3/library/asyncio.html",
query="how to bake chocolate chip cookies"
)
if result.metrics.get('is_irrelevant', False):
print(f"Stopped after just {len(result.crawled_urls)} pages")
print(f"Reason: {result.metrics.get('stopped_reason', 'unknown')}")
# TEST 3: 语义缺口分析
adaptive = AdaptiveCrawler(crawler, config)
result = await adaptive.digest(
start_url="https://realpython.com",
query="python decorators advanced patterns"
)
print(f"Semantic gaps: {len(result.semantic_gaps)}")
print(f"KB embeddings shape: {result.kb_embeddings.shape if result.kb_embeddings is not None else 'None'}")
print(f"avg_best_similarity: {result.metrics.get('avg_best_similarity', 0):.3f}")
print(f"coverage_score: {result.metrics.get('coverage_score', 0):.3f}")
print(f"validation_confidence: {result.metrics.get('validation_confidence', 0):.2%}")
asyncio.run(main())
运行 python docs/examples/adaptive_crawling/embedding_strategy.py 即可复现。三个演示分别验证嵌入策略的三大能力:
- 查询扩展:
map_query_semantic_space()会生成n_query_variations个语义变体(crawl4ai/adaptive_crawler.py#L726),用一组点表示查询的“语义空间”,而不是只依赖原始句子; - 无关查询检测:若最佳相似度低于
embedding_min_confidence_threshold(默认 0.1),策略判定查询与站点内容不相关并提前停止,result.metrics['is_irrelevant']置为 True,避免把预算浪费在注定无果的抓取上; - 语义缺口(semantic gaps):
find_coverage_gaps()基于查询点集与知识库嵌入的距离矩阵,找出“查询想要但知识库还没有”的区域(#L841),并可用 alpha shape 计算覆盖包络(compute_coverage_shape,#L804)。
嵌入模型来源有两条路径:
- 本地模型:默认
embedding_model="sentence-transformers/all-MiniLM-L6-v2"(见AdaptiveConfig定义,#L180),需要安装sentence-transformers; - API 模型:通过
embedding_llm_config传入 dict 或LLMConfig对象,如'provider': 'openai/text-embedding-3-small'。仓库中还提供了一个使用LLMConfig对象的完整写法 llm_config_example.py:
from crawl4ai import LLMConfig
openai_llm_config = LLMConfig(
provider='openai/text-embedding-3-small',
api_token=os.getenv('OPENAI_API_KEY'),
temperature=0.7,
max_tokens=2000
)
config = AdaptiveConfig(
strategy="embedding",
max_pages=10,
embedding_llm_config=openai_llm_config, # 支持 LLMConfig 实例
embedding_k_exp=4.0,
n_query_variations=12
)
四、策略选型:统计 vs 嵌入的正面对比
embedding_vs_statistical.py 用同一组 AdaptiveConfig(max_pages=20, top_k_links=3, min_gain_threshold=0.05)在三类查询上分别跑两种策略,并输出页数、耗时、置信度、词面覆盖率与语义缺口数的量化对比:
test_cases = [
{ # 精确技术词:统计策略的主场
'url': 'https://docs.python.org/3/library/asyncio.html',
'query': 'asyncio.create_task event_loop.run_until_complete'
},
{ # 概念性查询:需要语义理解
'url': 'https://docs.python.org/3/library/asyncio.html',
'query': 'concurrent programming patterns'
},
{ # 模糊查询
'url': 'https://realpython.com',
'query': 'python performance optimization'
},
]
对比维度包括:crawled_urls 数量差异(谁用更少页面达标)、耗时倍率、置信度差值,以及嵌入策略特有的 expanded_queries 数量与 semantic_gaps 数量;统计策略还可检查 result.term_frequencies 计算“查询词命中率”。
官方 README 给出的选型速查表(与示例脚本结尾打印的结论一致):
使用统计策略(默认)的场景
- 抓取对象是技术文档、结构良好的站点;
- 查询包含具体术语或代码(函数名、API 名);
- 速度优先,预算敏感;
- 环境无 LLM/嵌入 API 访问条件(纯本地、零额外依赖)。
使用嵌入策略的场景
- 查询是概念性或模糊表述(如 “performance optimization”);
- 需要超越精确匹配的语义理解;
- 需要自动识别无关内容并尽早止损;
- 内容来源多样、措辞与查询词汇差异大。
运行 python docs/examples/adaptive_crawling/embedding_vs_statistical.py 即可在你的目标站点上复现这类 A/B 对比,把“选哪种策略”从经验判断变成数据判断。
五、参数调优指南:嵌入策略的 6 种典型配置
embedding_configuration.py 给出了面向不同目标的 6 组配置,全部参数均可在 AdaptiveConfig 中找到(定义与校验逻辑见 crawl4ai/adaptive_crawler.py#L153-L256):
# 1. 严格覆盖(研究/学术场景):宁可多爬,也要覆盖全面
config_strict = AdaptiveConfig(
strategy="embedding",
max_pages=20,
embedding_k_exp=5.0, # 默认 1.0,越高相似度要求越严
embedding_coverage_radius=0.15, # 默认 0.2,越小“已覆盖”判定越严
embedding_validation_min_score=0.6, # 默认 0.3,验证门槛提高
n_query_variations=15, # 默认 10,更多变体提升覆盖
)
# 2. 快速探索(Quick Overview):放宽一切阈值,尽快收敛
config_fast = AdaptiveConfig(
strategy="embedding",
max_pages=10,
top_k_links=5, # 每页跟进更多链接
embedding_k_exp=1.0, # 低 k 更宽容
embedding_min_relative_improvement=0.05, # 低于默认 0.1,更早停止
embedding_quality_min_confidence=0.5, # 降低对外展示置信度的下限
embedding_quality_max_confidence=0.85,
n_query_variations=5, # 减少变体提速
)
# 3. 无关查询检测优先:激进地尽早停下
config_irrelevance = AdaptiveConfig(
strategy="embedding",
max_pages=5,
embedding_min_confidence_threshold=0.2, # 高于默认 0.1,更敏感的无关判定
embedding_k_exp=5.0,
embedding_min_relative_improvement=0.15, # 改进缓慢即停
)
# 4. 高质量知识库:重去重、重验证
config_quality = AdaptiveConfig(
strategy="embedding",
max_pages=30,
embedding_overlap_threshold=0.75, # 低于默认 0.85,更激进去重
embedding_validation_min_score=0.5,
embedding_quality_scale_factor=1.0, # 线性质量映射
embedding_k_exp=3.0,
embedding_nearest_weight=0.8, # 更聚焦最佳匹配
embedding_top_k_weight=0.2, # 与上一项之和必须为 1(validate 强制)
)
# 5. OpenAI 嵌入:模型质量更高,可配合更严参数
config_openai = AdaptiveConfig(
strategy="embedding",
max_pages=10,
embedding_llm_config={
'provider': 'openai/text-embedding-3-small',
'api_token': os.getenv('OPENAI_API_KEY')
},
embedding_k_exp=4.0,
n_query_variations=12
)
每组配置跑完后脚本打印 Pages crawled / Final confidence / Stopped reason,若命中无关判定还会打印 ⚠️ Query detected as irrelevant!。
关键参数速查表(示例文件注释 + AdaptiveConfig 源码默认值合并;注意示例注释中个别“默认值”以源码 dataclass 为准):
| 参数 | 源码默认值 | 调大/调小的效果 |
|---|---|---|
embedding_k_exp |
1.0(#L196) | 指数衰减因子,相似度映射为 score = exp(-k_exp × distance)。1~2 更宽容、收敛更快;4~5 更严格、精确度更高 |
embedding_coverage_radius |
0.2 | 查询点被判定“已覆盖”的距离半径;0.1~0.15 要求更近匹配,0.25~0.3 接受更宽泛匹配 |
n_query_variations |
10 | 查询语义变体数量;5~7 快但覆盖弱,15~20 覆盖好但更慢 |
embedding_min_confidence_threshold |
0.1 | 无关判定阈值;0.15~0.2 激进止损,0.05 则几乎不判无关 |
embedding_validation_min_score |
0.3 | 收敛验证门槛;0.5~0.6 要求强验证,0.2 允许更早停 |
embedding_min_relative_improvement |
0.1 | 每批最小相对改进,越小越“耐心”,越大越早停 |
embedding_overlap_threshold |
0.85 | 与知识库相似度过高的链接会被降权去重;调低更激进 |
embedding_nearest_weight / embedding_top_k_weight |
0.7 / 0.3 | 混合打分权重(最近邻 vs Top-K 均值),validate() 强制两者之和为 1 |
embedding_quality_min/max_confidence / scale_factor |
0.7 / 0.95 / 0.833 | 内部控制分到“用户可见置信度”的映射,只影响展示口径 |
link_preview_timeout |
5.0 秒 | 链接预览抓取超时,影响打分质量与速度的平衡 |
调参经验(来自示例脚本末尾的 Parameter Tuning Guide):
- 研究类任务:高
k_exp、更多变体、严格验证; - 探索类任务:低
k_exp、少变体、放松阈值; - 质量优先:重点调
overlap_threshold与验证分数; - 速度优先:减少变体数、提高
min_relative_improvement。
六、高级配置:阈值、断点续爬与链接选择策略
advanced_configuration.py 演示了四个进阶主题,对两种策略均适用(其参数来自 AdaptiveConfig 的通用部分,#L153-L177)。
6.1 置信度阈值三档配置
confidence_threshold 决定“何时认为信息足够”,默认 0.7;min_gain_threshold 控制“继续爬取的最低信息增益”,默认 0.1:
# 高精度(穷尽式抓取):高置信度要求 + 放宽增益门槛
high_precision_config = AdaptiveConfig(
confidence_threshold=0.9,
max_pages=50,
top_k_links=5,
min_gain_threshold=0.02 # 增益再低也继续,直到置信度拉满
)
# 均衡(默认场景)
balanced_config = AdaptiveConfig(
confidence_threshold=0.7,
max_pages=20,
top_k_links=3,
min_gain_threshold=0.05
)
# 快速探索:低置信度即可 + 严格页数上限
quick_config = AdaptiveConfig(
confidence_threshold=0.5,
max_pages=10,
top_k_links=2,
min_gain_threshold=0.1
)
对比运行时可同时观察 len(result.crawled_urls)、adaptive.confidence 与 adaptive.coverage_stats['coverage'] 三个指标,验证“阈值—页数—置信度”之间的权衡关系。
6.2 状态持久化与断点续爬
AdaptiveConfig 内置 save_state / state_path 两项持久化参数(默认 save_state=False)。底层由 CrawlState.save()/load() 实现 JSON 序列化,包括词频表、待爬链接、以及嵌入向量(numpy 数组转 list 存储,#L53-L110)。示例流程是“先以 max_pages=5 人为模拟中断,再用 resume_from 从存档继续”:
state_file = "crawl_state_demo.json"
# 第一阶段:受限页面数,模拟中断
interrupt_config = AdaptiveConfig(
confidence_threshold=0.8,
max_pages=5,
save_state=True,
state_path=state_file
)
adaptive = AdaptiveCrawler(crawler, config=interrupt_config)
result1 = await adaptive.digest(
start_url="https://docs.python.org/3/",
query="exception handling try except finally"
)
# 第二阶段:从存档恢复,提高页数上限继续爬
resume_config = AdaptiveConfig(
confidence_threshold=0.8,
max_pages=20,
save_state=True,
state_path=state_file
)
adaptive2 = AdaptiveCrawler(crawler, config=resume_config)
result2 = await adaptive2.digest(
start_url="https://docs.python.org/3/",
query="exception handling try except finally",
resume_from=state_file # 关键参数:加载已爬 URL 与知识库
)
digest() 的 resume_from 参数在 crawl4ai/adaptive_crawler.py#L1330 的签名中,加载后会跳过 crawled_urls 中已存在的链接,直接基于既有知识库继续增益计算。相关测试可参考 tests/adaptive/test_adaptive_crawler.py。
6.3 链接选择策略:保守 vs 激进
top_k_links(每页跟进链接数)与 min_gain_threshold 的组合刻画了爬虫的“分支风格”:
conservative_config = AdaptiveConfig(
confidence_threshold=0.7,
max_pages=15,
top_k_links=1, # 每页只跟最优链接 → 深而窄
min_gain_threshold=0.15 # 高增益门槛
)
aggressive_config = AdaptiveConfig(
confidence_threshold=0.7,
max_pages=15,
top_k_links=10, # 每页跟 10 个链接 → 宽而浅
min_gain_threshold=0.01
)
脚本会统计两种模式下的总页数、唯一域名数、最大深度,以及 new_terms_history 的饱和趋势(新词发现数递减即趋于饱和),帮助你按站点结构选择分支策略。
6.4 进度监控与知识导出
result = await adaptive.digest(
start_url="https://httpbin.org",
query="http methods headers"
)
adaptive.print_stats(detailed=True) # 完整统计
adaptive.export_knowledge_base("knowledge_export_demo.jsonl") # 导出 JSONL
print_stats(detailed=True) 输出覆盖/一致/饱和明细与历史曲线(实现见 #L1570);export_knowledge_base() 将知识库逐行写为 JSONL(#L1781)。
七、自定义策略:领域评分与混合打分
内置策略是通用实现;针对特定领域(API 文档、学术论文等),可以按 custom_strategies.py 的思路写领域评分类。该示例定义了三个层次的定制方式:
7.1 链接级评分:API 文档策略
from crawl4ai.adaptive_crawler import CrawlState, Link
class APIDocumentationStrategy:
def __init__(self):
self.api_keywords = {'endpoint', 'request', 'response', 'parameter',
'authentication', 'header', 'curl', 'python', ...}
self.valuable_patterns = [r'/api/', r'/reference/', r'/endpoints?/', ...]
self.avoid_patterns = [r'/blog/', r'/news/', r'/about/', ...]
def score_link(self, link: Link, query: str, state: CrawlState) -> float:
score = 1.0
url = link.href.lower()
if any(re.search(p, url) for p in self.valuable_patterns):
score *= 2.0 # API 路径加权
if any(re.search(p, url) for p in self.avoid_patterns):
score *= 0.1 # 博客/新闻降权
if link.text:
kw_count = sum(1 for kw in self.api_keywords
if kw in link.text.lower())
score *= (1 + kw_count * 0.2) # 锚文本关键词加成
depth = url.count('/') - 2
if depth <= 3: score *= 1.5 # 浅层 URL 多为概览页
elif depth > 6: score *= 0.5
return score
接入方式是 monkey-patch AdaptiveCrawler._rank_links:
original_rank_links = adaptive._rank_links
def custom_rank_links(links, query, state):
scored = [(link, api_strategy.score_link(link, query, state)) for link in links]
scored.sort(key=lambda x: x[1], reverse=True)
return [link for link, _ in scored[:config.top_k_links]]
adaptive._rank_links = custom_rank_links
策略类还提供 calculate_api_coverage(),基于正则(GET /、curl -、params: 等模式)统计知识库中 endpoint/example/parameter 三类内容的覆盖率,得到领域化的“知识完备度”指标。
7.2 内容级评分与混合策略
ResearchPaperStrategy.calculate_academic_relevance() 演示了内容级打分:学术关键词命中、引用密度([1]、(Author 2024)、doi: 模式)、查询词与摘要/结论区段的共现,最终得分截断在 2.0。HybridStrategy 则展示如何按权重组合多个策略(API 0.7 + 研究 0.3),对 get_relevant_content(top_k=5) 返回的每篇文档做加权评分。
7.3 性能优化策略
PerformanceOptimizedStrategy 演示了两个实用技巧:域名级限额(单域超过 5 页即跳过)与域名移动平均评分(低于 0.3 的域不再访问),并输出 pages/sec 与“每页置信度贡献”(confidence / pages)两个效率指标,用于评估策略的实际吞吐。
需要说明的是:CrawlStrategy 抽象基类(calculate_confidence / rank_links / should_stop / update_state,#L277-L298)是策略扩展的“正规”入口,示例采用 patch 方式是为了演示轻量定制;若需长期维护的自定义策略,从源码结构看更稳妥的做法是继承 CrawlStrategy 并覆盖四个钩子方法。
八、知识库的导出、分析与跨项目合并
export_import_kb.py 展示了知识库作为可复用资产的完整生命周期,分四个阶段:
阶段 1:构建知识库
对同一 AdaptiveCrawler 实例连续调用两次 digest()(不同起始页、不同查询),知识在 state.knowledge_base 中累积:
adaptive = AdaptiveCrawler(crawler)
await adaptive.digest(start_url="https://httpbin.org",
query="http methods headers status codes")
await adaptive.digest(start_url="https://httpbin.org/anything",
query="rest api json response request")
adaptive.export_knowledge_base("web_tech_knowledge.jsonl")
阶段 2:离线分析 JSONL
导出文件为 JSONL,每行一篇文档,包含 url、content(markdown)、links、query、metadata 等字段(序列化逻辑见 AdaptiveCrawler._crawl_result_to_export_dict,crawl4ai/adaptive_crawler.py#L1808)。可用标准 JSON 解析直接做统计:
documents = [json.loads(line) for line in open(kb_path)]
# 统计总字符数、平均每文档长度、按域名分布
阶段 3:导入续爬
在新实例上 import_knowledge_base() 后,已导入的 URL 自动进入 crawled_urls(后续 digest 会跳过),知识库文档参与增益计算:
adaptive = AdaptiveCrawler(crawler)
await adaptive.import_knowledge_base("web_tech_knowledge.jsonl")
print(f"Imported {len(adaptive.state.knowledge_base)} documents")
# 用新查询继续扩展
await adaptive.digest(
start_url="https://httpbin.org/status/200",
query="error handling retry timeout"
)
adaptive.export_knowledge_base("web_tech_knowledge_extended.jsonl")
阶段 4:跨项目合并
两个独立项目分别导出各自的知识库后,在第三个实例上依次 import_knowledge_base(project_a_kb)、import_knowledge_base(project_b_kb),即可得到合并知识库并再次导出,实现知识资产的共享与复用。示例的 finally 块统一清理了生成的 .jsonl 文件。
九、环境要求与延伸阅读
按示例目录 README 的 Requirements 一节,运行环境要求为:
- 已安装 Crawl4AI(
AsyncWebCrawler依赖 Playwright,首次使用需安装浏览器); - 嵌入策略 + 本地模型:需要
sentence-transformers; - 嵌入策略 + OpenAI:设置
OPENAI_API_KEY环境变量。
全部示例均可直接运行:
python docs/examples/adaptive_crawling/basic_usage.py
python docs/examples/adaptive_crawling/embedding_strategy.py
python docs/examples/adaptive_crawling/embedding_vs_statistical.py
延伸阅读与验证资源:
- 核心文档:docs/md_v2/core/adaptive-crawling.md
- 数学框架:PROGRESSIVE_CRAWLING.md
digest()API 参考:docs/md_v2/api/digest.md- 实现源码:crawl4ai/adaptive_crawler.py
- 测试用例(置信度调试、嵌入策略性能、LLM 嵌入配置等):tests/adaptive/test_adaptive_crawler.py、tests/adaptive/test_confidence_debug.py、tests/adaptive/test_embedding_strategy.py
十、小结
| 场景 | 推荐策略 | 关键参数 |
|---|---|---|
| 技术文档 + 精确术语 + 速度优先 | statistical(默认,零额外依赖) | confidence_threshold、min_gain_threshold、top_k_links |
| 概念性/模糊查询、需语义理解 | embedding + 本地 sentence-transformers | n_query_variations、embedding_k_exp、embedding_coverage_radius |
| 需自动止损无关查询 | embedding | embedding_min_confidence_threshold 调高至 0.15~0.2 |
| 研究级完备知识库 | embedding + 严格验证 | 高 k_exp、高 validation_min_score、低 overlap_threshold |
| 任务中断/预算恢复 | 任意 + 持久化 | save_state=True、state_path、digest(resume_from=...) |
| 领域定制(API/学术站点) | 自定义评分 | 继承 CrawlStrategy 或 patch _rank_links |
自适应抓取的价值在于把“爬多少、往哪爬、何时停”从人工经验变成可配置、可量化、可恢复的算法决策:统计策略以 BM25 词频模型保证速度与零依赖,嵌入策略以向量空间覆盖与缺口分析换取语义鲁棒性,而 AdaptiveConfig 中每一项阈值都能在源码的 validate() 约束下被精确控制。掌握本文的示例路径与参数表后,你可以直接在自己的目标站点上复现对比实验,并按第九节的资源继续深入。
atomcodeClaude Code 的开源替代方案。连接任意大模型,编辑代码,运行命令,自动验证 — 全自动执行。用 Rust 构建,极致性能。 | An open-source alternative to Claude Code. Connect any LLM, edit code, run commands, and verify changes — autonomously. Built in Rust for speed. Get StartedRust0623
Hy4-previewHy4 preview 是由腾讯混元团队研发的新一代混合专家(MoE)旗舰模型。模型总参数量 770B,每个 token 激活 49B,主干共包含78层,第一层采用标准 FFN,其余 77 层均为 MoE 结构,每层包含 256 个路由专家与 1 个共享专家,每个 token 激活 top-8 路由专家及共享专家。主干之外原生内置 1 层 MTP(总参数量 10B,激活 0.7B)以支持投机解码。Python00
GLM-5.3GLM-5.3 与 GLM-5.2 使用相同的基座模型——所有提升均来自后训练。与 GLM-5.2 相比,它在复杂编程和长程任务上的表现显著提升。Jinja00
GLM-5.3-FlashGLM-5.3-Flash (320B-A18B),是GLM-5系列的首个原生多模态模型。320B总参数,能力超过GLM-5.2Jinja00
Spark-X2.5-4BSpark-X2.5-4B 旨在让强大的 AI 更实用、更高效、更易获得。在广泛日常任务中表现强劲,涵盖对话、写作、翻译、推理、编码、工具调用以及智能体工作流,并在同等规模的开源模型中取得领先成绩。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00
Spark-X2.5-1.7BSpark-X2.5-1.7B 旨在让强大的 AI 更加实用、高效且易于获取。这些模型在广泛的日常任务中表现出色,涵盖对话、写作、翻译、推理、编程、工具调用和智能体工作流,并在同等规模的开源模型中取得领先结果。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00