作业帮 大模型算法 一面(暑期)

1. 自我介绍

2. 介绍一个你做得比较完整、个人成长最多的项目,背景、目标、方案和效果是什么?

3. 做这个项目时具体用了哪些方案或手段达成目标?

答案:最核心的是把问题拆开,没有直接把所有文档塞给大模型。文档侧先做结构化解析,保留标题层级、版本号、适用部门、发布时间和权限标签;检索侧用了 BM25 和向量召回融合,因为制度类问题经常包含专有名词、系统名和缩写,单纯向量召回容易漏;生成侧强制模型基于证据回答,不允许没有证据时编造。

训练侧做了两类任务,一类是意图分类和工单类型预测,用历史工单标题、正文、处理队列作为弱标签,再人工抽检;另一类是指令微调样本,用高质量问答、证据片段和标准处理建议构造。线上 badcase 会回流到评测集和训练集里,不会直接只改 prompt。这个项目里提升最大的不是换模型,而是把检索、证据约束和数据闭环做扎实。

4. 整个系统的技术链路是怎样的?

答案:系统链路可以分为离线链路和在线链路。离线链路负责知识入库,包括文档抓取、OCR、正文抽取、表格解析、标题树构建、chunk 切分、embedding 计算、倒排索引和向量索引构建。在线链路从用户 query 进来后,先做 query 清洗和意图识别,再根据意图走不同检索策略,比如制度问答走知识库召回,工单问题走历史工单召回,接口问题走接口文档召回。

召回之后会做权限过滤、去重、rerank、上下文压缩,再交给 LLM 生成答案。生成结果还要经过引用校验、敏感信息过滤和结构化字段提取,最后写入日志系统供后续分析。技术上主要用了 Python、FastAPI、Elasticsearch、Milvus、Redis、PyTorch、Transformers 和 vLLM。

用户 query
  -> query 清洗/改写
  -> 意图识别
  -> BM25 + 向量混合召回
  -> 权限过滤
  -> rerank
  -> 上下文压缩
  -> LLM 生成
  -> 引用校验/字段抽取
  -> 日志与反馈回流

5. 整个系统存储数据用的是什么?存在哪些地方?采用了什么记录方案?

答案:系统里不是所有数据都存在一个库里。原始文档和附件存在对象存储,方便保留版本和回溯;解析后的结构化文本、标题树、元数据存在 PostgreSQL;全文检索索引放在 Elasticsearch;向量索引放在 Milvus;会话状态、热点缓存、prefix cache 的业务侧 key 存在 Redis;线上请求日志和模型中间结果写入日志平台。

记录方案上,每个 chunk 都有唯一 chunk_id,同时关联 doc_idversion_idtitle_pathpermission_tageffective_timesource_url。这样生成答案时可以追踪到底引用了哪个文档的哪个版本。对于历史工单,会保留脱敏后的问题、处理步骤、最终结论和工单分类,但不会把个人敏感字段直接进入训练集。

chunk_record = {
    "chunk_id": "c_202506_00021",
    "doc_id": "doc_hr_policy_008",
    "version_id": "v3",
    "title_path": ["员工服务", "账号权限", "权限申请流程"],
    "content": "权限申请需由直属主管审批后提交至 IT 服务台。",
    "permission_tag": ["internal", "it"],
    "effective_time": "2025-06-01",
    "embedding_id": "emb_77291"
}

6. query 做了什么处理?

答案:query 处理不是简单去空格,主要做了清洗、改写、分类和路由。清洗会处理错别字、特殊符号、无意义口语和复制进来的日志片段;改写会把省略表达补全,比如“这个怎么申请”要结合上下文改写成“VPN 权限怎么申请”;分类会判断是制度问答、故障排查、接口查询、闲聊还是无权限问题;路由决定后面走哪套检索和生成策略。

比较重要的是 query decomposition。复杂问题经常同时问多个点,比如“账号锁了怎么解,顺便查一下审批要多久”,这时如果用一个 query 召回,结果会混乱,所以会拆成多个子问题分别召回。对于包含代码、报错日志的 query,会保留关键错误码、接口名、堆栈关键词,不会过度语义改写。

