面灵AI→

字节跳动抖音电商 Agent 开发一/二/三面

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

《面试题目》

一面

  1. 请做一个简单的自我介绍。
  2. 你第一段实习在哪里,所在团队和主要工作是什么?
  3. 你在字节实习为什么没有转正?什么时候知道没有转正 HC?
  4. 这次求职主要倾向什么方向?
  5. 平时是主要使用 AI 工具,还是也学习大模型和 Agent 的基础知识?
  6. 舆情分析 Agent 是学校项目还是个人兴趣项目?项目定位是什么?
  7. MySQL 索引通常是什么结构?InnoDB 中应该怎样设计索引?
  8. 为什么数据库索引常用 B+ 树,而不是二叉搜索树、红黑树或 B 树?
  9. B+ 树与平衡二叉搜索树的查找复杂度有什么区别?
  10. 给定一个订单表和高频查询,这个表和查询的索引应该怎样设计?
  11. 联合索引为什么通常先放等值过滤列?什么是最左前缀原则?
  12. 查询要返回 id 和 amount 时,哪些列应该放进联合索引?怎样权衡覆盖索引与索引体积?
  13. InnoDB 的主键索引和非主键索引有什么区别?
  14. 查询包含 ORDER BY created_at 时,联合索引应该怎样设计?一定要写 DESC 吗?
  15. 建立两个独立索引后,底层是一棵 B+ 树还是两棵 B+ 树?两个独立索引怎样参与查询?为什么它们通常不能同时高效完成过滤和排序?
  16. 对于「按订单和状态过滤、按创建时间取最新若干条」的查询,最终的联合索引和查询过程是什么?
  17. 使用 LIMIT offset, size 扫描百万或上亿行数据有什么性能问题?怎样用游标分页优化深分页?游标为什么要包含唯一键?
  18. 如果一个订单有一亿条子订单,需要逐批调用 RPC 并更新状态,怎样设计可靠的离线处理任务?
  19. Redis 有没有类似数据库二级索引的能力?Redis 和 MySQL 各有什么优缺点,什么场景分别选择它们?
  20. MVCC 是做什么的?它怎样服务于事务隔离?
  21. Redis 有事务吗?它与 MySQL 事务有什么区别?
  22. Redis 命令大体串行执行,为什么业务上仍然会出现并发问题?Redis 6 引入 I/O 多线程后,是否变成多个线程并发修改同一个 Key?
  23. 为什么不能先 GET 判断锁不存在再执行 SET?SET NX 解决了什么问题?一个基本正确的 Redis 分布式锁应该怎样获取?
  24. 已经使用 SET NX,为什么释放锁还需要 Lua?为什么不能直接 DEL?如果业务没有执行完锁就过期了,怎样处理?
  25. Pipeline 和 Lua 分别解决什么问题?Pipeline 中的一批命令是原子的吗?
  26. Redis 内存达到上限时有哪些淘汰策略?除了 LRU,还了解哪些缓存替换算法?
  27. LRU 的核心原理和数据结构是什么?get、put 的复杂度是多少?
  28. 请用你熟悉的语言实现一个支持构造、get 和 put 的 LRU Cache。

