综合模拟面试 1 · 架构与安全#
面试官画像: 大厂 AI 平台组 Tech Lead,有自研 Agent 系统经验 时长: 50-60 分钟 · 难度: ★★★★☆ 覆盖方向: AgentLoop 设计 → 同质 Fork → 安全四层 → Harness 治理 → 上下文压缩
第一阶段 · 暖场(5 分钟)#
面试官: 做个自我介绍。
候选人: 我是一名 AI 应用工程师,主要项目是 ShoppingX——对话式全球购物 Agent。用户自然语言说需求,系统跨 6 个电商平台并行检索、比价、算关税运费、按偏好精挑。数据 138 万条商品。技术栈 FastAPI + LangGraph + Qdrant + BGE-M3 + Langfuse。
面试官: 你在这个项目里负责什么?
候选人: 整个 Agent 系统从零到一。三块核心:第一 Agent 主循环与多 Agent 并行调度——四层安全防护。第二统一 Harness 治理框架——6 个 Hook 点覆盖 Agent 全生命周期。第三零 GPU 评测迭代闭环——Rubric 动态评测加 bad case 飞轮。
第二阶段 · Agent 主循环(10 分钟)#
面试官: 为什么做成 Agent 不做 Workflow?
候选人: Workflow 一刀切全链路——“最近什么旅行包比较火”只需查品类知识库,但全链路跑一遍白费 5 轮检索。Agent Think 阶段自己判断调什么工具。后来进一步重构成意图驱动:planner 输出 tasks,模型按 tasks 组合工具子集。
面试官: 怎么保证模型不乱调?还没搜就直接出清单?
候选人: 做了阶段状态机。四阶段 PLANNING→SEARCHING→COMPARING→CONCLUDING。模型在 PLANNING 阶段调 item_search 被执行层哨兵拒绝。关键选择:拦截而非摘除——摘工具改 system prompt 破坏 prompt cache 前缀。工具表恒定,执行层拦截,前缀稳定。
面试官: cache miss 的代价具体有多大?
候选人: system prompt ~3000 token + 10 轮历史 ~8000 token。每次 miss 多付 ~11000 token 输入费。一次被哨兵拦的无效 tool_call 消耗 ~50-100 token。选择很明确。
第三阶段 · 同质 Fork(12 分钟)#
面试官: 跨平台并行为什么不直接 asyncio.gather(5 × item_search)?
候选人: 每个平台检索不只一次调用。子 Agent 可能换关键词重搜、查品类常识——自己也是完整 Agent 循环。所以 fork 出完整子 AgentLoop。
面试官: 同质意味着子和父完全一样?
候选人: 能力同质但授权不同质。四点不同:LLM 档位(子关 reasoning)、thread_id 独立、session_dir 继承、depth_gate 硬拦聚合/终结工具。
面试官: 检索预算为什么不用 ContextVar?
候选人: 踩过坑。asyncio.create_task 拷贝 context 给子——子 set 父读不到。改 module dict + session_dir 做 key。隔离用 ContextVar,聚合用 module dict。
面试官: 子 Agent 异常会搞崩主 loop 吗?
候选人: 不会。_run_sub_agent 所有异常 catch 转字符串,asyncio.gather(return_exceptions=True) 一个炸不连累其余。5 个全超时就走 chat_fallback 告诉用户”搜索暂时不可用”。
第四阶段 · Harness 治理(10 分钟)#
面试官: Harness 框架解决什么问题?
候选人: 早期控制逻辑全堆在 400 行的适配器类里。重构成 Hook Pipeline:6 个 Hook 点,每个检查是 async 函数 + @harness_hook 装饰器。当前 15+ 模块。新增检查改一个文件一行装饰器,不动主流程。
面试官: LangGraph 有 Callback,你为什么不用?
候选人: Callback 只能观察(记日志打 metrics),Hook 能拦截和改写。pre_tool_call Hook 能 raise HookRejectSignal 拒绝工具执行,post_tool_call 能改写返回,post_reflect 能注入消息。分工清楚:观测走 Callback,拦截走 Hook。
第五阶段 · 压力挑战(10 分钟)#
面试官: 这不就是 Workflow 披了 Agent 的皮?
候选人: 流程次序没有一行代码强制。真 Workflow 是 r = search(); c = compare(r) 焊死在代码里。这里是 create_agent(FULL_TOOL_SET) + ainvoke(),模型完全可以跳步。品类查询只走 2 步就出结果——Workflow 做不到。
面试官: 如果要支持 1000 QPS 怎么改?
候选人: 逐层解决。① 多 Uvicorn + LB,ConnectionManager 改 Redis Pub/Sub ② LLM 网关排队 + failover ③ Qdrant 分布式 + read replica ④ Agent 执行改消息队列。当前瓶颈完全在 LLM 响应时间。
面试官: 你觉得这个项目最能体现什么能力?
候选人: 三个维度。一是系统设计——多层防护哲学,核心是”怎么让 LLM 可靠工作”。二是工程落地——每个”最优方案”来自真实踩坑。三是技术判断力——知道什么不做,每个”不做”都有”什么时候该做”的标准。