自然语言处理入门到进阶:一个百度搜索算法工程师的血泪踩坑实录

产品说很简单
2025-12-19 06:49
阅读 823

大家好,我是阿哲,在百度干了两年搜索算法,日常和 Query 理解、意图识别、召回排序打交道。坐标杭州,最近看着阿里网易的 HC 心痒痒,但又怕自己 NLP 基础不够硬——毕竟现在大厂面试张口就是 BERT 优化、prompt engineering、RAG 架构,再不系统补一补,简历都投不出去。

去年双11期间,我们组临时接到 PM 的“神需求”:用户搜“便宜好用的蓝牙耳机”,不仅要理解“便宜”是价格敏感,“好用”是体验导向,还得把“蓝牙耳机”这个品类拆出来做结构化召回。当时我内心 OS:“这不就是个简单的实体识别+情感分析?小意思!” 结果上线第二天线上 P0 报警——模型把“便宜”误判成“贬义词”,一堆低价劣质商品被推到首页,用户投诉量暴增。那天晚上我盯着监控面板,差点想把键盘砸了。

痛定思痛,我决定从零梳理 NLP 的完整技术栈。这篇文章不是教科书式的罗列概念,而是记录我从“以为会”到“真会了”的实战路径,顺便分享一些被面试官拷打过的面试题挑战、踩过的坑、以及真正能跑起来的工具链。希望你别像我一样,等到线上事故才开始恶补。


别一上来就上 BERT!先搞懂你的问题到底是什么

很多新人(包括半年前的我)有个误区:NLP = 深度学习 = Transformer。结果呢?用 BERT 做一个 100 行规则就能搞定的关键词匹配,GPU 跑得冒烟,QPS 还不到 50。

在百度,我们有个铁律:能用规则解决的,绝不调模型;能用传统 ML 解决的,绝不碰大模型。为什么?因为搜索场景对延迟极度敏感,用户等不及你加载 300MB 的模型。

所以第一步:明确任务类型。我整理了一个快速自查表:

任务类型 典型场景 推荐起步方案
文本分类 意图识别、情感分析 TF-IDF + SVM / FastText
序列标注 NER、分词 BiLSTM-CRF / spaCy 规则
匹配/相似度 Query-Title 相关性 BM25 / Sentence-BERT
生成 摘要、改写 T5 / ChatGLM 微调

比如我们那个“便宜好用”需求,其实是个典型的方面级情感分析(Aspect-based Sentiment Analysis)。初期根本不用上 BERT,用 spaCy 提取名词短语(aspect),再用 TextBlob 计算形容词极性,准确率就能到 80%。剩下的 20% 再交给模型 fine-tune。


工具链选型:别重复造轮子,但也别无脑套用

作为爱看源码的人,我特别反感那种“pip install transformers 就完事”的教程。真实场景中,工具的选择直接决定你能不能活到下班。

数据预处理:spaCy vs Stanza vs LTP

中文 NLP 第一关永远是分词。百度内部用自研分词器,但开源项目我试过三家:

  • spaCy:英文无敌,中文靠 jieba 插件,效果一般
  • Stanza(Stanford):准确率高,但慢得像乌龟,不适合线上
  • LTP(哈工大):中文专精,支持 POS/NER/依存句法,我的首选
from ltp import LTP
ltp = LTP()
seg, hidden = ltp.seg(["便宜好用的蓝牙耳机"])
pos = ltp.pos(hidden)
ner = ltp.ner(hidden)

# 输出:
# seg: [['便宜', '好用', '的', '蓝牙', '耳机']]
# pos: [['a', 'a', 'u', 'n', 'n']]  # 形容词、形容词、助词、名词、名词
# ner: [[(3, 4, 'Product')]]       # 识别出“蓝牙耳机”为产品实体

注意:LTP 默认模型对电商术语覆盖不足,我们后来用内部数据微调了词向量,F1 提升了 7 个点。

模型训练:HuggingFace 是神器,但别乱用