二面

  1. 请简单做一下自我介绍。
  2. 是否收到面试前的 AI Coding 题?目前完成得怎么样?展示一下完成合同审核题的过程,你是怎样使用 AI 开发的?
  3. 你对 AI 生成的技术方案提了哪些修改?AI 给出的技术方案很长,人应该怎样 Review、抓重点和做取舍?
  4. 除了主要流程,Review 和开发时还关注哪些点?当前实现处于什么阶段?不接模型的 baseline 能做什么?
  5. 输入有歧义时,下面输出的关系是怎么得出的?有歧义就不建立关系吗?
  6. 原始信息不完整、不确定时,所谓「默认结果」应该如何处理?结论会不会也有问题?
  7. 开发时是否给 AI 明确说明过这些边界情况?是否确认过它的处理逻辑?
  8. 这道 AI Coding 题实际花了多长时间?如果时间更充足,你会怎样继续优化,并怎样和 AI 交互?
  9. 没有产品同学可以确认需求时,遇到模糊信息怎么办?如果产品同学也是新人,也不知道正确答案,怎么办?
  10. 两个条款名称很相似,怎样确认它们是不是同一个条款?能否直接制定一个判断逻辑?
  11. 最终报告怎样区分确定的关系和疑似关系?置信度应该怎样处理?
  12. 如果给你两天时间,最应该优先优化哪些模块?
  13. 是否需要引入大模型?哪些部分交给模型,哪些部分交给代码规则?判断一个任务适合模型还是规则,有什么通用标准?
  14. 怎样判断最终报告的质量,确认输出的关系是否正确?将报告与人工标准答案比较后,发现差异应如何迭代?
  15. 差异一定要人工逐个分析吗?这个过程怎样利用 AI?让 AI 分析差异、辅助修复,需要提供哪些信息?
  16. 只知道正确答案、不知道最佳实现策略时,怎样让 AI 帮忙?告诉 AI 自己设想的实现策略,还是提供输入和正确输出让它推导,哪种更好?
  17. 是否实践过把测试用例交给 AI,让它验证、发现偏差并自行迭代?
  18. 合同变成一两百页、超过 Agent 上下文窗口时怎么办?文档具体怎样切分?如何处理切分边界和块大小?
  19. 文档切分以后怎样得到最终答案?不同子 Agent 分别处理文档块之后,怎样汇总结果?
  20. 汇总后的结果又超出上下文怎么办?如何让 300 页合同的处理链路真正跑通?
  21. 压缩或丢弃信息时,怎样判断哪些信息无效?渐进式披露在这个合同场景中具体怎样落地?
  22. 如果业务强约束 AI 不能基于虚构信息得出关系和结论,工程上怎样设计?
  23. 用另一个 Agent 评估结果,但评估 Agent 本身也有幻觉,怎么办?判断结论是否基于事实,一定要经过 AI 吗?怎样把非 AI 校验纳入工程链路?
  24. 为什么没有继续在原团队实习并转正?实习期间怎样学习 AI、从哪里获取信息?
  25. 信息很多时优先关注什么?关注之后有什么实践动作?学到的新知识有没有用到实习开发中?
  26. 除了辅助开发,AI 有没有用到国际支付风控的业务场景中?
  27. 怎样理解 CLI 和 MCP Tool,它们有什么区别?什么场景使用 MCP,什么场景使用 CLI,什么场景需要 Skill?
  28. 同一项能力支持多种接入方式时怎样选择?自己的业务能力如何开放给 Agent?
  29. 如果重点追求性能和低延迟,CLI、MCP、Skill 应该怎样选型和设计?

三面

  1. 请做一下自我介绍。
  2. 你在实习团队拿到转正 Offer 了吗?为什么没有转正?
  3. 介绍一件实习期间能体现个人技术成长和能力的事情。
  4. 可以现场演示一下舆情分析 Agent 产品吗?这个项目是否已经上线并被真实用户使用?
  5. 项目的目录结构是什么,为什么这样设计?你认为项目中最关键的代码和技术方案是什么?
  6. 为什么自己实现这套流程,而不是直接使用成熟的开源 Agent 框架?
  7. 为什么要持久化任务、工具调用和执行过程数据?
  8. 算法题:实现「最短无序连续子数组」——给定一个无序数组,找到最短的连续覆盖区间,对区间内的元素递增排序,使得数组整体递增。

《参考解析》

索引为什么是 B+ 树:从磁盘 I/O 次数倒推

数据库索引的瓶颈不在比较次数,而在磁盘随机读的次数。红黑树、二叉搜索树都是二叉的,树高是 log₂N,千万级数据就是二三十层,最坏情况接近二三十次随机 I/O;B 树的每个节点可以存多个键,树高降到了 logₘN,但它的数据行同时挂在内部节点和叶子节点上,范围扫描要在层与层之间来回跳。B+ 树把这两点都解决了:内部节点只存键、不存数据,同样大小的页能塞进更多键,树高进一步降到三四层;所有数据行都在叶子节点,且叶子之间用链表串起来,BETWEEN、ORDER BY、LIMIT 这类范围操作只要定位到起点再顺着链表走即可。代价是等值查询必须一路走到叶子,但多走的一两次内存级比较远比省下的磁盘 I/O 便宜。InnoDB 的页默认 16KB,按这个设计三层 B+ 树大致能撑两千万行左右的表。

联合索引的列序:等值在前、范围在后,覆盖索引换回表

