京东 AI Agent开发一面:架构、上下文与超时重试
- 轮次
- 一面
- 时间
- 2026-10
- 来源
- 牛客网
《面试题目》
- 自我介绍,重点介绍你做过的最有技术含量的 Agent 项目。
- 你这个 Agent 项目整体架构是怎么设计的?画一下架构图,讲清楚每一层负责什么。
- 你刚才提到用了 ReAct 模式,具体是怎么实现的?Thought、Action、Observation 这三个环节在你的代码里怎么体现?每一步的输入输出格式是什么?
- 如果 LLM 返回的 tool call 格式不合法,或者参数类型不对,你的系统怎么处理?有没有做校验和重试?
- 你这个 Agent 在执行长任务的时候,如果中间某一步工具调用了 3 秒还没返回,你怎么处理?超时时间怎么设?
- 上下文管理是怎么做的?如果对话超过 100 轮,你怎么控制 token 消耗?
- 你说做了上下文压缩,具体怎么压缩的?压缩提示词怎么写的?压缩后丢失关键信息怎么办?
- Agent 执行过程中,工具调用失败或者任务被中断,应该如何设计恢复机制?比如失败重试、状态保存、任务恢复等。
- 如果 Agent 分析出的故障根因存在错误,后续如何重新触发诊断流程?在 LangGraph 工作流中,如何设计节点之间的跳转条件和边界判断?
- 为什么告警系统选择定时任务轮询,而不是通过 MQ 消息触发?两种方案各自有什么优缺点?
- 当定时轮询任务数量快速增长时,如何避免大量任务同时执行造成服务压力?分批执行、任务调度应该如何设计?
- 在 ReAct Agent 调用外部工具时,如果工具服务启动较慢(例如 Pod 启动需要 30 秒),你怎么处理?
- 你的 Agent 系统怎么处理分布式事务?Saga 模式?TCC?还是别的方案?
- 如果让你设计一个「智能客服 Agent」来处理退换货,你会怎么设计?涉及哪些工具?
- 你们的 Agent 和传统 API 服务有什么区别?在部署、监控、运维上有什么不同?
- 你怎么做 Agent 的监控和告警?关注哪些指标?告警阈值怎么设置?
- 如果 Agent 服务挂了,怎么保证用户无感知?有没有做熔断、降级、限流?
- 你怎么做 Agent 的灰度发布?怎么保证新版本不出问题?
- 如果 Agent 生成了违规内容,你怎么检测和拦截?
- 多模态在 Agent 中能做什么?比如用户上传截图,Agent 怎么理解?
- 如果让你设计一个企业知识问答 Agent,对接飞书、钉钉、邮件,整体方案怎么做?
- 你怎么理解 Agent 和普通大模型调用的本质区别?除了工具调用,Agent 还多了哪些能力?
- 如果 Agent 调用外部服务超时了,你的超时时间怎么设置?重试策略是什么?重试会不会导致重复操作?
- 在电商场景下,Agent 如何保证库存扣减的准确性?幂等怎么设计?
- 手撕题:实现一个简单的 Agent Loop,要求支持接收用户输入、调用 LLM、解析 tool call、执行工具、把结果返回给 LLM、判断是否结束。追问:如果 LLM 返回的 tool call 是多个并行的,怎么处理?如果工具执行需要异步,怎么设计?
《参考解析》
架构先分层,再谈每层的职责:讲架构图不要从 Spring Boot 启动流程讲起,而是按「接入层(会话、鉴权、限流)— 编排层(Planner、ReAct 循环、状态机)— 能力层(工具注册与执行、MCP Client、沙箱)— 记忆层(短期窗口、长期存储、检索)— 支撑层(可观测、评测、配置与灰度)」五块画,每块一句话说清输入输出和边界。面试官接下来一定会挑一层往下钻,所以每层都要准备一个「为什么这么切」的理由,比如工具协议统一成 schema 注册表是为了让新增工具不改编排代码,记忆层独立是因为它要被多个 Agent 复用。把「我的职责」说清(哪部分是我设计的、哪部分是团队既有能力)同样重要——被问到细节答不上来时,这决定了你是扣分还是被理解。
ReAct 的实现要落到数据格式:ReAct 在工程上就是「模型输出结构化动作 → 宿主执行 → 把观察结果拼回上下文 → 再问模型」的循环。要能讲出每一轮的消息结构:system 里的工具清单与约束、assistant 的 thought 与 tool_calls、tool 角色的返回(工具名 + 结果或错误)。tool call 的健壮性有三道闸:一是用 JSON Schema / Pydantic 做参数校验,不合法就把校验错误原文回灌给模型让它重发(限制重试次数);二是格式兜底,模型偶尔会输出包裹在 markdown 里的 JSON,需要容错解析并记录一次「格式修复」指标;三是语义校验,比如查订单的工具要求订单号存在,不存在就直接返回可读错误而不是抛异常。所有失败都要带上可判定的错误码回给模型,否则它只会换个说法反复重试。
超时、重试与幂等是一道题的三面:超时不能只设一个全局值,要分层:单次 LLM 调用(几十秒)、单次工具调用(读操作 1~5 秒、写操作可放宽但要设上限)、整个任务(分钟级,超过就转异步并通知用户)。超时后先判断「这个动作可不可以重试」——读操作可自由重试;写操作必须带幂等键(会话 ID + 步骤 ID + 工具名 + 参数哈希),服务端以唯一索引去重,重试时返回首次结果而不是再执行一遍。重试策略用指数退避加抖动,并限制次数(比如 3 次),超过就熔断该工具并降级(走备用通道或转人工)。对慢启动的服务(Pod 冷启 30 秒),正确做法不是拉长超时,而是限流加预热、就绪探针排除未就绪实例、把长耗时调用改成异步任务 + 轮询状态,等结果就绪再回到 Agent 循环。
上下文管理:分层压缩,而不是等超了再删:控制 token 的基本框架是分层——最近 N 轮原文保留;更早的历史做摘要(按主题分段总结,保留决定、约束、未完成的待办和关键实体 ID);大块工具输出(日志、代码、检索结果)只存引用与摘要,需要时再按 ID 取回;稳定知识(工具说明、系统规范)走前缀缓存。压缩提示词要结构化:让它输出「已完成的事、当前状态、待办与约束、必须保留的实体」,并明确要求不要臆测。压缩最大的风险是丢关键信息,所以要做两件事:一是把关键事实(订单号、文件路径、用户明确要求)单独抽成结构化状态存在对话之外,不依赖摘要保真;二是压缩后做一次自检,比如让模型复述当前任务与约束,答不上来就回退到上一个检查点重新压缩。
恢复机制:状态机 + 检查点 + 一致性校验:长任务要随时可中断可恢复,前提是每一步的状态都落库。做法是给任务定一张状态机表(task_id、当前步骤、步骤输入输出、外部副作用单号、状态、重试次数、版本号),每个步骤开始与结束各写一次检查点;服务重启后按状态机找未完成任务,从最后一个成功的检查点继续。恢复时最怕重复副作用,所以对外部写操作坚持幂等键;跨服务的多步操作可以用 Saga(每步配一个补偿动作,失败时反向补偿)或 TCC(Try 预留、Confirm 提交、Cancel 释放),对一致性要求不高的场景用「先预留后确认 + 对账」也够。恢复失败要有兜底:重试预算用尽后落死信表并告警,而不是静默放弃;一致性校验可以在恢复时比对本地状态与外部真实状态(查订单、查库存),不一致以外部为准再继续。
监控、灰度与内容安全,顺带把运维视角补齐:Agent 的观测比传统 API 多三类信号:轨迹(每一轮的 thought、工具名、参数、耗时、成败,建议用 OpenTelemetry 的 trace 串起来)、成本(token 与调用次数按会话维度统计)、质量(任务成功率、人工介入率、工具调用被拒率)。告警阈值按分位数设而不是按均值(P95 延迟、连续失败次数),并区分「模型侧抖动」和「工具侧故障」两类根因。灰度发布用提示词版本 + 模型版本 + 工具版本三个开关做组合,先小流量再全量,同时用固定的评测集跑回归;服务挂了要靠熔断、限流、降级兜住,至少给用户一个「任务已受理、稍后通知」的确定性答复。违规内容要走输入与输出双向检测(敏感词 + 分类模型 + 规则),命中就拦截并按策略转人工,全程留审计日志。