面灵AI→

字节跳动搜广推引擎架构一面面经

轮次
一面
时间
2026-09
来源
牛客网

《面试题目》

  1. 请介绍一下实习项目的整体技术链路是什么样的?
  2. 系统、子系统和最小粒度模块如何划分?
  3. 项目效果的提升具体做了哪些工作?
  4. 如果 Agent 必须输出指定格式,例如 JSON,应该怎样设计,保证输出符合要求?
  5. 如果你的项目有 100000000 个人用,怎么办?
  6. 了解 HNSW 算法吗?
  7. 你是计算机专业的吗?
  8. 进程、协程和线程这三个概念,你大概说一下自己的理解。
  9. 线程之间共享地址空间,那么哪些内容是线程私有的?
  10. 假如 TCP 只有两次握手:一个旧连接请求在网络中滞留很久,客户端重新发起连接,正常通信并断开后,旧请求才到达服务端,这时可能发生什么不好的事情?
  11. 现在有大量用户及订单,要按用户当天的购买数量、金额等计算价值分,评分方法简单但可能变化;需要生成每天的 Top K 日榜并向用户展示。你会怎么设计?
  12. 手撕:给定一个网格,从左上角走到右下角,每次只能向右或向下移动,返回路径数字之和的最小值。

《参考解析》

  1. 进程、线程与协程:进程是资源分配的单位,有独立地址空间;线程是调度的单位,共享进程的地址空间,但各自保有独立的栈、寄存器上下文和线程局部存储,这也是「线程私有」那题的答案。协程是用户态自己调度的执行流,切换不陷入内核,适合高并发 I/O 场景,代价是一个线程上的协程如果执行了阻塞调用,会把同线程的其它协程一起卡住。
  2. TCP 两次握手的缺陷:两次握手意味着服务端收到一个连接请求就直接进入连接状态,没有反过来确认客户端当前是否真的想连。旧连接请求在网络里滞留很久后到达时,服务端会为一个早已放弃的客户端分配资源并维护连接,形成半开连接、白白占用 backlog 与内存;如果带上数据还可能把过期请求当成新业务处理。三次握手让客户端再确认一次,正是为了同步双方序号并排除这类历史报文。
  3. Top K 日榜的设计:关键是写少读多、且评分规则会变。实时累加部分用 Redis 的 ZSet 或 Hash 按 uid 存当天的购买件数与金额,写入时只做自增;计算时先把当天的聚合结果按当前评分公式算成分数,再取 Top K,避免把公式固化在写入路径上,规则变化时重算即可。全量用户每天算一次 Top K 可以用堆或者分桶,达到千万级时按 uid 哈希分区并行算再归并;榜单结果写进缓存并设置当天有效期,展示侧只读这份结果。要注意的是跨天切换和榜单并发更新的一致性,可以按日期分 key 做版本隔离,切日时原子替换。
  4. 让 Agent 稳定输出指定格式:分三层做——输出侧用结构化约束(工具调用或受约束的解码)把格式限制在语法层,而不是只在提示词里写「请输出 JSON」;解析侧做校验和重试,解析失败时把错误信息回灌给模型重试有限次数;业务侧对字段值做语义校验(枚举、范围、必填),不合法就判失败而不是带着脏数据往下走。追问通常落在「重试几次、每次都失败怎么办」,答案是降级为人工确认或者返回明确的失败,不要静默兜底。
  5. HNSW 的取舍:它是分层的可导航小世界图,上层稀疏、负责长距离跳转,下层稠密、负责精细定位,查询时从入口点逐层贪心下降。优点是召回率高、查询是近似对数复杂度、不需要训练;代价是索引常驻内存、构建比 IVF 慢,删除只能标记,参数 M 和 efSearch 直接决定内存占用与召回率的平衡。工程上常和倒排检索配合,先粗排再精排。
  6. 网格路径最小和:经典的动态规划,dp[i][j] = grid[i][j] + min(dp[i-1][j], dp[i][j-1]),第一行与第一列只能从一个方向过来需要单独初始化,最后答案是右下角。空间可以优化成一维数组,滚动更新时注意 dp[j] 在覆盖前代表的是上一行的值、dp[j-1] 已经是本行的值。面试官常接着问「如果允许上下左右四个方向移动」——那就变成了最短路问题,需要 Dijkstra 而不是 DP。