Skip to content

13 · 面试实战:带着问题通关 ​

这一站是毕业答辩:十三站的知识主线已经走通,这一篇反过来——用 Agent 全栈岗位的高频面试题逐个拷问,每道题都落到本项目的真实实现上。「带着问题去学习是最容易学懂的」:学后自检验证掌握程度,倒序预习则把每道题当成一站的入口。

前置:十三站任一进度皆可用(每题标注出处站号);完整走完则当毕业自检 配套:所有「项目证据」都指向 agent-app 的真实代码与测试——答不上来就回去跑对应章节 深读:每题末尾的「追问链」是面试官的深挖路径,顺藤摸瓜直通参考库


怎么用这一篇 ​

  • 学后自检:遮住答案,每题先自己说 30 秒,再对照——说不出「项目证据」的题,回对应站重学;
  • 倒序预习:先把十七道题过一遍,带着问题进主线——每道题的「出处站号」就是你的学习地图;
  • 面试前夜:只看每题的「30 秒答案」+「追问链」——追问链是面试官的深挖路径,也是你知识的下一层。
  • 场景题专项:第二篇的四道场景设计题是高阶环节——答题框架 + 本项目的活答案,架构/资深岗的决胜点。

第一组 · LLM 基础(01 站) ​

Q1 · 让模型输出 JSON,为什么 function calling 比 JSON 模式可靠? ​

30 秒答案:JSON 模式(response_format)本质是提示词层面的请求,模型遵不遵守看它对指令的服从度——弱模型会静默无视,输出散文导致解析炸;function calling 是模型训练阶段专门学过的输出模式,调用结果以协议级独立字段返回(SDK 直接给解析好的对象),「一旦调用,结构必对」。可靠性排序:function calling > JSON 指令 + 宽松抽取兜底 > 裸 JSON 指令。

项目证据:packages/engine/src/json-utils.ts 的 extractJson(宽松抽取 + 校验 + 重试一次)就是路线 A 的工程止损;而工具循环全走 function calling(路线 B)。

追问链:那什么时候还用 JSON 指令?→ 只需要「分类判断」这类轻结构、不想定义工具时(如客服三分类路由,supervisor.ts)→ 兜底做了什么?→ 宽松抽取 + zod 校验 + 自动重试一次。

Q2 · 流式输出的原理?比非流式好在哪? ​

30 秒答案:SSE(Server-Sent Events)单向推送:BFF 逐段把模型 token 写进 HTTP 流,前端按帧解析追加。好处的本质是等待体验与信任——有进度就不焦虑、看得见模型查了什么回答就可信;Agent 场景还多两样:思考过程(step 事件)与审批(反向控制流)是普通「流式文本」装不下的。

项目证据:packages/shared 的 ChatStreamEvent 六事件契约(session → step* → token* → done),前端 lib/api.ts fetch + ReadableStream 手解析(不用 EventSource:要带 sessionId 且需读非 200 错误体)。

追问链:一帧怎么切?→ 按 \n\n 分隔 + data: 行;流结束没分隔符怎么办?→ flush 尾帧。


第二组 · Agent 核心(02 站) ​

Q3 · 现场手写一个 Agent 工具循环(编码题) ​

30 秒答案:四步——思考(generateText 带工具清单)→ 出口(无工具调用即最终回答)→ 行动(执行点名的工具)→ 回灌(结果包成 tool 消息塞回历史)。加上 maxSteps 保险丝防死循环,就是完整的最小形态(15 行)。

项目证据:02 站「循环的最小形态」有逐行推导;真实实现在 packages/engine/src/agent-loop.ts(带五道防御的完整版)。这道题必须能白板写——所有框架剥到最里层就是它。

追问链:为什么 maxSteps 是 5?→ 保险丝:止损优先,调大换复杂任务、付失控风险 → 步数用完为什么不硬答?→ 半成品结论=编造,宁要明确失败。