联合索引 (a, b, c) 的排序规则是先按 a 排、a 相同再按 b 排,所以只有「a 等值、b 等值、c 范围」这种前缀连续用上的写法才能把索引当有序结构来用——这就是最左前缀原则。因此设计列序的口诀是等值过滤列放前面、范围列放后面、排序列紧跟等值列。WHERE order_id = ? AND status = ? ORDER BY created_at DESC LIMIT 20 的理想索引是 (order_id, status, created_at),一次索引扫描就能同时完成过滤和排序,省掉 filesort。要不要把 amount 也塞进去做覆盖索引,是体积与回表的权衡:覆盖索引能免掉回表,但如果 amount 很大、或者查询还会要别的列,把宽列放进索引会让每个索引页能装的键变少、树变高、写放大也更大。ORDER BY 的 DESC 在 MySQL 8 里不必显式声明——索引可以正向也可以反向扫描,真正影响能否用上索引的是排序列有没有落在索引里、以及多列排序方向是否与索引一致,混合方向(一个 ASC 一个 DESC)在 8.0 之前就没法用索引排序,8.0 之后才有降序索引。

深分页与游标分页:为什么 offset 越翻越慢、游标为什么要带唯一键

LIMIT offset, size 的代价与 offset 成正比:服务端必须先把前 offset + size 行取出来再丢掉前 offset 行,LIMIT 1000000, 20 意味着要顺着索引扫一百万行、还要对每一行回表取数据。翻到后面越翻越慢,本质是在为「已经看过的数据」重复付费。游标分页(keyset pagination)换了个思路:记住上一页最后一条的排序键,下一页用 WHERE (created_at, id) < (?, ?) ORDER BY created_at DESC, id DESC LIMIT 20,直接从索引的定位点往后取 20 行,复杂度与页深无关。游标必须带唯一键,是因为排序列可能有大量重复值——只用 created_at 做游标时,同一毫秒内的多条记录在两次查询之间没有确定顺序,会出现漏行或重复行;把主键拼进游标与排序键,排序才是一个全序,翻页才稳定。它的代价是不能随机跳页,只能上一页/下一页,这正好也是信息流产品的交互形态。

Redis 分布式锁:SET NX PX 加锁、Lua 校验持有者后释放、过期靠续期兜底

先 GET 再 SET 的问题在于这两步之间不是原子的,两个客户端可以同时判断出「锁不存在」然后都去 SET,锁就失效了。SET key value NX PX 30000 把「判断不存在」和「写入」合成一个原子命令,是加锁的最小正确形态。释放锁必须用 Lua,是因为要保证「校验 value 是不是自己持有的那个 token」和「删除 key」两步原子:直接 DEL 会误删别人的锁——A 的业务超时、锁自动过期,B 拿到了锁,此时 A 执行完回来 DEL,删掉的是 B 的锁。Lua 脚本里先 GET 比对 token、一致才 DEL,Redis 单线程执行脚本,中间不会被插队。业务没执行完锁就过期,是所有方案都要面对的根问题:可以开一个看门狗线程按锁租期的三分之一续期、把租期按业务 P99 放大、或者给业务加可重入与超时中止;但根本上要接受分布式锁只能降低冲突概率,真正不能重复执行的操作还得靠下游的幂等键兜底。

Redis 命令串行执行,为什么业务上仍然会并发出错

「串行执行」说的是 Redis 内部对单条命令的处理不被打断,不等于「多条命令组成的一个业务动作」具有原子性。GET 判断不存在、再 SET 写入,这是两条命令、两个事件循环轮次,另一条连接完全可以在中间插进来。Redis 6 的 I/O 多线程只是把网络读写与协议解析分摊到多个线程,命令的执行仍然是单线程的(核心的命令执行路径没有放开),所以它既没有引入「多线程并发改同一个 Key」的新问题,也没有把多条命令变成原子操作。要跨越单命令的边界保原子,只有三条路:用 Lua 脚本把多步操作打包(脚本内不会被插入其他命令)、用 MULTI/EXEC 事务(注意它不提供回滚,只是批量执行,且不能在中间读结果做判断)、或者用 WATCH 做乐观锁重试。

LRU 的实现:哈希表定位 + 双向链表维护时序

