2026-08-30 秋招XX AI全栈开发一面复盘

Published 2026-08-30 04:00 2616 words 14 min read Handwritten Every word here was typed by me.

Zhiheng Wang avatar

Zhiheng Wang

技术文章、个人随笔、项目与作品体验记录

This post is not yet available in English. Showing the original.
2026-08-30 秋招XX AI全栈开发一面复盘 XX AI 全栈工程师(上海)的一面,形式是牛客 AI 面试。8月30日面完后记下了这些,结果没有留下记录。 整体流程是自我介绍、八股、Agent、项目追问,少了一个手撕环节。我当时觉得它挺公式化,但转念一想,真人面试官的追问就不公式了吗? 题目与我的作答 1. 前端与 Redis 八股 八股选了 TypeScript 方向,记得四道:...

2026-08-30 秋招XX AI全栈开发一面复盘

XX AI 全栈工程师(上海)的一面,形式是牛客 AI 面试。8月30日面完后记下了这些,结果没有留下记录。

整体流程是自我介绍、八股、Agent、项目追问,少了一个手撕环节。我当时觉得它挺公式化,但转念一想,真人面试官的追问就不公式了吗?

题目与我的作答

1. 前端与 Redis 八股

八股选了 TypeScript 方向,记得四道:

  1. JavaScript 在浏览器里的事件是怎么执行的?
  2. TypeScript 泛型有什么作用?
  3. 缓存穿透、缓存击穿、缓存雪崩有什么区别?
  4. Redis 的两种持久化机制有什么区别?当时记成一个 A 开头、一个 R 开头。

这部分留下了题目,没有留下我逐题回答的原话。下面把它们按复习时能讲清楚的程度补上。

2. Function Calling → 私有 API → Agent 设计模式

后面这组是递进追问,不是几个互不相关的八股。

先问 Function Calling。我当时说,本地内置了 Python 解释器,把 Tools 写好、规约好,模型自己调用工具去跑。但我又提到,本地环境不能覆盖所有场景,还会涉及一些 API。

于是它继续问:私有 API、网络服务这种工具,具体怎么实现?我回答了 MCP。

再往后问 Agent 有哪些设计模式。我当时只知道 ReAct,不清楚还有哪些更通用的模式。这两块是我自己觉得答得不好的地方。

3. 最自豪的 AI 项目,以及和 AI 迭代中发现的问题

Agent 部分结束后,开始问项目:

  • 讲一个自己最自豪、最想讲的 AI / Vibe Coding 项目,解决了什么问题,怎么做的。
  • 有没有一开始没发现,后来和 AI 反复迭代才发现的问题?最后怎么定位、怎么解决?
  • 再围绕这个问题继续追问一些细节。

我记住了这条追问线,但没有留下具体讲的是哪个项目、举了哪个问题,后面几次追问也记不清了。这一段先保留到这里。

复盘与重做

以下是事后整理的知识解释和重答思路,不是把它们补写成我当时已经答出来的内容。

1. 浏览器事件执行:同步代码、微任务、任务

可以先从一段最短的代码说起:

console.log(1);

setTimeout(() => console.log(2), 0);

Promise.resolve().then(() => console.log(3));

console.log(4);

输出是 1、4、3、2。

1 和 4 是同步代码,先执行。Promise.then 的回调进入微任务队列,setTimeout 的回调是后续任务。当前这段代码执行完、调用栈清空后,先清空微任务,再有机会处理下一个任务,所以 3 在 2 前面。计时器写0也不表示回调会立刻打断当前代码。

讲事件循环时,把这条顺序说清楚,再按追问补浏览器提供的计时器、网络等异步能力,以及渲染时机,就比较容易展开。这里讲的是同一个页面 JavaScript 执行环境里的顺序,不是说整个浏览器只有一个线程。

2. TypeScript 泛型:保留输入和输出的类型关系

泛型可以把类型当成参数。同一份函数能处理不同类型,同时保留类型检查。

function identity<T>(x: T): T {
  return x;
}

const a = identity(123);      // number
const b = identity("hello");  // string

如果写成 any,函数确实也能接收这些值,但返回值和输入之间的类型关系就丢了。这里的 T 表示:传进来是什么类型,返回的仍然是那个类型。

需要限制参数能力时,就加约束:

function printLength<T extends { length: number }>(x: T) {
  console.log(x.length);
}

这时 T 可以变化,但必须有 length。接口也一样,例如 ApiResponse<T> 可以复用响应结构,让 data 分别是 User、Product,不用每次重写一遍。Python 的 TypeVar、list[int] 也是类型参数化的例子,只是 Python 的类型提示本身不会把运行时变成静态类型语言。

3. 缓存三件套:先分清故障发生在哪里

情况发生了什么常见处理
穿透查的数据根本不存在,缓存和数据库都没有,请求反复打到数据库参数校验、缓存空值、布隆过滤器
击穿某个热点 Key 失效,大量请求同时回源合并回源请求、互斥更新、提前刷新或逻辑过期
雪崩大量 Key 同时失效,或者缓存服务整体不可用TTL 加随机值,配合限流、降级、多级缓存和高可用