Q4 · 模型幻觉参数怎么办? ​

30 秒答案:三层——①工具的 zod schema 在执行前 safeParse(带病参数到不了业务代码);②失败不炸循环,把带修正方向的错误说明包成 error-json 回灌(错误消息写给模型看:哪个字段、为什么、怎么改);③实测闭环:模型幻觉 2022-09 → 被拒 → 读到「按当前年份重试」→ 自我修正。

项目证据:agent-loop.ts 校验闸;时间窗口校验的 message 写成祈使句(「按当前年份重试」)——zod message 身兼报错与重试指南两职。

追问链:为什么用 safeParse 不用 parse?→ 校验失败要「从容处理成回灌材料」而非抛异常 → 参数直接执行的后果?→ 查错数据是小、写错数据(createTicket 建错单)是大。

Q5 · 工具结果怎么回到模型?为什么必须回灌? ​

30 秒答案:包成 role: "tool" 的 tool-result 消息 push 进对话历史(带 toolCallId 一对一回执)。必须回灌:模型无状态,每次调用只看 messages 数组——不回灌=下一轮失忆,查询白查。

项目证据:agent-loop.ts 回灌块;「回灌之后才触发 onStep 广播」——订阅方看到的一定是已提交状态。

追问链:历史无限增长怎么办?→ 03 站压缩(40 条触发滚动摘要)。

Q6 · 多轮对话怎么管理上下文? ​

30 秒答案:窗口(最近 20 轮进 prompt)+ 压缩(超 40 条触发滚动摘要:旧消息+旧摘要压成 ≤150 字新摘要,保最近 20 条原样)+ 降级(摘要模型挂了退化为纯截断,对话不中断)。

项目证据:packages/engine/src/memory/compression.ts(COMPRESS_AFTER=40 / KEEP_RECENT=20 / 可注入 Summarizer)。

追问链:摘要是有损的怎么办?→ 关键实体不靠摘要兜底——进偏好/情景层 → 工具结果在会话历史里吗?→ 不在(只存问答文本)——这引出实体继承缺口(解法:工具结果扫描实体注入 system 动态段,实测修复「追问丢 ID」)。

Q7 · Agent 陷入死循环怎么办? ​

30 秒答案:maxSteps 保险丝——步数用完抛明确失败而非硬挤回答(半成品结论=编造)。配 abort signal:客户端断开后停止烧 token(三层贯穿:HTTP → 循环 → 模型调用层)。

项目证据:agent-loop.ts 循环末尾的保险丝 + ToolLoopAbortedError 类型化错误(调用方按 instanceof 静默收场)。

追问链:什么信号说明该调大 maxSteps?→ 合理流程真需要更多步(如多数据源汇总)→ 调大的代价?→ 失控风险放大。


第三组 · 知识与安全(04 / 06 站) ​

Q8 · 讲讲 RAG 的全流程?检索不准怎么排查? ​

30 秒答案:五步链路——切块(递归瀑布 500/80,太大混主题太小断上下文)→ 向量化(语义变坐标)→ 存储(memory/json/pgvector 三档)→ 检索(余弦 topK)→ 带引用生成(编号后端分配,模型编不了出处)。检索不准按序排查:切块大小 → embedding 模型是否同款(入库与查询混用=坐标失真,最高频翻车点)→ 是否需要重排/Hybrid(本项目未做,诚实边界)。

项目证据:packages/engine/src/rag/ 六步链路;ingest 逐块过注入扫描(命中拒收+审计)——入库也是攻击面。

追问链:为什么引用编号由后端分配?→ 编号检索时已定,模型只能引用不能编造 → 「资料是数据不是指令」怎么落地?→ 提示词声明 + 入库扫描双闸。

Q9b · 什么时候用 RAG,什么时候微调? ​