def normalize_query(query, history=None):
    q = query.strip()
    q = q.replace("\u3000", " ")
    q = " ".join(q.split())

    if history and any(x in q for x in ["这个", "刚才那个", "它"]):
        q = f"结合上下文:{history[-1]}。当前问题:{q}"

    return q

7. 你自己做了一些模型微调,训练数据是从哪里来的?

答案:训练数据主要来自三部分。第一部分是历史工单和知识库问答,经过脱敏、去重、规则版本对齐和人工抽检后,用来构造意图分类、工单类型预测和字段抽取样本。第二部分是线上 badcase 回流,比如召回错、分类错、拒答错、格式错,这部分样本价值最高,因为它反映真实错误分布。第三部分是人工构造的边界样本,主要覆盖权限不足、证据冲突、问题不完整、多意图和敏感信息场景。

不会直接把所有历史数据丢进去训练。比如历史工单里有很多处理结论已经过期,或者包含个人信息、临时 workaround,这些都要过滤。用于 SFT 的样本必须保证输入、证据、答案和规则版本一致;用于分类的样本要处理类别不均衡;用于偏好训练的样本会从同一个 prompt 的多个候选答案中筛出 chosen/rejected。

def build_cls_sample(ticket):
    return {
        "text": ticket["title"] + "\n" + ticket["description"],
        "label": ticket["final_category"],
        "meta": {
            "source": "ticket",
            "version": ticket["policy_version"],
            "checked": ticket["human_checked"]
        }
    }

8. 当时微调用的模型是什么,选的是什么尺寸?

答案:分类和字段抽取任务用的是 DeBERTa-v3-base 和 RoBERTa-wwm-ext 这类 encoder 模型,原因是这类任务更需要稳定的判别边界和低延迟,没有必要上大参数生成模型。生成类任务做过 Qwen 系列 7B 级别模型的 LoRA 微调,主要学习企业内部问答风格、证据引用格式和拒答策略。没有直接选择更大的模型,是因为部署成本和延迟压力比较大,7B 级别配合 RAG 已经能覆盖大多数场景。

尺寸选择主要看任务。意图识别、工单分类这类高频链路,base 级别 encoder 更划算;复杂答案生成才走 LLM;如果是强规则判断,会放到规则引擎而不是模型里。微调方式上,生成模型主要用 LoRA/QLoRA,分类模型全参 fine-tune 或者只微调上层都试过,最终按验证集 F1、P95 延迟和线上资源成本综合选择。

lora_config = {
    "r": 16,
    "lora_alpha": 32,
    "target_modules": ["q_proj", "k_proj", "v_proj", "o_proj"],
    "lora_dropout": 0.05,
    "task_type": "CAUSAL_LM"
}

9. 传统 NLP 做分类场景训练时,最后的损失函数一般是什么?

答案:单标签多分类一般用 Cross Entropy Loss,多标签分类一般用 BCEWithLogitsLoss。如果类别极不均衡,可以用加权交叉熵、Focal Loss 或者重采样。传统 NLP 分类里,模型最后通常输出每个类别的 logits,交叉熵会先做 softmax,再最大化真实类别的概率,本质上是在优化负对数似然。

import torch
import torch.nn as nn

logits = torch.tensor([[2.0, 0.3, -1.2], [0.1, 1.5, 0.4]])
labels = torch.tensor([0, 1])

loss_fn = nn.CrossEntropyLoss()
loss = loss_fn(logits, labels)
print(loss.item())

10. 除了交叉熵,还有没有其他可以衡量两个分布之间差异的方式?

答案:可以用 KL 散度、JS 散度、Wasserstein 距离、Total Variation Distance、Hellinger Distance,也可以在蒸馏场景中用 MSE 对齐 logits 或 hidden states。交叉熵更偏训练目标,KL 更常用于分布对齐和蒸馏,JS 是对称且有界的,Wasserstein 在两个分布支撑集不重叠时也能提供更平滑的距离信号。

在大模型里,KL 很常见,比如 RLHF/DPO/GRPO 里会用 KL 控制当前模型不要偏离 reference model 太远。蒸馏里也常用 teacher/student 的 soft label 做 KL,这比只学 hard label 能保留类别间相似性。

import torch
import torch.nn.functional as F

student_logits = torch.tensor([[2.0, 0.5, -1.0]])
teacher_logits = torch.tensor([[1.5, 1.0, -0.5]])
temperature = 2.0