要在 O(1) 内同时完成「按 key 查值」和「按访问时序淘汰」,必须一个哈希表配一个双向链表:哈希表的 value 指向链表节点,链表头是最新访问、链表尾是最久未用。get 命中时把节点摘下来插到头部,未命中返回空;put 若 key 存在则更新值并移到头部,不存在则新建节点插到头部、把 size++,超过容量就删掉尾节点并从哈希表里移除。两处容易写错:一是删除尾节点时必须同步从哈希表里删掉对应 key,否则 map 会泄漏;二是 put 已存在的 key 时不能重复插入新节点。更进一步的话题是「Redis 的 LRU 并不精确」——Redis 3.0 之后用的是近似 LRU,随机采样若干 key 淘汰其中最久未用的,为的是省下维护全局有序链表的指针开销和内存;练手可以从零实现精确 LRU,再把 LRU-K、LFU(Redis 4.0 的 allkeys-lfu)以及「扫描式淘汰」的取舍讲清楚。

长文档超出上下文:分层切分 + 并行子任务 + 有损汇总 + 渐进式披露

把一两百页合同塞进单个上下文,工程上拆成四步。第一步切分要按语义边界切而不是按固定字数切:先按条款/章节标题做一级切分,超长的条款再按段落重叠切(例如每块带 10% 重叠),重叠是为了不让一个跨块的实体被切成两半。第二步并行处理:每个块交给一个子任务抽取「实体 + 关系 + 出处」,输出结构化 JSON 而不是自然语言长文,因为结构化结果的体积比原文小一到两个数量级,这一步就是把文档压小的关键。第三步分层汇总:先合并同一实体的多块结果并去重,再让上一层只读合并后的摘要而不是原文,如果仍然超限就再建一层——树形归并的层数与文档规模成对数关系。第四步渐进式披露:主链路只带全局摘要和索引,需要细节时再按索引回查具体块,避免把全部细节常驻上下文。判断哪些信息可以丢,标准是「丢了以后还能不能支撑最终结论」:与结论无关的修饰、模板条款可以丢,涉及金额、期限、责任主体、例外条件的必须保留,并记下它在原文的位置以便复核。

模型与规则的边界:确定性的事交给代码,语义理解交给模型

划分标准可以落成几个可判定的问题。一是「答案是不是唯一且可枚举」:日期格式校验、金额加减、编号是否连续、字段是否为空,这类有确定判定过程的必须交给代码规则,用模型做只会引入不确定性还更慢。二是「输入是否规范化」:两个条款名称相似但不完全相同,靠字符串匹配无法判定,要靠语义理解,这就该交给模型,但要让模型输出「是同一实体/不是/不确定」三态而不是必须二选一。三是「错了的代价有多大」:涉及金额、法务责任、对外结论的关卡加代码校验(汇总是否等于明细之和、外键是否闭合、数值是否在量级区间内),模型只产出候选、由规则决定能否放行。四是「能否给出处」:模型给出的每条关系都要能回溯到原文位置,指不出出处的一律降级为「疑似」,交由人工确认——把置信度当一等公民,比调提示词更能提升可信度。至于质量评估,可行的做法是先用少量人工标好的标准答案做对照集,把差异按类型归类(漏抽、错抽、边界判错),再让模型辅助分析差异原因并给修复建议,但「用模型评模型」不能闭环,必须保留规则校验与人工抽检。

CLI、MCP Tool 与 Skill 的选型

三者的差别在调用路径和上下文开销上。CLI 是一次进程调用,启动与退出有固定开销,但输入输出走管道、可以流式、便于本地调试和复用现有命令行工具,适合批量、离线、需要和文件系统打交道的能力。MCP Tool 把能力以结构化 schema 暴露给模型,省掉「怎么调、参数是什么」的猜测,代价是每个工具的定义都要占用上下文、且走一层协议转发,工具数量一多上下文会被工具清单吃掉;追求低延迟和高吞吐时,一次问答里挂几十个工具反而不如给一个 CLI 入口加 --help。Skill 更接近「按需加载的知识与流程」,它不提供运行时能力,而是在合适的时机把领域步骤和注意事项注入进来——所以判断标准是:能力和执行属于 CLI/MCP,流程和判断属于 Skill。业务能力对外开放给 Agent 时,优先给稳定、幂等、可校验的接口,把鉴权与配额留在服务端,而不是靠提示词约束模型不要乱调。