30 秒答案:知识经常变或属于私有数据(公司制度、产品手册、实时订单)→ RAG(改知识库即生效,可溯源可撤回);要改变的是模型的「行为方式」而非「知识」(输出风格、领域话术、固定格式)→ 微调才有意义。两者正交不互斥:成熟方案常常 RAG 供知识 + 少量微调调行为。默认答案永远是先 RAG——成本三个量级的差距、知识可随时撤回、引用可溯源,微调这些一条都不占。

项目证据:本项目全部私有知识走 RAG(kb 产品线),零微调——面试官若追问「为什么不微调」,答案就是上面这句成本与溯源的对比。

追问链:微调的代价具体是什么?→ 数据准备/训练成本/版本管理/知识更新要重新训练 → RAG 的短板?→ 检索质量决定上限(所以 04 站的排查顺序是核心技能)。

Q9 · 怎么防 Prompt 注入? ​

30 秒答案:红队驱动(先当攻击者)——八实验矩阵打穿自己后按洞设防:①规范化扫描(全角/零宽/leet 变体归一化后过黑名单,实测拦 ign0re prev1ous 类混淆);②入库闸(投毒文档整篇拒收,E3 头条 3/3 沦陷的修复);③工具白名单(最小权限);④审计账本(JSONL 只追加,事件可追溯)。诚实边界:围栏是提示层缓解、零宽变体仍有漏网——防御是概率不是绝对。

项目证据:packages/engine/src/guardrails/ 四件套;SECURITY.md 覆盖面地图;投毒样例实测 ingest.rejected(samples/red-team/poisoned-note.md 可复现)。

追问链:为什么扫描默认关(AGENT_GUARD_INPUT 灰度)?→ 零变化默认铁律:改行为需要显式开启 → 与「审批默认开」矛盾吗?→ 不矛盾——部署形态的属性(灰度)vs 安全属性(默认安全)是两种默认。


第四组 · 工程化(05 / 08 / 11 站) ​

Q10 · 写操作被重复执行怎么办? ​

30 秒答案:幂等壳——键 = 会话 scope + 工具名 + 参数指纹(键排序规范化),TTL 窗口内重放直接返回首次结果。三条纪律:成功才缓存(失败重试是真重试)、在途共享(同键并发等同一个 Promise)、scope 隔离(跨会话同参是两笔业务)。设计对照:Stripe 用显式 Idempotency-Key 头;Agent 场景模型不可靠生成键,退一档用参数指纹。

项目证据:packages/engine/src/tools/idempotency.ts;实测同会话重复建单拿到同一个工单号(契约级测试覆盖三条纪律)。

追问链:为什么键必须带 scope?→ 跨会话误去重=两笔业务变一笔 → 多实例部署怎么办?→ 进程内存换 Redis SETNX + TTL(接口不变,演进路径已留)。

Q11 · 高危操作怎么控制? ​

30 秒答案:审批壳——名单内工具执行前挂起,发审批事件等人工裁决(SSE 事件 → 前端卡片 → POST 裁决回传),60 秒超时自动拒绝(fail-closed:没接电话就不扣款);拒绝值是结构化数据({denied, reason}),模型看得见、能礼貌收尾而非当失败重试。叠加顺序:审批壳在外、幂等壳在内——被拒绝的调用不污染缓存。

项目证据:apps/api/src/chat/tool-approval.ts(默认名单 createTicket、60s)+ web 审批卡片全链路(实测:拒绝后模型礼貌收尾、同参重放幂等命中)。

追问链:为什么审批要在幂等外面?→ 见上 → 非流式端点怎么处理审批?→ 直接 400(无 SSE 通道白等 60 秒,安全默认)。

Q12 · Agent 系统怎么测试和评估? ​

30 秒答案:单测断「代码对不对」,评测量「行为好不好」。三层:单测(打分器/纯函数,vitest);契约测试(同接口多实现跑同一套断言,memory 常跑 + redis/pgvector 门控);评估考卷(76 例版本化数据集 + 三档判分 + 基线对比——改 prompt 前后跑分说话)。诚实边界:Tier 1(确定性 18 例)已进 CI 门禁;Tier 2/3 需网关 key;在线评估(真实流量回流)未做。

