面灵AI→

袋鼠云前端二面:长对话上下文、Agent 工具权限与流式消息处理

轮次
二面
时间
2026-10
来源
牛客网

《面试题目》

  1. 自我介绍。
  2. 介绍实习。
  3. 介绍项目。
  4. 场景题:有一个请求 a 发出,后面又一个请求 b 发出,用户应该看到哪个请求的结果?怎么来解决?
  5. AI 聊天对话接口设计,怎么来确保长对话上下文信息不出错?
  6. Agent 工具权限设计,流程应该是怎么样的?
  7. AI 正在生成内容,现在要发送条消息,应该怎么来处理和设计?
  8. 怎么学习的?平时写不写博客?
  9. 反问:后续有机会做些什么、接触什么业务?

《参考解析》

并发请求该展示谁的结果:先定语义,再谈取消

这道题没有唯一答案,考的是你能不能先把「用户期望看到什么」问清楚,再给方案。要拆成三种语义分别回答。第一种是「后发先至」的搜索联想类场景,用户敲字触发的请求天然以最后一次输入为准,做法是给每个请求打上单调递增的序号(或时间戳),响应回来时只接受序号等于最新一次的结果,其余直接丢弃——这是最便宜的方案,不做真正的取消也不会有错。第二种是同一份数据的刷新,比如列表下拉刷新连点两次,正确的做法是取消前一个:AbortController 传进 fetch,或者切到 axios 的 signal,在发新请求前 abort() 掉旧的;注意 abort 之后要区分「用户主动取消」和「网络失败」,别把取消错误弹成失败提示。第三种是写请求,这种绝不能用「丢弃旧结果」的思路——两个写请求都要落到服务端,前端要处理的是顺序与幂等:按发起顺序排队串行、给每个写请求带幂等键、用乐观更新加服务端返回的真实状态做收敛。还有一个容易被追问的点:如果两个请求改的是同一份状态,最终展示要以服务端最后确认的版本为准,本地用版本号或 etag 比对,避免旧响应覆盖新状态。

长对话上下文不出错:窗口、摘要与一致性三条线

「不出错」要拆成三类问题分别解。第一类是超出模型上下文窗口,做法是按 token 预算做滑动窗口,保留最近若干轮原文,更早的内容做摘要压缩(分层摘要:先按会话段摘,再把段摘要合并),并在 prompt 里明确标注哪些是摘要、哪些是原文。第二类是「信息在压缩中被改写」,这要靠把真正不能被改写的东西脱离自然语言——用户画像、订单号、权限、待办这类结构化状态单独存字段并在每轮拼进 prompt,而不是指望摘要保留它们;同时给摘要加引用来源(哪几轮来的),需要时可回溯原文。第三类是并发与串话,多轮对话的请求必须带上会话 ID 并在服务端按会话串行落库,前一轮 assistant 消息还没落库就发起下一轮会造成上下文缺一段;前端也要做本地消息队列,保证同会话的请求有序。工程上还要有兜底:把「用户实际看到的消息序列」和「发给模型的消息序列」都打日志,出错时能一眼看出是丢了消息还是摘要跑偏;再加上 token 用量监控和超限告警。可以顺带提一句取舍:上下文越长成本越高、注意力越稀释,所以真正好的设计是「尽量不进窗口」——用检索(RAG)按当前问题召回历史片段,而不是把所有历史都塞进去。

Agent 工具权限:能力最小化、显式授权、可审计

权限设计的主线是「模型只能提出意图,能不能执行由外层决定」。第一层是工具白名单:Agent 在某个会话里能用的工具由服务端按会话下发的清单决定,模型不能自己发明工具或调用清单外的工具——这跟「用户显式设定状态、不交给模型猜」是同一个原则。第二层是参数校验与能力收窄:每个工具声明自己的参数 schema 和范围(比如文件工具限定在某目录、SQL 工具只允许只读语句、发信工具限定收件人域名),校验在工具执行前做,不靠提示词约束。第三层是分级授权:读操作自动放行,写操作按影响面分档——低风险(改自己的草稿)直接执行,高风险(删除数据、付款、对外发送)要求用户显式确认一次,并且确认要绑定具体的参数摘要,防止模型在确认后偷改参数(确认令牌与参数哈希绑定、一次性使用)。第四层是运行时隔离:工具执行放进沙箱并带超时、限流和额度上限,防止一次循环把配额烧光;危险动作要求二次确认或双人复核。第五层是审计:每次调用记录谁、什么会话、哪个工具、什么参数、结果如何,出问题能回放。还要讲清两个常见误解:提示词里写「不要删数据」不是权限控制;把工具开放给模型之后指望它自己克制也不是。权限必须是代码里的硬约束,且默认拒绝、按需开通。

AI 正在生成时用户又发消息:先决定语义

同样要先定语义:用户这条新消息是「打断并替换」还是「排队等当前回答结束」。如果产品语义是打断(大多数聊天产品的默认),做法是把正在进行的流式请求 abort 掉,把已经生成的部分作为一条完整的 assistant 消息落库(标注为「已中断」),然后把新消息作为下一轮输入发出去;关键是落库要落在那部分文本上,否则上下文里就会出现「用户打断了一个不存在的回答」的错位。如果语义是排队,就维护一个本会话的待发送队列,当前流结束后按顺序逐条发出,界面上把待发消息显示成灰色或带「待发送」标记。两种语义都要处理的边界包括:abort 之后服务端可能还在跑,要用会话 ID 通知服务端停止生成,避免它继续写库;流式增量要按消息 ID 落库,重连或刷新后能接着渲染;快速连发多条时要用序号保证顺序。工程细节上,前端的流式渲染用「按消息 ID 追加增量」而不是整段重渲染,输入框的禁用只针对真正不允许并发的状态,别一刀切把用户锁死;另外要区分「用户主动中断」和「网络断开」,前者落「已中断」,后者要能自动重连并从已有前缀续传,不然用户会看到回答断在半句。

学习方式与反问

「怎么学习的、写不写博客」这类问题的价值在于给出可验证的证据:说清你的信息源(官方文档、源码、动手复现)、节奏(比如每周固定时间)、输出(博客、笔记、开源提交、团队分享),并挑一个最近的例子讲清楚「遇到什么不会 → 怎么找到答案 → 沉淀成了什么」。写博客加分的地方不是数量,而是它逼你把「好像懂了」变成「能讲清楚」,可以举一个自己写完之后才发现理解有偏差的案例。反问可以问「团队现在做的是 AI 应用的哪一层:是对话产品、还是把模型能力嵌进既有业务系统」,以及「前端在这个链路里的边界在哪,是负责交互与流式渲染,还是也参与 Agent 编排」,这两个问题能帮你判断岗位实际的技术密度。