Agent 面试通关 / 07

工程化踩坑:死循环、状态丢失与成本控制

踩坑题是面试的“照妖镜”——没做过的人编不出来。面试官问这类题不是要标准答案,而是看你有没有在生产环境里摔过跤、摔完有没有系统性地解决。答得出具体的坑和对应的工程方案,比答十道理论题都管用。



Q:如何评审 AI 生成的技术方案并进行重点提炼与技术取舍?

来源:秋招-字节跳动-抖音电商-Agent开发一/二/三面

新手答:“先确认需求,再检查 AI 方案的可行性、风险和成本,最后用小实验验证关键结论。”

高手答:

评审 AI 方案时,先把长文压缩成目标、约束、关键假设、候选架构和决策结论,确认它是否真正回答业务问题。再逐项检查数据流、依赖、失败模式、幂等、并发、安全、隐私、成本、可观测性和回滚路径;把事实、推断和未经验证的数字分开,要求关键结论有文档、代码实验或压测证据。工程上建议建立包含收益、复杂度、风险、可运维性和迁移成本的决策表,用小范围原型验证最不确定的环节,并为上线设置质量、延迟和错误率门槛。取舍不是选最复杂或最先进的方案,而是在明确约束下保留必要能力,删除没有证据支撑的装饰;同时预设失败回退和复盘机制。

差距在哪:浅层评审停留在检查格式和“能不能做”,面试官更看重能否识别假设与失败模式、用证据验证关键路径,并在收益、风险和运维成本间做取舍。

踩坑与经验总结

Q:Agent 的成本怎么控制?线上烧钱太快怎么办?

来源:Agent 岗面试高频题【字节实习二面追问:LobeChat 为什么烧 token】【顺极 Agent 开发二面追问:Agent 全量开放后的成本与容量治理】【字节 AI 应用开发二面追问:具体 Token 成本控制】【百度 - Agent 研发岗(架构方向)追问:大规模部署下如何控制 Token 成本(缓存、模型选型、结果复用)?】;本轮追问:大规模部署时Token成本怎么控制?(百度Agent二面,不看简历不问八股);本轮追问:模型推理成本怎样判断是否合理,还有哪些优化空间?(9.15快手二面AI应用);本轮追问:介绍一下 token 消耗优化的一些手段。(【社招】腾讯一面面经);虾皮agent开发一面;秋招第二挂 小红书

新手答:“用更便宜的模型。”

高手答:

换模型是最后的手段,换了可能效果也打折。成本控制要从架构层面系统性地做:

  1. 分级调度:不是所有步骤都需要最强模型。意图识别、参数校验这种简单任务用小模型(7B / 14B),只有核心推理环节才用大模型。一个任务里可能 80% 的调用走小模型,只有 20% 走大模型
  2. Token 预算制:每个任务有 token 预算上限,执行过程中实时统计。接近预算时自动触发“省钱模式”——压缩上下文、跳过非必要步骤、简化输出
  3. 缓存复用:相似请求的中间结果做缓存。比如“查北京天气”这种高频工具调用,5 分钟内的结果直接复用,不重复调用 API 也不重复让模型处理
  4. 超预算熔断:单用户单日消费超过阈值,自动限流或降级。这不只是省钱,也是防止恶意用户用 prompt injection 让 Agent 无限循环烧钱

追问补充:成本按实际计费单位逐次累加:各请求的计费输入、输出及缓存 Token 分别乘对应单价,再计工具、重试等费用,不能在累计 Token 费用上重复乘调用次数。自部署按资源占用、利用率和运维投入摊销;用每个成功任务的成本,在同一质量与延迟目标下比较方案。

追问补充:量化时先固定同一批流量、任务成功率和延迟目标,建立优化前基线,再做灰度对照;分别统计输入、输出、缓存 Token、模型调用次数和工具重试,计算单次成功任务成本及降幅。还要按任务类型、缓存命中率和长尾请求分层,避免平均值掩盖退化。

差距在哪:新手的“换模型”是一维思考——只在模型选择上做文章。高手的方案是四维的:调度策略(谁用什么模型)、预算控制(花多少停)、缓存复用(重复的不花)、熔断保护(异常的不让花)。面试官考的是“你有没有成本意识和系统设计能力”——这和后端系统的限流、降级、熔断是同一套思路。

追问:开源 Agent 框架(如 LobeChat)为什么特别容易烧 token?

来源:字节实习二面

LobeChat 等开源 Agent 框架烧 token 的原因不是框架本身“浪费”,而是默认配置追求通用性而非经济性:

  1. 全量对话历史注入:每次请求把完整对话历史发给模型,10 轮对话后上下文可能已经 8000+ token,但其中大部分和当前问题无关。没有做摘要压缩或滑动窗口
  2. System Prompt 膨胀:支持多种场景的通用 System Prompt 往往很长(2000+ token),每次请求都重复发送
  3. 插件/工具描述全量加载:即使用户只需要搜索功能,所有已安装插件的 schema 都会写进 tools 参数,每次调用都消耗 token
  4. 缺少缓存层:相似问题每次都重新调模型,没有语义缓存。尤其高频场景(“今天天气”“最新新闻”)可以直接返回缓存结果
  5. 模型选择不分级:所有任务都走同一个大模型,没有根据任务复杂度做路由——简单的意图识别和复杂的推理任务用同样贵的模型

优化方向就是上面四条策略的具体化:压缩历史、动态加载工具 schema、加语义缓存、做模型路由。

追问:Agent 从小流量试点变成全量开放后,成本预算和推理容量怎么治理?

不能只把单任务 Token 上限乘以用户数。先按任务类型统计到达率、并发时长、模型调用次数、上下文长度和工具等待,形成“每任务成本 + 峰值容量”基线;再给租户、任务和执行阶段分配独立预算。意图识别、抽取和校验优先走小模型或确定性代码,复杂推理才升级大模型;队列接近容量时执行限流、延迟低优先级任务或降级到可解释的简化流程。

预算治理还要和质量一起看。按任务切片监控成功率、P95 延迟、单次成功任务成本、超预算率和人工接管率,避免为了省 Token 把任务做失败。扩量采用分阶段配额和容量压测,模型、Prompt 或工具变更后重新估算,而不是沿用试点阶段的平均值。


Q:开发 Agent 时踩过什么坑?

来源:Agent 岗面试高频题 / 阿里国际 Agent 开发三面 / 快手 AI 全栈一面

新手答:“模型有时候不听话,输出格式不对。”

高手答:

坑太多了,挑几个最痛的:

坑一:死循环——模型反复调同一个工具

模型调了一个工具拿到错误结果,然后用一模一样的参数再调一次,无限循环。

解法:① 加失败计数器,同一工具连续失败 2 次直接终止该路径;② 每次重试前让模型先分析上次失败原因,强制改变参数或策略;③ 超过全局步数上限(比如 15 步)直接结束,输出当前最优结果。

坑二:状态丢失——多轮对话里关键信息不翼而飞

用户在第 3 轮说了“预算 5000 以内”,到第 10 轮模型推荐了个 8000 的方案。不是模型故意忽略,是上下文太长被截断了,或者关键信息被淹没。

解法:① 关键参数实时抽取,写入独立的状态存储(Redis / 数据库),不依赖上下文承载;② 每次调用模型时,把当前任务的关键约束作为 System Prompt 的一部分强制注入,而不是埋在历史消息里;③ 定期用模型做自检——“当前任务的约束条件有哪些?”,发现遗漏立刻补回来。

坑三:JSON 解析翻车——模型输出“差一点点”的 JSON

模型返回的 JSON 格式上“几乎正确”——多了个逗号、少了个引号、在 JSON 前面加了句“好的,以下是结果:”。用 json.loads() 直接崩。

解法:① 用正则先提取 JSON 块(匹配 {...} 或 [...]),再解析;② 用 json-repair 之类的库做容错解析;③ 最根本的解法:用模型原生的 function calling / structured output,不要让模型自己拼 JSON 字符串。

坑四:成本失控——一个任务烧掉几十块

复杂任务里模型思考了 30 步,每步都带完整上下文,token 量指数级增长。一个用户的一次请求可能烧掉几十块钱。

解法:① 限制每轮 token 数上限,每个 Agent 有独立的 token 预算;② 实时监控单任务累计成本,超过阈值自动告警并降级(比如切换到更便宜的模型);③ 上下文管理做好——中间结果落库、历史消息压缩,从源头减少 token 消耗。

差距在哪:新手只能说出一个笼统的“输出格式不对”。高手每个坑都有三层结构:① 具体的故障现象(什么情况下出的);② 根因分析(为什么会这样);③ 系统性的解法(不是临时 patch,而是工程化方案)。面试官考的是“你踩过坑之后有没有复盘和系统性修复的习惯”。


Q:为什么很多 Agent Demo 很惊艳,但一上线就不稳定?

来源:腾讯大模型应用开发二面

新手答:“因为线上环境比 Demo 复杂。”

高手答:

Demo 往往是在理想条件下演示的——输入干净、工具有限、单次任务、短上下文。模型只要看起来会做事就行了。但线上环境完全不一样:

Demo 环境:理想输入、有限工具、单次任务、短上下文
线上环境:输入脏、任务长、工具多、状态复杂、异常频繁、权限安全约束

Demo 能跑通,只能说明“这个方向可能”。线上稳定,说明的是你把模型的不确定性关进了工程笼子里。

真正难的是做治理,不是做演示。很多团队一开始觉得问题在模型不够强,后来才发现大量问题其实来自状态管理、工具设计、上下文污染和缺少容错机制。

差距在哪:新手只说了“环境复杂”——这是现象不是分析。高手指出了 Demo 和生产环境的具体差异(输入质量、任务长度、状态管理、异常处理),且点出了核心观点:“稳定不靠模型强,靠工程治理”。面试官考的是你有没有把 Agent 从 Demo 推到生产的实战经验。


AI 工具与框架

Q:平时用过哪些 AI Agent 工具?

来源:腾讯 Agent 应用开发一面 / 杭州和为机电 AI 应用工程师面试;本轮追问:平时用什么AI编码工具?(本轮追问);本轮追问:平时是否使用 AI Coding 或 AI 数据分析?(本轮追问);本轮追问:你对 AI 工程了解多少?(本轮追问);本轮追问:平时工作中一般会用到哪些 Agent 工具和模型?(本轮追问);本轮追问:你平时开发用什么模型?(本轮追问)

新手答:“用过 ChatGPT。”

高手答:

AI Agent 工具按用途分三类:

类别 代表工具 特点
通用对话型 ChatGPT、Claude、Kimi 单轮/多轮问答,不主动执行操作
开发框架型 LangChain、LangGraph、Dify、Coze 提供编排、工具调用、记忆等基础设施,开发者搭建 Agent
AI Coding 型 Cursor、Claude Code、GitHub Copilot 直接辅助写代码,有项目上下文感知

关键认知:这三类工具解决的问题不同——通用型解决“问答”,框架型解决“编排”,Coding 型解决“开发效率”。实际做 Agent 开发时,框架型和 Coding 型通常同时使用:用 Coding 工具写代码,用框架搭 Agent 流程。

选工具的标准不是“哪个最热”,而是你的任务需要什么级别的控制力:简单任务用 Dify/Coze 拖拽搞定;需要自定义编排的用 LangGraph;需要最大灵活性的直接用 SDK + 自建。

差距在哪:新手只列了名字。高手按用途做了分类,且说清了选型标准。面试官考的是你对 Agent 工具生态的全局认知。


Q:你熟悉的 Agent 框架,在架构设计上有什么优势?

来源:腾讯 Agent 应用开发一面;本轮追问:如果不使用框架,原生实现Agent你写过吗?使用框架的优劣势?(美团AI Agent一面);本轮追问:聊一个你熟悉的 AI 应用框架:解决什么问题、设计巧思、落地使用场景。(恒生电子技术岗ai面);本轮追问:请聊一个你熟悉或自研的AI应用框架。它的核心是为了解决什么问题,在实现上有哪些技术设计上的巧思,你又在什么场景里真正用它落地过?(27秋招-恒生电子AI面试-AI应用开发岗-26.9.23);本轮追问:Agent 框架有哪些?(中兴未来领军计划AI算法一面);乐堡AI应用开发岗四面面经,面试官非常nice!;传化智联一面;秋招第二挂 小红书

新手答:“它用了 LLM,很智能。”

高手答:

以 OpenClaw 为例,它的架构优势体现在三个层面:

  1. 编排层和能力层分离:编排层(状态机/DAG)负责“做什么、按什么顺序做”,能力层(LLM 调用、工具执行)负责“具体怎么做”。分离后编排逻辑可以独立测试和复用,不和模型调用耦合
  2. 工具即插件:工具通过标准化接口(类似 MCP 的 tool schema)注册,新增工具不需要改编排代码。这让工具生态可以独立演化
  3. 上下文管理可配置:不是硬编码“保留最近 N 轮”,而是提供多种上下文策略(滚动窗口、摘要压缩、按需召回),开发者根据场景组合

这三个优势的共性是关注点分离——编排、能力、工具、上下文各自独立演化,互不干扰。这和微服务架构的设计哲学是一致的。

原生实现通常是状态机或循环:维护对话状态,调用模型决定下一步,按 schema 分发工具,并补上超时、重试、权限、上下文裁剪和 Trace。优点是链路透明、可控、依赖少;缺点是要自行维护编排、异常恢复和工具协议。框架能提效和标准化,但也可能带来抽象泄漏、调试困难与版本耦合。

常见框架可按定位区分:LangChain/LangGraph偏组件与流程编排,AutoGen偏多智能体协作,LlamaIndex偏数据与检索接入。实际选型要结合场景,例如客服知识库用检索加工具编排,复杂任务用状态图控制分支、重试和人工介入。

追问补充:建议把框架层限定为可替换的编排与运行时,通过模型、工具、存储和回调接口扩展;业务记忆策略、评测集、质量门禁由应用实现。用相同任务和故障注入对比状态恢复、工具失败、流式中断和迁移成本,再判断框架带来多少实际收益。

差距在哪:新手用“智能”概括一切。高手从编排/能力分离、工具插件化、上下文可配置三个架构决策分析优势。面试官考的是你对框架的理解是“会用”还是“理解设计”。


Q:平时写的代码有多少是 AI 生成的?怎么保证质量?

来源:腾讯 Agent 应用开发一面 / 杭州和为机电 AI 应用工程师面试【抖音电商Agent全栈开发工程师一面追问:AI Coding 的占比大概是多少?】【9.2百度AI测开2面追问:在你们日常的 Coding 工作中,大约有多少比例的代码是通过 AI Coding 或 Vibe Coding 生成的?】;本轮追问:你在 Skill 或项目中提交的代码大概是什么量级?都是 AI 写的吗?(度小满 AI 全栈二面)

新手答:“大概 50%,然后自己改改。”

高手答:

比例因任务类型而异:

  • 样板代码(CRUD、配置、测试骨架):80%+ 由 AI 生成,人工只做审查和微调
  • 核心业务逻辑(算法、状态机、并发控制):AI 生成初版,人工大幅修改,实际保留 30-40%
  • 架构设计和技术选型:AI 提供选项和分析,但决策完全由人做

保证质量的方法不是“自己改改”,而是流程化的质量门禁:

  1. 生成前约束:给足上下文(类型定义、接口规范、项目规则文件),让 AI 一次生成质量更高的代码
  2. 生成后审查:AI 生成的代码必须过 Code Review,重点看边界条件、安全漏洞、和已有代码的一致性
  3. 自动化验证:类型检查(TypeScript)、lint、单元测试必须通过。AI 容易写出“看起来对但类型不安全”的代码

核心原则:AI 生成的比例不重要,重要的是每行代码都经过了验证。

怎么回答“占比多少”这类问题:

面试官问这道题不是想听一个数字,而是考察你对 AI 辅助开发的认知成熟度。回答时避免两个极端:说“90% AI 写的”会让面试官觉得你不审代码;说“很少用”会让面试官觉得你效率低。正确的回答结构是:按任务类型分层 → 每层给一个合理比例 → 重点讲质量保障流程。数字本身不重要,展示你对“人机协作边界”的清晰认知才重要。

如果被追问具体量级,应按实际仓库的文件数、提交范围或功能模块说明,而不是虚构一个比例。提交内容不会全部由 AI 生成:需求拆解、架构设计、关键逻辑、调试和最终审查由人负责,AI 主要承担样板代码、测试骨架和局部实现。

差距在哪:新手只给了一个比例。高手按任务类型分了不同比例,且给出了系统化的质量保障方法。面试官考的是你对 AI 辅助开发的成熟度。


Q:用过哪些 Code Agent?优缺点?

来源:腾讯 AI 应用开发 【淘天Agent开发追问:AI辅助编程工作流拆解 + 提示词策略与人工审核介入点】【字节火山引擎 Managed Agent 一面追问:如何用 Coding Agent 完成项目开发】 / 杭州和为机电 AI 应用工程师面试 / OPPO IT 开发一面

新手答:“用过 Copilot,挺好用的。”

高手答:

目前 Code Agent 工具分两类:IDE 集成型和终端独立型,工程定位不同。

类型 代表工具 优点 缺点
IDE 集成型 Cursor / Windsurf / Copilot 感知项目上下文(目录、类型、导入),补全即时、改完直接看 diff 对大规模跨文件重构支持有限
终端独立型 Claude Code / Codex CLI / Aider 能执行 shell 验证代码、跑测试、做 git 操作;全局视角 没有实时补全体验,需要更多上下文描述

实际使用策略——两类互补而非互斥:

  • 写新功能、局部修改 → IDE 集成型(实时补全 + 即时预览)
  • 跨文件重构、项目搭建、调试排查 → 终端型(能执行验证 + 全局操作)
  • 两类工具都受益于项目级规则约束(CLAUDE.md / .cursorrules),定义编码规范和技术栈约束后输出质量显著提升

核心认知:Code Agent 的瓶颈通常不是模型能力,而是上下文不足和约束不够——给足项目规则和相关代码上下文,输出质量有质的飞跃。

日常 AI Coding 的实战工作流:

“平时怎么用 AI Coding”是近期高频面试题,面试官想听的不是“用 Cursor 写代码”,而是你的工作流和方法论:

高效使用的三层模式:

模式 场景 具体做法 效率提升
自动驾驶 重复性任务(CRUD、测试用例、类型定义) 给 Agent 明确指令 + 格式要求,让它一次性生成 5-10x
副驾模式 中等复杂度任务(重构、Bug 修复) 自己做设计决策,让 AI 执行具体代码变更 2-3x
导航模式 探索性任务(学新框架、理解陌生代码) 让 AI 解释代码、提供方案对比,自己做最终判断 1.5-2x

关键实践原则:

  1. 先给上下文再给指令:不是直接说“帮我写个排序”,而是先让 AI 读懂项目结构、了解编码规范,再给具体任务
  2. 小步验证:不要让 AI 一次改 20 个文件,而是分步执行、每步验证。一次大改出错了很难定位
  3. AI 生成 → 人类审查 → AI 修正:不盲信 AI 输出,但也不逐行手改——用 AI 的速度生成,用人的判断审核
  4. 知道什么时候不用 AI:涉及核心业务逻辑的架构决策、安全敏感代码、需要深度理解上下文的 Debug——这些场景人工效率更高

差距在哪:新手只评价了“好不好用”。高手按工具类型做了系统对比,且给出了互补使用策略和提升质量的方法论。面试官考的是你对 AI Coding 工具的实际使用深度。

追问:公司里有几十个应用,改一个需求要动多个系统,AI Coding 怎么处理?

来源:蚂蚁 Agent 开发一面

这道题考的是当前 AI Coding 的能力边界——大部分候选人只在单 repo 里用过 AI Coding,面试官想知道你对企业级多系统场景的认知。

核心矛盾:当前 AI Coding 工具以单项目为粒度工作,但企业需求往往跨多个仓库(前端、BFF、后端、基础设施)。一个需求改三个系统,AI 只能看到一个。

分层解决思路:

层级 方案 适用场景
人工拆解 + AI 执行 人工把跨系统需求拆成每个系统的独立任务,每个任务用 AI 完成 当前最实际的方案
共享接口契约 把接口定义(OpenAPI/Proto/GraphQL Schema)作为上下文注入到每个系统的 AI 会话中 保证跨系统一致性
多 Worktree / 多 Session 每个系统开独立 session,通过 CLAUDE.md 注入全局需求背景和接口约定 Claude Code 已原生支持 worktree
编排层协调 用一个 orchestrator Agent 分解需求、分发子任务、校验接口一致性 未来方向,当前不成熟

当前最佳实践:

1. 人工做需求拆解和接口设计(AI 最弱的环节)
2. 把接口契约写成文档,作为每个系统 AI 会话的上下文
3. 每个系统用 AI 独立实现,实现完跑集成测试
4. 接口变更时手动同步到其他系统的 AI 上下文

诚实回答:这个场景是当前 AI Coding 的硬伤——跨系统状态同步、接口一致性保障、变更顺序依赖这些问题,AI 暂时没法自主解决。但人工拆解 + AI 分系统执行 + 契约共享,已经比纯人工效率高很多。


Q:自己做 Agent 时,踩过最大的坑是什么?

来源:腾讯 Agent 应用开发一面;阿里云二面

新手答:“模型输出不稳定。”

高手答:

最大的坑是过度信任模型的“理解力”,导致状态管理全靠上下文承载。

早期做 Agent 时,觉得模型能“记住”之前的对话,所以把关键参数(用户偏好、任务进度、中间结果)全放在对话历史里。结果上下文一长,模型就开始丢信息、乱推理——用户在第 3 轮说的约束条件,到第 10 轮完全被忽略。

系统性修复:把“模型记住”改成“系统记住”——

  1. 关键参数实时提取到独立的状态存储(Redis / 数据库),不依赖上下文
  2. 每轮调用前把当前约束条件作为 System Prompt 的固定部分强制注入
  3. 中间结果落库,上下文里只留一句摘要

这个坑的本质是:Agent 的上下文窗口是“工作台”,不是“仓库”。工作台上只放当前步骤需要的东西,其他全放仓库里按需取。

差距在哪:新手说“不稳定”是表象。高手指出了根因(过度依赖上下文承载状态)和系统性解法(状态外置 + 强制注入 + 落库)。面试官考的是你踩坑后有没有做过根因分析和系统性修复。


代码质量与测试

Q:如何保证 AI 代码生成的质量与掌控性?

来源:蚂蚁集团 Agent 开发一面 / 字节 AI 应用开发二面 / 去哪儿 AI 全栈 AI 面【阶跃星辰(Stepfun)- 大模型算法岗(Post-train)追问:AI Coding 习惯及代码质量保证?】【快手 - Agent 开发岗(应用落地 + AI 工具)追问:如何确保 AI 生成代码逻辑可靠?;AI 编码工具(Cursor/Codex)如何协作及保证代码质量?】【要务科技-面筋追问:如何让AI写业务代码?】【作业帮一面 9.5追问:之后怎么保证代码质量?怎么验证?还有别的机制吗?】;本轮追问:如何与AI协作的(本轮追问);本轮来源;本轮来源;本轮追问:从 0 设计一个通用的、规范驱动的 CLI/SDK 代码生成平台(支持 OpenAI、Arazzo 等多样输入规范,支持 Java、Python 多语言,保证用户手写代码不被覆盖,支持团队多人协作),讲讲你的系统分层设计。(本轮追问);本轮追问:这里面有好几个环节,产物的生成怎么保证?(本轮追问);本轮追问:对于编程任务,如何评估 Agent 生成代码的质量?(9.14小红书 PE(产品工程师/全栈方向–实习)二面 (流程泡到9.21挂));科大讯飞 Agent开发 一面;(秋招) 9.16 字节中交广 - 交易与广告业务 - AI全栈开发工程师;9.15快手二面AI应用;本轮追问:模型生成的代码会全部人工 Review 吗,如何控制改动范围?(9.15秋招东方财富AI应用一面);【社招】腾讯三面面经;经纬恒润ai应用开发一面面经;美团 正式批 一面 自动驾驶算法工程师;度小满 - AI 全栈研发 - 二面;美团ai全栈二面;恒生一面;9.30 binance AI全栈开发实习一面