先用“不存在、一个热点、大面积失效”把三种情况分开,再针对场景展开。TTL 加随机值能缓解同时过期,解决不了 Redis 整体宕机,不能把所有方案混在一起背。

4. RDB 和 AOF:快照与写操作日志

RDB 保存某个时间点的数据快照,文件通常比较紧凑,适合备份和恢复。代价是宕机时可能丢掉最近一次快照之后的修改。

AOF 记录写操作,通过重放恢复数据。具体能丢多少数据取决于刷盘策略:always 尽量及时刷盘;everysec 每秒刷盘,通常可能丢最近约一秒的写入;no 交给操作系统决定。它也会做重写,不能理解成日志永远只增不减。

两种可以结合使用,重点是根据可接受的数据丢失窗口、性能和恢复需求选择,不能简单说一种在所有场景都更好。

5. Function Calling:把模型和执行程序分开

我当时说“模型自己调用 Python 解释器去跑”,容易把两层混在一起。

模型看到工具说明和参数格式后,生成的是“调用哪个工具、传什么参数”的结构化请求。真正执行函数、操作解释器、访问网络或数据库的是外面的程序。执行完,再把结果交回模型,让它继续判断。

用户问题
  → 模型返回工具名、参数
  → 程序检查参数与权限,执行工具
  → 工具结果放回上下文
  → 模型继续回答,或再调用工具

所以“内置 Python 解释器”可以是工具的一种实现,但不是 Function Calling 本身的定义。先讲清楚这两层,后面的远程工具问题也就容易接了。

6. 私有 API:先解释调用怎么发生,再说 MCP

模型不需要自己持有私有服务的密钥,也不直接替我完成网络请求。可以在后端封装一个工具函数,由它带着服务需要的身份和权限,通过 HTTP、SDK 或 RPC 调用接口,把结果整理好再返回。

我当时直接回答 MCP,跳到了工具接入方式这一层。MCP 可以用来标准化工具发现和调用,但不用 MCP,也能把一个私有 API 包装成工具。

把这条路径说完整会更清楚:

模型提出工具调用
  → 后端工具函数
  → 带认证访问私有服务
  → 得到业务结果
  → 返回模型

如果工具通过 MCP 接入,宿主里的 Client 先向 Server 查询可用工具及参数说明,再把这些能力提供给模型;执行时由 Client 把调用交给 Server。常见的方法名是 tools/list 和 tools/call。

MCP Server 可以在本机,也可以在远端。本机常见 STDIO,远端可以使用 HTTP;它不等于“远程 API”,也不是所有工具调用的必经步骤。除 Tools 外,它还可以提供 Resources 和 Prompts。

7. Agent 设计模式:从 ReAct 往外展开

我当时只知道 ReAct。复习时可以按任务怎么组织来记几种思路:

  • ReAct:推理、行动、观察结果,再继续推理,边做边决定下一步。
  • Plan-and-Execute:先列计划,再逐步执行,必要时调整计划。
  • Reflection:先得到一版结果,再检查、修正。
  • Router / Supervisor:按任务类型分发,或由一个协调者安排其他 Agent。

这不是一个互斥、穷尽的分类表。实际系统往往会混合使用,再配合重试、超时、最大步数、检查点、人工确认等控制。

8. 项目追问:需要补一个具体故事

这一部分还缺当时的具体回答,不能拿现在的项目经历直接回填。后续回忆时,只需要把一件事说清楚:

做的是哪个项目 → 最初漏掉了什么问题 → 怎么发现 → 和 AI 怎么迭代 → 最后怎么确认解决了。

如果某次追问已经记不起来,就留在这里,不把通用答题建议写成当时的对话。

顺带整理几个容易混的概念

这些来自后续复习,不另外算成面试官问过的题:

  • Multi-Agent 是多个 Agent 分工协作;职责、工具和上下文可以不同,但会增加通信、成本和调试难度。
  • Trace 记录一次任务里的模型调用、工具调用、耗时和错误,是排查执行过程的线索,不是一种 Agent 架构。
  • Swarm 在不同系统里的具体含义不同,常用来描述多个 Agent 之间动态协作或交接,不能把某个框架的做法当成唯一标准。
  • Memory 可以存放在外部;只有被取出并放进当前请求的部分,才是模型这一次真正看到的上下文。
  • RAG 主要解决取什么资料来辅助生成;Agent 主要讨论怎样决定和执行后续行动,两者可以结合。
  • Redis 的过期删除处理到期的 Key,内存淘汰处理内存不足时留谁;LRU 看最近使用,LFU 看频率。主从复制复制数据,Sentinel负责监控与故障切换,Cluster通过16384个槽分片并提供相应故障转移能力。

当时想写的帖子叫“秋招第一面和第一挂”,但“第一挂”说的是另一家公司的结果,不能因此把这场也记成挂了。

Written by Handwritten

Random Posts

© 2026 Zhiheng Wang @traceonsnow
Powered by theme astro-koharu · Inspired by Shoka
Loading...