度小满一面 后端基础与 Agent 场景连环追问
- 轮次
- 一面
- 时间
- 2026-09
- 来源
- 牛客网
《面试题目》
- 你在京东实习中主要负责什么?
- Work Memory 是怎么做的?为什么有效?
- Memory 只是文件处理吗?是否使用数据库?
- 面对一份混乱文档,如何让大模型提取出结构化 JSON?
- 从文档中「提取什么内容」,也是由 Prompt 决定吗?
- Agent 的核心组成是什么?各组件的作用是什么?
- 如何设计一个「天气与穿搭」的 Skill/工具?
- Skill 怎么让大模型知道什么时候用、怎么用?
- 系统有几十个 Skill,每次调用都把它们放进上下文,Token 消耗大、命中率下降,怎么优化?
- 你如何理解 Agent 运行治理/编排引擎?
- Workflow 和 LoopFlow 有什么区别?
- 为什么会从早期方案演变到 Harness、上下文工程和 Graph Engineer?它们有什么区别?
- Redis 和 MySQL 如何保证一致性?除了延迟双删,还有哪些不是八股的办法能保障强一致性?
- 支付接口如何设计幂等性?除了常见两种还有哪些做法?
- 支付订单超时自动取消如何设计?
- 如何设计短链接系统?
- 限流、熔断、降级分别是什么,有什么区别?
- 令牌桶和漏桶有什么区别?谁更适合高并发?
- 脏读、不可重复读、幻读分别是什么?
- 间隙锁的产生原因和作用是什么?
- 如何提高一条 SQL 的查询性能?
- MySQL 主从复制的过程是什么?
- Redis 除了缓存还能做什么?
- Redis 持久化机制是什么?
- TCP 三次握手和四次挥手怎么做?挥手后要等待多久?
- 从序列号机制和 ACK 机制讲起,一路讲到网络控制、滑动窗口,再讲粘包和半包的原因。
- SSE 和 WebSocket 有什么区别?
- SSE 是基于什么协议的?断线重连怎么做?
- 什么是写时复制(Copy-on-Write)?
- 进程之间如何通信?
- 重排链表:将 L0→L1→…→Ln 重新排列为 L0→Ln→L1→Ln-1…,能优化吗?
- 请做一下自我介绍。
《参考解析》
混乱文档抽取结构化 JSON:核心是别让模型「自由发挥」。先用 function calling 或 JSON mode 把输出约束到一份明确的 JSON Schema 上,字段名、类型、枚举值、必填项全部写死,字段抽不到就显式返回 null 并附上置信度,绝不允许编造。文档很长时先做版面还原(PDF 先转结构化文本,表格单独抽出),再分段抽取、每段带原文片段作为证据,最后按主键归并去重。工程上还要加两层兜底:解析失败就带错误信息重试一次,仍失败则走正则/模板规则补齐,并把失败样本落库用于迭代 Prompt。Prompt 里要给出 2~3 个正反例,明确「只输出 JSON,不要解释」。Work Memory 这类记忆如果只落在文件里,只能解决单机单会话回放;要跨会话、跨用户检索,就得落到数据库(结构化字段存 MySQL,语义检索走向量库),并设计写入时机、去重和过期策略。
几十个 Skill 的上下文与路由:把「全量塞进上下文」换成两阶段加载。第一阶段只给模型每个 Skill 的 name 加一句话 description(必要时加分类标签),先用向量检索或关键词召回 top-5~top-10;第二阶段命中后才把该 Skill 的完整参数 schema 注入上下文,调用完立刻从上下文里移除。再配合:按会话状态和用户权限过滤可见工具集,把高频 Skill 的完整定义固化进 system prompt、长尾走检索;用轻量分类器或小模型先做意图路由,把工具选择从主生成模型里剥离;对历史消息做摘要压缩、缓存工具 schema 的 token 化结果。衡量指标要盯住工具命中率和无效调用率,而不是只看 token 降了多少。
Redis 与 MySQL 强一致性(跳出延迟双删):延迟双删只是「删两次」的启发式,无法真正保证强一致。更硬的做法有几类:一是让缓存只做只读副本,写路径直接落 MySQL,用订阅 binlog(Canal/Debezium)异步失效缓存,天然不丢事件;二是给缓存值带版本号或时间戳,读的时候比对 DB 版本,过期就回源,避免旧值覆盖新值;三是热点 key 用「逻辑过期」——不设 TTL,值里存过期时间,读到已过期就返回旧值同时异步刷新,保证读不阻塞且最终一致;四是资金这类关键数据干脆不用缓存,或者用一把按 key 分片的分布式锁把读写串行化,代价是吞吐下降;五是加对账补偿任务,按 binlog 位点或更新时间扫差异并修正。真正的「强一致」在分布式下要付代价,面试里更该讲清你能接受哪种一致性级别。
支付幂等与订单超时取消:幂等要靠「唯一约束 + 状态机」双保险。业务侧生成全局唯一的商户订单号并建唯一索引,重复请求直接命中唯一键;状态流转只允许合法迁移,用条件更新落地(update orders set status=支付成功 where order_no=? and status=待支付),影响行数为 0 说明已被处理,直接把已有结果返回而不是报错。再叠加:请求进来先抢分布式锁或用 token 机制防重复提交,渠道回调按渠道流水号去重,本地消息表保证「扣款」和「发消息」同事务。超时自动取消的常见方案是延迟队列(RabbitMQ 的 TTL+死信、RocketMQ 延迟消息)、Redis ZSet 按到期时间戳轮询、时间轮,或按更新时间建索引分片小批量扫表。无论哪种,取消动作本身要幂等,且必须和支付回调竞争同一个状态机——谁先把状态改过去谁赢,另一边读到终态就放弃。
限流、熔断、降级:限流控入口(计数器、滑动窗口、令牌桶、漏桶;单机用 Guava/内存计数,分布式用 Redis + Lua 保证原子),熔断保护自己不被下游拖死(滑动窗口统计错误率和慢调用比例,超阈值跳闸直接失败,冷却后半开放少量请求试探,成功再合闸),降级是主动放弃非核心能力保核心链路(返回兜底数据、关掉推荐和风控的复杂策略、把同步调用改异步)。令牌桶按固定速率放令牌、桶容量决定允许的突发量,平均速率可控又能吃突发;漏桶以恒定速率流出、桶满即丢弃,削峰更平滑但对突发流量不友好。高并发入口一般选令牌桶,需要严格保护下游按固定速率消费时选漏桶。注意限流要区分集群限流和单机限流,别把阈值按单机配置却部署了 20 个实例。
短链接系统设计与重排链表:短链的写路径用发号器(数据库号段、雪花算法或 Redis INCR)拿到自增 id,转 Base62 得到 6~7 位短码,长度可控且无冲突;也可以用长链做 MurmurHash 再转 62 进制,但必须做冲突检测与重试。映射关系以短码为主键存 MySQL,长链建唯一索引用于复用同一短链;读路径多写少,前面挂 Redis 缓存加布隆过滤器防穿透,热点 key 做本地缓存。跳转一般用 302 而不是 301——301 会被浏览器长期缓存,导致点击统计失真。还要考虑过期回收、防刷限流、敏感链接黑名单。手撕题重排链表:最直观的是用数组存下所有节点再首尾交替串起来,O(n) 空间;O(1) 空间的做法是三步——快慢指针找中点、把后半段原地反转、再把两段交替合并,注意最后把尾节点的 next 置空避免成环。