项目证据:packages/engine/src/evals/(corpus→dataset→fixtures→runner→report+baseline 五件套 + 四评分器);pnpm eval 无 key 也出报告(skipped ≠ failed)。

追问链:剧本模型是什么?→ fixtures 注入 MockLanguageModelV2 按剧本走——夹具换环境、被测系统(真实 runToolLoop)必须是真的 → 基线怎么比?→ avg 分容差 3%、通过率零容差。

Q13 · 你的项目离生产还差什么? ​

30 秒答案:一张诚实的三档成熟度矩阵——多数模块在「单实例」档(env 工厂持久化、契约测试背书),明确的生产前置项:重试与退避、RBAC 多租户、限流、在线评估、OTel 可观测、幂等跨实例(Redis SETNX)、审计账本只追加存储。诚实清单比「什么都能」值钱。

项目证据:packages/engine/docs/MATURITY.md(三档 × 全模块)+ BACKLOG.md 挂账。

追问链:先补哪个?→ 压缩水位线(设计稿最全/边界最小)> 重试退避(bug 级缺口)> RBAC(需要认证体系先落地)。


第五组 · 架构与生态(07 / 09 / 09b / 12 站) ​

Q14 · MCP 是什么?解决什么问题? ​

30 秒答案:Model Context Protocol——工具接入的行业标准(Anthropic 推)。没有它,每接一个工具源都要写一份私有胶水(M×N 问题);有了它,任何 MCP 服务器的东西即插即用(M+N)。实现三文件闭环:server(自家工具暴露成服务)/ client(spawn 子进程 + 握手 + listTools)/ adapter(JSON Schema 照单全收适配成自家工具表)——并入后循环一行不改。

项目证据:packages/engine/src/mcp/;狗粮实测 pnpm chat --mcp "cmd /c pnpm mcp:server" 自己接自己;重名时 MCP 版本胜出 + 警告。

追问链:Windows 的坑?→ spawn 的 pnpm/npx 是 .cmd 垫片,不开 shell 直唤 ENOENT——包一层 cmd /c(安全纪律非 bug)→ 子进程怎么收尾?→ stdin EOF → SIGTERM → SIGKILL 三段。

Q15 · 多 Agent 架构有哪些模式? ​

30 秒答案:至少三种——Supervisor 星型(一个路由 Agent 分发给专职工人,本项目 09 站已实现:硬规则+三分类路由三工人);流水线(planner → executor → critic 的规划-执行-批判闭环);A2A 对等(Agent Card 互相发现)。多 Agent 引入三个新问题:任务分工、共享状态、质量闭环——每个都是真问题,别为拆而拆。

项目证据:单 Agent(09 站客服)已覆盖单机场景;多 Agent 已由编排器落地(pnpm team "目标" 可跑:LLM 拆单 → DAG 并行派发 → 逐任务验收,深讲见 reference/10)——A2A 对等与在线观测仍在 BACKLOG.md 挂账。

追问链:什么时候才需要多 Agent?→ 单 Agent 工具表超过职责承载/上下文需要隔离时 → 你的项目到了吗?→ 编排器已建好待命(pnpm team 可跑),但两条产品线仍是单 Agent——不为拆而拆的原则不变,触发条件到了才把编排器接进业务。

Q15b · Agent 和 Workflow 的区别?(Anthropic 必考 framing) ​

30 秒答案:Workflow 是开发者预先写死代码路径,LLM 只在固定节点被调用——流程可控、可测、成本低;Agent 是模型自主决定过程(调什么工具、调几步、何时停)——灵活但不可预测。判断标准一句话:任务能拆成确定步骤就写 Workflow,只有路径无法预知的开放任务才用 Agent。多数生产系统是混合体:Workflow 骨架 + 局部 Agent(本项目的客服系统就是——硬规则路由是 Workflow,模糊分类才是 LLM)。

