306 lines
14 KiB
Markdown
306 lines
14 KiB
Markdown
---
|
||
id: plan.week16
|
||
title: "第 16 周:阶段 4(下)——面试准备、终点验收、投递"
|
||
type: week
|
||
domain: plan
|
||
stack: []
|
||
week: [16]
|
||
est_hours: 12
|
||
order: 16
|
||
---
|
||
|
||
# 第 16 周:阶段 4(下)——面试准备、终点验收、投递
|
||
|
||
> 整个计划的最后一周。上周 `week15-package-resume.md`。总纲见 `README.md` 第 14 节“终点验收清单”。
|
||
|
||
**本周目标**:整理一份自己的面试笔记(每题“一句话答案 + 我的项目里怎么用的”),做两次模拟面试,完成终点验收,开始投递并建立“面试 → 复盘 → 补笔记”的循环。
|
||
|
||
**原则**:面试笔记是**自己的话**,不是复制的八股文。每道题都要能落到自己的项目代码上,这是和只背题的候选人最大的区别。
|
||
|
||
## 本周最终目录
|
||
|
||
```text
|
||
career/
|
||
├── interview-notes.md # 面试笔记(按主题,每题一个 ### 标题)
|
||
├── drill.py # 随机抽题练习
|
||
├── tests/test_drill.py
|
||
├── mock-interviews.md # 模拟面试记录
|
||
└── applications.md # 投递记录
|
||
```
|
||
|
||
---
|
||
|
||
## 第 1 天:面试笔记(上)——Python 和 FastAPI
|
||
|
||
### 学习内容
|
||
|
||
- 说明:笔记的格式固定,方便抽题练习:
|
||
|
||
```markdown
|
||
## Python
|
||
|
||
### asyncio 的事件循环是什么?什么时候用异步?
|
||
- 一句话:单线程里调度多个协程,遇到 I/O 等待就切换到别的协程;适合大量网络 I/O(调模型、查数据库),不适合 CPU 密集计算。
|
||
- 我的项目:rag-qa 用 httpx.AsyncClient 并发调嵌入接口;agent-mini 的后台执行器和 SSE 推送都跑在同一个事件循环里。
|
||
- 追问:在 async 函数里调用同步阻塞库会怎样?(卡住整个事件循环;换异步库或放进线程池)
|
||
```
|
||
|
||
- 本主题至少准备这些题(答案要点见括号,写笔记时换成自己的话并补上项目例子):
|
||
- GIL 是什么,对多线程有什么影响(同一时刻只有一个线程执行 Python 字节码;I/O 密集用线程 / 协程,CPU 密集用多进程)。
|
||
- 列表、元组、字典、集合的区别和时间复杂度(字典和集合查找平均 O(1))。
|
||
- 装饰器和上下文管理器分别用来做什么(包装函数加功能 / 保证资源释放)。
|
||
- 类型标注和 pydantic 的作用(静态检查 / 运行时校验外部输入)。
|
||
- 生成器和 `yield`(惰性产生数据;SSE 流式输出就是异步生成器)。
|
||
- FastAPI 的依赖注入、中间件、lifespan、后台任务分别用在哪(第 4 周第 7 天)。
|
||
- 同步 `def` 和 `async def` 接口在 FastAPI 里的区别(前者放线程池执行)。
|
||
- pytest 的 fixture、参数化、怎么测试异步代码和外部依赖(假实现 / MockTransport)。
|
||
|
||
### 要建的文件
|
||
|
||
- `career/interview-notes.md` 的“Python / FastAPI”部分(≥ 8 题)
|
||
|
||
### 完成标准
|
||
|
||
- 每题都有“一句话 + 我的项目 + 追问”三部分。
|
||
|
||
---
|
||
|
||
## 第 2 天:面试笔记(中)——RAG 和 Agent
|
||
|
||
### 学习内容
|
||
|
||
- 本主题是面试重点,至少准备:
|
||
- **RAG 全流程**(加载 → 切分 → 嵌入 → 入库 → 检索 → 重排 → 拼上下文 → 生成 → 引用)和每一步的关键参数。
|
||
- 切分怎么做、块大小怎么选(按标题 / 段落切 + 长度上限 + 重叠;用评测集调)。
|
||
- 为什么要混合检索(向量擅长语义相近,BM25 擅长专有名词和精确匹配;RRF 按排名融合,不用对齐分数)。
|
||
- 重排是什么(用交叉编码模型对“问题—片段”逐对打分,比向量相似度准但慢,所以只对候选做)。
|
||
- 怎么减少幻觉(阈值 + 拒答、提示词约束、引用、评测);怎么评测 RAG(Hit@K、MRR、拒答准确率、回答质量评分)。
|
||
- **Function Calling 流程**;**MCP** 是什么、三类能力、两种传输方式;MCP 和 Function Calling 的关系(MCP 标准化“工具从哪来”,Function Calling 是“模型怎么调用”)。
|
||
- **LangGraph**:State、节点、边、条件边、reducer;检查点和 `thread_id`;interrupt 和 `Command(resume=...)`;短期记忆和长期记忆(Store)。
|
||
- 多 Agent 怎么设计(角色分工、谁决定下一步、结束条件、最大轮数、成本控制)。
|
||
- Agent 常见失败和处理(死循环 → 最大轮数;工具参数错 → 校验并把错误返回给模型;模型输出格式错 → 解析兜底;外部服务失败 → 重试 + 降级;需要人决定 → interrupt)。
|
||
- Agent 怎么评测、怎么观测(第 13 周)。
|
||
- 上下文工程(Context Engineering):上下文放什么、放多少、放哪里(系统提示词、检索结果、历史、工具结果的取舍和截断)。
|
||
|
||
### 要建的文件
|
||
|
||
- `interview-notes.md` 的“RAG”“Agent”两部分(合计 ≥ 15 题)
|
||
|
||
### 完成标准
|
||
|
||
- 每题都能指到自己项目里的具体文件,例如“`retrieval/hybrid.py` 的 `rrf` 函数”。
|
||
|
||
---
|
||
|
||
## 第 3 天:面试笔记(下)——后端、前端、Go
|
||
|
||
### 学习内容
|
||
|
||
- 后端(第 2、3、14 周的笔记汇总,挑高频题):
|
||
- MySQL:索引原理、最左前缀、索引失效、EXPLAIN、隔离级别和 MVCC、死锁;和 PostgreSQL 的差异。
|
||
- Redis:数据结构和用途、缓存三大问题、缓存一致性、分布式锁、持久化。
|
||
- 消息队列:不丢、不重(幂等)、顺序、积压;RabbitMQ 和 Kafka 怎么选。
|
||
- Docker:镜像和容器、多阶段构建、Compose 网络;部署和回滚流程。
|
||
- 接口设计:RESTful、状态码、幂等、鉴权(JWT 和 Session)、限流。
|
||
- 前端(你的强项,面试 AI 全栈岗位时一定会问):
|
||
- Vue 3 响应式原理(Proxy)、`computed` 和 `watch`、Pinia;React Hooks 规则、`useEffect` 依赖、渲染优化。
|
||
- Vite 和 Webpack 的区别;性能优化手段;SSR / SSG / CSR。
|
||
- 流式输出在前端怎么做(fetch + ReadableStream 解析 SSE,第 7 周的 `parseSSE`)。
|
||
- Go(加分项):goroutine 和 channel、`context` 的作用、接口、错误处理、`defer`、切片扩容。
|
||
|
||
### 要建的文件
|
||
|
||
- `interview-notes.md` 的“后端”“前端”“Go”部分(合计 ≥ 20 题)
|
||
|
||
### 完成标准
|
||
|
||
- 总题数 ≥ 43;每个主题至少一题能结合项目讲 2 分钟。
|
||
|
||
---
|
||
|
||
## 第 4 天:项目深挖和系统设计
|
||
|
||
### 学习内容
|
||
|
||
- 说明:中高级岗位一定会对项目“往下挖”,一般连问 3~5 层。准备方法:从简历的每一行出发,自己写一条“追问链”。
|
||
- 案例:追问链
|
||
|
||
```text
|
||
问:你的 Agent 任务怎么做到崩溃后续跑?
|
||
答:每个节点执行完,LangGraph 把状态写进检查点;任务表记录状态和租约,看门狗发现租约过期就重新领取,从最近的检查点继续。
|
||
追问 1:崩溃时正在执行的节点怎么办? → 会重新执行一次(至少一次语义),所以节点里的副作用要幂等。
|
||
追问 2:怎么保证同一个任务不会被两个进程同时跑? → 领取用带条件的 UPDATE(没人持有或租约过期),看影响行数;执行中定期续租,续租失败就停止。
|
||
追问 3:如果要支持一万个并发任务呢? → SQLite 换 PostgreSQL;执行器多实例水平扩展;任务分发改用消息队列;事件推送用 Redis Pub/Sub 或 Streams 让任意实例都能推。
|
||
追问 4:模型调用很贵,怎么控制成本? → 最大轮数、缓存、小模型做路由和总结、监控每个任务的 token。
|
||
```
|
||
|
||
- 系统设计题(准备 2 道,每道 15 分钟讲完):
|
||
1. **设计一个企业知识库问答系统**:需求澄清(文档量、并发、权限)→ 入库流水线(异步、幂等、增量)→ 检索(混合 + 重排 + 权限过滤)→ 生成(流式、引用、拒答)→ 评测和反馈 → 部署和成本。
|
||
2. **设计一个多 Agent 任务平台**:任务模型和状态机 → 后台执行和租约 → 检查点和续跑 → 人机协作 → 事件流 → 可观测性和评测 → 扩展(多实例、队列)。
|
||
- 说明:系统设计的讲法:**先问清需求和规模,再画整体架构,然后挑 1~2 个关键点深入,最后说取舍和扩展**。不要一上来就讲技术细节。
|
||
|
||
### 要建的文件
|
||
|
||
- `interview-notes.md` 增加“项目追问链”(简历每个项目至少 2 条)和“系统设计”(2 道,各附一张架构图)
|
||
|
||
### 完成标准
|
||
|
||
- 每条追问链至少 3 层;两道系统设计题各对着图讲一遍并计时。
|
||
|
||
---
|
||
|
||
## 第 5 天:模拟面试和抽题练习
|
||
|
||
### 学习内容
|
||
|
||
- 说明:找朋友或用 AI 扮演面试官,按真实流程模拟两次:自我介绍 → 项目讲解 → 项目追问 → 技术题 → 系统设计(可选)→ 反问。录音,结束后对照录音记下答得不好的题。
|
||
- 说明:平时用抽题脚本练习:随机抽 5 题,每题限时 2 分钟口述。
|
||
- 案例:
|
||
|
||
```python
|
||
# 文件:career/drill.py
|
||
"""随机抽题:python drill.py interview-notes.md 5"""
|
||
import random
|
||
import re
|
||
import sys
|
||
from pathlib import Path
|
||
|
||
|
||
def parse_questions(markdown: str) -> list[tuple[str, str]]:
|
||
"""返回 [(主题, 问题)]:## 是主题,### 是问题;忽略代码块里的内容。"""
|
||
topic, out, in_code = "", [], False
|
||
for line in markdown.splitlines():
|
||
if line.startswith("```"):
|
||
in_code = not in_code
|
||
continue
|
||
if in_code:
|
||
continue
|
||
if m := re.match(r"^##\s+(.+)", line):
|
||
if not line.startswith("###"):
|
||
topic = m.group(1).strip()
|
||
if m := re.match(r"^###\s+(.+)", line):
|
||
out.append((topic, m.group(1).strip()))
|
||
return out
|
||
|
||
|
||
def pick(questions: list[tuple[str, str]], n: int, seed: int | None = None) -> list[tuple[str, str]]:
|
||
return random.Random(seed).sample(questions, min(n, len(questions)))
|
||
|
||
|
||
def main() -> None:
|
||
qs = parse_questions(Path(sys.argv[1]).read_text(encoding="utf-8"))
|
||
n = int(sys.argv[2]) if len(sys.argv) > 2 else 5
|
||
for i, (topic, q) in enumerate(pick(qs, n), 1):
|
||
input(f"\n第 {i} 题【{topic}】{q}\n(口述 2 分钟后按回车)")
|
||
|
||
|
||
if __name__ == "__main__" and len(sys.argv) > 1:
|
||
main()
|
||
```
|
||
|
||
```python
|
||
# 文件:career/tests/test_drill.py
|
||
from drill import parse_questions, pick
|
||
|
||
FENCE = "`" * 3 # 代码块标记(这里不直接写三个反引号,免得和外层 Markdown 冲突)
|
||
NOTES = f"""# 面试笔记
|
||
## Python
|
||
### asyncio 是什么?
|
||
- 一句话……
|
||
## Agent
|
||
### MCP 是什么?
|
||
{FENCE}text
|
||
### 代码块里的不算
|
||
{FENCE}
|
||
### 多 Agent 怎么结束?
|
||
"""
|
||
|
||
|
||
def test_parse_and_pick():
|
||
qs = parse_questions(NOTES)
|
||
assert qs == [("Python", "asyncio 是什么?"), ("Agent", "MCP 是什么?"), ("Agent", "多 Agent 怎么结束?")]
|
||
assert pick(qs, 2, seed=1) == pick(qs, 2, seed=1) and len(pick(qs, 10)) == 3
|
||
```
|
||
|
||
- 行为面试题也要准备(用 STAR 回答,素材来自上周的 `star.md`):
|
||
- 为什么从前端转 AI 应用 / Agent 开发?(AI 应用的难点在工程:编排、状态、长任务、评测;我在公司已经碰到这些问题,并且用项目验证了解决方案。)
|
||
- 讲一个你解决过的最难的问题。
|
||
- 和后端 / 产品意见不一致时怎么处理?
|
||
- 你怎么用 AI 编程工具?(让 AI 生成,自己负责设计、审查、测试;举一个 AI 写错、你发现并修正的例子。)
|
||
- 你最近在学什么?(这 16 周的计划本身就是答案。)
|
||
- 反问环节准备 2~3 个问题:团队的 AI 应用做到什么阶段、主要的技术挑战、怎么评估 Agent 的效果。
|
||
|
||
### 易错点 / 面试常问
|
||
|
||
- 易错点:答题先给结论(一句话),再展开;不会的题直接说“这个我没有实际用过,我理解的是……”,不要硬编。
|
||
- 易错点:模拟面试只“过一遍”没有用,一定要记下答得不好的题并当天补进笔记。
|
||
|
||
### 要建的文件
|
||
|
||
- `career/drill.py`、`career/tests/test_drill.py`、`career/mock-interviews.md`(两次模拟的问题、表现、改进点)
|
||
|
||
### 运行方式
|
||
|
||
```bash
|
||
cd career && uv run --with pytest python -m pytest -q tests
|
||
python drill.py interview-notes.md 5
|
||
```
|
||
|
||
### 完成标准
|
||
|
||
- 两次模拟面试完成并记录;抽题练习至少 3 轮。
|
||
|
||
---
|
||
|
||
## 第 6 天:终点验收
|
||
|
||
### 学习内容
|
||
|
||
- 说明:对照总纲第 1 节“终点”四条和第 14 节“终点验收清单”逐项打勾。**缺哪条补哪条,不开新需求**。补不完的写进下面的“延期项”,给出完成日期,但不要因此推迟投递。
|
||
- 案例:验收记录写进总纲进度区:
|
||
|
||
```markdown
|
||
### 终点验收(YYYY-MM-DD)
|
||
- 能讲清:☑ 口述稿 3 分 40 秒(录音在 career/)
|
||
- 能做小:☑ agent-mini 崩溃续跑演示视频
|
||
- 能举证:☑ 案例卡 A、C 可对外讲
|
||
- 能对标岗位:☑ 简历 3 个版本,10 个岗位关键词对照完成
|
||
- 延期项:Go 网关接入部署(预计 MM-DD)
|
||
```
|
||
|
||
### 要建的文件
|
||
|
||
- 更新总纲 `README.md` 第 13、14 节
|
||
|
||
### 完成标准
|
||
|
||
- 终点四条全部满足;清单中未完成的项都有明确的延期日期。
|
||
|
||
---
|
||
|
||
## 第 7 天:开始投递,建立复盘循环
|
||
|
||
### 学习内容
|
||
|
||
- 说明:投递策略(总纲第 11 节):主投 AI Agent 开发、大模型应用开发、AI 全栈;兼投全栈。每个岗位用对应版本的简历,投递前跑一次关键词对照。标注了“统招”的岗位也可以投递试试。
|
||
- 说明:用一张表记录每次投递和面试,**每次面试后 24 小时内复盘**:被问到的新题补进 `interview-notes.md`,答得不好的题加进抽题练习。
|
||
- 案例:`career/applications.md`
|
||
|
||
```markdown
|
||
| 日期 | 公司 / 岗位 | 渠道 | 简历版本 | 状态 | 被问到的新题 / 复盘 |
|
||
| --- | --- | --- | --- | --- | --- |
|
||
| | | | 偏 Agent | 已投递 / 一面 / 二面 / offer / 未通过 | |
|
||
```
|
||
|
||
- 说明:每过一个月按总纲第 4 节的方法重新搜一次岗位,更新岗位对照表和简历关键词。
|
||
|
||
### 要建的文件
|
||
|
||
- `career/applications.md`
|
||
|
||
### 完成标准(本计划的最后一项)
|
||
|
||
- [ ] 第一批至少 10 个岗位已投递
|
||
- [ ] 面试复盘循环已经开始(至少有一条复盘记录)
|
||
- [ ] 总纲开头状态改为“已完成(YYYY-MM-DD)”,并写下“下一步如果继续学”选哪一个(总纲第 12 节),提交并推送
|