说到 HuggingFace,它确实是 NLP 工程师的瑞士军刀。但上周五我同事就翻车了:直接用 AutoModel.from_pretrained("bert-base-chinese") 做分类,结果 OOM(Out of Memory)炸了测试机。

血泪经验

  1. 中文任务优先用 hfl/chinese-bert-wwm-ext(哈工大 & 讯飞联合发布),比原生 BERT 中文效果好太多
  2. batch_size 别贪大,线上服务建议 ≤ 16
  3. 一定要加 gradient checkpointing 省显存
from transformers import BertTokenizer, BertForSequenceClassification, TrainingArguments, Trainer

model = BertForSequenceClassification.from_pretrained(
    "hfl/chinese-bert-wwm-ext",
    num_labels=3,  # 例如:正面/中性/负面
    gradient_checkpointing=True  # 关键!省 40% 显存
)
tokenizer = BertTokenizer.from_pretrained("hfl/chinese-bert-wwm-ext")

面试题挑战:那些让我冷汗直流的问题

最近刷面试题,发现大厂对 NLP 的考察越来越“工程化”。分享几个真实被问到的:

Q1:如何优化 BERT 的推理速度?

A:别只答“蒸馏”!要结合场景:

  • 如果是 CPU 部署:ONNX + Quantization(INT8 量化)
  • 如果是 GPU:TensorRT 加速 + 动态 batching
  • 如果延迟要求 < 10ms:考虑 DistilBERT 或 TinyBERT

Q2:线上 NER 模型突然掉点,怎么排查?

A:别一上来就说“数据分布变了”!按优先级查:

  1. 输入文本是否含特殊符号/emoji(LTP 可能崩)
  2. 是否有新类目上线(如“元宇宙耳机”未覆盖)
  3. 模型版本是否被误回滚(运维背锅现场)

Q3:如何评估一个文本相似度模型的好坏?

A:除了 accuracy,一定要提 业务指标

  • 搜索场景:NDCG@10、跳出率
  • 推荐场景:CTR、停留时长
  • 客服场景:首次解决率

进阶:当规则和单模型都不够用了

回到开头那个事故。最终我们搞了个混合架构:

  1. 规则层:用正则匹配价格词(便宜/实惠/百元内)、体验词(好用/流畅/续航强)
  2. 轻量模型层:BiLSTM-CRF 做 aspect-term extraction
  3. 大模型兜底:Sentence-BERT 计算 query 与商品标题的语义相似度

关键代码片段(简化版):

def hybrid_intent_parser(query):
    # Step 1: 规则提取关键词
    price_words = re.findall(r"便宜|实惠|低价", query)
    experience_words = re.findall(r"好用|流畅|音质好", query)
    
    if price_words and experience_words:
        # Step 2: 用 LTP 提取核心产品词
        product = extract_product_with_ltp(query)
        return {
            "intent": "price_sensitive_good_experience",
            "product": product,
            "score": 0.95  # 规则置信度高
        }
    
    # Step 3: 规则没覆盖?走模型
    inputs = tokenizer(query, return_tensors="pt", padding=True)
    with torch.no_grad():
        logits = model(**inputs).logits
    return decode_model_output(logits)

上线后,相关性准确率从 72% → 91%,P0 报警归零。最爽的是,PM 再也不敢说“就加个小功能”了。


最后几句真心话

NLP 这条路,没有银弹。我在百度这两年最大的感悟是:算法工程师的核心能力不是调参,而是定义问题 + 选择合适的技术杠杆

如果你也像我一样,正面临跳槽压力或线上事故,别慌。从一个小任务入手(比如用 TF-IDF 做个垃圾邮件分类器),跑通 pipeline,再逐步替换组件。过程中多看开源项目源码(推荐 WeNet、DeepKE),你会发现大佬们写的代码也没那么神秘。

对了,最近在学 LangChain 和 RAG,感觉又是新坑…… 但为了阿里网易的 offer,冲吧!要是这篇笔记帮你避开了哪怕一个坑,评论区请我喝杯瑞幸就行(杭州滨江店常驻,懂的来)。

评论 0

最热最新
暂无评论
产品说很简单Lv.1
0
影响力
0
文章
0
粉丝