项目证据:09 站客服系统的两级路由就是活例子——硬规则(Workflow)优先于三分类(Agent);对照 Anthropic《Building Effective Agents》 的核心论点:能 Workflow 别 Agent。

追问链:那你的主循环(02 站)是 Agent 还是 Workflow?→ 循环骨架是固定结构(Workflow 性),但「调什么工具、几步停」由模型自主(Agent 性)——所以准确说法是「受约束的 Agent」→ 这有什么好处?→ 保险丝/校验闸/审批壳这些确定性防御才挂得上去。

Q16 · 框架(LangChain 等)和手写怎么选? ​

30 秒答案:判断标准一句话——当你在手写循环里重复造「消息裁剪、工具缓存、并行调度」这三个轮子时,才考虑框架。学过手写循环再看 LangChain 1.0 的 create_agent:它幕后生成的正是你手写的那套装配与路由;而它的扩展点 middleware(历史自动摘要、工具执行前等人批准)恰好对应你手写过的压缩与审批壳——手写经验让你能看穿框架的每一层。低代码平台(Dify/Coze)适合原型,但黑盒:多 Agent 状态机、深度人机协同、评估体系是它「到顶」的三个信号。

项目证据:全程无框架交付了七模块引擎 + 三端(本仓库就是反例证据)。

追问链:LCEL 为什么退出官方推荐?→ 管道符串的是直线,装不下 Agent 的环。

Q17 · 你这个项目最大的难点是什么?(STAR 必考) ​

三个真实故事任选(都有实测证据链):

  • 参数幻觉的闭环治理(S:弱模型幻觉年份查错数据;T:不能靠提示词求自觉;A:zod 校验闸 + error-json 回灌带修正方向 + 红队实验入回归;R:实测模型自我修正年份、投毒样例被拒收);
  • 会话记忆的颗粒度(S:多轮追问丢实体反问用户;T:会话历史只存问答文本的工具结果缺口;A:工具结果实体扫描注入 system 动态段;R:实测追问自动带上文 agentId);
  • SSG 预渲染崩溃(S:文档站构建全页面失败;T:主题路由在 Node 无浏览器 API;A:主题入口补 rAF/cAF 的 no-op 垫片——视觉调度回调在静态渲染本就不该执行;R:225 页全部产出零错误)。

追问链:为什么 A 是这个方案?→ 每个故事都能答出「备选方案与放弃原因」(error-json 回灌 vs 抛异常终止;实体注入 vs 工具结果入史)——说清放弃了什么,比说清做了什么更有说服力。


第二篇 · 场景设计题(高阶环节) ​

知识问答考「知道什么」,场景题考「怎么思考」——「设计一个企业智能客服系统」没有标准答案,面试官看的是四件事:先澄清再设计(场景题最大的坑是直接开答——用户量/数据敏感度/实时性/预算,面试官故意留模糊)、分层作答(数据层→引擎层→交互层→运维层)、取舍显式化(选了什么、放弃什么、为什么)、风险与边界主动交代。下面四道高频场景题,每道都给出答题框架——而它们的完整活答案,就是 agent-app 本身。

场景一 · 设计一个企业智能客服系统(本项目的完整映射) ​

答题框架(五层,每层一个决策点):

  1. 先澄清:接入渠道?业务范围(只答还是能操作)?人工团队规模?数据敏感度?——这四个答案直接决定后三层;
  2. 交互层:web/IM 渠道 → BFF(SSE 流式 + 审批事件通道);
  3. 引擎层:路由先行——硬规则(转人工关键词/高危白名单/连续未解决)纯函数零 LLM,模糊地带才交模型三分类;工具表按工人裁剪(最小权限:订单工人只查、售后只建、知识只检索);
  4. 安全层:写操作过审批壳 + 幂等壳、输入过注入扫描、全程审计账本;
  5. 运维层:会话持久化、压缩防窗口爆炸、评估考卷守质量。