新手答:“生成后人工 review 一下。”

高手答:

人工 review 是最后一道线,但不能是唯一一道。保证质量和掌控性要在生成前、生成中、生成后三个阶段都做控制:

生成前——约束输入,减少出错空间:

  1. 上下文精准投喂:给模型完整的类型定义、接口规范、相关测试用例,而不是只给一句需求描述。上下文越精确,生成质量越高
  2. 项目规则注入:通过 CLAUDE.md / .cursorrules 定义编码规范(命名风格、错误处理模式、禁用的 API),让模型生成时就遵守项目约定
  3. Spec 先行(SDD):对复杂功能,先让 AI 生成技术规格说明,人工确认后再生成代码。在理解阶段就拦住方向性错误

生成中——约束输出,缩小自由度:

  1. Structured Output:函数签名、返回类型、错误码这些关键接口用 schema 约束,不让模型自由发挥
  2. 增量生成:不让模型一次生成 500 行。拆成小步——先生成函数骨架、再填充逻辑、再补异常处理,每步可验证
  3. Diff 模式:修改已有代码时,要求模型输出精确的 diff 而非整文件重写,减少意外修改

生成后——验证结果,兜住底线:

  1. 自动化门禁:生成的代码必须通过类型检查(TypeScript/mypy)、lint、现有测试套件。不过门禁不允许合入
  2. AI 自验证:让模型同时生成代码和对应的测试用例,跑通测试才算完成。这不完美,但能抓住明显的逻辑错误
  3. 安全扫描:自动检测常见漏洞模式(SQL 注入、XSS、硬编码密钥),AI 生成的代码更容易引入这类问题
flowchart LR
    subgraph before["生成前"]
        B1["上下文精准投喂"]
        B2["项目规则注入"]
        B3["Spec 先行"]
    end
    subgraph during["生成中"]
        D1["结构化约束"]
        D2["增量生成"]
        D3["Diff 模式"]
    end
    subgraph after["生成后"]
        A1["类型检查 + lint"]
        A2["AI 自验证"]
        A3["安全扫描"]
    end
    before --> during --> after

掌控性的核心原则:生成的每一步都要有人类可审查的检查点。不是“生成完看一眼”,而是“每个阶段都有明确的验收标准”。

“代码能运行”只是最低门槛,不代表它满足业务不变量、异常边界、性能预算和长期可维护性。质量门禁还要把项目规范变成可执行约束:格式、类型、lint、测试、安全扫描由 Hooks 或 CI 确定性执行,人工 Review 负责业务语义和架构影响;模型自评只能提供线索,不能替代这些门禁。

不必对所有生成代码做同等深度的人工 Review:所有改动都先经过自动化门禁,高风险模块、权限与数据处理必须人工审查。通过独立分支、任务级文件白名单、最小 diff 和禁止整文件覆盖控制范围;若 diff 超出预期或触及无关文件,直接退回重生成。

追问补充:定位 Bug 时先让 Agent 根据复现步骤、日志、堆栈和最近 diff 提出假设,明确修改范围与验证命令;人先确认假设,再让它做最小补丁。通过新增回归测试、运行定向测试及全量门禁验证,若失败要求分析反例而非反复盲改,并保留每次 diff 便于回滚。

追问补充:前端和客户端应先让 AI 遵循组件库、交互规范和接口契约,按页面或组件小步生成;除类型、单测和 lint 外,还要做视觉回归、不同屏幕与系统版本测试,并在真机验证权限、网络异常、性能和无障碍,避免只在模拟器或单一路径可用。

追问补充:对比 AI Coding 不能凭主观观感,应固定同一需求、上下文和提示,比较编译通过率、测试覆盖与通过率、缺陷率、改动范围、可维护性和安全问题。解释生成代码时逐段核对数据流、异常分支、并发与权限边界,指出违反规范或业务不变量的具体位置,并用测试或反例验证判断。

差距在哪:新手只有事后 review 一道防线。高手在生成前(约束输入)、生成中(约束输出)、生成后(自动验证)三个阶段构建了九道防线。面试官考的是你对 AI 代码生成的质量体系有没有工程化的设计。


Q:如何解决大模型 API 服务的响应延迟问题?

来源:字节 Agent 实习一面 【小红书数据库智能化二面追问:产品层面的等待体验优化】【小舒一面追问:异步调用与线程阻塞】 / 互联网金融 Agent 开发三面【9/4泰隆一面追问:如何提高大模型响应速度?】;本轮追问:座舱场景对延迟要求极高,怎么优化Agent的响应速度?(蔚来——大模型算法岗(智能座舱/自动驾驶)实习一面);本轮追问:多 Agent 编排的“响应慢”问题如何解决(赛诺贝斯 面经 一面过 笔试过 hc无);本轮追问:为了降低TTFT替换了豆包1.8 flash模型,还做了KV缓存优化,在平衡响应速度、回答准确性、调用成本这三者的时候,你们最终做了哪些关键取舍?(27秋招-恒生电子AI面试-AI应用开发岗-26.9.23);腾讯 260824 一面面经;10.8 pdd秋招 agent 一面

新手答:“用更快的模型。”

高手答:

API 服务延迟分两部分:首 token 延迟(TTFT) 和生成吞吐(TPS),优化思路不同。

1. 流式输出(Streaming)——最直接的体感优化:

  • 不等全部生成完再返回,逐 token 流式输出。用户感知延迟从“等 10 秒”变成“0.5 秒就开始看到内容”
  • SSE(Server-Sent Events)或 WebSocket 实现

2. 模型层面:

  • 模型分级调度:简单请求(分类、提取)用小模型(7B/14B),复杂请求(推理、创作)用大模型。80% 的请求可以用小模型处理,延迟降 5-10 倍
  • 量化部署:INT4/INT8 量化减少计算量和显存占用,推理速度提升 2-3 倍
  • 推测解码:小模型快速生成草稿,大模型批量验证,整体速度提升 2-3 倍

3. 服务架构层面:

  • KV Cache 复用:多轮对话中,前几轮的 KV Cache 不需要重算,缓存后复用,TTFT 大幅缩短
  • Prefix Caching:共享相同 System Prompt 的请求复用前缀计算结果
  • 连续批处理:vLLM/SGLang 的 continuous batching,请求到达即处理,不等凑满一批
  • 负载均衡:多实例部署 + 按当前负载智能路由,避免单实例过载

4. 缓存层面:

  • 语义缓存:对高频相似请求做语义匹配,命中缓存直接返回,不调模型。适合 FAQ 类场景
  • 工具结果缓存:Agent 场景中,工具返回值(天气、股价等)设 TTL 缓存,避免重复调用

5. 产品交互层面:

  • 尽早通过 SSE 返回首个可见事件,把“正在检索、已找到 N 条证据、正在生成”作为结构化进度,而不是伪造模型思考过程
  • 长任务提供取消、超时后后台继续和结果通知,让用户能在方向错误时尽早终止,减少无效 token 消耗
  • 产品层优化不降低真实总耗时,但能降低无反馈等待;必须和后端 TTFT、P95/P99 指标分开评估

6. 调用与任务执行模型:

  • 不要让 Web 请求线程用同步 SDK 阻塞等待几十秒的 LLM 调用。在线短请求使用异步客户端、连接池和有界并发,避免请求量上升后线程、连接和内存一起耗尽
  • 长任务进入队列或 Job 系统,请求先返回 task_id,结果通过 SSE 推送或轮询获取;生成过程与客户端连接解耦
  • 为整条请求和每个模型/工具步骤设置 deadline、超时、取消传播和有限重试,并用幂等键避免重试造成重复副作用

async 不会缩短单次模型推理时间,它解决的是等待期间不占住请求线程,从而保住并发吞吐和取消能力。真正的总耗时仍要靠模型、上下文、并行路径和缓存优化。

座舱应优先采用本地轻量模型处理唤醒、意图识别和高频指令,并为安全相关请求设置硬截止时间和无模型兜底。多 Agent 编排时先由编排器裁剪无关 Agent,共享上下文,按依赖将独立任务并行执行;支持首个可用结果提前返回、超时取消和降级,避免串行等待全部 Agent。

取舍应以离线质量集和线上 P95 TTFT、回答准确率、单请求成本共同决策:简单问答路由 Flash,复杂推理保留更强模型;KV 缓存只复用稳定前缀,用户上下文或权限变化时失效,并保留超时和质量降级兜底。

差距在哪:新手只想到换模型。高手从流式输出、模型分级、服务架构、缓存、产品交互和任务执行六个层面做了系统优化,且区分了 TTFT、TPS、并发吞吐与用户感知等待。面试官考的是你对大模型服务工程化的理解——延迟优化不只是“模型更快”,而是一个全栈工程问题。


Q:AI Coding 产品怎么测试?从 Demo 到生产可交付还差什么?

来源:蚂蚁集团智能体与大模型应用二面【字节 AI Agent 开发岗一面追问:如何将 Spec-Driven Development 与 Agent 结合?】【DeepSeek Harness 方向面试追问:Spec-driven development 在 AI 时代如何与 Agent 结合?】

新手答:“写几个 case 测一下就行。”

高手答:

AI Coding 产品的测试和传统软件测试有本质区别——输出是概率性的,同样的输入不一定得到同样的输出,所以不能只靠“写几个 case 通过了就行”。

测试方法论:

1. 构造评估集,不是测几个 case:

  • 设计覆盖不同代码复杂度(纯函数 / 有依赖 / 异步 / 并发)和任务类型(生成 / 修复 / 重构 / 解释)的评估集
  • 每个 case 要有明确的验收标准:不是“看起来对”,而是能编译、能通过测试、符合代码规范
  • 评估集要包含边界和对抗 case:超长文件、语法错误的输入、故意误导的 Prompt

2. 评估维度不只是“对不对”:

维度 指标 说明
正确性 Pass@K、编译通过率 K 次生成中至少一次正确的概率
一致性 同一输入多次生成的方差 输出是否稳定
安全性 有无注入漏洞、敏感信息泄露 生成的代码是否安全
效率 Token 消耗、端到端延迟 成本和速度

从 Demo 到生产可交付,还差什么:

  1. 鉴权和权限控制:Demo 不需要考虑谁能用、能操作哪些文件。生产环境必须有用户身份验证和操作权限隔离
  2. 错误恢复和回滚:Demo 出错了重来就行。生产环境需要操作日志、变更回滚(类似 git revert)、异常告警
  3. 并发和多用户:Demo 是单用户。生产环境要支持多用户同时使用,状态隔离,资源限制
  4. 监控和可观测性:生成质量监控、成本监控、异常检测、用户反馈收集——没有这些,线上问题完全是黑盒
  5. 安全审计:AI 生成的代码可能引入安全漏洞,生产环境需要自动化安全扫描(SAST/DAST)
  6. CI/CD 集成:生成的代码要能自动跑 lint、测试、构建,不能只靠人工 review

差距在哪:新手的“测几个 case”只是验证“能不能跑”。高手从评估集设计、多维度指标、生产化六大能力(鉴权、回滚、并发、监控、安全、CI/CD)展开。面试官考的不是“会不会测试”,而是你对“把 AI 能力做成产品”这件事的完整认知。


Q:什么是 SDD(Spec-Driven Development)?它和 Skills 有什么区别?

来源:蚂蚁集团智能体与大模型应用二面

新手答:“SDD 就是先写规格再写代码,Skills 是预定义能力。”

高手答:

SDD(Spec-Driven Development,规格驱动开发)是 AI Coding 领域的一种工作流方法——先让 AI 生成详细的技术规格说明(Spec),人工审核确认后,再让 AI 按照 Spec 生成代码。

SDD 的核心流程:

flowchart LR
    A["用户需求"] --> B["AI 生成 Spec\n(接口定义/数据结构/\n流程设计/边界条件)"]
    B --> C["人工审核 Spec\n修改/确认"]
    C --> D["AI 按 Spec 生成代码"]
    D --> E["自动化验证\n(类型检查/测试/lint)"]
    E -->|不通过| D
    E -->|通过| F["代码交付"]

为什么要这么做:直接让 AI 写代码的问题是——需求理解错了,生成的代码再完美也没用。SDD 把“理解需求”和“写代码”拆开,在理解阶段就做人工确认,避免代码写完才发现方向错了。

SDD vs Skills 的对比:

维度 SDD Skills
本质 开发工作流方法论 Agent 的可复用能力单元
解决的问题 “怎么让 AI 写出正确的代码” “怎么让 Agent 处理特定类型的任务”
关注点 需求→规格→代码的转化质量 触发匹配→Prompt→工具→输出的执行流程
人工参与 核心环节(审核 Spec) 可选(配置后自动执行)
适用场景 代码生成、架构设计 任何 Agent 能力扩展
输出物 Spec 文档 + 代码 任务执行结果

两者的关系:不互斥,可以结合。一个“代码生成 Skill”可以内部采用 SDD 流程——Skill 定义了“什么时候触发、用什么工具”,SDD 定义了“触发后按什么步骤生成代码”。

Skills 是能力的封装方式,SDD 是代码生成的质量保障方法。前者回答“Agent 能做什么”,后者回答“怎么做得对”。

进一步说,Spec 不应只是一段更长 Prompt,而应是版本化、可验收的工程契约:定义目标、非目标、用户场景、接口/数据不变量、约束、验收用例和未决问题。GitHub Spec Kit把流程组织为 constitution、specify、plan、tasks 等阶段;这是一个具体工具实现,团队可以采用相同原则而不绑定它。

Coding Agent 执行时,每个任务和代码变更都应引用 spec_id / requirement_id,Verifier 从验收条款生成独立测试。发现实现与 Spec 冲突时,Agent 应分别提出 code diff 或 spec change,不能同时放宽验收标准并修改代码来制造“通过”。探索阶段可以做带预算的 Spike,但发现必须回写成待审 Spec diff,稳定需求再进入强门禁。

差距在哪:新手把两者简单对立。高手看到了它们在不同维度上的定位——SDD 是方法论层面的流程设计,Skills 是系统架构层面的能力封装,两者可以组合使用。面试官考的是你能不能区分“工作流方法”和“系统架构”这两个层次的抽象。


基础设施与算法

Q:数据库索引失效的常见场景?LIKE 查询会不会导致索引失效?

来源:快手 AI Agent 开发一面;度小满AI全栈一面;美团ai全栈一面;字节跳动Agent开发1面凉经;本轮追问:你了解 MySQL 常见的索引优化吗?慢查询如何处理,索引有哪些注意点?(度小满 AI 全栈二面);记录最爽,不折腰的一次面试:小红书秋招一面;百度agent harness一面

新手答:“LIKE 查询会导致索引失效。”

高手答:

索引失效不是 LIKE 的专利——有很多常见写法会让优化器放弃使用索引:

索引失效的常见场景:

场景 示例 失效原因
对索引列使用函数 WHERE YEAR(create_time) = 2024 函数运算破坏了索引的有序性
隐式类型转换 WHERE varchar_col = 123 varchar 列和 int 比较,触发隐式转换
LIKE 前缀通配 WHERE name LIKE '%张三' 无法利用 B+ 树的有序性
OR 混合非索引列 WHERE indexed_col = 1 OR non_indexed = 2 优化器可能放弃索引走全表扫描
违反最左前缀原则 联合索引 (a,b,c),查 WHERE b=1 跳过了最左列 a
索引选择性太低 WHERE gender = '男'(50% 数据命中) 优化器判断全表扫描更快
NOT / != / <> WHERE status != 'deleted' 部分情况下优化器放弃索引
IS NULL / IS NOT NULL WHERE col IS NOT NULL 取决于数据分布和数据库版本

LIKE 查询的索引命中情况:

✅ 会走索引:
  WHERE name LIKE '张三%'    -- 前缀匹配,B+ 树可以范围扫描
  WHERE name LIKE '张三%王'  -- 前缀固定,仍可利用索引

❌ 不走索引:
  WHERE name LIKE '%张三'    -- 前缀通配,无法确定扫描起点
  WHERE name LIKE '%张三%'   -- 前后通配,只能全表扫描

本质原因:B+ 树索引是按键值有序排列的。前缀匹配相当于范围查询(“张三”开头的所有记录在一个连续范围内),可以利用有序性。但前缀通配意味着匹配位置不确定,B+ 树无法定位起点,只能全表扫描。

需要模糊匹配怎么办:如果业务必须支持 %关键词% 查询,应该用全文索引(MySQL FULLTEXT)或搜索引擎(Elasticsearch),而不是在关系数据库上硬撑。

慢查询先通过慢查询日志定位,再用 EXPLAIN 检查访问类型、候选索引、实际扫描行数与回表情况,结合过滤条件设计联合索引并遵循最左前缀;避免索引过多、低选择性列单独建索引和忽略写入成本,优化后需用真实数据对比执行计划与耗时。

追问补充:联合索引 (a,b,c) 中,通常先用 a 的等值条件,再利用 b;遇到范围、LIKE 前缀或不等值后,后续列往往不能继续用于定位(但可能仍用于过滤或覆盖)。跳过 a、对列做函数或隐式转换、排序分组方向与索引不匹配,或选择性不足,都可能使其不走;应以 EXPLAIN 和实际执行计划验证。

差距在哪:新手笼统地说“LIKE 会失效”——其实前缀匹配不会。高手区分了八种索引失效场景,且说清了 LIKE 的前缀匹配 vs 通配的本质区别(B+ 树的有序性)。面试官考的是你对数据库索引原理的理解深度,而不是背条目。


Q:分布式限流算法——令牌桶、漏桶、滑动窗口的区别和实现?

来源:快手 AI Agent 开发一面;本轮追问:令牌桶和漏桶有什么区别?谁更适合高并发?(度小满一面);本轮追问:如何用 Redis 实现令牌桶?(字节agent一面凉经);美团ai全栈一面;小红书 Product Engineer(AI与全栈方向)-社区工程 一面面经;本轮追问:设计一个热点限流器,key 很多时怎么减少内存开销?预热的时候怎么识别冷 key 和热 key?不能一次大批量读数据库时怎么做预热?(腾讯 TEG 云架构平台部一面、二面面经)

新手答:“用令牌桶限流,每秒放几个令牌。”

高手答:

三种限流算法各有适用场景,核心差异在于对突发流量的处理方式:

算法 核心思想 允许突发 流量整形 适用场景
令牌桶 桶以固定速率填充令牌,请求消耗令牌 ✅ 桶满时可突发 ❌ API 限流(允许短时突发)
漏桶 请求先入桶,桶以固定速率漏出处理 ❌ 强制匀速 ✅ 流量整形(保护下游)
滑动窗口 统计滑动时间窗口内的请求数 ❌ 窗口内硬上限 ❌ 精确的请求频率控制

令牌桶算法:

参数:桶容量 capacity、填充速率 rate(个/秒)
状态:当前令牌数 tokens、上次填充时间 last_refill

每次请求:
  1. 计算距上次的时间差,补充令牌:tokens += elapsed × rate
  2. tokens = min(tokens, capacity)  // 不超过桶容量
  3. if tokens >= 1: tokens -= 1, 放行
     else: 拒绝

漏桶算法:

请求入桶(队列),桶以固定速率出队处理。
桶满时新请求直接丢弃或排队等待。
效果:无论入口流量多不均匀,出口始终匀速。

滑动窗口算法:

参数:窗口大小 window_ms、最大请求数 max_count

结构体字段:
  window_start: int64    // 当前窗口起始时间戳
  request_count: int      // 窗口内已有请求数
  window_size_ms: int     // 窗口大小(毫秒)
  max_requests: int       // 窗口内允许的最大请求数
  // 精确版还需要:request_timestamps: list  // 每个请求的时间戳

每次请求:
  1. 清除窗口外的过期记录
  2. 统计窗口内请求数
  3. if count < max_count: 记录时间戳, 放行
     else: 拒绝

令牌桶 vs 滑动窗口:

令牌桶:允许突发(桶满时一次性用完所有令牌),适合"平均速率限制"
滑动窗口:任何时刻窗口内请求数不超限,适合"严格频率限制"

例:限制 100 请求/分钟
  令牌桶:可能在第 1 秒就用完 100 个令牌(突发)
  滑动窗口:任意 60 秒窗口内最多 100 个请求(平滑)

Redis 实现:

算法 Redis 数据结构 实现思路
令牌桶 String + EXPIRY 存剩余令牌数,用 Lua 脚本原子操作(补充 + 扣减)
滑动窗口 Sorted Set(ZSET) 每个请求以时间戳为 score 加入 ZSET,用 ZREMRANGEBYSCORE 清除窗口外记录,ZCARD 统计窗口内数量
固定窗口 String + INCR + EXPIRY key 为“窗口起始时间”,INCR 计数,EXPIRY 到窗口结束

分布式场景下,所有操作必须用 Lua 脚本保证原子性,避免并发竞态。

高并发并非简单由算法决定:令牌桶适合允许短时突发、保护吞吐,漏桶适合必须平滑下游流量。Redis 中为每个限流 key 保存 tokens 与 last_refill,Lua 内按 Redis 时间计算补充、截断到 capacity,再判断并扣减;脚本返回剩余量和重试等待时间,避免客户端并发竞态。

key 很多时可用 TTL、分层存储和近似计数结构只保留活跃状态,并用采样或 TopK 统计识别热 key;预热按优先级分批、分页扫描,放入限速队列控制数据库并发,失败可重试,避免一次性全量读取和击穿。

差距在哪:新手只知道令牌桶一种。高手把三种算法的核心差异(是否允许突发、是否整形)讲清楚了,且给出了滑动窗口的结构体设计和 Redis 数据结构选型。面试官考的是你对限流这个经典系统设计问题的工程化理解。


Q:大规模数据处理场景设计——从千条到百万级如何扩展?

来源:快手 AI Agent 开发一面;本轮追问:你之前那一段实习的这样一个大数据导出是如何优化的?(美团ai全栈一面);本轮追问:除了 SQL 手段以外,有没有考虑过通过其他技术手段解决出数任务的效率问题,让出数任务跑得更快?((秋招) 9.16 字节中交广 - 交易与广告业务 - AI全栈开发工程师);秋招-字节跳动-抖音电商-Agent开发一/二/三面

新手答:“用循环累加就行。”

高手答:

千条数据:单机单线程直接处理,没必要引入复杂架构。一个循环累加,时间复杂度 O(n),毫秒级完成。

百万级数据:核心挑战从计算变成了内存、IO、和故障恢复:

flowchart LR
    D["百万级数据"] --> S["分片\n按范围/哈希拆分"]
    S --> W1["Worker 1\n局部求和"]
    S --> W2["Worker 2\n局部求和"]
    S --> W3["Worker N\n局部求和"]
    W1 --> A["汇总节点\n合并局部结果"]
    W2 --> A
    W3 --> A
    A --> R["最终结果"]