student_logp = F.log_softmax(student_logits / temperature, dim=-1)
teacher_p = F.softmax(tea

剩余60%内容,订阅专栏后可继续查看/也可单篇购买

AI-Agent面试实战专栏 文章被收录于专栏

本专栏聚焦 AI-Agent 面试高频考点,内容来自真实面试与项目实践。系统覆盖大模型基础、Prompt工程、RAG、Agent架构、工具调用、多Agent协作、记忆机制、评测、安全与部署优化等核心模块。以“原理+场景+实战”为主线,提供高频题解析、标准答题思路与工程落地方法,帮助你高效查漏补缺.

全部评论
感觉写的很好呢
点赞 回复 分享
发布于 04-23 23:35 北京

相关推荐

气笑了,写了半个小时感觉没GPT讲的好,喂给GPT帮我重写了一下,但是有些缩写没说明LCS = Longest Common Subsequence,最长公共子序列LIS = Longest Increasing Subsequence,最长上升子序列BIT = Binary Indexed Tree,树状数组suf[i] = suffix 的缩写,这里表示“从 i 开始的最优长度”给你两个长度为 2e5 的排列 p 和 q,求它们的最长公共子序列中字典序最大的一个。例如:104 7 8 9 5 10 2 1 3 63 2 6 10 8 9 1 4 5 7ans: 8 9 5补了半天,也是补出来了。整体思路其实分两步:第一步,先把 LCS 转化成 LIS。因为 p 和 q 都是排列,所以每个数在 q 中出现的位置唯一。把 p 中每个数替换成它在 q 里的下标,原问题就转化成了求最长上升子序列。第二步,为了方便构造字典序最大的答案,记录每个位置的 suf[i]。suf[i] 的意思是:如果当前选了第 i 个位置,并且把它作为这一段的开头,那么从这里开始最多还能选出多长的合法序列。注意,这个长度是包含当前位置自己的。然后贪心构造答案。从最大的 suf 开始往下做,每次都在当前这一层里选能选到的最大值。这里“能选到”不只是原排列里位置要在后面,还要求它映射到 q 里的位置也在后面。这两个条件都满足,才能保证它仍然是公共子序列。时间复杂度分析:映射下标 O(n)。算 suf[i],本质上还是 LIS 的 DP,可以用二分 / 树状数组 BIT 加速到 O(nlogn)。构造时,把 suf 相同的位置放到同一个桶里,同时记录它们的原值和原下标。每个桶内按值从大到小排序,然后从大到小枚举 suf,顺着扫一遍找第一个合法位置即可。这样排序总复杂度是 O(nlogn),最后构造整体扫一遍是 O(n)。所以总复杂度是 O(nlogn),2e5 可以通过。下面说一下为什么能转成 LIS。最长公共子序列这题,如果两个序列都是排列,那么把其中一个排列里的元素,替换成它在另一个排列中的下标,就可以转成 LIS。核心原因是:“值相同且顺序一致”等价于“映射后的下标严格递增”。这一步成立的关键条件就是:排列里的每个数只出现一次。比如在 p 中选出一个公共子序列:p[i], p[j], p[k]如果它在 q 中也按同样顺序出现,那么它们在 q 里的位置一定满足:pos[p[i]] < pos[p[j]] < pos[p[k]]所以公共子序列就对应着一个上升子序列,LCS 也就变成了 LIS。最后说一下 BIT 为什么能算 suf。这个本质上还是 LIS 的 DP。如果从右往左扫,设 suf[i] 表示以 i 位置开头时最多能选多少个,那么转移就是:suf[i] = 1 + max(suf[j]),其中 j > i 且 p[j] > p[i]也就是:要从右边、并且值比当前大的位置里,找一个最优的接在后面。这个可以用 BIT 维护前缀 max 来加速。因为 BIT 的结构天然适合维护前缀信息,后面的块会汇总前面的信息,而前面的不会被后面的影响。只要维护的是 max 这种可合并的信息,就能像维护前缀和一样维护前缀最大值。而这里值域又正好是 1..n 的排列,所以非常适合直接用 BIT 做到 O(nlogn)。
查看5道真题和解析
点赞 评论 收藏
分享
评论
点赞
1
分享

创作者周榜

更多
牛客网
牛客网在线编程
牛客网题解
牛客企业服务