加分项:主动交代「路由为什么硬规则优先」(确定性、省钱、可测——能 if/else 的不用 LLM);「多 Agent 什么时候才需要」(单 Agent 工具表超载时,不为拆而拆)。

雷区:一上来就画 LangChain 架构图;说「全靠大模型理解用户意图」;不提转人工(好客服系统的核心指标是人工接管率,不是自动化率)。

场景二 · 设计一个企业知识库问答系统(RAG 全链映射) ​

答题框架:

  1. 澄清:文档形态(结构化 FAQ 还是长文档)?更新频率?精度要求(错了的代价)?
  2. 入库链:切块(大小两难→瀑布+overlap)→ 向量化(同模型铁律)→ 存储(规模决定 pgvector/内存)→ 入库过注入闸(知识库也是攻击面);
  3. 查询链:同模型向量化 → topK → 引用编号后端分配(出处可信靠机制)→ 提示词声明「资料是数据不是指令」;
  4. 兜底:零命中诚实说不知道;LLM 挂了降级返回检索原文。

加分项:主动给「效果不好」准备排查树(切块大小 → 同模型 → 重排,按序排查);提评估(检索 Recall@k 用测试查询集量化,不靠感觉)。

雷区:不谈切块策略直接说「用向量数据库」;承诺 100% 准确(RAG 的上限=检索质量,诚实边界是加分项)。

场景三 · 给现有产品加一个 AI 助手(渐进式思维) ​

答题框架(关键考点是节奏,不是架构):

  1. 一期 · 只读:先上查询类工具(查订单/查库存)——只读天然幂等,风险最低;配评估考卷建基线;
  2. 二期 · 写操作:加创建类工具——必须配审批壳(高危名单)+ 幂等壳(参数指纹防重放);
  3. 三期 · 自主:开放多步任务——此时才需要步数保险丝、实体继承、压缩水位线;
  4. 全程:评估考卷随功能同步生长;MCP 接入现有系统(不重写接口层)。

加分项:「每期上线前跑评估基线,通过才放量」——把 08 站的考卷变成发布门禁。

雷区:一期就开放写操作无审批;没有评估基线就「根据用户反馈迭代」(无法度量)。

场景四 · Agent 上线后效果不好,怎么排查? ​

答题框架(排查树,先定位再治理):

  1. 先量化:「效果不好」具体是什么?——用评估考卷跑一遍,把「不好」拆成检索失分 / 路由失分 / 生成失分;
  2. 检索失分 → 按序排查:切块大小 → 同模型 → 命中数 → 重排(未做则诚实说这是候选方向);
  3. 路由失分 → 硬规则覆盖不足还是三分类漂移?前者补规则(纯函数可测),后者查 prompt 与考卷;
  4. 生成失分 → 参数幻觉?(校验闸日志)空数据编造?(诚实化声明在位吗)说而不做?(提示词硬规则 + 实体注入);
  5. 治理后跑基线对比——「变好了」必须有分数证据。

加分项:把 week19 红队的三原则带进来——「先挨打后加固 / FAIL 记 FAIL / 载荷入回归」,排查树本身就是红队实验的逆运用。

雷区:不量化就改 prompt(「感觉变好了」是幻觉);一次改多个变量(无法归因)。


面试策略三则 ​

  1. 每答必带项目证据:「模型会幻觉参数」谁都会说——「我们的 zod 闸实测拦下 2022-09 并引导模型自我修正」只属于跑通过的人;
  2. 主动暴露边界:「检索重排我们没做,这是已知的下一课」比假装全知加分得多(面试官对诚实的边界感极其敏感);
  3. 追问是礼物:追问链走到答不上来的那一层,就是你与岗位的距离——记下来,它就是你的下一章。

延伸 ​