分治并行(MapReduce 思想):

  1. Map 阶段:将数据按分片键(如 ID 范围)拆分为 N 个子集,每个 Worker 独立计算局部和
  2. Reduce 阶段:汇总节点收集所有局部和,做最终聚合
  3. 总耗时 ≈ 单个分片处理时间 + 网络传输时间,而非 N 倍

保证效率和稳定性:

挑战 解决方案
内存不够 流式处理:逐批读取数据,不一次性加载全量到内存
Worker 失败 检查点(Checkpoint):每处理一批保存中间结果,失败后从断点恢复而非从头开始
数据倾斜 均匀分片:避免某个 Worker 分到的数据远多于其他
结果正确性 幂等设计:重试不会导致重复计算(去重或幂等累加)
监控 进度追踪:每个 Worker 上报处理进度,整体进度可视化

技术选型:

百万级:多线程/多进程 + 内存流式处理即可
千万级:单机多核(Python multiprocessing / Go goroutine)
亿级以上:分布式计算框架(Spark / Flink)

导出接口不应同步拼装全量结果:先创建异步任务,按游标或主键范围分批读取并流式写入分片文件,再合并或上传对象存储;记录任务进度、失败重试和幂等分片,完成后返回下载地址,并用压测校验内存、吞吐和耗时。

追问补充:将一亿条子订单按主键范围切成可重试批次,任务表或队列持久化批次状态、租约和检查点;Worker 用幂等键调用 RPC,设置限流、超时、退避重试和死信人工处理。状态更新须可重复执行,完成后按总量、成功数和失败明细对账。

差距在哪:新手用循环就结束了——千条数据确实够用,但百万级完全不同。高手用分治并行处理,且考虑了内存、故障恢复、数据倾斜、幂等性四个生产环境必须面对的问题。面试官考的是你从“能跑”到“能在生产环境稳定跑”的工程化思维跃迁。


Q:LangGraph 定义的搜索节点做不到并发执行吗?怎么做?

来源:AI 工程师面试;本轮追问:Agent 要调用一些工具或脚本,目前是串行的,怎么判断并修改成并行?(淘天供应链ai应用研发一面)

新手答:“LangGraph 是顺序执行的,做不了并发。”

高手答:

LangGraph 完全支持并发执行,有三种方式,适用场景不同:

方式一:Fan-out / Fan-in(静态并行)

在 graph 定义时,让多个节点从同一个上游节点出发,形成并行分支,最后汇聚到一个下游节点:

graph.add_edge("plan_node", "search_node_1")
graph.add_edge("plan_node", "search_node_2")
graph.add_edge("plan_node", "search_node_3")
graph.add_edge("search_node_1", "merge_node")
graph.add_edge("search_node_2", "merge_node")
graph.add_edge("search_node_3", "merge_node")

三个 search 节点会并发执行,全部完成后进入 merge_node。适合编译时就知道要并行几路的场景。

方式二:Send API(动态并行)

并行数量在运行时才确定时,用 Send API 动态创建并行分支:

from langgraph.types import Send

def plan_node(state):
    queries = state["search_queries"]  # 运行时才知道有几个查询
    return [Send("search_node", {"query": q}) for q in queries]

graph.add_conditional_edges("plan_node", plan_node)

每个 Send 创建一个独立的并发执行分支,适合搜索数量取决于规划结果的场景。

方式三:节点内部 asyncio 并发

如果只是一个节点内部需要并发调用多个 API:

import asyncio

async def search_node(state):
    queries = state["search_queries"]
    results = await asyncio.gather(*[
        search_api(q) for q in queries
    ])
    return {"search_results": results}

状态合并是关键问题:

并发节点同时写同一个 state 字段会冲突。LangGraph 用 Reducer 函数解决:

from typing import Annotated
import operator

class State(TypedDict):
    # operator.add 表示多个并发节点的结果做列表拼接
    search_results: Annotated[list, operator.add]

每个并发分支返回的 search_results 会被自动拼接成一个大列表,而不是互相覆盖。

先分析工具调用的依赖图:互不读写同一状态、无顺序要求且副作用可隔离的调用可 fan-out;存在前置结果、共享写入或非幂等副作用时保持串行。并发还要设置限流、超时、失败隔离和有界协程,汇聚时按任务 ID 稳定合并,避免结果错配。

差距在哪:新手以为 LangGraph 不支持并发——说明没深入用过。高手给出了三种并发方式(静态 Fan-out、动态 Send、节点内 asyncio),且指出了并发状态合并(Reducer)这个关键问题。面试官考的是你对 LangGraph 并发执行机制的实际掌握程度。


Q:PostgreSQL 的索引结构是什么?索引如何优化查询速度?在 Checkpoint 场景下如何用索引加速?

来源:AI 工程师面试

新手答:“就是 B+ 树,查询快。”

高手答:

PostgreSQL 支持多种索引类型,不同索引适用不同查询模式:

索引类型 底层结构 适用查询 典型场景
B-Tree(默认) 平衡多叉树 等值查询、范围查询、排序 绝大多数场景的首选
Hash 哈希表 纯等值查询 精确匹配,如 session_id = ‘xxx’
GIN 倒排索引 包含查询、全文搜索 JSONB 字段查询、数组包含
GiST 通用搜索树 范围重叠、最近邻 地理空间、区间查询
BRIN 块范围索引 大表上的范围查询 时间序列、日志表(数据物理有序时)

B-Tree 索引如何加速查询:

B-Tree 是一棵平衡多叉排序树,每个节点存多个键值和指向子节点的指针。查询时从根节点开始,每一层通过比较快速定位到目标区间,时间复杂度 O(log N):

无索引:全表扫描 100 万行 → 逐行比较 → O(N)
有 B-Tree 索引:树高约 3-4 层 → 3-4 次磁盘 IO → O(log N)

关键优化手段:

  1. 覆盖索引(Covering Index):把查询需要的列都放进索引,查询直接从索引返回,不需要回表
  2. 复合索引:CREATE INDEX ON checkpoints (thread_id, checkpoint_id DESC) 一个索引同时支持按 thread_id 过滤 + 按 checkpoint_id 排序
  3. 部分索引(Partial Index):CREATE INDEX ON checkpoints (thread_id) WHERE is_active = true 只索引活跃数据,索引体积更小
  4. Index-Only Scan:当查询的所有列都在索引中时,PostgreSQL 直接扫描索引,完全跳过堆表

Checkpoint 场景下的索引设计:

Checkpoint 表的核心查询模式是:给定 session_id(thread_id),找到最新的 Checkpoint。

-- 最常见的查询:加载最新 checkpoint
SELECT * FROM checkpoints
WHERE thread_id = 'abc-123'
ORDER BY checkpoint_id DESC
LIMIT 1;

最优索引:

-- 复合索引:thread_id 精确匹配 + checkpoint_id 倒序排列
CREATE INDEX idx_checkpoints_thread_latest
ON checkpoints (thread_id, checkpoint_id DESC);

这个索引让查询一次 B-Tree 查找就能定位到目标行——先按 thread_id 定位到该会话的所有 checkpoint,B-Tree 内部已按 checkpoint_id 倒序排列,直接取第一条就是最新的。

如果 Checkpoint 表还有 JSONB 类型的 metadata 字段需要查询(如按节点名过滤):

-- GIN 索引支持 JSONB 内部字段查询
CREATE INDEX idx_checkpoints_metadata ON checkpoints USING GIN (metadata);

-- 查询:找所有在 search_node 节点暂停的 checkpoint
SELECT * FROM checkpoints WHERE metadata @> '{"node": "search_node"}';

差距在哪:新手只知道 B+ 树一个名字。高手区分了五种索引类型及适用场景,详细说明了 B-Tree 的查询加速原理,且结合 Checkpoint 实际场景给出了复合索引 + GIN 索引的具体设计。面试官考的是你能不能把数据库基础知识应用到 Agent 系统的实际存储设计中。


Q:用 Claude Code 做一个比较长的任务,如果遇到单次 session 跑不完、中间断网怎么办?

来源:AI 工程师面试

新手答:“重新开一个 session 从头做。”

高手答:

长任务中断是 AI Coding 工具的常见问题。解决方案分预防和恢复两个层面:

预防——降低中断的影响:

  1. 任务拆分:长任务不要一口气交给 Agent。先用 Plan Mode(/plan)生成整体方案,再按模块逐步执行。每完成一个模块就 commit 一次,确保进度不丢
  2. CLAUDE.md 持久化上下文:把项目的关键信息、架构约定、已完成的进度写在 CLAUDE.md 文件中。新 session 启动时会自动读取,相当于给 Agent 一个“接班备忘录”
  3. TodoList 跟踪进度:用 Claude Code 的任务管理功能(或直接在 CLAUDE.md 中维护 checklist),标记每个子任务的完成状态。中断后可以精确知道“做到哪了”
## 当前任务进度
- [x] 数据库 schema 设计
- [x] API 路由层实现
- [ ] 业务逻辑层实现  ← 断点
- [ ] 单元测试
- [ ] 集成测试
  1. 高频 git commit:每完成一个有意义的改动就 commit,不要攒到最后。即使 session 崩了,代码改动不会丢

恢复——中断后快速接续:

  1. --continue 继续上次对话:Claude Code 支持 claude --continue 直接恢复上一次 session 的对话上下文,从断点继续
  2. /resume 恢复任务:在新 session 中使用 /resume 命令,可以加载之前的对话历史和任务状态
  3. Git diff 定位进度:新 session 中让 Claude Code 执行 git diff 和 git log,快速了解已完成的改动,从断点处继续

最佳实践流程:

flowchart TB
    A["长任务开始"] --> B["Plan Mode\n生成整体方案"]
    B --> C["写入 CLAUDE.md\n+ TodoList"]
    C --> D["按模块逐步执行"]
    D --> E["每个模块完成后\ngit commit"]
    E --> F{"中断?"}
    F -->|"否"| D
    F -->|"是"| G["claude --continue\n或 /resume"]
    G --> H["读取 CLAUDE.md\n+ git log"]
    H --> D

核心认知:长任务的可靠性不靠 session 稳定性保证,而靠“频繁保存 + 上下文持久化 + 快速恢复”的工程习惯。这和写代码要频繁 commit 是同一个道理——不要把所有筹码押在“一次跑通”上。

差距在哪:新手遇到中断只会重来。高手从预防(任务拆分 + CLAUDE.md + TodoList + 高频 commit)和恢复(–continue + /resume + git diff)两个层面给出了完整方案。面试官考的是你用 AI Coding 工具做大型任务时的工程化习惯。


Q:布隆过滤器的原理?会出现什么问题?如何控制误判率?

来源:快手 AI Agent 开发一面

新手答:“用来判断一个元素是否在集合中。”

高手答:

布隆过滤器是一个空间效率极高的概率型数据结构,用于快速判断“某元素是否可能在集合中”。

原理:

数据结构:一个 m 位的 bit 数组(初始全 0)+ k 个独立哈希函数

添加元素:对元素做 k 次哈希,将对应的 k 个位置置 1
查询元素:对元素做 k 次哈希,检查 k 个位置
  - 全部为 1 → "可能存在"(可能是误判)
  - 任一为 0 → "一定不存在"(绝无漏判)
示例:m=10, k=3

添加 "apple":hash1→2, hash2→5, hash3→8
  bit: [0,0,1,0,0,1,0,0,1,0]

添加 "banana":hash1→1, hash2→5, hash3→9
  bit: [0,1,1,0,0,1,0,0,1,1]

查询 "cherry":hash1→2, hash2→5, hash3→9 → 全部为 1 → "可能存在"(误判!)
查询 "grape":hash1→3, hash2→7, hash3→9 → 位置 3 为 0 → "一定不存在"

会出现什么问题:

  1. 假阳性(False Positive):说“在集合中”但实际不在。多个元素的哈希位重叠导致
  2. 不支持删除:清除某个位可能影响其他元素(它们的哈希位重叠)。变体 Counting Bloom Filter 用计数器替代 bit 可支持删除
  3. 无假阴性:说“不在”就一定不在——这是布隆过滤器的核心保证

如何控制误判率:

误判率公式:FPR ≈ (1 - e^(-kn/m))^k

三个可调参数:
  m:bit 数组大小 → 越大误判率越低
  k:哈希函数数量 → 存在最优值
  n:已插入元素数量 → 固定的业务参数

最优 k = (m/n) × ln2 ≈ 0.693 × (m/n)

实际估算:
  n = 100 万元素,目标 FPR = 1%
  m ≈ -n × ln(FPR) / (ln2)² ≈ 958 万 bit ≈ 1.2 MB
  k = 7

  n = 100 万元素,目标 FPR = 0.1%
  m ≈ 1437 万 bit ≈ 1.8 MB
  k = 10

典型应用场景:缓存穿透防护(快速判断 key 是否存在)、爬虫 URL 去重、垃圾邮件过滤、大规模数据去重。

差距在哪:新手只知道“判断是否存在”。高手讲清了原理(bit 数组 + k 次哈希)、两个核心问题(假阳性 + 不可删除)、误判率控制公式及实际估算。面试官考的是你对概率数据结构的工程化理解——不只是“知道这个东西”,还能算出实际场景需要多大空间。


性能与延迟优化

Q:AI 应用中 SSE 流式数据怎么处理?数据格式是什么?

来源:百度实习 AI 应用开发一面【字节agent一面追问:SSE 在项目里用来做什么?推送的数据格式是什么样?】【百度Agent一面追问:有流式输出吗?具体的流式响应是怎么处理的?】;本轮追问:这种流式协议是不是比较适合音频、视频这种流式数据?(本轮追问);本轮追问:SSE底层实现原理是什么?(字节数据中台Agent全栈面经)

新手答:“就是后端一直发数据,前端一直收。”

高手答:

SSE(Server-Sent Events)是 AI 应用做流式输出的主流方案——模型逐 token 生成,后端逐 token 推送,用户不需要等全部生成完就能看到内容。

SSE 数据格式:

SSE 是纯文本协议,每条消息由字段组成,消息之间用空行分隔:

event: message
data: {“content”: “你”, “role”: “assistant”}

event: message
data: {“content”: “好”, “role”: “assistant”}

event: done
data: [DONE]
字段 作用 示例
data: 消息体(必须),多行 data 会自动拼接 data: {“token”: “hello”}
event: 事件类型(可选),客户端按类型监听 event: tool_call
id: 消息 ID(可选),断线重连时用 id: 42
retry: 重连间隔毫秒(可选) retry: 3000

Content-Type 必须是 text/event-stream,连接是单向的(服务端 → 客户端)。

前端处理:

核心 API:EventSource(原生)或 fetch + ReadableStream(更灵活)

EventSource 方式:
  - 自动重连、自动解析 SSE 格式
  - 缺点:只支持 GET,不能带自定义 header

fetch 方式(主流):
  - fetch(url, {method: 'POST', body: ...})
  - 拿到 response.body(ReadableStream)
  - 用 TextDecoder 逐 chunk 解码
  - 手动按 \n\n 分割 SSE 消息
  - 优点:支持 POST、自定义 header、更灵活的错误处理

工程上要处理的边界情况:

  1. 断线重连:网络波动导致连接断开,需要用 Last-Event-ID 从断点续传,而非从头开始
  2. 消息拼接:一个 SSE chunk 可能包含不完整的消息(TCP 拆包),需要在客户端做缓冲区拼接
  3. 背压处理:模型生成速度可能超过前端渲染速度,需要控制 DOM 更新频率(requestAnimationFrame 或节流)
  4. 超时处理:长时间无数据推送时,客户端需要区分“模型还在思考”和“连接已断”
  5. 优雅关闭:用户中途取消生成时,前端 abort 请求,后端需要同步停止推理以节省算力

SSE vs WebSocket:

维度 SSE WebSocket
方向 单向(服务端→客户端) 双向
协议 HTTP 独立协议(ws://)
重连 内置自动重连 需手动实现
适用场景 LLM 流式输出、通知推送 实时聊天、协同编辑
基础设施兼容性 好(走 HTTP,CDN/代理友好) 需要额外配置代理

AI 应用中,模型输出是单向流,SSE 足够且更简单。只有需要客户端实时发送大量数据(如语音流)时才需要 WebSocket。

其底层是长连接 HTTP 响应:服务端返回 text/event-stream 后不结束响应,持续写入事件字节流;HTTP/1.1 常借助分块传输,HTTP/2 则复用流,浏览器按空行解析事件并触发回调。代理若缓冲响应会破坏实时性,通常需关闭缓冲并发送心跳保活。

差距在哪:新手对 SSE 的理解停留在“后端发前端收”。高手说清了 SSE 的数据格式规范、两种前端处理方式的取舍、五个工程边界情况、以及和 WebSocket 的选型对比。面试官考的是你对流式通信的工程化理解——AI 应用开发绕不开 SSE。


Q:开发 Agent 的时候,你用的是什么开发流程?为什么选这个流程?

来源:字节 Agent 开发实习一面 / 阿里云 SOC Agent Infra 一面;合肥某头部企业软件开发实习生面试问题汇总(时长1个小时);度小满 - AI 全栈研发 - 二面

新手答:“想到什么做什么,边做边调。”

高手答:

Agent 开发和传统软件开发有本质区别——行为是概率性的、测试更难、需求往往要通过实验才能明确。所以不能用传统的“写需求→写代码→上线”流程,需要一套以评测驱动为核心的开发方法论。

六阶段 Agent 开发流程

flowchart LR
    A["需求定义\n+ 边界划定"] --> B["Prompt 原型"]
    B --> C["工具集成\n+ 编排"]
    C --> D["评测集构建"]
    D --> E["迭代优化"]
    E --> F["上线 + 监控"]
    E -->|"评测未达标"| D

阶段一:需求定义 + 边界划定

定义 Agent 应该做什么,更重要的是定义它不应该做什么。边界划定是 Agent 项目成败的关键——范围无限膨胀的 Agent 项目必然失败。

阶段二:Prompt 原型

用一个简单的 Prompt + 手动工具描述快速验证核心假设:模型能不能理解这个任务?这个阶段只需要几个小时,不要花几天搭架构。

阶段三:工具集成 + 编排

接入真实工具(MCP/原生函数调用),搭建执行循环。先跑通 Happy Path,不要在这个阶段处理所有边界情况。

阶段四:评测集构建

这是整个流程中最关键的一步——在优化之前构建评测集。评测集的组成:

类别 占比 作用
基础用例 60% 验证核心功能
边界用例 20% 覆盖异常输入和极端情况
对抗用例 10% 测试 Prompt 注入、恶意输入
回归用例 10% 防止优化过程中旧功能退化

没有评测集就去优化 Prompt,等于闭着眼睛调参数——不知道改好了还是改坏了。

阶段五:迭代优化

跑评测 → 找失败模式 → 修复(调整 Prompt / 增加工具 / 改善上下文) → 重新跑评测。每一轮迭代都是数据驱动的,不是凭感觉调。

阶段六:上线 + 监控

部署时加上日志记录、行为监控、高风险操作的人工审批。Agent 上线不是结束,是持续监控和迭代的开始。

为什么选这个流程?

核心理念是评测驱动开发(Eval-Driven Development),类似于传统软件的 TDD。评测集就是 Agent 开发的“测试套件”——每次改动都必须提升评测指标,否则就是退化。

Skill 应贯穿这条流程,而不是上线前临时写一份说明:开发阶段把可复用步骤、输入输出契约和工具权限固化为 Skill;测试阶段用固定 case 验证触发、执行顺序、失败退出和副作用;发布阶段绑定 Skill 版本、评测报告与灰度范围;线上复盘再把失败 Trace 归因到内容、工具、运行时或边界设计,生成候选修订并重新走评测和发布门禁。

Agent 开发 vs 传统软件开发

维度 传统软件开发 Agent 开发
需求定义 确定性的功能规格 概率性的行为边界
测试方式 单元测试 + 集成测试 评测集 + 人工审查
调试方式 堆栈追踪 + 日志 执行链分析 + Prompt 考古
迭代节奏 写代码 → 跑测试 → 部署 调 Prompt → 跑评测 → 观察 → 调整
发布策略 功能开关 + 回滚 灰度发布 + 人工兜底

什么做法是错的

  • 不要一上来就搭复杂的多 Agent 架构——先用单 Agent 验证核心假设
  • 不要没有评测集就反复调 Prompt——这是盲人摸象
  • 不要不测边界情况就上功能——Agent 的失败模式远比传统软件多

追问补充:拿到需求后,可先让 AI 提炼目标、边界、异常场景和验收标准,由开发者确认方案与接口契约;随后生成代码骨架、测试和文档。分批 Review 权限、依赖、错误处理与副作用,在隔离环境运行静态检查和定向测试,回归通过后再合并,保留可回滚的小批次改动。

差距在哪:新手没有流程,想到什么做什么,遇到问题靠感觉调。高手有一套六阶段的系统化流程,核心是评测驱动开发——用数据说话而不是凭直觉。面试官考的是你有没有把 Agent 开发当成一个工程问题来系统性地解决,而不是当成“调 Prompt”的手艺活。


Q:针对包含 3 个以上工具调用且高频请求的任务,通过什么方式可以压低系统整体的端到端延迟?

来源:淘天 AI Agent 一面【字节跳动9.3 Agent开发一面面经追问:如何解决上述长程任务运行延迟问题?】

新手答:“用更快的模型。”

高手答:

模型推理速度只是延迟的一部分。Agent 任务的端到端延迟是一条串行链路的总和——模型推理 + N 次工具调用 + 网络传输 + 最终合成。要压延迟,必须拆开这条链路,逐段优化。

延迟拆解:

一次典型的多工具 Agent 任务延迟组成:

模型推理(工具选择)    ~500ms
├─ 工具调用 1(API 请求)  ~300ms
├─ 工具调用 2(数据库查询) ~200ms
├─ 工具调用 3(网页抓取)   ~800ms
模型推理(结果合成)    ~1000ms
─────────────────────────────
串行总延迟              ~2800ms

核心策略:从串行到并行:

flowchart TB
    subgraph 串行执行[“串行执行(2800ms)”]
        direction LR
        A1[“模型推理\n500ms”] --> B1[“工具1\n300ms”] --> C1[“工具2\n200ms”] --> D1[“工具3\n800ms”] --> E1[“结果合成\n1000ms”]
    end

    subgraph 并行执行[“并行执行(1500ms)”]
        direction LR
        A2[“模型推理\n500ms”] --> B2[“工具1 ┐”]
        A2 --> C2[“工具2 ├ 并行 800ms”]
        A2 --> D2[“工具3 ┘”]
        B2 --> E2[“流式合成\n200ms”]
        C2 --> E2
        D2 --> E2
    end

    style 串行执行 fill:#fee,stroke:#f66
    style 并行执行 fill:#efe,stroke:#6f6

六大优化策略:

1. 工具并行调用:识别无依赖关系的工具调用,用 asyncio.gather 并行执行。总耗时 = max(各工具耗时),而非 sum。

# 依赖分析示例
用户问:”北京明天天气怎么样,顺便帮我查一下机票价格”
  - 查天气 API ← 独立
  - 查机票 API ← 独立
  → 可并行,耗时从 300+400=700ms 降到 max(300,400)=400ms

2. 投机执行(Speculative Execution):在当前工具还没返回时,预测下一步可能需要的工具调用并提前发起。如果预测正确,省掉一轮等待;如果错误,丢弃结果即可(前提是工具调用是只读的)。

3. 结果缓存:高频且时效性要求不高的工具结果做 TTL 缓存。

工具类型 缓存 TTL 示例
天气查询 10 分钟 同一城市短时间内多次查询
汇率查询 5 分钟 同一币种对
知识库检索 1 小时 同一 query 的 RAG 结果
数据库聚合 按业务需求 日报、周报类统计

4. 流式生成:不等所有工具结果全部返回再开始合成,而是边收结果边生成。第一个工具结果返回后立即开始流式输出,后续结果到达时追加合成。用户感知到的首 token 延迟大幅降低。

5. 工具调用批处理:多次调用同一服务时,合并为一次批量请求。比如需要查 5 个用户的信息,合成一次 SELECT ... WHERE id IN (...) 而非 5 次单独查询。

6. 模型分级:工具选择和参数提取用小模型(7B),速度快且准确率够用;只有最终结果合成才用大模型保证质量。

综合效果对比:

优化手段 延迟降低 实现复杂度 适用条件
工具并行调用 40-60% 低 工具之间无依赖
结果缓存 30-80%(命中时) 低 工具结果有时效性容忍
流式生成 首 token 延迟降 50%+ 中 客户端支持流式接收
工具调用批处理 20-40% 中 多次调用同一服务
投机执行 10-30% 高 工具调用只读且可预测
模型分级 20-40% 高 有合适的小模型可用

实际工程组合:

第一优先级(低成本高收益):
  ├─ 工具并行调用:改一下调度逻辑即可
  └─ 结果缓存:加一层 Redis 缓存

第二优先级(中等投入):
  ├─ 流式生成:需要改前后端交互协议
  └─ 批处理合并:需要识别可合并的调用

第三优先级(高投入):
  ├─ 模型分级:需要评估小模型的工具选择准确率
  └─ 投机执行:需要建立工具调用预测模型

差距在哪:新手只盯着模型速度——这只是链路中的一环。高手把端到端延迟拆成多段,逐段分析瓶颈,从并行化、缓存、流式、批处理、模型分级五个维度给出方案,并按投入产出比排了优先级。面试官考的是你对分布式系统延迟优化的工程直觉——Agent 系统本质上就是一个“模型 + 多服务调用”的分布式系统,优化思路和后端微服务架构是相通的。


Q:AI 应用的前端资源缓存怎么配的?

来源:百度实习 AI 应用开发一面

新手答:“用浏览器缓存就行。”

高手答:

AI 应用的前端缓存策略和普通 Web 应用一样,核心是按资源变更频率分层——频繁变化的资源不缓存或短缓存,稳定的资源强缓存。

分层缓存策略:

资源类型 缓存策略 HTTP 头配置 原因
JS/CSS(带 hash) 强缓存一年 Cache-Control: max-age=31536000, immutable 文件名含 hash,内容变则 URL 变,无需重新验证
HTML 入口文件 协商缓存 Cache-Control: no-cache + ETag 每次请求都验证是否更新,保证用户拿到最新版本
图片/字体 强缓存 + CDN Cache-Control: max-age=2592000 静态资源很少变,CDN 边缘节点分发
API 响应 不缓存或短缓存 Cache-Control: no-store 或 max-age=60 AI 生成结果通常不可复用

关键机制:

  1. 内容哈希命名:构建工具(Vite/Webpack)给 JS/CSS 文件名加 hash(如 app.3a7f2b.js),内容变则文件名变。这样可以对带 hash 的文件设超长缓存,部署新版本时旧缓存自动失效
  2. 协商缓存:HTML 文件用 ETag(内容指纹)或 Last-Modified。浏览器每次请求时带 If-None-Match,服务器内容没变则返回 304,省带宽
  3. CDN 配置:静态资源上 CDN,配置 CDN 缓存 TTL + 部署时主动刷新 CDN 缓存
  4. Service Worker:PWA 场景下可用 Service Worker 做离线缓存,但 AI 应用通常依赖后端实时响应,离线场景有限

AI 应用的特殊点:

  • SSE/WebSocket 连接不走缓存:流式响应是实时的,缓存无意义
  • 对话历史可以缓存在客户端:用 IndexedDB 或 localStorage 存已完成的对话,减少重复请求
  • 模型响应缓存:相同 query 的模型响应可以在服务端做 KV 缓存(语义缓存),但这是后端策略,不是前端配置

差距在哪:新手只说“浏览器缓存”——太笼统。高手按资源类型分层配置,说清了强缓存 vs 协商缓存的选择逻辑、内容哈希命名的原理、以及 AI 应用的特殊缓存考量。面试官考的是你对前端工程化的基本功。


Q:任务执行远大于单次 Token 限制时,如何设计以支持断点继续生成?

来源:淘天 AI Agent 一面;本轮追问:超过单次模型时长限制后如何处理?(携程 AI 应用开发二面(已oc))

新手答:“让模型一次生成完。”

高手答:

现实中很多 Agent 任务的规模远超单次上下文窗口——比如分析一份 200 页的合同、生成一套完整的测试用例、或执行一个需要 50+ 步的复杂工作流。不可能一次塞进去,也不能指望一次调用就跑完。必须设计断点续传机制,像分布式任务调度器一样管理 Agent 的执行状态。

三层架构设计:

flowchart TD
    A[“大任务输入”] --> B[“任务分解层”]
    B --> C1[“子任务 1”]
    B --> C2[“子任务 2”]
    B --> C3[“子任务 N”]

    C1 --> D1[“执行 ✅”]
    C2 --> D2[“执行 ✅”]
    C3 --> D3[“执行中 ⏳\n↓ 中断”]

    D1 --> E[“检查点存储\n(DB / Redis)”]
    D2 --> E
    D3 --> E

    E --> F[“恢复执行”]
    F --> G[“从子任务 N\n的断点继续”]

    style D3 fill:#ffa,stroke:#333
    style E fill:#6cf,stroke:#333,color:#fff
    style G fill:#6f6,stroke:#333

第一层:任务分解

把大任务拆成多个子任务,每个子任务的输入输出在单次上下文窗口内可完成:

示例:分析 200 页合同
  → 子任务 1:提取合同基本信息(甲乙方、日期、金额)
  → 子任务 2:分析第 1-20 页的条款风险
  → 子任务 3:分析第 21-40 页的条款风险
  → ...
  → 子任务 N:汇总所有风险点,生成报告

每个子任务独立可执行,中间结果持久化到数据库

第二层:检查点机制

每完成一个关键步骤,保存结构化的检查点状态:

Checkpoint 数据结构:
{
  “task_id”: “contract-analysis-001”,
  “total_subtasks”: 12,
  “completed”: [1, 2, 3, 4, 5],
  “current_subtask”: 6,
  “current_progress”: “已分析到第 108 页”,
  “intermediate_results”: {
    “基本信息”: { ... },
    “风险点”: [ ... ],
    “待确认项”: [ ... ]
  },
  “constraints”: {
    “输出格式”: “结构化 JSON”,
    “关注重点”: “知识产权条款”
  },
  “created_at”: “2026-04-23T10:30:00Z”,
  “last_updated”: “2026-04-23T10:45:00Z”
}

第三层:状态恢复与上下文重建

恢复时不需要重放完整历史,而是构建一个“恢复提示词”:

恢复提示词 =
  系统指令(角色 + 约束)
  + 任务概述(原始目标的一句话摘要)
  + 已完成进度(完成了什么、关键结论)
  + 当前子任务(从哪里继续、还剩什么)
  + 核心约束(必须遵循的格式和规则)

关键原则:恢复提示词的 token 数应远小于上下文窗口
  完整历史可能有 50K+ token
  恢复提示词只需要 2K-4K token

关键工程细节:

问题 解决方案
幂等性 工具调用必须幂等,或用执行日志去重。恢复后不能重复执行已完成的操作(比如重复发邮件、重复写数据库)
检查点粒度 太粗(每个子任务一次)→ 恢复代价大;太细(每步一次)→ 存储开销大。实践中按“关键里程碑”保存
上下文一致性 恢复时外部状态可能已变化(比如数据库数据更新了),需要校验检查点中引用的数据是否仍然有效
超时与重试 单个子任务设超时时间,超时后保存当前进度、切换到下一个子任务或进入等待队列
人工介入点 在关键决策节点设置人工确认,避免长时间无人监控的自动执行走偏

与传统分布式任务框架的对比:

特性 Agent 断点续传 Temporal / Airflow
状态管理 自然语言摘要 + 结构化 JSON 严格的状态机
恢复策略 上下文重建(可能有信息损失) 精确重放(无损)
任务拆分 动态的,模型自行判断 静态的 DAG 定义
错误处理 模型可自适应调整策略 按预定义规则重试
适用场景 开放式、探索性任务 确定性流程

实际上,最成熟的方案是两者结合:用 Temporal 等工作流引擎管理子任务编排和检查点持久化,用 Agent 负责每个子任务内部的智能推理。工作流引擎保证可靠性,Agent 保证灵活性。

差距在哪:新手以为模型的上下文窗口是无限的——“一次生成完”在 4K token 的小任务上能凑合,但面对真实的复杂任务完全行不通。高手设计了任务分解 → 检查点 → 状态恢复的三层架构,并考虑了幂等性、粒度、一致性等生产级问题,还能类比到传统分布式任务框架。面试官考的是你对长时间运行任务的工程化设计能力——Agent 不只是“调一次 API”,而是一个需要持久化状态、支持故障恢复的分布式系统。


扩展与排查

Q:用 AI Coding 工具写代码达不到预期怎么办?

来源:CVTE/AI应用工程师一面;本轮追问:如何让AI写业务代码?(本轮追问);本轮来源;本轮追问:AI Coding 有哪些局限性?(携程 AI 应用开发一面(已oc))

新手答:“多试几次,换个写法描述需求,或者自己手写。”

高手答:

“达不到预期”要先定位是哪层的问题,然后针对性解决:

1. 意图传达问题(最常见)

AI 不理解你要什么。表现为:生成的代码逻辑方向完全错误。

解法:不要一句话描述需求,而是给结构化上下文——输入/输出示例、约束条件、已有代码片段、类似功能的参考实现。本质上你在做上下文工程,和给 Agent 写 Prompt 一样的方法论。

2. 知识边界问题

AI 对你用的框架/库版本不熟。表现为:API 不存在、用法过时。

解法:把相关源码、类型定义、文档片段喂给它。Claude Code 的 @file 引用、Cursor 的 @codebase 都是这个思路——扩充 AI 的工作上下文。

3. 架构一致性问题

AI 生成的代码能跑但不符合项目风格/架构。表现为:命名混乱、模式不统一。

解法:用 CLAUDE.md / .cursorrules 定义项目规范,或者用 Skill 封装项目特有的代码模式,让 AI 每次生成都对齐架构约束。

4. 复杂度超限问题

任务太复杂,超出单次生成能力。表现为:前半段对后半段错。

解法:拆任务。把一个大需求拆成 3-5 个小步骤,每步验证后再进行下一步。用 Plan 模式先对齐方案,再逐步实现。

差距在哪:新手的“多试几次”是盲目重试。高手先分类问题(意图/知识/架构/复杂度),每类有不同的解法策略。面试官考的是你对 AI 辅助开发的方法论——不是“用不用 AI”,而是“AI 不好使时怎么系统性解决”。


Q:Agent 系统的缓存选型——本地缓存 vs Redis,怎么选?

来源:字节实习二面;本轮追问:如果没有 Redis,怎么设计缓存?使用什么数据结构?(cvte应用软件开发一面);小红书 Product Engineer(AI与全栈方向)-社区工程 一面面经;本轮追问:集群部署后,本地缓存是否最终会覆盖大部分数据? / 使用本地缓存对发布、冷启动和日常运维有什么影响? / 本地缓存对 GC 和单实例内存的影响是多少?(9.14字节推荐架构一面);本轮追问:Guava/Tair 两级缓存和 JVM 本地缓存解决什么业务问题,为什么需要? / 通过广播更新 JVM 本地缓存靠谱吗?有没有其他方法?(9.15科大讯飞AI应用一面)

新手答:“数据量大用 Redis,小用本地缓存。”

高手答:

数据量只是一个维度。选型的核心是根据一致性要求、访问模式和部署架构综合判断:

维度 本地缓存(Guava/Caffeine) Redis
访问延迟 纳秒级(堆内存) 毫秒级(网络 IO)
一致性 单进程内一致 跨进程/跨机器一致
容量 受 JVM 堆限制(通常 < 1GB) 独立内存,可扩展到 TB
故障影响 进程重启即丢失 持久化可恢复
适合场景 热点数据、不常变更、可容忍短暂不一致 共享状态、需要跨实例一致、数据量大

Agent 系统中的典型选型:

  • 工具 schema 缓存 → 本地缓存。schema 很少变更,每台机器缓存一份即可,不需要跨实例一致
  • 用户会话状态 → Redis。多个 Agent 实例需要读取同一个用户的会话上下文
  • LLM 响应缓存(语义缓存) → Redis。相同语义的请求可以跨用户复用
  • Token 消耗计数 → Redis。需要实时跨实例汇总,做预算熔断

二级缓存架构:

很多生产系统同时使用两者——本地缓存做 L1(减少网络 IO),Redis 做 L2(保证一致性):

请求 → L1 本地缓存(命中?) → L2 Redis(命中?) → 数据源
                ↑ 回填                    ↑ 回填

关键工程问题:

  1. 热 Key:某个 Agent 工具被高频调用,对应的 Redis Key 请求量暴涨。解法:本地缓存兜底 + Redis 读副本分散压力
  2. 大 Key:长对话的会话状态可能达到几 MB。解法:拆分存储(按轮次分 key)或压缩后存储
  3. 缓存命中率计算:命中率 = 缓存命中次数 / 总请求次数。L1 命中率低于 60% 说明缓存策略需要调整(TTL 太短或缓存容量不足)
  4. 迁移注意点:从本地缓存迁到 Redis 后,JVM 堆内存压力减小(GC 频率降低),但网络延迟增加。需要在延迟和一致性之间找平衡

没有 Redis 时可用进程内有界缓存,以哈希表实现按键查找,配合双向链表实现 LRU,并用 TTL、最大容量和并发控制防止内存失控;以数据库或文件为事实源,接受重启丢失及多实例间短暂不一致。

集群中的本地缓存是每实例副本,不会自动覆盖全量数据;发布或冷启动会出现空缓存和回源抖动,应设置预热、限流和随机过期。需限制条目数与大小、监控堆占用和 GC。广播适合失效通知但可能丢失,可结合版本号校验、定期拉取或直接查询 L2;两级缓存用本地副本降延迟,用共享缓存承接一致性与回源。

差距在哪:新手只按数据量做判断——这是最表面的维度。高手从一致性、延迟、容量、故障影响四个维度对比,且给出了 Agent 场景下的具体选型建议和二级缓存架构。面试官考的是你对缓存体系的工程化理解——不只是“知道 Redis”,而是知道什么场景用什么缓存、为什么。


Q:使用 LangGraph 开发 Agent,遇到最大的困难是什么?

来源:bilibili AI研发实习一面;本轮追问:你是否实际使用过 LangChain 或 LangGraph?(本轮追问);本轮追问:简述主流Agent的核心组成架构。LangGraph在落地应用中的短板是什么?(小红书多模态秋招二面);恒生电子技术岗ai面

新手答:“文档看不太懂。”

高手答:

LangGraph 的核心价值是把 Agent 的执行逻辑建模为有状态的图(Graph),但这也带来了几个实际开发中非常痛的问题:

困难一:状态设计是最大的架构决策

LangGraph 中所有节点共享一个 State 对象,State 的字段设计直接决定了整个 Agent 的行为。设计不好的 State 会导致:

  • 字段太少 → 节点之间信息传递不够,每个节点都要重新推理
  • 字段太多 → 状态膨胀,调试困难,且不相关的字段可能干扰模型判断
  • 类型不对 → 并发节点写同一个字段时覆盖(忘了用 Reducer)
# 常见的 State 设计错误
class BadState(TypedDict):
    messages: list  # ❌ 并发节点同时 append 会互相覆盖

class GoodState(TypedDict):
    messages: Annotated[list, operator.add]  # ✅ Reducer 自动合并

困难二:调试极其困难

传统代码用断点就能调试。LangGraph 的执行是“图遍历 + 模型推理”的混合,出了问题很难定位:

  • 不知道是模型推理错了,还是图的边条件判断错了,还是 State 传递有问题
  • 节点之间的数据流是隐式的(通过 State),不像函数调用那样有明确的参数传递
  • 解法:用 LangSmith 做执行链追踪,每个节点的输入输出都可视化;对关键节点加日志断点

困难三:并发和状态合并

LangGraph 支持 Fan-out 并行,但并发节点写回同一个 State 字段时必须用 Reducer 函数处理合并。这个机制初学时很容易忽略——结果是多个并发节点的输出互相覆盖,只剩最后一个。

困难四:图的复杂度失控

项目初期图很简单(3-5 个节点),但随着功能增加,边和条件判断快速膨胀。超过 10 个节点的图已经很难在脑子里追踪执行路径了。

  • 解法:用 subgraph 做模块化——把相关节点封装成子图,主图只编排子图之间的关系
  • 给每个条件边起有意义的名字,画出来能读懂

困难五:Checkpoint 和恢复

LangGraph 的 checkpointer 机制允许在任意节点暂停和恢复,但实际使用中 checkpoint 的序列化和反序列化经常出问题——特别是 State 中包含不可序列化的对象(如数据库连接、模型实例)时。

困难 根因 解法
状态设计难 State 是全局共享的,字段设计影响所有节点 先画数据流图,再定义 State;并发字段必须加 Reducer
调试难 执行链路是图遍历+模型推理的混合 用 LangSmith 可视化执行链;关键节点加日志
并发合并 Reducer 机制不直观 任何可能被并发写入的字段都显式定义 Reducer
复杂度失控 节点和边增长后图不可读 用 subgraph 模块化;控制单图节点数 < 10
Checkpoint 序列化 State 包含不可序列化对象 State 中只放可序列化数据,非序列化对象放工厂函数

主流 Agent 通常由模型、状态与记忆、规划/决策、工具调用、执行与观察、反馈循环及安全护栏组成。LangGraph 的短板是图和状态管理带来较高开发维护成本,流程复杂后可读性、调试、持久化和跨版本迁移都较难;应通过节点级日志、状态快照和故障注入验证链路。

差距在哪:新手只说“文档看不懂”——这是学习阶段的问题不是工程问题。高手点出了状态设计、调试、并发合并、复杂度控制、Checkpoint 五个实际工程难点,每个都有具体的根因和解法。面试官考的是你对 Agent 开发框架的实战理解深度——踩过的坑越具体,越说明你真正用过。


Q:AI Coding 检查错误的时间比自己写还长,怎么提效?

来源:字节实习二面【拼多多 复活赛 一面追问:日常 coding 或改策略往往是不确定的事情,怎么让 Agent 提效?】;本轮追问:平时有用 Coding Agent 吗?如何提效?(本轮追问);本轮追问:讲下你平时 AI Coding 工作流(CC/Codex)(本轮追问)

新手答:“那就不用 AI 写了,自己写更快。”

高手答:

这个“悖论”很常见,但问题不在 AI Coding 本身,而在使用方式。检查时间长,通常是因为三个原因:

1. 生成粒度太大

一次让 AI 生成整个模块(几百行),review 时完全不知道它的意图和设计决策,只能逐行检查。

解法:小步生成,逐步确认。每次只让 AI 生成一个函数或一个逻辑块(20-50 行),确认正确后再继续。Claude Code 的 plan 模式就是这个思路——先生成计划,确认后再执行。

2. 对生成结果没有结构化验证

只用肉眼 review 是最慢的方式。

解法:让机器帮你检查。配置好 TypeScript 类型检查、Lint 规则、已有测试套件,AI 生成后自动跑一遍。通过了静态检查和测试的代码,人工只需要 review 业务逻辑正确性,工作量减少 70%。

3. 上下文给得不够精确

AI 不了解项目上下文,生成的代码风格不一致、用了错误的 API、不符合项目规范。这些“小问题”累积起来,review 成本极高。

解法:投入上下文工程。把项目规范、API 文档、代码风格写进 CLAUDE.md 或 Rules;用 @file 引入相关代码作为参考。上下文给得越精确,生成质量越高,检查成本越低。

效率公式:

AI Coding 的实际效率 = 生成速度 × 首次通过率
                    = 生成速度 × f(上下文质量, 任务粒度, 自动化验证)

检查时间长说明“首次通过率”太低,根因是上下文质量差、任务粒度大、没有自动化验证——不是 AI Coding 不行,是使用姿势需要优化。

差距在哪:新手直接放弃 AI Coding——这是把工具的学习曲线当成工具的上限。高手分析了检查成本高的三个根因(粒度大、无自动化验证、上下文不足),且给出了对应的提效方案。面试官考的是你对 AI Coding 工作流有没有深入思考——不是“用没用过”,而是“怎么用才高效”。


Q:模型离线 AUC 很高但上线后效果暴跌,怎么排查?

来源:淘宝闪购 Agent 一面(AI Coding 压轴题);本轮追问:线上效果是否一上来就是正向的?是否遇到过离线好但线上差的案例?(本轮追问);快手二面

新手答:“可能是数据有问题,重新训练一下。”

高手答:

离线 AUC 92%、测试 89%、上线跌至 62%——这是工业界最经典的 Train-Serving Skew 问题。排查需要从数据、标签、Serving 三个维度系统展开,按影响幅度排序:

数据层(影响最大,优先排查)

排序 原因 影响幅度 排查方法
1 Train-Serving 特征分布偏移 10-30% AUC 下降 对比线上/线下特征分布(KL 散度、PSI)
2 线上样本分布与训练集不一致 5-20% 对比线上流量的类别分布 vs 训练集
3 特征泄露导致离线 AUC 虚高 可达 20%+ 检查是否用到了只有离线才有的“未来特征”

标签层

排序 原因 影响幅度 排查方法
4 标签定义口径不一致 5-15% 比对离线标签定义 vs 线上业务指标定义
5 Label Delay 问题 3-10% 检查标签回收窗口是否覆盖完整转化周期
6 标注噪声线上放大 3-8% 抽样人工复审标注质量

Serving 层

排序 原因 影响幅度 排查方法
7 模型版本与 Feature Schema 未对齐 可致严重错误 比对模型期望的特征列表 vs 线上实际提供的
8 在线推理精度损失/缺失填充策略不一致 1-5% 对比离线 batch 推理 vs 在线实时推理的输出

排序依据:数据层 skew 对 AUC 的影响幅度最大(可达 10-30%),且在工业界出现频率最高,因此排在前三。标签问题通常灰度期可被发现。Serving 层问题通过日志比对可快速定位,实际频率相对低。

排查方法论:

flowchart TD
    A["上线 AUC 暴跌"] --> B["Step 1: 离线重跑线上数据"]
    B -->|"AUC 恢复"| C["Serving 层问题\n检查精度/Schema/缺失值"]
    B -->|"AUC 仍低"| D["Step 2: 检查特征分布"]
    D -->|"分布偏移"| E["数据层问题\nPSI > 0.25 的特征逐个排查"]
    D -->|"分布正常"| F["Step 3: 检查标签"]
    F --> G["标签层问题\n口径/延迟/噪声"]

追问补充:线上成功率下降且离线不变时,先按版本、流量和配置确认是否真实回归:核对模型、提示词、工具及路由灰度、错误率和超时;再用线上原始请求回放,逐步对比规划、检索、工具调用和最终判定,定位首个分叉;最后检查数据分布、标签回收窗口与业务口径,并以分桶成功率和 trace 抽样复核。

差距在哪:新手只能模糊地说“数据有问题”。高手从数据、标签、Serving 三个维度列出 8+ 具体原因,按影响幅度排序,并给出每个原因对应的排查方法。面试官考的不只是你知不知道这些原因,更是你能不能按优先级系统排查——工业界的 debug 不是靠灵感,是靠方法论。


Q:数据量和 QPS 增大后,Agent 架构怎么改进?需要什么硬件?RT 要求高时怎么部署?

来源:阿里国际 AI 应用研发二面;9.22 阿里千问二面;本轮追问:平台接入了哪些模型?走内部 API 还是自己部署?部署用了多少卡?(9.15快手二面AI应用)

新手答:“加机器,用更好的 GPU。”

高手答:

按 QPS 量级分层的架构改进

QPS 量级 架构策略 硬件配置
< 10 单机部署,vLLM/Ollama 单卡 A100/H100,或 4090 开发机
10-100 多实例 + 负载均衡,连续批处理 2-4 卡 A100/H100,CPU 用于编排层
100-1000 微服务拆分(编排/推理/检索分离),推理集群 GPU 集群 + 独立向量 DB 节点 + Redis 缓存
1000+ 模型分级(大小模型混合),全链路异步,缓存命中率优化 混合 GPU 集群(H100 给大模型 + A10 给小模型)

RT(响应时间)优化的关键手段

  1. 推理加速:量化(INT4/INT8/FP8)、推测解码、KV Cache 复用、Prefix Caching
  2. 模型分级调度:简单请求走 7B/14B 小模型(延迟 < 200ms),复杂请求走大模型
  3. 服务架构:推理和编排分离部署,编排层用 CPU 即可;推理层用 vLLM/TensorRT-LLM/SGLang,continuous batching
  4. 缓存策略:语义缓存(相似 query 命中率可达 30-50%),工具结果缓存,KV Cache 跨请求复用

GPU 选型参考

GPU 显存 适用场景 性价比
A100 80G 80G 70B 模型推理/微调,主力生产 GPU 中
H100 80G 高吞吐推理,支持 FP8 高(新项目首选)
A10/L4 24G 小模型推理(7B-14B),性价比高 高
4090 24G 开发测试,不建议生产(缺 ECC、NVLink) 开发最优

Agent 特有的扩容挑战

Agent 和普通 LLM 推理不同——单次请求可能触发 5-15 次模型调用(规划 + 多次工具调用 + 总结),所以 Agent 的 QPS 要乘以平均调用次数来估算推理集群的真实负载。

还应明确模型接入清单:哪些请求走内部模型 API,哪些模型因时延、成本或数据隔离要求自部署;卡数不能按模型名固定,应结合参数规模、量化、并发和副本数核算,并用部署配置与压测结果核对。

差距在哪:新手只想到“加机器加 GPU”。高手按 QPS 量级分层给出了架构策略和硬件配置,且区分了推理加速和服务架构两个优化层面,并指出 Agent 的 QPS 需要乘以平均调用次数来估算真实负载。面试官考的是你对 Agent 系统从开发到生产扩容的全链路工程认知。


Q:Agent 异步任务管线中引入消息中间件(如 Kafka),会不会反而变慢或成为瓶颈?扫表和消息驱动各有什么优缺点?

来源:淘天 Agent 开发;本轮追问:为什么文档更新这里考虑使用 MQ,而不是直接在定时任务中处理?(字节 Agent 秋招一面);10.10 无锡赫玛科技

新手答:“Kafka 是异步的,肯定更快。”

高手答:

消息中间件不是万能提速器——引入 Kafka 后系统延迟可能反而增加,关键看任务类型:

什么时候 Kafka 反而变慢?

场景 直接调用延迟 Kafka 延迟 结论
单次简单任务(<100ms) ~50ms ~50ms + 入队 + 消费延迟 ≈ 200ms Kafka 更慢
多步串行任务 步骤间直接调用 每步都经 Kafka 中转,延迟倍增 严重更慢
高并发异步任务 线程池打满,排队阻塞 削峰填谷,稳定吞吐 Kafka 优势明显
长时任务(分钟级) 占线程等待,资源浪费 发消息后释放线程,异步回调 Kafka 优势明显

核心认知:Kafka 的价值不是「更快」,而是「更稳」——通过解耦生产者和消费者,让系统在流量突增时不崩溃。延迟可能增加几十毫秒,但换来的是吞吐稳定性和可靠性。

流量变大后 Kafka 本身会不会成为瓶颈?

会,但可控。常见的瓶颈点和解法:

瓶颈 表现 解法
分区数不足 消费速度跟不上生产速度 增加 partition 数 + 消费者组扩容
单条消息过大 序列化/网络传输耗时 消息体只传 ID/引用,大数据走对象存储
消费者处理慢 消息堆积、lag 持续增长 业务侧限流(令牌桶) + 结合业务频次限制

扫表 vs 消息驱动管理长时任务:

维度 扫表(定时轮询) 消息驱动(如 Kafka 双 Topic)
实时性 取决于扫描间隔(秒级延迟) 近实时(毫秒级)
资源开销 持续查库,空转浪费 事件驱动,无空转
可靠性 数据库是天然持久化,断电不丢 需配置持久化和消费确认
复杂度 简单直接,一条 SQL 搞定 需维护 Topic、消费者组、死信队列
适用规模 小规模(<1000 任务/分钟) 大规模(10000+ 任务/分钟)
状态可查 数据库直接查,运维友好 需额外建状态表或监控面板

生产中的最佳实践:小规模用扫表(简单可靠),中大规模用消息驱动 + 状态表(消息负责流转,数据库负责状态持久化和查询),两者结合取长补短。

追问补充:当前体量若任务量和并发仍可由单实例承载,可用线程池配合阻塞队列:本地排队、限流和背压更简单,少了序列化、网络跳转及 Kafka 运维成本。需监控队列长度、拒绝数和任务耗时;超过进程故障域或需要跨实例削峰、持久消费时再引入 Kafka。

差距在哪:新手认为异步就等于更快。高手区分了 Kafka 适用和不适用的场景,且给出了扫表和消息驱动在不同规模下的选型依据。面试官考的是你对异步架构 trade-off 的理解——不是「用不用」,而是「什么时候用」。


Q:LangGraph 的 State Snapshot(状态快照)机制是怎么实现的?解决什么问题?

来源:字节后端开发 Agent 一面;本轮追问:LangGraph里用到断点跑、快照存储,怎么实现快照持久化、HITL人工介入,中断之后如何恢复?(药明康德(AI数据方向-二面))

新手答:“就是保存一下当前状态,方便恢复。”

高手答:

LangGraph 的 State Snapshot 机制本质是基于 Checkpoint 的确定性状态管理——让 Agent 的执行过程可追溯、可回退、可分叉。

解决的核心问题:

Agent 执行多步任务时,中间任何一步可能失败或产生分支。没有快照机制,失败后只能从头重跑;有了快照,可以从任意中间状态恢复或分叉。

实现机制:

flowchart TD
    A["Node A 执行"] --> B["Checkpoint 1\n保存完整 State"]
    B --> C["Node B 执行"]
    C --> D["Checkpoint 2\n保存完整 State"]
    D --> E["Node C 执行失败"]
    E -->|"回退到 Checkpoint 2"| C
    D -->|"分叉"| F["Node D\n(另一条路径)"]
组件 职责
State 图执行的全局状态对象(TypedDict),包含所有节点共享的数据
Checkpointer 在每个节点执行后序列化并持久化当前 State
Thread 一次完整的图执行实例,通过 thread_id 标识
Checkpoint ID 每个快照的唯一标识,支持精确回退到任意历史状态

Checkpointer 的存储实现:

存储后端 适用场景
MemorySaver 开发调试,内存存储,进程结束丢失
SqliteSaver 单机持久化,轻量部署
PostgresSaver 生产环境,多实例共享状态

快照解决的三个工程问题:

  1. Human-in-the-loop:节点执行到需要人工确认时,保存快照暂停;人工审批后从快照恢复继续执行
  2. 错误恢复:工具调用失败时回退到上一个快照,换策略重试,而不是从头重跑整个流程
  3. 状态分叉:同一个快照可以沿不同路径继续执行(类似 Git 分支),用于 A/B 测试不同的 Agent 决策路径

和 Git 的类比:

Checkpoint ≈ Git Commit(记录某一刻的完整状态)
Thread ≈ Git Branch(一条执行路径)
回退 ≈ Git Reset(回到历史状态)
分叉 ≈ Git Branch(从某个 Commit 开出新分支)

持久化应把 thread_id、checkpoint_id、父快照、状态版本和待执行位置原子写入可靠存储,并配置 TTL、加密、权限与幂等。HITL 节点发出 interrupt 后提交人工任务并暂停;审批结果写回任务,客户端携带 thread_id 和 checkpoint_id resume,恢复前校验版本,避免重复执行工具或消息。

差距在哪:新手只理解“保存状态”——这和普通变量序列化没区别。高手理解 Checkpoint 是 LangGraph 实现确定性执行、人工干预、错误恢复的基础设施,且能讲清具体的存储实现和应用场景。面试官考的是你对 Agent 框架状态管理的理解深度——不是“用过 LangGraph”,而是理解它为什么要这样设计。


Q:高并发场景下同时调 10 个 Embedding 接口,asyncio.gather 相比多线程有什么资源优势?

来源:阿里淘天 AI应用开发一面

新手答:“asyncio 更快。”

高手答:

“更快”不准确——asyncio 和多线程在 IO 密集场景下的完成时间几乎一样,真正的差距在于资源消耗。

核心区别:

维度 多线程(threading) 协程(asyncio)
调度层级 OS 内核态调度 用户态调度(Python 解释器内部)
内存开销 每线程 ~8MB 栈内存(默认) 每协程 ~KB 级(几百字节到几 KB)
上下文切换 内核态切换,涉及寄存器保存/恢复、TLB 刷新 用户态切换,只需保存/恢复 Python 帧对象
创建销毁成本 高(系统调用) 极低(普通 Python 对象)
GIL 影响 受 GIL 限制,同一时刻只有一个线程执行 Python 代码 单线程内运行,天然不受 GIL 影响

10 个并发 Embedding 调用的场景分析:

瓶颈在网络 IO(等 API 返回),不在 CPU 计算。IO 密集型任务是协程的最佳场景——协程在 await 时让出执行权,单线程就能管理上千并发连接。

资源对比:

多线程方案(10 个线程):
  内存:10 × 8MB = 80MB 额外栈内存
  线程池管理开销:线程创建/销毁/调度
  OS 资源:10 个内核线程对象

asyncio 方案(10 个协程):
  内存:10 × ~几KB = ~几十 KB
  无线程池,单线程 event loop 调度
  OS 资源:1 个线程

差距:内存开销差 1000 倍+

asyncio 方案实现:

import asyncio
import aiohttp

async def embed_one(session, text):
    async with session.post(EMBED_URL, json={"input": text}) as resp:
        return await resp.json()

async def embed_batch(texts):
    async with aiohttp.ClientSession() as session:
        tasks = [embed_one(session, t) for t in texts]
        results = await asyncio.gather(*tasks)
    return results

# 10 个并发请求,单线程完成
results = asyncio.run(embed_batch(texts[:10]))

asyncio 的局限——什么时候不适用:

如果 Embedding 是本地 CPU 计算(比如用 sentence-transformers 在本地跑模型),asyncio 无法并行——因为 Python 的 GIL 限制,单线程内 CPU 密集计算无法真正并行执行。这时需要 ProcessPoolExecutor:

from concurrent.futures import ProcessPoolExecutor
import asyncio

async def embed_batch_cpu(texts):
    loop = asyncio.get_event_loop()
    with ProcessPoolExecutor(max_workers=4) as pool:
        # CPU 密集任务交给进程池
        results = await loop.run_in_executor(pool, local_embed, texts)
    return results

实际工程中的混合方案:

asyncio + aiohttp      → 网络并发(调远程 Embedding API)
ProcessPoolExecutor     → CPU 密集(本地模型推理)
两者结合               → 最优资源利用

典型场景:
  10 个文本需要 Embedding
  ├─ 远程 API(OpenAI / BGE API)→ asyncio.gather + aiohttp
  └─ 本地模型(sentence-transformers)→ ProcessPoolExecutor + batch inference
场景 推荐方案 原因
远程 API 调用(IO 密集) asyncio + aiohttp 内存占用极低,单线程管理上千连接
本地模型推理(CPU 密集) ProcessPoolExecutor 绕过 GIL,真正多核并行
本地 GPU 推理 batch inference(一次送入) GPU 本身并行计算,不需要多线程/多进程
混合场景 asyncio 编排 + executor 处理 CPU 部分 各取所长

差距在哪:新手只说“更快”。高手区分了 IO 密集 vs CPU 密集场景,给出了具体的内存开销对比,且知道什么时候协程不适用。面试官考的是你对 Python 并发模型的工程理解。


Q:Agent 系统可观测性设计——怎样的结构才能更好地追踪整个 Trace?

来源:美团Agent开发(智能客服方向)二面 【懂车帝 Agent 开发一面追问:Trace、日志、指标和配置版本联合归因】【阿里 Agent Infra 一面题库追问:Agent Trace 字段与成功率突降排查】 / 阿里千问 Agent 开发一面 / 百度 Agent 二面【阿里巴巴(阿里云)- Agent Infra追问:如何设计 Agent 全链路追踪(Trace)和可观测性(Metrics)?】【百度Agent一面追问:用户的一次请求在最终的 Trace 展示上是什么形式?Trace 具体怎么用,会做分析吗?】【格物致信(一面过,二面线下拒)追问:Agent很容易变成黑盒,任务失败你如何做可观测性?】;本轮追问:怎么控制agent的,是否有观测的方式?(本轮追问);快手大模型agent研发一面;【社招】腾讯一面面经;本轮追问:全链路观测的数据用什么存储?(【社招】腾讯二面面经);9.24 普通の快手一面(发券);同花顺一面 10.9

新手答:“每一步打个日志就行。”

高手答:

Agent 的可观测性和传统微服务 tracing 有本质区别——它是非确定性的。核心设计:

  1. Trace 结构:每次 Agent 调用生成唯一 trace_id,内部用 span 表示 LLM 调用、工具调用、记忆检索等步骤,形成树状结构
  2. 结构化日志:每个 span 记录输入输出摘要、token、延迟、重试、缓存命中、错误码和业务主键;敏感原文按权限脱敏或不落盘
  3. 决策依据:记录“选了哪个动作、基于哪些可公开的证据和规则”,不要依赖不可审计的原始思维链
  4. 跨 Session 关联:用 user_id + session_id + trace_id 三级关联,支持用户维度的行为分析
  5. 异常检测:设置 token 消耗异常、循环调用、工具连续失败等自动告警规则
  6. 版本指纹:在根 span 和关键子 span 记录 Prompt、模型、Tool Schema、Skill/路由规则、知识库索引和运行配置版本

定位问题时要联合四类证据:Metrics 先确认影响范围和异常时段,Trace 找到慢或错的首个 span,结构化日志还原该节点的输入、重试和错误上下文,版本指纹判断是否由发布变更引起。只看其中一种,容易把下游等待误判成模型慢,或把路由变化误判成数据波动。

线上成功率突降时,回答顺序可以固定为 Scope → Change → Breakdown → Trace:先切分租户、地区、模型和 Agent 版本,再核对变更,按 LLM/RAG/Tool/Runtime/Infra 分层比较失败率,最后用成功与失败 Trace 找到第一个分叉点。

日志本身也可能制造假象:把真正失败记成 INFO/DEBUG、捕获异常后返回空结果、只记录最终 fallback 成功,都会让错误率看似正常。异常被降级时仍应设置 span error status,保留原始错误分类和 fallback 链路;日志级别、指标计数与用户看到的结果要使用同一套错误语义。

入口层应在鉴权、路由和协议解析后统一创建根 span,并把 traceparent、业务请求 ID 和版本指纹传到模型网关、RAG、工具服务与异步队列;每个服务只补自己的子 span,避免跨服务后断链。排查“哪个 Agent 最慢”时,先从端到端 Trace 找首个耗时异常或错误 span,再区分本节点计算、排队、重试和下游等待,不能把最后返回的服务当成首因。Metrics 负责发现趋势和影响面,Trace 负责定位路径,Logs 负责解释节点细节,三者通过同一组关联 ID 汇合,不需要背厂商组件清单。

存储上通常采用分层方案:Trace 元数据、span 索引和聚合指标放在可按时间与业务维度查询的结构化存储,完整事件和大字段落对象存储或日志系统,热数据短期保留、冷数据归档。需统一 trace_id 建索引,并设置脱敏、访问控制、保留期和采样策略,保证排障可查且成本可控。

追问补充:补充闭环:在取得用户授权并脱敏后,按 session 保存对话事件、Trace 摘要及用户反馈或人工标注;定时任务按版本、场景聚合成功率、工具失败、延迟、成本和满意度,抽样回放异常 Trace,生成缺陷清单并关联责任版本。修复后用同一评估集复测,跟踪指标是否回归,避免只统计日志量。

差距在哪:面试官要看你是否理解 Agent 的 Trace 不是 request→response 那么简单,需要记录决策过程才能 debug。


Q:SSE 流式输出中断后如何保证之前的输出不丢失?

来源:某教育agent开发【字节跳动 - AI Agent 开发岗(工程方向)追问:如何设计 SSE 流式输出网关,处理断线重连和消息重放?】【百度 - Agent 研发岗(架构方向)追问:如何设计 SSE 流式网关,处理断线重连和消息重放?】;本轮追问:SSE 如何处理断连?心跳保活怎么做?(本轮追问);本轮追问:SSE 是基于什么协议的?断线重连怎么做?(度小满一面);度小满 - AI 全栈研发 - 一面

新手答:“断了就重新生成呗。”

高手答:

SSE 流式断连是 Agent 应用的常见问题(用户关闭浏览器、网络波动等),解决方案分层:

  1. 服务端持久化:每个 SSE 事件带递增 event_id,服务端将已发送内容写入 Redis/DB(key = task_id)
  2. 断点续传:客户端重连时携带 Last-Event-ID,服务端从该位置继续推送
  3. 异步任务分离:将 LLM 生成与 SSE 推送解耦——生成结果写入消息队列,SSE 连接只负责消费和推送。即使连接断开,生成不中断
  4. 轮询兜底:如果 SSE 重连失败,降级为轮询接口拉取 task_id 对应的已生成内容
  5. 前端状态恢复:客户端本地缓存已收到的 chunk,重连后只接收增量

SSE 基于 HTTP 长连接,响应类型为 text/event-stream,特点是服务端到客户端的单向推送。客户端可按 Retry-After 或退避策略自动重连,并携带 Last-Event-ID;服务端据此补发未确认事件,心跳注释用于避免连接被中间设备回收。

追问补充:要保证文本和卡片有序可靠,应按任务维护单调序号或版本号,并将事件写入同一有序日志;卡片更新尽量采用带版本的完整快照或可重放增量。客户端按序缓存、去重和补发,缺号时重连拉取,确认后再推进消费,避免重复应用或旧版本覆盖新版本。

差距在哪:关键是“生成过程和推送过程解耦”的架构思想,不要让连接状态影响计算状态。


Q:产品的用户量、每日 token 消耗和底层模型选型怎么估算?

来源:快手AI应用开发一面;本轮追问:项目底层模型如何选择?选型的考量是什么?(本轮追问);本轮追问:估算此时此刻上空有多少架飞机,并说明完整推导过程。(本轮追问);本轮追问:token的计费规则是什么?(本轮追问);虾皮agent开发一面

新手答:“看产品有多少用户,乘以每次对话的 token 数就行了。”

高手答:

这类问题不能只报一个数字,要展示估算方法论。核心公式:

日 token 消耗 = DAU × AI 触发率 × 平均轮数 × 每轮 token 量

以理赔场景为例:DAU 5 万,20% 触发 AI 审核/解释(1 万次 AI 会话),每次平均 3 轮,每轮输入上下文 1500 token + 输出 500 token:

1万会话 × 3轮 × (1500 + 500) = 6000万 token/天

底层模型不会只用一个,需要分层路由:

graph LR
    A[用户请求] --> B{任务复杂度}
    B -->|简单| C[小模型]
    B -->|复杂| D[大模型]
    B -->|检索| E[Embedding 模型]
    B -->|排序| F[Rerank 模型]
    C --> G[意图识别/槽位抽取/JSON修复]
    D --> H[复杂解释/多证据综合/争议总结]
模型层 用途 选型考虑
小模型 意图识别、JSON 修复 低延迟、低成本
大模型 多证据综合、争议解释 准确性优先
Embedding 知识库向量化 维度/召回率
Rerank 重排精排 精度/延迟

延迟要求严格时还要做模型路由和降级:大模型 P95 超时后返回模板化解释或进入人工审核队列。

成本估算要覆盖:模型调用费、Embedding 索引存储、向量检索 QPS、GPU 推理实例数。线上的实际消耗 = 估算值 × 1.3(缓存未命中、重试、上下文膨胀的安全系数)。

追问补充:一次查找和故障归因没有固定 Token 数,应按步骤拆分估算:问题改写、检索与工具参数、若干轮证据分析、归因总结及重试,并分别统计输入、输出和上下文复用量。上线后按任务类型记录 P50/P95,得到单次成功任务的实际消耗。

差距在哪:新手只能报一个“大概多少 token”。高手能展示完整估算链路:DAU → 触发率 → 轮数 → token → 分层模型路由 → 降级策略 → 成本。面试官考的不是精确数字,而是你的工程化容量规划能力——能否从业务指标推导到资源需求。


Q:Agent 如何做版本管理与灰度?

来源:Agent面经八股系列 / 蚂蚁 Agent 开发一面;本轮追问:你怎么做Agent的版本管理和OTA升级?(蔚来——大模型算法岗(智能座舱/自动驾驶)实习一面);南方基金 AI应用大模型方向 笔面试梳理

新手答:“把 Prompt 存到数据库,每次改了就更新版本号。”

高手答:

Agent 的版本管理涉及三层:Prompt/Tool Schema/Model 各自独立版本号管理。灰度方案:

  1. 影子模式(Shadow Mode):新版 Agent 并行执行但只记录建议不真实执行,对比老版结果
  2. 金丝雀发布:先对 1% 用户群开放,观察成功率、成本、违规数等关键指标
  3. 快速回滚:保留前 N 个版本快照,任何指标异常一键回滚
  4. AB 对比:同一批请求同时发给新旧版本,diff 输出差异自动告警

OTA 不只是替换 Prompt:将 Prompt、工具 Schema、模型及运行时打成带依赖清单的可回滚发布包,签名校验后在设备或租户上分批下发;客户端先做兼容性检查并原子切换,持续上报下载、启动、失败和回滚状态,异常自动暂停灰度。

差距在哪:面试官要看你是否理解“Agent 不是一个函数而是一个系统”——Prompt 改了、工具改了、模型换了都算版本变更,需要联动管理。


Q:怎么设计一个大模型网关系统?

来源:猎豹移动Agent全栈开发 / 阿里淘天一面;本轮追问:你简历中写到网关路由,网关的主要作用是什么? / 你觉得网关最主要的功能是什么?(度小满 AI 全栈二面)

新手答:“做个 API 代理,转发请求到不同模型就行。”

高手答:

大模型网关是 Agent 系统的基础设施层,核心职责:

  1. 统一接口:屏蔽不同模型厂商 API 差异(OpenAI/Anthropic/本地模型),对上层提供一致的 chat/completion 接口
  2. 路由策略:根据任务类型/成本/延迟要求,智能选择模型(复杂推理→大模型,简单分类→小模型)
  3. 限流与配额:按 team/user/app 维度的 token 预算控制、QPS 限流、优先级队列
  4. 缓存层:语义缓存(相似 prompt 复用历史结果)+ 精确缓存(相同 prompt hash)
  5. 可观测性:记录每次调用的 token 消耗、延迟、模型版本、是否降级
  6. 降级与容灾:主模型超时/报错时自动 fallback 到备用模型,保证服务可用性
  7. 安全审计:敏感词过滤、PII 脱敏、Prompt 注入检测

错误契约也要统一。请求尚未进入流时,用 HTTP 状态表达认证、限流、参数、上游不可用等失败;流已经返回 200 后,后续错误只能作为带 code、retriable、provider 和 request_id 的结构化流事件发送,并以明确的终止事件收尾。网关把供应商错误归一化,但保留原始错误码用于排障;只有超时、限流或确认无副作用的瞬时故障可重试,不能把所有错误都包装成成功响应。

差距在哪:面试官期望你把网关当成一个完整的中间件来设计,而不是简单的 HTTP 代理。


Q:如何设计 Agent 的流式输出以提升用户体验,特别是包含工具调用和多次大模型交互时?

来源:Agent开发八股合集(南京大学) / 阿里千问 Agent 开发一面;本轮追问:大模型生成的内容如何与后续工具代码对接?如何约束输出规范?(本轮追问);字节 Agent 秋招二面

新手答:“用 SSE 把模型输出一个字一个字推给前端就行了。”

高手答:

简单的 LLM 流式输出只需要 SSE token-by-token 推送,但 Agent 场景复杂得多——一次用户请求可能包含多次模型调用、工具执行、结果整合,用户等待时间远超纯生成场景。UX 设计的核心原则是:让用户始终知道系统在做什么,而不是面对空白等待。

Agent 流式输出的分层设计:

graph TD
    A[用户发送请求] --> B[思考阶段]
    B --> C[工具调用阶段]
    C --> D[结果整合阶段]
    D --> E[最终回答流式输出]

    B -->|推送| B1["💭 正在分析您的问题..."]
    C -->|推送| C1["🔧 正在查询航班信息..."]
    C -->|推送| C2["🔧 正在检索酒店价格..."]
    D -->|推送| D1["📝 正在整理结果..."]
    E -->|流式| E1[逐字输出最终回答]

具体工程实现:

  1. 事件类型分层:SSE 不能只有 data: 一种类型,需要区分:
    • thinking:模型推理中间过程(可选展示)
    • tool_call:工具调用开始,附带工具名和参数摘要
    • tool_result:工具返回结果摘要
    • content:最终回答的流式 token
    • status:状态更新(“正在搜索”、“已找到 3 条结果”)
  2. 工具调用期间的“占位体验”:
    • 工具执行时前端展示进度指示器 + 当前步骤文案
    • 并行工具调用时展示多个进度条,完成一个标绿一个
    • 工具超时时给用户可操作的提示(“查询耗时较长,是否继续等待?”)
  3. 部分结果渐进展示:
    • 多步任务不必等全部完成才输出——检索到的中间结果可以先展示为“草稿”,最终整合后替换
    • 类似 Deep Research 的“研究进展”面板:实时展示已完成步骤和发现
  4. 异常与中断处理:
    • 工具失败时立即推送错误状态,不让用户干等
    • 支持用户中途取消(发送 cancel 事件),后端优雅中止当前工具链
    • SSE 连接断开后支持断点续传(通过 event ID 重连恢复)
  5. 延迟隐藏技巧:
    • 模型还在 plan 时就开始展示“理解您的需求:xxx”
    • 第一个工具调用结果返回后立即开始生成部分回答,不等全部工具完成
    • 预测性 UI:根据 plan 预先渲染结果骨架(skeleton),数据到了填充

流上语义判断要在质量和时延之间分层:字符拼接、协议校验可只看当前增量;安全、完整句和工具参数判断使用有限滑动窗口;需要全文关系的任务在句末、工具结束或阶段完成时生成语义 checkpoint,再异步做全量复核。消费者跟不上时应通过有界缓冲、暂停上游或合并低价值进度事件施加背压;业务接入层还要按租户并发、任务预算和风险做准入或拒绝,不能把无限请求都推给流处理器。

差距在哪:面试官考的是你对“Agent 不是 ChatBot”的 UX 理解。纯 LLM 只需 token 流,Agent 需要多阶段状态反馈、并行任务进度、异常即时通知。能设计出分层事件协议 + 渐进展示策略,说明你做过面向用户的 Agent 产品而非只写后端。


Q:高并发场景下,如何设计 Agent 服务的弹性伸缩策略?

来源:阿里淘天智能体开发;本轮追问:如果这个 AI 应用出现高并发,你会怎么处理?(小红书 Product Engineer(AI与全栈方向)-社区工程 一面面经)

新手答:“加机器、加副本就行。”

高手答:

Agent 服务的伸缩和普通 Web 服务有本质不同——单次请求可能持续数十秒、消耗大量 token、调用多个外部工具:

  1. 请求粒度拆分:将 Agent 执行拆为“调度层”和“执行层”。调度层轻量可快速水平扩展;执行层(LLM 调用 + 工具执行)按资源消耗独立伸缩
  2. 异步队列削峰:高并发时不直接打到 LLM,而是入消息队列(Kafka/SQS),按 LLM 供应商的 RPM/TPM 限制控制消费速率
  3. 模型分级降级:流量高峰时自动将非关键任务降级到小模型(如 Haiku),保障核心任务用大模型(如 Opus)
  4. 长连接管理:Agent 的 SSE 长连接占用资源,需要独立的连接池管理和超时回收策略
  5. 成本感知伸缩:不只看 CPU/内存,还要基于 token 消耗速率和 API 配额做伸缩决策——token burn rate 超阈值时触发限流而非加机器
  6. 预热与冷启动:Agent 服务依赖模型连接池、向量数据库连接等,冷启动慢,需要保留最小实例数 + 预热机制

差距在哪:面试官要看你是否理解“Agent 的瓶颈不在 CPU 而在外部依赖(LLM API 限流、工具响应)”——传统的 HPA 按 CPU 扩容在 Agent 场景下几乎无效。


Q:Claude Code 用久了感觉响应越来越慢,这是什么原因?怎么解决?

来源:字节TikTok AI应用开发一面

新手答:“上下文太长了,清空一下就好。”

高手答: “用久了变慢”是上下文膨胀的典型症状,但根因不只是“上下文长”,还有几个容易被忽视的层次:

根因分析:

  1. 上下文窗口累积:每轮对话都把完整历史附加进去,随着对话轮数增加,每次 API 调用的 token 数线性增长,推理时间也随之增长(注意力机制是 O(n²))
  2. 工具调用结果堆积:Claude Code 每次读文件、运行命令的输出都会附在上下文里,长任务后上下文中可能有几十次工具调用的完整结果
  3. Prompt Cache Miss:Anthropic 的 Prompt Caching 对 system prompt 前缀做缓存,但如果每轮消息的前缀都在变化(比如动态插入时间戳),缓存命中率下降,实际计费 token 增多
  4. 并发请求排队:高负载时段 API 端侧本身有排队延迟,跟本地上下文无关

解决方案:

  1. 主动 /clear 或分段任务:长任务拆成多个独立 session,每个 session 只传必要上下文
  2. 利用 CLAUDE.md 做持久化:把跨 session 的关键约束、项目背景写入 CLAUDE.md,而不是每次在对话里重复说明——这样可以利用 system prompt 前缀缓存
  3. 精简工具调用输出:对大文件读取结果做截断,只保留关键段落,避免整个文件内容堆在上下文里
  4. 区分模型:快速的迭代性任务(改一行代码、解释报错)用 Haiku/Sonnet,复杂规划任务才用 Opus——响应速度差异在 3-10x
  5. 本地缓存复用:重复查询相同文件的场景,可以在 session 开头一次性读取并引用,避免多次触发工具调用

差距在哪:面试官考的不只是“怎么解决变慢”,而是你对 Claude Code 运行机制的理解——上下文管理、Prompt Caching、工具调用成本。高手会把“变慢”拆解成几个独立的根因,而不是只给一个“清空上下文”的答案。


流式返回中的非文本事件

Q:流式返回时,如何插入非文本事件(工具调用标记、思考过程、错误提示、分段标识),且不影响前端渲染?

来源:牛客Agent面经汇总(含答题思路);字节 aime 一面 9.10

新手答:“把工具调用信息也当文本发回去就行了。”

高手答:

核心思路是结构化事件流——不是所有内容都是文本,SSE 的 event 字段天然支持事件分类。

协议设计:

event: text
data: {"content": "让我帮你查一下..."}

event: tool_call
data: {"tool": "search", "params": {"query": "xxx"}, "status": "start"}

event: thinking
data: {"content": "用户想要对比两个方案..."}

event: tool_result
data: {"tool": "search", "status": "done", "summary": "找到3条结果"}

event: text
data: {"content": "根据搜索结果,..."}

event: error
data: {"code": "TOOL_TIMEOUT", "message": "搜索服务超时,已使用缓存结果"}

前端渲染策略:

事件类型 渲染方式
text 追加到主回答区,支持 Markdown 流式渲染
thinking 折叠区域,默认收起,用户可展开
tool_call 状态卡片(加载动画 → 完成打勾)
error 内联 toast 或黄色提示条,不打断主流
separator 分段线,标记逻辑段落边界

工程细节:

  1. 每个事件带序号(id 字段):断线重连时从上次 ID 续传
  2. 工具调用用 start/done 配对:前端据此展示“正在调用 XX”的 loading 态
  3. 文本和非文本事件交错:前端维护一个渲染队列,按序号严格顺序渲染
  4. 错误事件分级:warning 级不中断流,error 级中断当前段落

差距在哪:面试官考的是“你做过面向用户的 Agent 产品吗”。只会拼接文本字符串说明你没处理过工具调用的中间态展示。能设计出分层事件协议 + 前端分类渲染,说明你理解 Agent 和纯 ChatBot 在交互设计上的本质区别。


SSE、WebSocket 与单次调用

Q:SSE 和 WebSocket、单次调用的区别是什么?Agent 场景该怎么选?

来源:成都agent面试(社招)【阿里 Agent Infra 一面题库同题】 / 阿里淘天一面

新手答:“WebSocket 双向通信,SSE 单向推送,单次就是普通 HTTP。”

高手答:

三种方式的核心差异在于通信模型和适用场景:

维度 单次调用 SSE WebSocket
方向 请求-响应,一次性 服务端→客户端单向流 双向全双工
连接 短连接,用完即断 长连接,服务端持续推送 长连接,双方随时发
协议 HTTP HTTP(text/event-stream) 独立协议(ws://)
断线恢复 无需(每次独立) 内建 Last-Event-ID 续传 需自行实现
适用 同步工具调用、简单 QA 流式生成、Agent 执行过程 实时协作、多人编辑

Agent 场景选型:

  1. 纯问答/单步工具调用:单次 HTTP 即可。延迟低、实现简单、无状态
  2. 流式生成 + 工具调用进度:SSE 最优。90% 的 Agent 产品用这个——模型 token 流式输出 + 工具状态推送,前端只需要“被动接收”
  3. 人机协作/多 Agent 对话:WebSocket。用户需要在 Agent 执行中途插话、发送取消指令、上传追加文件

SSE 重连能可靠重放的是已持久化事件,不是要求模型从相同位置继续采样出相同 token。服务端为事件分配递增 ID 并持久化,客户端带 Last-Event-ID 重连后按 ID 去重续传;若生成进程已失败,只能从语义检查点重新生成后续内容,并显式开启新分支。有副作用的工具调用必须按幂等键查询既有终态,不能因断线重跑。

为什么大多数 Agent 产品选 SSE 而非 WebSocket?

  • Agent 交互本质是“用户发一条 → 系统执行一大段”,单向流足够
  • SSE 基于 HTTP,天然兼容 CDN、负载均衡、API 网关,运维成本低
  • WebSocket 需要维护长连接状态,服务端扩缩容更复杂

差距在哪:面试官考的不是定义背诵,而是“你在做 Agent 产品时选了什么、为什么”。能说出 SSE 在 Agent 场景的优势(HTTP 兼容 + 内建断线续传 + 单向够用)以及 WebSocket 的使用边界(需要客户端主动发消息时),说明你做过技术选型。


AgentState vs 全局变量

Q:AgentState 的作用是什么?为什么不使用全局变量?

来源:字节Agent开发一面(某大厂);本轮追问:C 语言中全局变量存储在哪里?(本轮追问);本轮追问:本地 Agent 为什么会出现空转?(本轮追问)

新手答:“用全局变量也能存状态吧,AgentState 就是框架的封装。”

高手答:

AgentState 解决的核心问题是状态的可追踪、可回溯、可序列化——这三点是全局变量做不到的。

全局变量的致命问题:

  1. 不可追踪:不知道谁在什么时候改了什么值,调试多步 Agent 像猜谜
  2. 不可回溯:Agent 执行到第 5 步发现走错了,没法回到第 3 步的状态
  3. 不可序列化:没法做 checkpoint 持久化,进程挂了状态全丢
  4. 并发不安全:多个节点并行执行时,全局变量竞争写入导致数据覆盖
  5. 默认覆盖语义:Python dict 赋值是覆盖,但 Agent 很多场景需要累加(如 messages 列表追加)

AgentState 的设计价值:

能力 实现
状态版本化 每个节点执行后生成新版本的 State snapshot
Checkpoint 序列化到 SQLite/Redis,支持断点续跑
Reducer 语义 字段可以定义 add(累加)而非 replace(覆盖)
类型安全 TypedDict 定义 schema,节点间契约明确
调试追踪 每步状态变化有记录,出错时精确定位哪个节点改坏了什么

LangGraph 的经典踩坑:默认 State 是覆盖式更新。如果你在 State 里放了一个 messages: list,节点 A 返回 {"messages": [msg1]},节点 B 返回 {"messages": [msg2]}——结果是 B 覆盖 A,而不是追加。必须用 Annotated[list, operator.add] 声明累加语义。

差距在哪:面试官考的是你对“状态管理”的工程理解。只把 AgentState 当成“框架的 dict 封装”说明你没用它做过多步任务。能说出 checkpoint、reducer 语义、状态回溯这些设计意图,说明你真的在 LangGraph 上踩过坑。


基础工程能力


Q:多模型如何动态路由?根据视频特征、任务特征、成本、延迟和效果选模型?

来源:商汤/大模型算法应用实习二面【百度Agent一面追问:模型路由的依据是什么?】【作业帮秋招一面追问:从大模型切到小模型主要是为了响应时长吗,实际效果对比大模型怎么样?】;本轮追问:小模型如何选择?(本轮追问);本轮追问:后面是否会训练专门的路由模型?(本轮追问);本轮追问:国内和海外内容是否使用同一个模型?(携程 AI 应用开发二面(已oc));本轮追问:生成内容不符合领域常识、成本、延迟之间如何取舍?(恒生电子技术岗ai面);本轮追问:结合LangGraph这套体系,从成本、准确率综合性价比看,中文场景下哪个模型效果比较好?是千问3.8-7B吗?(药明康德(AI数据方向-二面));度小满 - AI 全栈研发 - 一面;虾皮agent开发一面;合肥某头部企业软件开发实习生面试问题汇总(时长1个小时);度小满 - AI 全栈研发 - 二面

新手答:“根据任务类型写 if-else 选模型。”

高手答:

动态路由本质是一个在线决策问题,需要平衡多个目标。if-else 只能处理最简单的情况,真正的路由系统要做到多维度决策 + 数据驱动调整。

路由决策维度:

维度 信号 权重策略
任务复杂度 token数、步骤数预估 复杂任务→大模型
延迟要求 用户场景SLA 实时→小模型/规则
成本约束 月度budget剩余 预算紧→小模型优先
质量要求 任务类型(创意/事实/代码) 高精度→大模型
历史表现 该类任务各模型的成功率 数据驱动选型

三层实现方案:

flowchart TD
    A["用户请求"] --> B["规则层(快)\n特征初筛 <1ms"]
    B --> C["打分层(准)\n综合评分 <10ms"]
    C --> D["反馈层(学)\nBandit 动态调权"]
    D --> E["选定模型执行"]
    E -->|"效果反馈"| D

第一层:规则层(快速初筛)

用硬性特征规则排除不合格的候选模型:

  • 视频 >1080p 且 >5min → 只保留支持长视频的模型
  • 需要代码生成 → 排除纯文本模型
  • 延迟要求 <500ms → 排除大模型

第二层:打分层(精确选型)

对候选模型按综合分数排序:

score = α × quality + β × (1/latency) + γ × (1/cost)

其中:
  quality = 该模型在该任务类型上的历史成功率
  latency = 该模型的 P95 响应时间
  cost = 该模型的千 token 单价
  α, β, γ = 根据场景动态调整的权重

第三层:反馈层(持续优化)

用 Bandit 算法(如 UCB/Thompson Sampling)根据实际效果动态调整权重——不需要离线训练,在线即可学习“哪个模型在哪类任务上表现更好”。

故障兜底:首选模型超时 → 自动 fallback 到次选模型,不中断用户体验。实现方式:并发发起请求但只用首选结果,超时后切换到次选的已有结果。

关键洞察:路由本身不能太耗时——路由决策应在 <10ms 完成,否则还不如直接用默认模型。所以规则层和打分层都是纯内存计算,不涉及网络调用。

不必强行共用一个模型:先按用户或内容区域、语言、数据处理边界和供应商可用性做硬路由,再在各区域候选模型中按质量、延迟和成本打分。两地保持统一接口与评测口径,并分别监控效果、失败率和漂移;只有离线评测与数据边界都满足时才合并模型池。

领域常识不能只看模型主观置信度,应用领域规则、检索证据和人工抽检做事实校验,不通过则重写、换模型或转人工。成本、延迟、质量先按业务SLA设硬约束,再用同一中文任务集和线上反馈比较候选模型;不能直接断言某个型号最优,应按任务分层实测选择。

追问补充:关键推理步骤可按风险和收益升级到强模型,但需设置预算、超时和输出校验,避免全链路使用强模型造成成本与延迟上升。选型不能只按品牌:分别在中文理解、代码、长上下文、工具调用和稳定性任务集上实测;Claude、GPT、DeepSeek 的适用场景应以具体评测和可用性为准。

追问补充:默认由系统按风险、预算和历史效果自动路由;可在不暴露复杂模型细节的前提下提供用户偏好或“重答/更高质量”入口。用户选择应受权限、成本和延迟约束,自动重答需限制次数并记录原因,避免无限切换。

差距在哪:新手的 if-else 只能处理静态规则,无法适应模型表现的动态变化。高手设计了规则层(快速排除)+ 打分层(精确选型)+ 反馈层(持续学习)的三层架构,且强调路由决策本身的延迟约束。面试官考的是对“模型即资源”的调度思维——像调度微服务一样调度模型,需要考虑成本、延迟、质量的多目标优化。


Q:系统里多租户隔离是怎么实现的?

来源:视频面经汇总【阿里 Agent Infra 一面题库同题:数据、资源与权限隔离】【字节跳动 - AI Agent 开发岗(工程方向)追问:如何设计多租户隔离,包括状态和知识库隔离?】【百度 - Agent 研发岗(架构方向)追问:如何实现多租户状态与知识库隔离?】【百度Agent一面追问:不同用户之间是怎么隔离的?】;本轮来源;本轮追问:存储中的 Key 怎样区分场景,不同用户是否读取不同数据?(9.14字节推荐架构一面);本轮追问:Agent 是如何部署的?不同用户的会话和工作区如何隔离?(9.22 阿里千问二面)

新手答:“每个租户一个数据库。”

高手答:

多租户隔离的方案取决于隔离强度和运维成本的权衡:

方案 隔离强度 成本 适用场景
独立数据库 最强 最高 金融/医疗等强合规
共享库+独立 Schema 中等 中等 SaaS 中型客户
共享表+tenant_id 字段 最弱 最低 通用 SaaS 平台

在 Agent/RAG 系统中,我们用的是逻辑隔离方案:

  1. 数据层:向量数据库用 collection_id 或 metadata 中的 tenant_id 做过滤,检索时强制注入 tenant 条件,SQL 层面 WHERE 子句必加
  2. 模型层:System Prompt 注入租户专属规则和知识范围边界,不同租户可配置不同的 Skill 集合和工具权限
  3. 接口层:API Gateway 做认证 + 租户路由,token 解析后注入 tenant context 到请求上下文,下游服务无感
  4. 存储层:向量库索引按租户分 partition(Milvus 的 partition_key),文件存储用 /{tenant_id}/ 前缀隔离

防泄漏关键点:

  • 检索时 tenant_id 过滤放在向量数据库的 filter 条件中(非应用层过滤),避免先召回再过滤导致的信息泄漏
  • 日志脱敏:跨租户的 trace 信息不能出现其他租户数据
  • 压测:专门做跨租户渗透测试(tenant A 是否能检索到 tenant B 的文档)

存储 Key 统一按 tenant_id、user_id、workspace_id、scene 和 resource_id 分层拼接,并由服务端从认证上下文生成,禁止客户端自报;读取时同时校验租户、成员权限和场景,避免仅靠 Key 猜测。部署上按无状态 Agent 服务加会话、工作区持久化,session 与 workspace 绑定租户及用户,任务队列、缓存和临时目录也带同一隔离标签,必要时按租户分 namespace 或实例。

差距在哪:新手只想到“分库”——这是最暴力也最贵的方案。高手按数据层/模型层/接口层/存储层分层设计,说明理解了 Agent 系统中多租户不只是数据库的问题,还涉及向量检索、Prompt 注入和权限管控。


Q:Redis 在 Agent 系统中适合承担哪些职责,哪些数据不应只放 Redis?

来源:点点互动/Agent开发秋招一面;本轮来源;cvte应用软件开发一面;本轮追问:把数据放到 Redis 里,再用 MySQL 做持久化,为什么要持久化?直接使用 Redis 不行吗?((秋招) 9.16 字节中交广 - 交易与广告业务 - AI全栈开发工程师);美团一面全栈开发日常实习面经;字节跳动火山引擎agent开发秋招一面;秋招-字节跳动-抖音电商-Agent开发一/二/三面

新手答:“Redis 可以缓存对话和工具结果,提高速度。”

高手答:

Redis 适合高频、短生命周期、允许重建的数据:会话热状态、短期记忆窗口、工具结果缓存、幂等键、限流计数器、分布式锁、任务队列和流式事件。设计时必须为 key 加租户与会话命名空间,设置 TTL,并明确缓存穿透、击穿和热 key 的保护策略。

不应只放 Redis 的数据包括:审计日志、长期用户事实、不可丢的工作流 checkpoint、训练反馈和计费记录。这些需要持久数据库或对象存储作为事实源,Redis 只做热缓存或加速层。否则淘汰、过期、故障切换都可能造成状态不可恢复。

典型分层是:Redis(热状态/协调) + PostgreSQL(事实与事务) + 向量库(语义记忆) + 对象存储(大结果)。关键不是“用了 Redis”,而是每类状态的持久性、一致性和恢复目标是否匹配。

追问补充:Redis 的 RDB/AOF 主要解决重启恢复,仍可能因异步落盘、故障切换或淘汰造成数据丢失;同时它缺少数据库擅长的事务约束、复杂查询和审计能力。因此不可恢复的事实数据仍应以数据库为源,Redis 只作加速或协调层。

差距在哪:新手把 Redis 当万能高速数据库,高手能按生命周期、一致性和可恢复性划分职责。面试官考的是 Agent 状态工程,而不是 Redis 数据类型背诵。


Q:在浏览器输入一个 URL 到页面显示,完整经历了哪些过程?

来源:小红书 Agent 岗一面;本轮来源;字节数据中台Agent全栈面经;度小满AI全栈一面;字节业务中台AI全栈面经——日常实习;字节跳动火山引擎agent开发秋招二面

新手答:“DNS 找到服务器,HTTP 请求页面,然后浏览器渲染。”

高手答:

可以沿着“解析地址—建立连接—服务端处理—浏览器渲染”讲完整链路:

  1. 浏览器解析 URL,检查 HSTS、Service Worker、HTTP 缓存和本地资源策略。
  2. DNS 依次查询浏览器/系统缓存、递归解析器和权威服务器,得到 IP;CDN 可能按位置调度边缘节点。
  3. 客户端通过 ARP/NDP 找到下一跳,经路由与 NAT 发包。HTTP/1.1、HTTP/2 通常先建 TCP;HTTPS 再进行 TLS 握手、证书校验和密钥协商。HTTP/3 则基于 QUIC/UDP。
  4. 浏览器发送 HTTP 请求。请求可能经过 CDN、WAF、负载均衡、网关和反向代理,再到应用服务;服务端访问缓存或数据库后返回状态码、响应头和正文,可使用压缩、分块或流式传输。
  5. 浏览器处理缓存、重定向、Cookie 和安全头,HTML 解析为 DOM,CSS 解析为 CSSOM;预加载扫描器并行请求 CSS、JS、字体和图片。
  6. DOM 与 CSSOM 形成渲染树,随后 style、layout、paint、composite。脚本可能阻塞解析或修改 DOM,引发重新布局与重绘。
  7. 页面可见不代表完成:异步请求、懒加载、事件循环任务和性能指标仍会继续;排障时可按 DNS、连接、TLS、TTFB、资源下载和渲染阶段定位。

差距在哪:高手能说明协议分支、缓存与代理层,以及网络完成后浏览器主线程如何把字节变成像素。


Q:如何记录 Agent 的非确定性边界,实现可重复的故障回放?

来源:腾讯互娱全栈开发(AI)二面(2026-08-13)【字节火山引擎 Managed Agent 一面追问:记录耗时、Token、结果和失败路线】;本轮追问:如何确认离线构造的故障、标准答案和线上真实排障流程一致?(本轮追问);记录最爽,不折腰的一次面试:小红书秋招一面;美团Agent一面凉经

新手答:“保存完整日志,回放时设置相同 temperature。”

高手答:确定性回放不要求模型再次生成相同文本,而是记录每个非确定性边界的请求哈希和结果:模型响应、检索快照、工具返回、随机种子、时间、配置和运行时版本。每轮还应写入 run_id/step_id/parent_step_id、开始结束时间、输入输出 Token、费用、状态、失败类型和下一条路线,让系统能重建时间线、成本和分支因果关系。回放默认注入历史结果,只重跑指定节点;有副作用的工具使用模拟器或只读影子环境。若请求哈希变化,应明确标记无法复用,而不是静默加载旧结果。

追问补充:回放流程应先从线上故障抽取脱敏事件,冻结当时的提示词、模型配置、检索语料、工具响应和版本,再按 run_id 重建步骤;先注入历史结果复现原路径,再只替换一个变量做定位。用故障类型、时间线、工具副作用和最终断言与线上记录逐项对齐,确认样本、标准答案及判定规则来自真实排障,而非事后臆造,并将复现用例纳入回归集。

差距在哪:新手依赖随机种子,高手把外部世界和模型输出都变成可替换的事件记录。


Q:多模型供应商如何抽象统一 Provider,而不丢失差异能力?

来源:成都晓多科技 Agent 开发岗二面(2026-08-12);本轮追问:讲一下为什么DeepAgents要做模型无关性,而Claude和GPT他们为什么不做?(杭州微链词元 AI应用开发);度小满 - AI 全栈研发 - 二面;模思智能(Moss)多模态voice相关测评;快手二面

新手答:“定义统一的 chat 和 stream 接口,再写适配器。”

高手答:先定义最小公共协议:消息、工具调用、流式事件、usage、错误分类和取消;供应商特性通过 capability negotiation 和显式扩展字段暴露,不能硬塞进最低公分母。适配器负责角色、schema、finish reason、错误码和流事件转换;网关再做路由、限流、重试、观测与版本兼容。契约测试同时验证普通文本、并行工具、截断、流式中断和安全拒绝。

DeepAgents这类框架面向多供应商和可替换后端,需要模型无关层来降低迁移、测试和运维成本,同时通过能力发现保留差异。Claude或GPT厂商主要优化自家模型、API和产品闭环,直接暴露原生能力更能形成差异化,因此没有动力承担跨厂商中立抽象。

追问补充:通常会带,但不是把上一个模型的原始请求全部透传。应保存规范化的会话消息、任务状态、必要的工具调用与结果,并按新模型能力重新序列化;隐藏推理、无关历史和过期结果应裁剪或脱敏。若只是独立重试,则可不带历史,需由路由策略明确。

追问补充:多 scaffold 的差异通常在配置入口、消息与工具 schema、流式事件、上下文拼装、鉴权和错误语义;适配层逐项映射并保留 capability,公共层处理规范化结果。通过文本、工具调用、流中断和错误注入的契约测试验证兼容性,不能把一种供应商的 system 语义强套给其他接口。

差距在哪:新手统一函数签名,高手统一语义并保留能力发现与兼容测试。


Q:进程、线程、协程有什么区别?什么场景下协程更有优势?

来源:视频面经汇总;本轮追问:Python 的 asyncio 有了解吗?什么场景下适合用这个?(本轮追问);本轮追问:进程和线程有什么区别?(本轮追问);【面经】字节/AI 应用工程师 一面挂经……

新手答:“进程是资源分配单位,线程是执行单位,协程更轻量。”

高手答:

graph LR
    A[进程] -->|"包含多个"| B[线程]
    B -->|"包含多个"| C[协程]

    A ---|"独立地址空间<br/>切换成本最高<br/>OS 调度"| A
    B ---|"共享地址空间<br/>切换成本中等<br/>OS 调度"| B
    C ---|"共享线程栈<br/>切换成本极低<br/>用户态调度"| C
维度 进程 线程 协程
调度者 OS 内核 OS 内核 用户态(runtime)
切换成本 ~ms 级(TLB 刷新) ~μs 级(寄存器保存) ~ns 级(仅保存少量寄存器)
内存开销 MB 级(独立地址空间) ~1MB(默认栈大小) ~KB(可按需增长)
并行能力 真并行(多核) 真并行(多核) 并发但不并行(单线程内)
通信方式 IPC(管道/共享内存/Socket) 共享内存+锁 直接 yield/resume

协程的优势场景——Agent 系统中的 IO 密集任务:

Agent 系统的典型操作都是 IO 密集型:调大模型 API(网络 IO)、查向量数据库(网络 IO)、读文件(磁盘 IO)。这些操作等待时间远大于计算时间,用线程会导致大量线程阻塞在 IO 上白白占内存。

协程的解法:asyncio.gather 同时发起 10 个 Embedding 请求,底层只用 1 个线程,IO 等待时自动切换到其他协程执行——并发量上去了,内存开销几乎不变。

协程不适合的场景:CPU 密集计算(如大规模矩阵运算)——协程无法利用多核,此时需要多进程。

差距在哪:新手背定义但不理解本质区别。高手从调度者、切换成本、并行能力三个维度做结构化对比,并能绑定到 Agent 系统中“调 API 是 IO 密集型”这个具体场景,解释为什么 Python asyncio 是 Agent 开发的主流并发模型。


Q:LangGraph 图状态机里,怎么捕获每个节点的执行结果并实时推前端?

来源:淘天/AI Agent一面【深圳tuitti视界之外实习一面追问:能否完整描述这个图、图上的状态,以及每个节点的执行过程?】;本轮追问:单据的状态机怎么设计?(本轮追问)

新手答:“用回调函数。”

高手答:

问题本质:LangGraph 的节点是异步执行的,但前端需要实时看到“当前执行到哪一步”和“每步结果”。解决方案分三层:

第一层:LangGraph 层——流式获取节点 state diff

使用 stream_mode="updates" 流式获取每个节点的状态变更,每个节点执行完会 yield 一个 {node_name: state_update} 对象:

async for event in graph.astream(input, config, stream_mode="updates"):
    node_name = list(event.keys())[0]
    state_update = event[node_name]
    # 每个节点完成时都会产出一个事件

第二层:后端层(FastAPI + SSE)——包装为事件流

将 LangGraph 的 async generator 包装为 SSE EventSource,每个节点完成时发送一个 event:

event: node_end
data: {"node": "search_node", "result": "找到5条相关文档", "timestamp": "..."}

event: node_start
data: {"node": "generate_node", "status": "正在生成回答..."}

event: token_stream
data: {"content": "根据检索结果,..."}

第三层:前端层——按事件类型更新 UI

监听 SSE 事件流,按 node_name 更新 UI 组件状态:

"正在检索..." → "检索完成,找到5条" → "正在生成回答..." → 流式文本输出

关键细节:

事件类型 用途 处理方式
node_start 节点开始执行 前端展示 loading 动画
node_end 节点执行完成 前端展示节点结果摘要
tool_call 工具调用中间结果 展示搜索结果等中间信息
token_stream LLM 逐 token 输出 流式文本渲染
error 节点执行异常 展示“该步骤失败,正在重试”

完整架构:

flowchart LR
    A["LangGraph\nstream_mode=updates"] -->|"async generator"| B["FastAPI\nSSE 包装"]
    B -->|"event stream"| C["前端\nEventSource"]
    C --> D["按 node_name\n更新 UI 组件"]

对比 LangChain 的 callback 方案:callback 是同步拦截机制,不适合异步图执行;LangGraph 的 stream 是原生支持的一等公民,直接 yield 节点级别的状态变更,更适合图状态机的执行模型。

差距在哪:新手只知道 callback 这一种方式。高手给出了 LangGraph 层(stream_mode)+ 后端层(SSE)+ 前端层(事件驱动 UI)的三层方案,且区分了五种事件类型的不同处理方式。面试官考的是对 LangGraph streaming API 和前后端实时通信的实战经验——不是理论概念,而是你真的用 LangGraph 做过面向用户的产品。


Q:如何统计 Agent 各模块耗时并定位瓶颈?

来源:寒武纪AI应用开发一面&二面;度小满 - AI 全栈研发 - 二面;美团Agent一面凉经;智加 自动驾驶软件工程师

新手答:在每个模块前后打点,统计平均、P95/P99 和调用次数。

高手答:

采用统一 trace_id 和 span,覆盖排队、网络、模型首 token、生成、工具执行及序列化;用单调时钟记录耗时,异步链路传播上下文。按请求类型拆分分位数,结合 token、并发和错误率分析;采样保留原始 trace,聚合指标进监控,避免日志泄露提示词和隐私。

追问补充:对渲染流程先梳理任务依赖,形成 DAG:无数据依赖的取数、预处理或资源加载可并行,有依赖的保留串行,并设置并发上限避免争抢资源。通过 trace 的 span 时间线确认真实重叠,再观察关键路径、CPU/IO 利用率和结果顺序,验证并行化没有引入竞态。

差距在哪:考察端到端可观测性、分位数分析和隐私成本控制。

Q:如何设计同时兼顾吞吐、首 Token 延迟和租户公平性的推理调度器?

来源:智象未来 AI Infra 一面(2026-08-20);本轮追问:有没有关注过LLM首token返回时间(KVCACHE)?(本轮追问);腾讯混元 AI Infra 一面

新手答:“做动态批处理,批次越大吞吐越高。”

高手答:

调度器要显式承认三个目标冲突:大批次提高 GPU 吞吐,却会增加排队和 TTFT;长生成任务持续占用 KV Cache,又可能饿死短请求。入口先按租户设置并发与 Token 配额,队列按等待时间、请求长度、SLO 和租户权重做加权公平调度;Prefill 与 Decode 可分离或使用 chunked prefill,连续批处理只吸收不会突破延迟预算的请求。

运行时持续监控队列等待、TTFT、TPOT、完成延迟、有效 Token/s、KV Cache 占用和抢占次数。内存压力下优先暂停或换出可恢复请求,而不是随机失败;过载时用背压和明确的 429/retry-after 保护系统。验收必须同时看总体吞吐和每个租户、长度分桶的 P95/P99。

差距在哪:新手只优化平均吞吐,高手把延迟预算、KV 资源、长短请求和多租户公平放进同一个调度问题。面试官考的是是否理解线上推理不是单纯的 batching。


Q:自动回滚阈值如何设置,避免固定阈值误杀或放过回归?

来源:深信服 Agent 三面(2026-08-23);本轮追问:Agent自动回滚的触发条件是什么?(本轮追问)

新手答:“成功率下降超过 5% 就回滚。”

高手答:按任务、风险和流量切片建立历史基线,核心安全/副作用指标使用硬阈值,成功率、延迟、成本使用相对变化和置信区间。小流量阶段要求足够样本或序贯检验,严重事件可一票否决;同时设置告警、停止扩量和自动回滚三级动作。阈值与版本、评测集和回滚目标绑定,定期根据季节性和业务变化校准。

差距在哪:新手背固定百分比,高手处理样本量、分层风险和指标波动。


Q:如何设计类似 LangFlow 的 Agent 工作流可视化编排画布?

来源:商汤 AI Agent 开发面经(2026-03-05);本轮追问:Agent 动态工作流平台怎么实现的?(本轮追问);本轮追问:用户在画布上将一个节点拖拽出来,到最终连接底层图数据库(Neo4j)执行查询,中间代码底层经历了哪些过程? / 一个前端可视化的工作流是如何被持久化存储并转化为可复用应用的? / 从JSON结构到工作流组件是如何做反序列化还原的?(9.20 汇川技术 数字化全栈工程师 一面)

新手答:“前端用节点编辑器画流程,后端把节点按连线顺序执行。”

高手答:

先把画布定位为版本化工作流中间表示的可视化投影,而不是一张靠坐标驱动执行的图。组件注册表定义节点类型、配置 schema、输入输出端口、权限、超时、重试和版本;画布文档只保存稳定的 node_id、组件版本、配置、边、视图坐标和子图引用。端口使用 typed schema,连线时就检查类型、必填输入、单/多输入基数和作用域,避免等到运行时才发现两个节点不能连接。

前端按“节点库 + 画布 + 属性面板 + 运行面板”拆分。拖拽、连线、撤销重做和批量移动都转成可重放 command;自动保存采用文档版本与乐观锁,服务端拒绝基于旧版本的覆盖。大图只渲染可视区域,搜索、分组、折叠子图和键盘操作保证可用性。UI 状态与业务图状态分离,缩放和选中状态不能污染发布制品。

发布时由编译器完成四层门禁:

阶段 核心检查
静态校验 孤立节点、不可达节点、端口类型、必填配置、非法环和未绑定秘密
语义校验 条件分支是否完备、循环是否有退出条件、并行汇聚 reducer 是否确定
安全校验 节点权限、数据分级、跨租户引用和高风险工具审批
执行计划 拓扑/状态机编译、并发组、超时预算、checkpoint 和补偿边界

运行时只消费不可变的已发布版本,草稿修改不能影响在途任务。每个节点事件通过 run_id + node_id + attempt 回传,画布展示排队、运行、成功、失败、耗时和输入输出摘要,并能从失败节点基于 checkpoint 重放。组件升级要做 schema migration 和兼容检查,旧工作流仍绑定旧版本;验收既测编译正确性,也测大图交互性能、协同冲突、断线恢复和运行轨迹与节点高亮的一致性。

拖拽节点先根据组件注册表生成节点配置和 typed IR;保存时序列化为带 schema 版本的 JSON。加载或发布时校验版本后反序列化,按 type 恢复组件实例、端口和边,并注入运行上下文。执行到 Neo4j 节点时,适配器将输入映射为参数化 Cypher,连接池执行查询并把结果按输出 schema 回填后传给下游。发布制品绑定不可变 JSON 与组件版本,即可作为可复用应用运行。

差距在哪:新手把画布当拖拽 UI,高手把它设计成“组件元数据 → typed Graph IR → 编译门禁 → 可观测 Runtime”的完整产品,并处理版本、迁移、协作和安全边界。面试官考的是能否让低代码编排既好用又可执行、可治理。


Q:接入多个外部 Agent 时,如何用 Adapter 统一异构事件、工具调用和生命周期协议?

来源:北京 B 端 AI 小厂面经(2026-07);本轮追问:几千个业务能统一 Agent 流程吗?怎么合并?(本轮追问);本轮追问:如果让你对接企业知识问答Agent,飞书、钉钉、邮件怎么统一接入?(百度Agent二面,不看简历不问八股)

新手答:“为每个 Agent 写一个 Adapter,把它们的 JSON 转成统一格式。”

高手答:

核心是建立一层 anti-corruption layer:内部先定义稳定的 canonical protocol,外部 A2A、厂商 SDK、Webhook 或私有流式协议各自实现 Adapter。统一事件信封至少包含 tenant_id、run_id、task_id、event_id、sequence、type、timestamp、trace_id、causation_id、deadline、schema_version;type 用判别联合表达 message / tool_request / tool_result / status / artifact / error,厂商特性放显式 extension,不能为了最低公分母静默丢失语义。

Adapter 不只是改字段名,还要完成三类语义映射:

  1. 能力与工具:握手时发现模态、流式、取消、回调和工具能力;工具加命名空间,参数按内部 schema 校验,凭证由网关注入,外部 Agent 不能继承宿主的全部权限
  2. 状态机:把各家的 queued/running/waiting/completed/failed/cancelled 映射到受控状态迁移表;无法精确映射时保留原状态并标记 unknown,不能猜成成功
  3. 流式与制品:文本增量、工具事件、进度和 artifact 分通道处理;大对象只传受权引用与摘要,内部顺序由 sequence 和 causation 关系确定

可靠性边界由接入层兜住:按 event_id 幂等去重,对乱序事件做有界缓冲并检测序号缺口;取消和 deadline 向下传播,迟到事件必须携带当前 lifecycle_epoch,旧 epoch 的回调不能覆盖新任务状态。有副作用的工具使用幂等键、状态查询和人工审批,重连后从持久化 offset 恢复,而不是把整个任务盲目重跑。

每个 Adapter 都跑同一套 conformance suite,覆盖能力协商、正常/异常工具调用、流式中断、取消、重复与乱序事件、版本升级和鉴权失败;生产 trace 同时保留原始协议摘要与 canonical event,badcase 可离线回放。协议升级采用双读、单写和按 Agent 灰度,确认指标稳定后再退役旧映射。

对飞书、钉钉、邮件分别实现渠道 Adapter:统一解析 webhook/轮询事件、租户与用户身份、会话线程、附件和引用关系,再映射为 canonical message;发送侧按渠道调用对应 API 或 SMTP。邮件需处理 MIME、引用文本和附件,所有入口都做签名校验、幂等去重、重试及失败回执。

差距在哪:新手做 DTO 转换,高手统一的是事件语义、状态所有权、权限和恢复行为,同时保留扩展能力与原始证据。面试官考的是异构 Agent 接入能否长期演进,而不只是第一次联调成功。


Q:大型项目重构如何规划,如何处理模块正交与冗余?

来源:阿里控股 AI全栈开发 二面;字节 260907 一面面经;虾皮秋招 研发工程师

新手答:先梳理依赖和职责,拆成可回滚的小步迁移,删除重复实现。

高手答:

以业务边界和变更原因建立模块地图,识别高耦合和重复逻辑;定义稳定接口与数据契约,采用绞杀者模式逐步迁移。正交模块只暴露必要依赖,公共能力下沉为版本化库;用静态依赖分析、覆盖率和线上指标验证,双写/回放期间监控差异,完成后删除旧路径。

追问补充:一种工程划分方式是:系统承担完整业务目标,子系统围绕稳定领域能力组织,模块封装可测试的职责与依赖。业务边界、数据归属、变更频率和依赖方向比目录名称更重要;逻辑模块不必独立部署,只有扩缩容、隔离或团队交付确有需要时才拆成服务。

追问补充:先冻结旧版本作为基线,准备覆盖正常、边界、异常和权限场景的回放样本;新旧实现对同一输入分别执行,比较返回结果、排序、错误码及副作用。对不一致案例做归因,结合人工抽样和线上灰度流量确认差异来自预期修复而非回归,达到阈值后再切流。

差距在哪:考察重构的边界设计、迁移风险和冗余治理。


下一篇建议继续看:


Q:从原始诉求到可执行 PRD/Spec,谁负责清洗?如何判断需求完备,质量门禁放在哪层?

来源:电商库存一面 / 小得盈满一面 / 字节中国交易与广告 AI 全栈二面 / 蚂蚁 Agent 开发一面

新手答:“产品经理把需求写清楚,研发发现缺信息再问,最后让 Agent 按 PRD 开发。”

高手答:

需求清洗不是把一段口语润色成文档,而是把业务意图变成可验证的执行契约。业务 Owner/产品经理对目标和语义负责,需求接入层可以用 Agent 做抽取、归一化和缺口提示,架构或研发 Owner 判断技术可执行性;模型只能辅助整理,不能替人确认业务事实与风险。

结构化输入契约至少包含:目标与成功指标、目标用户和场景、范围内/范围外、业务事实与数据来源、前置条件、权限与依赖、接口和数据约束、明确的验收案例、性能/可用性/安全/隐私等非功能要求、风险与回滚方案,以及负责人和时间约束。每个关键结论要能回指原始诉求、会议记录或确认人。

判断完备可用 Definition of Ready:关键字段齐全;同一术语、优先级和约束之间没有未解决冲突;关键假设已标注;异常、边界和失败路径有处理方式;验收标准能写成测试或人工检查项;高风险操作有权限、审批和回滚。缺信息时输出“已知、未知、冲突、需谁确认”,而不是让 Agent 自行补全。

进入编码前还要做一次显式澄清和冻结:让 AI 按“原始诉求、当前理解、尚未确认、验收案例”复述,并把它与已批准 Spec 做 diff;业务 Owner 确认差异后再生成计划。任何影响验收、权限或范围的变更都应回到确认状态,不能由 Agent 在实现过程中静默解释。

质量门禁应分层放置:

  1. 接入层:schema、必填项、术语和来源校验,拦截结构性缺失。
  2. 规划前:做冲突、依赖、可行性、风险和非功能要求检查;未达到 Ready 状态不进入执行计划。
  3. 执行前:对写库、发版、付费、外发信息等不可逆或高风险动作设置人工批准,并绑定批准范围。
  4. 交付前:按验收案例、非功能指标和回滚演练做发布门禁。

PRD/Spec 必须版本化和可追溯:记录需求 ID、版本、变更原因、来源、Owner、审批人、验收用例及关联任务;每次规划和执行都绑定具体 Spec 版本。需求变化后生成 diff 并重新评估受影响的计划与测试,不能静默覆盖旧文档后继续跑。

差距在哪:新手把需求质量寄托在“有人写清楚”。高手明确语义责任人、结构化契约、完备性判据、分层门禁和版本追溯,让不完整需求在执行前暴露,并把高风险决策留给人。


Q:了解 Kubernetes 吗?在 Agent 项目里有没有实际用到?

来源:视频面经汇总 / 百度 Agent 二面

新手答:“了解一些,用过 Docker 部署。”

高手答:

K8s 在 Agent 项目中主要解决三个问题:

1. 弹性伸缩:Agent 请求是典型的“长连接 + 高 token 消耗”——一个复杂任务可能执行 30s+。用 HPA 基于自定义指标(如当前活跃 Agent 会话数)做 Pod 扩缩容,而不是简单的 CPU/内存。

2. 服务编排:一个完整 Agent 系统拆成多个服务——Gateway、Planner、Tool Executor、RAG Service、Memory Service。K8s 的 Service + Deployment 天然适合管理这种微服务拓扑,配合 ConfigMap 做各环境配置隔离。

3. GPU 调度:如果自部署 Embedding 或 Rerank 模型,K8s 的 nvidia.com/gpu 资源类型 + Node Affinity 可以精确调度 GPU Pod,避免抢占。

实际使用中的踩坑:

  • Agent 长任务 Pod 被 HPA 缩容杀掉 → 设置 terminationGracePeriodSeconds + 任务 checkpoint,被 kill 前保存状态
  • SSE 长连接通过 Ingress 时被 nginx 超时断开 → 调整 proxy_read_timeout 到 300s+
  • 向量数据库(Milvus)的 StatefulSet 扩容后需要 rebalance segment → 用 CronJob 定期触发

差距在哪:面试官不是要考你 K8s 八股,而是看你有没有在 AI 应用场景下用过。能说出 Agent 长任务的优雅终止、SSE 超时配置、GPU 调度,说明你真正在生产环境部署过 Agent 系统。


Q:多个子 Agent 延迟退出,同时更新同一对话的 Token 统计数据,线程竞争怎么解决?

来源:深信服 AI 全栈开发二面;本轮追问:同一个 JVM 中,Agent 类的两个实例同时对共享计数器执行加一操作,并更新同一个共享集合,最终出现计数丢失,可能是什么原因?(9.14小红书 PE(产品工程师/全栈方向–实习)二面 (流程泡到9.21挂))

新手答:“加个锁就行了。”

高手答:

“加锁”方向对,但具体怎么加、在哪个层面加、锁的粒度是什么——这些细节决定了方案是否适用于生产环境。

问题本质:

多个子 Agent 并行执行,各自消耗 token,最终需要汇总到同一个 session 的 token 统计字段。如果多个子 Agent 同时完成并尝试更新同一条记录:

子 Agent A 读取当前 total_tokens = 1000
子 Agent B 读取当前 total_tokens = 1000
子 Agent A 写入 total_tokens = 1000 + 500 = 1500
子 Agent B 写入 total_tokens = 1000 + 300 = 1300  ← 覆盖了 A 的更新!

经典的“读-改-写”竞态条件(Lost Update)。

四种解决方案对比:

方案 实现 优点 缺点 适用场景
原子增量操作 INCR / UPDATE SET x = x + delta 最简单、性能最好 只适合简单累加 token 计数(首选)
分布式锁 Redis SETNX + 过期时间 强一致 锁等待增加延迟 需要读-改-写的复杂更新
乐观锁(CAS) 带版本号更新,失败重试 无锁等待 高并发时重试多 中等竞争场景
归并队列 各子 Agent 写消息队列,单消费者汇总 完全无竞争 延迟略高 高并发 + 复杂统计

最佳方案:原子增量操作

对于 token 统计这种“只需要累加”的场景,根本不需要锁——用数据库的原子自增操作:

Redis 方案:
  HINCRBY session:{id}:tokens input_tokens 500
  HINCRBY session:{id}:tokens output_tokens 300
  → 原子操作,无竞态,O(1)

SQL 方案:
  UPDATE session_stats
  SET total_tokens = total_tokens + 500,
      updated_at = NOW()
  WHERE session_id = 'xxx';
  → 数据库内部保证原子性

为什么不用分布式锁:

分布式锁(如 Redis SETNX)虽然能解决问题,但引入了不必要的复杂度——锁超时设多少?获取锁失败怎么重试?死锁怎么处理?对于简单的计数累加,原子操作是最优解。

需要锁的场景——复杂统计:

如果统计逻辑不只是累加(比如“如果总 token 超过预算则拒绝,否则累加”),就需要原子的读-判断-写操作:

Redis Lua 脚本(原子执行):
  local current = tonumber(redis.call('HGET', key, 'total'))
  if current + delta > budget then
    return -1  -- 超预算,拒绝
  end
  redis.call('HINCRBY', key, 'total', delta)
  return current + delta

Lua 脚本在 Redis 中原子执行,不需要外部锁。

归并队列方案——高并发场景:

当并发子 Agent 数量极大(如 50+ 并发),且统计逻辑复杂时,用消息队列解耦:

flowchart LR
    A1["子 Agent 1"] -->|"token_delta"| Q["消息队列"]
    A2["子 Agent 2"] -->|"token_delta"| Q
    A3["子 Agent N"] -->|"token_delta"| Q
    Q --> C["单线程消费者\n顺序处理,无竞争"]
    C --> DB["更新统计数据"]

各子 Agent 只负责发消息(无阻塞),单消费者串行处理所有更新——彻底消除竞争,代价是统计延迟增加几十毫秒。

若两个实例实际引用同一个共享对象,计数器的“读取再加一”不是原子操作,会发生丢失更新;ArrayList、HashMap等非线程安全集合并发写入还可能导致数据覆盖、结构损坏或可见性问题。应改用并发集合,或用同一把锁保护完整复合操作,并验证共享引用、线程转储和并发测试结果。

差距在哪:新手只说“加锁”——这是最暴力且通常不是最优的方案。高手根据业务特征(简单累加 vs 复杂判断)选择不同方案:简单累加用原子操作(零锁开销),复杂逻辑用 Lua 脚本或归并队列。面试官考的是你对并发控制的方案选型能力——不是“会不会用锁”,而是“什么时候不需要锁”。


Q:Agent 框架如何实现流式并行?了解 Claude Code 的流式并行是怎么做的吗?

来源:广州某小厂 Agent 后端开发二面;本轮追问:MCP的stdio / Streamable HTTP这块是怎么实现的?Streamable HTTP是流式的吗?(本轮追问)

新手答:“用多线程同时跑多个 Agent 就行了。”

高手答:

流式并行(Streaming Parallelism)是指 Agent 在执行多步任务时,边流式输出边并行执行子任务——用户不需要等所有子任务完成才看到结果,而是每完成一个就实时推送一部分。

和普通并行的区别:

维度 普通并行 流式并行
用户体验 等所有任务完成才返回 每完成一个子任务就推送部分结果
输出模式 一次性返回完整结果 流式递增返回
适用场景 后台批处理 面向用户的实时交互
难点 并发控制 并发控制 + 流式输出顺序 + 部分结果合并

流式并行的核心架构:

flowchart TD
    A["用户请求"] --> B["主 Agent\n(Orchestrator)"]
    B --> C["Plan:拆分子任务"]
    C --> D1["子 Agent 1\n(流式输出)"]
    C --> D2["子 Agent 2\n(流式输出)"]
    C --> D3["子 Agent 3\n(流式输出)"]
    D1 -->|"stream"| E["流式合并器\n(Stream Multiplexer)"]
    D2 -->|"stream"| E
    D3 -->|"stream"| E
    E -->|"SSE"| F["用户端\n实时看到各子任务进展"]

实现的三个关键组件:

1. 子任务并行调度器

用 asyncio.gather 或类似机制同时启动多个子 Agent,每个子 Agent 独立执行并产出流式输出:

async def parallel_execute(subtasks):
    streams = [spawn_sub_agent(task) for task in subtasks]
    async for event in merge_streams(streams):
        yield event  # 实时推送每个子 Agent 的输出片段

2. 流式合并器(Stream Multiplexer)

多个子 Agent 同时产出 token 流,需要一个合并器决定“先推送谁的输出”:

  • 按完成顺序:谁先产出就先推送谁(最低延迟,但输出顺序不固定)
  • 按逻辑顺序:按子任务的编号顺序推送(有序但可能有等待)
  • 分区域推送:前端为每个子任务分配独立的渲染区域,各自独立流式显示(并行但有序)

3. 部分结果与最终合并

子 Agent 各自完成后,主 Agent 可能需要基于所有子结果做最终合成(如总结、去重)。这时有两种策略:

  • 增量合成:每个子结果到达后立即更新总结(延迟低但质量可能变)
  • 两阶段输出:先流式推送各子结果,全部完成后再推送一个“综合总结”

Claude Code 的流式并行实现思路:

Claude Code 的 Agent 工具支持并行启动多个子 Agent(run_in_background),每个子 Agent 独立执行并产出结果。其流式并行的设计哲学:

  1. 主 Agent 不阻塞:启动子 Agent 后立即继续处理其他任务或响应用户
  2. 子 Agent 独立上下文:每个子 Agent 有自己的上下文窗口,互不干扰
  3. 结果异步汇总:子 Agent 完成后通知主 Agent,主 Agent 按需合并结果
  4. 隔离性:子 Agent 可以在独立的 worktree 中工作,避免文件系统冲突

工程实现的难点:

难点 解决方案
子 Agent 输出交错导致用户困惑 前端按子任务分区渲染,每个区域独立流式
某个子 Agent 卡住拖慢整体 设置单任务超时,超时后用已有结果继续
子 Agent 之间有依赖关系 DAG 调度——无依赖的并行,有依赖的串行
流式输出中途某个子 Agent 失败 推送错误事件,其他子 Agent 继续执行
token 预算分配 总预算按子任务数均分,某个子任务省下的配额可以转移

差距在哪:新手把“流式并行”等同于“多线程”。高手理解这是一个涉及并行调度、流式合并、部分结果推送的完整架构问题,且能结合 Claude Code 的实际设计说明“非阻塞启动 + 独立上下文 + 异步汇总”的实现思路。面试官考的是你对 Agent 系统中“并行 + 流式”这两个维度交叉时的工程化设计能力。


Q:什么是死锁?死锁产生的条件、检测和解决方法是什么?

来源:小红书 Agent 岗一面;本轮来源

新手答:“两个线程互相等锁,所以程序卡住了。”

高手答:

死锁是多个执行单元永久等待彼此持有的资源,导致都无法继续。经典四个必要条件是:互斥、占有且等待、不可抢占、循环等待;四者同时成立才可能死锁。

工程上有四类处理方法:

  1. 预防:统一锁顺序,破坏循环等待;一次申请全部资源,破坏占有且等待。
  2. 避免:已知最大资源需求时用银行家算法,只进入安全状态。
  3. 检测与恢复:构建等待图检测环;发现后超时回滚、取消任务或重启受影响执行单元。
  4. 降低风险:缩小临界区、使用超时锁和 try/finally、避免持锁做网络 I/O,能用消息传递或不可变数据时少共享锁。

在 Agent 系统中也会出现逻辑死锁:主 Agent 等子 Agent,子 Agent 又等待主 Agent 提供信息;两个任务分别持有文件锁和数据库锁并交叉申请。除了线程 dump,还要用 task_id、锁持有者、等待边和超时事件构建可观测的等待图。

差距在哪:新手只描述现象;高手能说出四条件、破坏哪个条件,以及如何检测和恢复。


Q:编译器从源代码到可执行程序经历哪些阶段?

来源:小红书 Agent 岗一面

新手答:“编译原理就是把高级语言翻译成机器语言。”

高手答:

编译原理研究的是如何把源语言程序转换成目标程序,并在转换过程中保证语义、发现错误和进行优化。典型编译管线包括:

  1. 词法分析:字符流变成 Token,如关键字、标识符、数字和运算符。
  2. 语法分析:根据文法把 Token 组织成 AST,并报告结构错误。
  3. 语义分析:做作用域、名称绑定、类型检查和控制流合法性检查。
  4. 中间代码生成:把 AST 降低成便于分析和跨平台处理的 IR,如 SSA。
  5. 优化:常量折叠、死代码删除、公共子表达式消除、循环优化等;必须保持可观察语义。
  6. 目标代码生成:指令选择、寄存器分配和指令调度,生成汇编或目标文件。
  7. 汇编与链接:生成机器码,解析符号和重定位,组合库得到可执行文件。

解释器、JIT 和 AOT 不是完全割裂的三套理论:都可能复用前端和 IR,只是代码生成时机与运行时参与程度不同。

差距在哪:高手不止背阶段名称,还能说明每层输入输出、错误类型以及 IR 为什么是前后端解耦的关键。


Q:云端 Agent 的沙盒应该常驻还是按任务创建?如何优化启动和通信开销?

来源:顺极 Agent 开发二面(2026-08-23)

新手答:“常驻更快,按任务创建更安全,看业务选择。”

高手答:

默认采用“按任务隔离、池化复用”的混合方案:高风险或跨租户任务创建一次性沙盒,任务结束后销毁;同一租户的低风险连续任务可在短 TTL 内复用预热实例,但必须清理工作区、凭据、网络连接和进程树。不能为了冷启动把不同租户放进同一可写环境。

启动优化包括预拉镜像、分层快照、预热池和惰性挂载;通信只传结构化事件和对象存储引用,避免反复复制大文件。调度器要设置租户配额、并发预算和背压,沙盒用租约与心跳防止泄漏。验收同时看 P95 启动时间、任务成功率、隔离逃逸、空闲成本和销毁完整率。

差距在哪:新手把问题当成速度二选一,高手同时处理隔离边界、冷启动、资源池、数据清理和成本。面试官考的是能否把执行沙盒做成可运营的多租户基础设施。


Q:Agent 的中间与最终交付物应该如何版本化、校验和交接?

来源:福田 FDE 线下面试(2026-08-09)

新手答:“把生成文件保存到对象存储,最后给用户下载。”

高手答:每个交付物绑定 run_id、任务步骤、输入快照、模型/Prompt/Tool 版本、内容哈希、创建者和状态;草稿、已验证、已批准、已发布不可混用。结构化结果做 schema/业务校验,代码和文档运行对应测试,引用型报告保存证据映射。大文件进对象存储,状态与元数据进数据库;交接时提供产物、验证报告、未决风险和可复现命令,发布后仍保留回滚版本。

差距在哪:新手只保存文件,高手把交付物当可审计、可验收的发布制品。


Q:如何可靠采集 Coding Agent 轨迹,避免崩溃或异步退出时丢数据?

来源:MiniMax 平台研发一面(2026-08-20)

新手答:“每一步写日志,任务结束后上传。”

高手答:轨迹以 append-only 事件实时写入,事件带 run/step/event ID、因果关系和版本;本地 WAL 或持久队列先确认,再异步汇聚。模型、工具、文件 diff、测试和人工操作分别记录引用,敏感内容分级脱敏。任务结束只是写终止事件,不是唯一上传时机;采集器崩溃可按 offset 重放,服务端按 event ID 幂等去重,并监控缺口和迟到事件。

差距在哪:新手依赖正常结束,高手把轨迹采集做成可恢复的数据管道。


Q:如何估算 Agent 使用模型的月度成本?

来源:汇川技术一面

新手答:按调用量乘以输入、输出 token 单价,再加上工具和基础设施费用。

高手答:

建立成本模型:请求数 × 每次输入/输出 token × 对应价目,叠加重试、缓存未命中、Embedding、存储和 GPU。用真实 trace 统计 P50/P95,并按用户、功能和模型拆分预算;设置 token 上限、路由便宜模型、缓存和告警,按日核对账单。价格会变动,配置应来自可更新的价目表。

差距在哪:考察是否能把成本落到可观测数据和可执行的控制手段。

Q:子 Agent 和工具调用的 Token 用量统计缺失,怎么做容错补偿?(用户断连、子 Agent 延迟退出场景)

来源:深信服 AI 全栈开发二面(开源 Agent 项目贡献)

新手答:“每次调用完记一下 token 数就行了。”

高手答:

Token 用量统计看似简单,但在多 Agent 架构中,有几个场景会导致统计缺失:

问题场景分析:

flowchart TD
    A["用户发起请求"] --> B["主 Agent 启动子 Agent"]
    B --> C["子 Agent 调用工具 1"]
    B --> D["子 Agent 调用工具 2"]
    C --> E["Token 消耗记录"]
    D --> F["Token 消耗记录"]

    G["❌ 用户断连"] -.-> H["子 Agent 仍在运行\n结果无法回传"]
    I["❌ 子 Agent 超时退出"] -.-> J["退出前的最后几次\n工具调用未上报"]
    K["❌ 网络抖动"] -.-> L["上报请求丢失"]

    style G fill:#faa,stroke:#333
    style I fill:#faa,stroke:#333
    style K fill:#faa,stroke:#333

容错补偿的三层设计:

第一层:预扣费(Pessimistic Accounting)

在子 Agent 启动前,基于历史数据预估本次任务的 token 消耗上限,先从用户配额中预扣。任务正常完成后,用实际消耗替换预扣值;异常退出时,预扣值作为近似统计保留。

预扣策略:
  子 Agent 启动 → 预扣 estimated_max_tokens(基于任务类型 P95 消耗)
  正常完成 → 预扣释放,记录实际值
  异常退出 → 预扣值按衰减系数保留(如 0.7 × estimated_max)

第二层:异步上报 + 本地缓冲

子 Agent 和工具调用的 token 消耗不依赖同步回传,而是写入本地缓冲队列,异步批量上报:

  1. 本地 WAL(Write-Ahead Log):每次模型调用完成后,先写本地日志文件(追加写,不丢失),再异步上报到统计服务
  2. 重试队列:上报失败的记录进入重试队列,指数退避重试
  3. 进程退出前 flush:子 Agent 收到终止信号(SIGTERM)时,先 flush 缓冲区再退出。设置 graceful shutdown 超时(如 5s)

第三层:事后对账(Reconciliation)

对于极端情况(进程被 kill -9、机器宕机),用定期对账补偿:

对账方式 实现 适用场景
模型供应商账单核对 每小时拉取 API 使用量,和本地统计做 diff 使用云端 API 时
请求日志反推 从网关/负载均衡器的请求日志中提取 token 信息 自部署推理服务
估算补偿 按“同类任务的平均 token 消耗”补充缺失记录 日志完全丢失时的兜底

用户断连场景的特殊处理:

用户断连后,子 Agent 可能还在运行(尤其是异步任务)。这时需要:

  1. 子 Agent 的 token 统计独立于用户连接状态——即使用户断了,统计仍然正常记录
  2. 任务级别的 token 预算熔断——用户断连后,子 Agent 继续消耗 token 超过预算上限时自动终止
  3. 断连恢复后,客户端拉取任务级别的 token 汇总,补齐前端展示

差距在哪:新手只想到“调用完记一下”——这是理想路径。高手考虑了用户断连、子 Agent 延迟退出、网络丢失三类异常场景,用预扣费 + 异步缓冲 + 事后对账三层容错保证统计完整性。面试官考的是你对分布式系统中“数据完整性”问题的工程化思考——token 统计本质上是一个分布式计数器的可靠性问题。


Q:如何保证 AI 生成内容的版权合规并避免侵权?

来源:小红书多模态秋招二面

新手答:“不能保证绝对不侵权,只能通过使用合规数据、限制生成范围和人工审核来降低风险。”

高手答:

版权合规不是靠一句提示词或单次查重就能保证,而是端到端治理。先明确业务场景、输入输出边界和数据授权来源,建立数据许可、来源、版本与处理记录;检索增强时优先使用有明确授权的内容,并对输出做相似度、敏感片段和受限素材检测。对高风险用途设置拒答、引用溯源、人工复核和发布前审批,保留输入、模型版本、规则命中及处置日志。验证应覆盖已知作品、改写、拼接和长文本等测试集,并持续抽样审计;还要处理用户上传侵权内容、供应商条款和删除请求。无法做到绝对排除风险,需结合风险分级、降级和责任流程;以上是工程治理建议,不是法律意见。

差距在哪:浅层回答只会说查重和人工审核;面试官更关注数据授权、溯源检测、人工门禁、审计闭环及“无法绝对保证”的边界。


Q:语音 Agent 如何处理噪声、用户打断与多轮对话?

来源:蔚来——大模型算法岗(智能座舱/自动驾驶)实习一面

新手答:“通过降噪、语音活动检测和打断机制识别用户何时说话,再结合上下文维护多轮对话。”

高手答:

语音 Agent 通常拆成采集、回声消除/降噪、VAD、ASR、对话管理、TTS 和打断控制。噪声环境下应保留 ASR 置信度、端点检测和说话人状态,低置信度时确认或重问,而不是直接执行高风险操作;回声和双讲场景要避免把 TTS 当成用户输入。用户打断时立即停止或淡出 TTS,取消未完成任务,并用状态机区分“可打断播放、工具执行、不可撤销动作”。多轮上下文应按会话、任务和槽位管理,设置过期、压缩与敏感信息边界。验证要覆盖噪声类型、口音、重叠说话、网络抖动和连续打断,分别评估唤醒、端点、识别、响应时延和任务成功率;核心权衡是低延迟、低误触发与完整理解。

差距在哪:浅层回答停留在降噪和上下文;面试官会追问双讲、端点、可取消状态机、低置信度策略、敏感操作保护和分场景评估。


Q:如何设计面向用户的 AI 服务用量配额、限流与容量规划?

来源:cherrystudio面试

新手答:“可以按用户设置每日调用次数或 token 上限,并通过限流和监控控制整体 AI 服务用量。”

高手答:

应先定义计量单位和策略:按请求、输入输出 token、模型成本或并发占用计费,并区分租户、用户、项目和接口。入口执行认证、配额预检查与限流,配合令牌桶或并发信号量;配额扣减要考虑流式响应、超时、重试和部分失败,采用幂等键或可补偿记录,避免重复扣减或绕过限制。容量规划应基于评测流量、峰值并发、上下文长度、模型延迟和供应商限额,设置保留容量、队列、降级及预算告警。通过压测、突发流量、故障注入和账单对账验证;严格限流会损害体验,过度预留则增加成本,还需防止多账号、代理转发和恶意提示造成资源滥用。

差距在哪:浅层只关注次数限制,深层要回答计量与扣减一致性、并发和容量模型、降级告警、滥用防护及体验成本权衡。


Q:本地持久化配置和会话数据时,如何防止敏感信息泄露?

来源:快手大模型agent研发一面

新手答:“敏感配置和会话数据不应明文存储,应限制文件权限并使用加密、密钥管理和定期清理。”

高手答:

本地目录不是安全边界,尤其要考虑同机其他用户、恶意进程、容器挂载、备份和崩溃转储。敏感配置与会话令牌应尽量交给操作系统密钥环或受控密钥服务;必须落盘时采用加密、最小文件权限和独立密钥,避免把密钥与密文放在同一目录。写入要使用临时文件加权限设置后原子替换,日志、错误栈和诊断包必须脱敏,令牌设置过期、撤销与轮换机制。还要防止路径穿越、符号链接替换和不可信配置注入。验证可通过权限检查、静态扫描、日志审计、备份恢复测试和多用户隔离测试;加密不能替代进程权限控制。

差距在哪:浅层只会提文件权限和加密,深入回答还要覆盖密钥隔离、日志与备份泄露、原子写入、令牌生命周期及可验证的威胁模型。

这类题的答题模式

踩坑题的核心是真实 + 系统性:

1. 每个坑要有三层:故障现象 → 根因分析 → 工程化解法
2. 解法不能是"下次注意"——要是代码层面、架构层面的系统性方案
3. 成本控制不只是换模型——分级调度、预算制、缓存、熔断四管齐下
4. 踩坑经验要能泛化——"这个坑的本质是什么,其他场景会不会也遇到"

面试官听到“模型不听话”就知道你只在 Notebook 里跑过。听到死循环计数器、状态外置存储、JSON 容错解析、token 预算熔断,才会觉得你真的在生产环境里摔过跤,并且摔完站起来做了系统性修复。