字节跳动 AI 全栈实习一面(中国交易与广告):多 Agent 编排与 Redis 定位
- 轮次
- 一面
- 时间
- 2026-10
- 来源
- 牛客网
《面试题目》
- 面试官介绍此次面试时长和流程。
- 自我介绍。
- 你了解我们这个部门吗?这个岗位大概是怎么样?
- 实习时长和出勤时长?什么时候能到岗?
- 介绍一下项目 1。
- 输入是什么?多 Agent 怎么编排?
- 是面向内部还是面向用户?是一个 skill 的形式让大家用的吗?
- 介绍一下项目 2。
- 这个项目的必要性在哪里?现在大模型和智能体感觉已经能做了吧?
- 好,下面我要问你一些基础题,就问你一些数据库相关的可以吗?
- 用什么数据库?
- Redis 在项目 2 里做什么?
- 如果自己做着玩,Redis 确实可以做消息队列和任务队列,但是你知道 Redis 主要做什么吗?
- 了解 MySQL 的索引类型吗?有什么底层?
- 介绍一下 B+ tree。
- 你知道什么是回表吗?
- 知道什么是 MVCC 相关的东西吗?
- 给一个场景:10 亿条 URL,但是只有 1GB 内存,怎么找出 top100 的 URL?
- 手撕:合并重复区间。
- 反问。
《参考解析》
多 Agent 编排:输入、角色、协作方式要答清楚
被问「输入是什么、多 Agent 怎么编排」,要把编排讲成有明确契约的结构。先说输入形态:是自然语言目标、结构化参数,还是两者的组合;再说角色划分——常见做法是「规划者(拆解任务)+ 执行者(调用工具/检索)+ 校验者(检查结果与格式)」,每个角色只负责一件事,通过结构化消息(JSON)传递中间结果而不是自由文本,这样每一步都能校验、能重放。编排形态上要区分固定工作流与动态规划:固定流程(DAG)稳定、可观测、容易限流,适合步骤确定的场景;动态规划灵活但会漂,所以要限制可用工具白名单、最大步数、超时与预算,并设计失败回退(重试、换路径、交回人工)。协作的工程细节包括:共享状态放哪(一个显式的 state 对象比让 Agent 互相读对话历史可靠)、并发与顺序(能并行的子任务并行、有依赖的串行)、以及全链路 trace——每一步用了什么输入、调了什么工具、耗时多少,出问题时能回放。最后补一句取舍:Agent 越多协调成本越高,能用单次调用 + 工具链解决的就别拆成多 Agent。
「这个项目有必要吗,现在大模型是不是已经能做了」
这类质疑式问题的答法是把「模型能做」和「系统能稳定交付」分开。模型能做的是语义理解与生成,做不了或做不稳的是:确定性规则与权限边界(哪些数据能碰)、结果的可靠性与可复现(同样输入要给出同样结论)、成本与延迟控制、以及可审计。项目存在的必要性通常来自三件事之一——把专业知识沉淀成可检索的资料(否则模型只会给通用答案)、把重复流程自动化(人只在关键节点确认)、以及把结果落到既有系统里(工单、报表、审批流)。答题时最好举一个具体对比:没有这个系统时某件事要多久、错在哪里,有了之后变成什么样,用数字说明,比争辩「模型能不能做」有效。
Redis 的定位与 MySQL 索引、B+ 树、回表、MVCC
「Redis 主要做什么」这题的关键词是内存数据库与缓存,要压过「消息队列」。它的本职是高性能的键值存储:缓存热点数据降低数据库压力、做会话与 token 存储、计数与限流(INCR、令牌桶)、排行榜(ZSet)、分布式锁(SET NX PX + Lua 释放)、去重与布隆过滤器、以及地理位置(GEO)。消息队列可以用 List/Stream 实现,但缺少专业 MQ 的持久化保障、堆积能力与消费组语义(Stream 补齐了一部分),所以选型的判据是能不能接受丢与要不要顺序:能接受丢、量不大可以用 Redis,要求可靠投递与堆积能力就用 Kafka/RocketMQ。要顺带讲清 Redis 的代价与陷阱:内存成本、持久化(RDB/AOF)在故障时可能丢窗口内的数据、单线程模型下慢命令会阻塞(大 key、keys *、hgetall 大 hash),以及主从/集群下的一致性与热点分片。
MySQL 索引从数据结构分有 B+ 树(默认,最通用)、哈希(Memory 引擎、等值查询)、全文索引,从功能分有普通索引、唯一索引、主键(聚簇)、联合索引、前缀索引。InnoDB 的 B+ 树:非叶子只存键与页指针,扇出大、树高通常三到四层;数据全在叶子节点且叶子之间用双向链表相连,因此范围查询和排序高效;所有查询都要走到叶子,路径长度一致、性能稳定。回表是二级索引查到主键后再去聚簇索引取完整行的过程——想避免就做覆盖索引(查询列都在索引里),或者把常用列放进联合索引。MVCC 是多版本并发控制:每行记录带隐藏的 DB_TRX_ID(最近修改事务)与 DB_ROLL_PTR(指向 undo log 旧版本),读时通过 Read View 判断版本可见性,从而实现「读不加锁、读写不阻塞」。RC 与 RR 的差别就在 Read View 生成时机:RC 每次快照读都新建 Read View(所以能读到别人的提交),RR 只在事务内第一次快照读时生成并复用(所以可重复读),RR 下靠间隙锁(Next-Key Lock)防幻读。答题时说清「undo log 保存旧版本 + Read View 判断可见性」这两点,基本就到位了。
10 亿条 URL、1GB 内存找 Top100
这题考点是分治加上小顶堆。URL 总量远超内存,所以不能全部装进哈希表(1GB 内存装不下 10 亿个字符串)。标准解法两步:第一步哈希分片——对每个 URL 取哈希后模 N(比如 1024),追加写到 N 个小文件里,同一个 URL 一定落在同一个文件,因此每个文件内的重复项可以独立统计;第二步逐文件处理——对每个小文件用哈希表统计词频(此时单个文件规模已能装进内存),维护一个大小为 100 的小顶堆,堆顶是当前第 100 名,新的频次比堆顶大就替换并调整堆;最后把 N 个文件的 Top100 合并(最多 N×100 个候选),再用一次小顶堆得到全局 Top100。要主动说的细节:选 N 的依据是让每个分片能装进内存(可以按 总量×平均长度/内存 估算,不够就增大 N 或改成多轮);哈希要避免倾斜(可以用更好的散列或加盐),倾斜严重时个别分片仍装不下,可以对该分片再分一次。可以补一个变体:如果允许近似结果,用 Count-Min Sketch 加堆能在更小内存下给出近似 TopK,代价是有误差;如果能用多机,就直接把分片分到不同机器上并行。面试官追问「为什么用小顶堆而不是大顶堆」时答:小顶堆的堆顶是当前候选里最小的,新元素只要比它大就能替换,空间固定为 K。
手撕:合并重复区间
标准做法是先按区间起点排序(O(n log n)),再一次线性扫描:维护当前区间,若下一个区间的起点小于等于当前区间的终点则合并(终点取两者的较大值),否则把当前区间推入结果并开始新区间。要主动说清的细节:排序是必需的(否则要处理乱序);合并条件用 <= 还是 < 取决于是否认为端点相接算重叠(要跟面试官确认,比如 [1,3] 与 [3,5] 是否合并);输入为空或只有一个区间要能正常返回;如果区间已经有序可以省掉排序。写完之后用一个小例子跑一遍(比如 [1,3],[2,6],[8,10],[15,18] 得到 [1,6],[8,10],[15,18]),展示你能自测。追问常见延伸:如果要合并的是「时间区间且规模极大」,排序依然是瓶颈,可以考虑分桶或对已排序的数据流做在线合并。