恒美微站 Logo 恒美微站
  • 首页
  • 关于我们
  • 建站服务
  • 主题模板
  • 案例展示
  • 资讯中心
  • 联系我们

大厂面试题 Agent多轮对话上下文管理:原理与源码拆解

  • 首页
  • 资讯中心
  • /
  • 大厂面试题 Agent多轮对话上下文管理:原理与源码拆解

相关资讯

RAG被玩透了,港中大DocNavRAG少即是多 2026/8/8 4:50:37
Python符号计算库Sympy核心功能与应用解析 2026/8/8 4:50:37
从Token到概念:下一代语言模型训练范式Next-Concept Prediction解析 2026/8/8 4:50:37

最新资讯

生产级RAG架构设计:从原型到高可用系统的工程实践
堆叠式Pull Request:高效拆解AI生成巨型代码的工程实践
Apache Pulsar 3.0架构解析与生产实践指南
Harness模式:用Claude Code构建AI智能体团队,实现工程化协作开发
Prompt版本管理:从文本备份到工程化实践,实现AI应用可追溯与可协作
文件夹怎么压缩成压缩包?从系统自带方法、常见报错到实用工具推荐

今日推荐

Java图像处理实战指南
昇腾AI代理实现多号通话自动化
2026年Graph+AI Agents最新创新思路

本周热门

ncmdumpGUI:一键解锁网易云音乐ncm文件的终极解决方案
分布式配置中心选型实战:Nacos与Consul在创业场景下的对比
MoneyPrinterPlus实战指南:AI视频批量生成与自动化发布完整解决方案

本月精选

如何用DamaiHelper实现演唱会门票的智能自动化抢购:完整技术解决方案指南
第4篇:59 倍性能差距的索引瓶颈定位——一次教科书级的全表扫描调优
终极歌词批量下载神器:5分钟解决离线音乐库歌词同步难题

大厂面试题 Agent多轮对话上下文管理:原理与源码拆解

发布时间:2026/8/8 4:50:37
大厂面试题 Agent多轮对话上下文管理:原理与源码拆解 导读上周有粉丝留言说面试官问Agent 多轮对话上下文是怎么管理的回答把历史消息传给模型然后被追问五个问题全没答上来。这道题看起来简单藏的坑却很深。本文从根本原理出发结合真实框架源码把每一层细节讲清楚——Session 隔离、消息结构、上下文拼装、压缩策略、崩溃恢复最后附面试答题框架。小白友好建议收藏。一、这道题70% 的人只答了表面上周收到一条粉丝留言面试官问 Agent 多轮对话上下文怎么管理我说’把历史消息一起传给模型模型就能记住了’。面试官微微一笑问‘那如果对话很长超过 Token 上限了呢’我说‘压缩一下’他继续问‘怎么压缩压缩时工具调用的消息链如何保证合法并发场景下多个请求同时修改 Session 会冲突吗Agent 崩溃了恢复时怎么处理’然后我就……诶这个场景小编太熟悉了。“把历史传给模型这个答案没有错但它就像有人问飞机为什么能飞”你回答因为有翅膀——没错但只说了表面。今天这篇文章小编带你把这道题背后的工程细节一层层挖出来• LLM 为什么记不住根本原因是什么• 两种多轮怎么区分面试最容易混• Session 是什么怎么隔离为什么要加锁• 消息链里的 tool_call_id 是干什么的断链会发生什么• 上下文拼装时模型看到的远不止聊天记录• 对话太长了五层压缩防线如何兜底• 崩溃恢复、原子写入工程上怎么保证不丢数据• 记忆为什么要分层各层有什么区别最后附一份面试答题框架拿走直接用。二、从根上理解LLM 为什么记不住你讲上下文管理之前必须先搞清楚一件事大模型 API 本身是无状态的。无状态是什么意思小编举个例子。你在代码里调用 LLM API第一次发了这条消息# 第一次 API 调用response llm.call(messages[ {role: user, content: 我叫小张我在做 RAG 项目}])# AI 回复好的小张……紧接着第二次调用你只发了新问题# 第二次 API 调用只传了新问题response llm.call(messages[ {role: user, content: 我叫什么名字}])# AI 回复我不知道你叫什么名字……它真的不知道。不是在装傻。因为第二次调用你只发了一条新消息完全没有把第一次的对话传过去。每次 API 调用模型只能看到你这次传来的 messages上一次调用的内容对它来说根本不存在。每次调用 LLM API就像给一个完全失忆的人打电话。你得把所有背景从头告诉他他才知道你在说什么。一句话定义Agent 的多轮对话上下文管理不是模型自己记住了而是我们写的代码在每次调用模型前把需要的历史拼进 messages 重新发过去。记忆是代码维护的不是模型自带的。这就是上下文管理存在的根本原因。三、先分清两种多轮——面试必考容易混很多人把两种多轮混在一起说面试官一追问就露馅了。分清楚这两种后面每个章节才能对号入座。3.1 跨回合多轮用户和 AI 的来回对话这是大家最熟悉的多轮第 1 轮用户我叫小张我在做 RAG 项目AI你好小张RAG 是个好方向……第 2 轮隔了 10 分钟用户我的项目用什么语言AI你之前提到是 Python ← 它怎么知道的第二轮能回答Python是因为代码在发第二轮请求时把第一轮的对话历史一起塞进了 messages系统提示你是一个 AI 助手……[第一轮] 用户我叫小张我在做 RAG 项目[第一轮] AI你好小张……[当前] 用户我的项目用什么语言模型没有记忆代码帮它记的。3.2 单回合内部多轮Agent 自己在循环这种不太直观但做 Agent 开发必须理解。用户只发了一句话帮我查 pyproject.toml告诉我最低 Python 版本这句话背后Agent 内部发生的事是第 1 次调 LLM↓ 模型决定先用 read_file 工具读取文件执行 read_file↓ 返回文件内容可能有几十行配置第 2 次调 LLM把文件内容也塞进 messages↓ 模型根据内容生成最终答案最低版本是 Python 3.10用户只看到了一次对话内部经历了多次 LLM 调用——每次调用都要维护一份完整的上下文。为什么要分清这两种因为它们涉及的上下文管理机制不同跨回合多轮靠 Session 持久化来恢复历史单回合内部多轮靠 AgentRunner 在内存里维护当前循环的 messages。面试回答时分开说才能体现你真的理解了这两个层次。动图两种多轮——跨回合历史恢复左vs 单回合工具循环右四、一条消息进来系统到底做了什么好现在小编带你看一个真实的 Agent 框架nanobot是怎么处理一条消息的。4.1 七步状态机消息进来之后系统走七个阶段每个阶段职责清晰为什么用状态机而不是一个大函数因为状态机可以恢复。如果系统在 RUN 阶段崩溃下次重启时 RESTORE 阶段能识别出上次没做完从断点继续而不是从头重来。这是后面崩溃恢复章节的关键设计。下面我们逐步拆解 BUILD → RUN → SAVE 这三个核心状态。五、SESSION每段对话都有一张身份证5.1 session_key 是什么从第四章的状态机可以看到消息进来之后第一步就是识别 session_key——在 RESTORE、BUILD 等阶段开始之前系统先要搞清楚这条消息属于谁的对话。系统用session_key区分不同对话窗口# 默认格式频道:聊天IDsession_key f{channel}:{chat_id}# 实际例子telegram:12345 # Telegram 某个用户的私聊cli:direct # 在命令行直接运行slack:C001 # Slack 某个频道为什么要隔离小张在 Telegram 跟 Agent 聊了他的 RAG 项目小李在 Slack 问了一个完全不同的问题。如果没有session_key隔离两人的对话历史会混在一起——AI 可能拿着小张的背景去回答小李的问题。session_key就是每段对话的门牌号不同门牌对话不混。5.2 同一个 Session为什么必须加锁这是面试追问里很经典的一个点。想象一个场景同一个聊天窗口用户快速连发了两条消息消息 A帮我查一下明天天气消息 B顺便看看适不适合骑车两条消息几乎同时到达系统如果并发处理同一个 Session 会怎样nanobot 对每个session_key准备一把asyncio.Lock•同一个 Session串行一个处理完才轮到下一个•不同 Session可以并发互不影响5.3 Session 存在哪里nanobot 把每段对话保存成 JSONL 文件workspace/sessions/├── telegram:12345.jsonl ← 小张的对话记录├── cli:direct.jsonl└── slack:C001.jsonlJSONL 格式每行一个 JSON 对象。好处是哪怕写到一半进程崩溃已经写完的行不会损坏未完成的行顶多就是残缺的那一行。读取时的优先级先查内存缓存热数据最快 ↓ 没有命中再读 JSONL 文件从磁盘加载 ↓ 文件不存在创建新的 Session第一次对话六、消息结构工具调用那条链不能断6.1 四种角色的消息Session 里存的消息不只是用户说了什么、AI 说了什么。一段包含工具调用的完整对话在 Session 里长这样# ① 用户发来的问题{role: user, content: 帮我查北京今天的天气}# ② 模型决定调用工具只声明还没执行{ role: assistant, content: , # 没有文字只是在声明要调工具 tool_calls: [{ id: call_abc123, # ← 给这次工具调用分配了一个 ID function: { name: search_weather, arguments: {city: 北京} } }]}# ③ 工具执行完毕返回结果{ role: tool, tool_call_id: call_abc123, # ← 必须和 ② 里的 id 完全一致 name: search_weather, content: 北京今天晴25度东南风3级}# ④ 模型读取工具结果生成最终回答{role: assistant, content: 北京今天晴25度非常适合出门}6.2 tool_call_id这条链断了API 会报错注意消息 ② 和 ③ 之间那对 IDcall_abc123。小编把它理解成快递单号• 消息 ②模型填了一张发货单单号是call_abc123注明要取 search_weather 这个工具的结果• 消息 ③工具执行完带着同一个单号call_abc123把结果送回来• 单号对不上或者有单号但找不到对应的货或有货但找不到单号整个流程就断了6.3 “孤儿消息”——切历史时最容易踩的坑既然 tool_call_id 必须配对那切断历史就很有讲究了。假设 Session 里已经有 50 条消息现在因为 Token 预算只能取最近 20 条。很可能出现这种情况第 30 条assistant 声明调用工具call_id call_xyz← 被切掉了第 31 条tool 返回结果tool_call_id call_xyz ← 保留了...第 50 条当前消息发给模型的消息链里第 31 条工具结果找不到对应的工具声明。这就叫孤儿工具结果。主流模型 API 遇到这种不合法的消息链会直接报错拒绝请求。所以get_history()必须做额外检查从合法的用户回合边界开始切保证每一个 tool_call_id 都有对应的声明。 “上下文管理不只是’选多少条’更重要的是选出来的消息链结构必须是合法的。”七、上下文拼装模型看到的远不止聊天记录历史读取好了还要经过ContextBuilder把所有素材拼在一起才能变成发给模型的最终 messages。发给 LLM 的完整结构是messages [ {role: system, content: system_prompt}, ...history... ← 筛选过的历史消息 {role: user, content: 当前消息 运行时信息} ]三段拼在一起。重点说说每段里装了什么。7.1 System Prompt 里装了九样东西很多人以为 system prompt 就是你是一个智能助手这几个字。nanobot 的 system prompt 拼装了以下内容这就解释了两个常见问题“为什么 Agent 能记住我的偏好”用户说我习惯看简洁回答系统把这条信息写进USER.md。下次对话时USER.md的内容拼进 system prompt发给模型。模型每次都是刚醒的但有人帮它备好了用户档案。“隔了几天回来Agent 还知道上次聊了什么”旧对话生成的摘要保存在 Session metadata 里下次对话时作为第 ⑨ 条塞进 system prompt。不是模型自己记的是摘要帮它记的。7.2 当前消息后面还附了什么用户发来的消息末尾会自动附上一段运行时信息用户原始消息内容system_metadataCurrent Time: 2026-08-07 10:30:00Channel: telegramChat ID: 12345MCP 连接状态: 3 个工具可用/system_metadata这段信息为什么不放进 system prompt因为时间、连接状态每次都变化。放进 system promptsystem prompt 每次都不同Prompt Cache按前缀缓存就无法命中。把稳定内容放 system prompt把易变信息放用户消息末尾缓存命中率更高——实际上能省下不少 token 费用。八、Runner 内部LLM-工具循环是怎么工作的BUILD 阶段拼装好 messages 之后RUN 阶段的AgentRunner接手开始单回合内部的 LLM-工具循环就是第三章说的单回合内部多轮。核心逻辑用伪代码来看# -----------------------------------------------# AgentRunner 核心循环简化版# -----------------------------------------------# initial_messages 来自 BUILD 阶段 ContextBuilder 的输出# [system_prompt, ...history..., 当前用户消息]messages list(initial_messages)for iteration in range(max_iterations): # 设上限防止工具死循环 # ① 每次发给模型前先治理一遍上下文后面细讲 messages_for_model treat_context(messages) # ② 调用 LLM response await llm.call(messages_for_model) if response.has_tool_calls: # 模型要调工具 # ③ 把我要调工具这个声明追加到 messages messages.append({ role: assistant, tool_calls: [{id: call_abc123, function: {...}}] }) # ④ 真正去执行工具 results await execute_tools(response.tool_calls) # ⑤ 把工具结果也追加进去call_id 必须和 ③ 一致 messages.extend([{ role: tool, tool_call_id: call_abc123, # ← 和 ③ 里的 id 相同 content: 工具返回的内容 }]) continue # 让模型继续看工具结果决定下一步 # 模型给出了最终文字答案结束循环 messages.append(response.final_message) break8.1 每轮发送前的上下文治理注意步骤 ① 里的treat_context()——每次调用 LLM 之前都要先对 messages 做一遍治理。这一步很多人不知道但它是保证上下文合法和不超 Token 的关键治理操作干了什么为什么要做删孤儿工具结果删除找不到对应声明的tool 消息防止API 报错 参考第六章补缺失工具结果工具执行中断时 补一条合成错误信息保持call_id配对完整压缩旧工具输出把几轮前的大工具结果压缩变小防止单个工具结果撑爆上下文限制工具结果总量工具结果不能占超过预算的token给历史和用户信息留空间裁剪旧历史整体还超出预算时删最旧的消息控制整体token数重要区别治理只改变本次发给模型的副本messages_for_modelSession 文件里的完整记录不动。这两个不是同一份数据不要混淆。九、对话太长了五层压缩防线来救场这是整个上下文管理里最复杂也是生产环境最重要的部分。小编先给你看整体结构对话越来越长Token 越占越多 ↓ 超出回放窗口第一层Session 回放窗口限制 ↓ 发给模型前还是太长第二层Runner 实时治理压缩工具结果、裁旧历史 ↓ 估算整体 prompt 超预算第三层Consolidator——让 LLM 把旧消息写成摘要 ↓ 会话空闲超过 TTL第四层AutoCompact——后台自动压缩整个会话 ↓ Session 文件本身太大第五层文件硬上限强制保留最近合法后缀动图五层压缩防线依次兜底第一层Session 回放窗口BUILD 阶段get_history()读取历史时用两个条件决定选哪些消息条数上限比如只取最近 50 条Token 预算上限从最新消息往前倒推超预算就截止同时必须从合法的用户回合边界开始不留孤儿消息第六章讲过的。这一层是最轻量的过滤没有任何额外开销。第二层Runner 实时治理第八章里讲的treat_context()在每次调用 LLM 之前自动执行• 把几轮之前的大工具结果压缩比如读了个大文件后续几轮不需要全文• 整体还超预算就裁剪最旧的一段历史这层只改发给模型的副本Session 原始记录不动。第三层Consolidator——让 AI 给自己写摘要当估算整体 prompt 超过 Token 预算时Consolidator触发目标不是刚好压到预算边缘而是压到预算的 50% 左右留出下几轮的增长空间。第四层AutoCompact——空闲时的后台整理会话超过一定时间没有活动超过 TTL后台自动触发这就是为什么隔了几天回来AI 还知道上次说的那个项目——背后是这层在工作。第五层Session 文件硬上限JSONL 文件达到磁盘硬上限比如文件大小超过某个阈值强制处理保留最近合法的消息后缀有头有尾结构完整 ↓被移除的更旧部分做原始归档防止彻底丢失这是最后一道防线防止 Session 文件永久无限增长撑爆磁盘。十、崩溃了怎么办故障恢复机制这是面试追问里比较冷门、但很能体现工程功底的点。10.1 不处理崩溃会怎样假设 Agent 正在执行一个工具链突然进程崩溃assistant我要调用 3 个工具完成任务tool_1 结果已完成 ✅ 已写入 Sessiontool_2正在执行 ← 这时崩溃了 tool_3还没开始如果什么都不处理下次启动时 Session 文件里是assistant 消息声明要调用 tool_1、tool_2、tool_3三个 call_idtool_1 结果有 ✅tool_2 结果无 ← 孤儿 call_id声明有结果却没有tool_3 结果无 ← 同上发给模型API 报错。用户发来的消息永远得不到回复体验直接崩掉。10.2 四步恢复机制① 提前保存用户消息用户消息在真正调 LLM 之前就已经持久化。崩溃后用户的输入不会丢失下次启动时系统知道用户问了什么。② 工具执行边界保存 Checkpoint每执行完一个工具都把当前进度保存进 Session metadata# Session metadata 里的 runtime_checkpointruntime_checkpoint { assistant_message: ..., # 模型的工具声明含所有 call_id completed_tool_results: [...], # 已完成的工具结果 pending_tool_calls: [...], # 还没执行的工具 iteration: 2, # 当前是第几次迭代}就像打游戏每关结束自动存档——崩了可以从上次存档继续不用从头来。③ RESTORE 阶段重建消息链第四章状态机里的 RESTORE 阶段就是干这个的。下次处理同一个 Session 时检测到 Session metadata 里有runtime_checkpoint恢复已完成的工具结果对没完成的工具调用补一条合成错误“任务在完成前被中断”检查与 Session 尾部有没有重复避免重复追加清除 checkpoint消息链重新合法可以继续新的请求④ 原子写入防止文件半损坏JSONL 文件的写入不是直接覆盖而是# ① 先写到临时文件写到一半崩溃正式文件还是旧的完整版with open(session.jsonl.tmp, w) as f: f.write(content)# ② 写完确认无误原子替换正式文件os.replace(session.jsonl.tmp, session.jsonl)os.replace()在操作系统层面是原子操作——要么完全替换成功要么保持旧文件不会留下写到一半的损坏文件。十一、记忆的四个层次不要搞混了面试常被问到长期记忆和历史有什么区别很多人说不清楚。小编用一个员工的工作记录来类比这四层层次对应存储触发写入的时机主要用途原始消息sessions/每轮对话结束后save精确回放最近上下文session摘要session.metadataAutoCompact 或会话压缩注入System Prompt,帮模型“想起”就内容history.jsonmemory/history.jsonConsolidator 归档时可别Dream 进一步加工Memory.mdmemory/memory.mdDream模块提炼时跨会话的长期知识库最本质的区别•历史记录发生了什么每一句包括废话全都存•长期记忆保存以后还有用的稳定事实只存精华不要把每条聊天记录都当长期记忆——那叫流水账不叫记忆。十二、用一个完整例子串起来光讲概念容易绕小编带你把小张和 Agent 的对话完整过一遍把前面十一章的概念都对号入座。第一轮第一次对话小张我叫小张正在用 Python 开发一个 RAG 项目。系统做了什么第二轮让 Agent 读取文件小张帮我读取 pyproject.toml告诉我最低 Python 版本。系统做了什么聊了几十轮之后这就是完整的生命周期。最后这道面试题你该怎么答原理全讲完了最后帮你整理答题框架。这不是让你背的——理解了上面十二章这些话你自己也能说出来。一分钟版本大模型 API 是无状态的多轮对话能力由应用层实现。系统用 session key 隔离不同会话把 user、assistant、tool call、tool result 四类消息持久化。每次新请求从 Session 里按消息条数和 Token 预算选最近一段合法历史不能随意切切断了 tool\_call\_id 配对就报错再拼接 system prompt含长期记忆、历史摘要和当前消息发给模型。 Agent 单回合内工具调用和结果继续追加到 messages循环调用模型直到得出最终答案。上下文过长有五层兜底Session 回放窗口 → Runner 实时治理 → Consolidator LLM 摘要 → AutoCompact 空闲压缩 → 文件硬上限。同时要保证 tool call 与 result 的 call\_id 配对、同 Session 串行加锁、崩溃后 checkpoint 恢复消息链、JSONL 文件原子写入。五个高频追问面试官问核心回答Token 上限怎么处理五层回放窗口 → 实时治理 → LLM 摘要 → 空闲压缩 → 文件硬上限层层兜底为什么不能随意切历史随意切会产生孤儿 tool 消息声明和结果 call_id 不配对主流 API 直接报错并发请求怎么处理每个 session_key 一把 asyncio.Lock同 Session 串行不同 Session 并发Agent 崩溃了怎么恢复提前保存用户消息 工具边界存 checkpoint RESTORE 阶段补齐配对 原子写入长期记忆和历史有什么区别历史是完整流水账长期记忆是提炼后跨会话有价值的稳定事实记住这个口诀分、存、取、拼、跑、配、裁、压、记、复分 → session_key 隔离每段对话存 → 持久化 user/assistant/tool 消息到 JSONL取 → 按条数Token预算合法边界选历史拼 → 拼 system_prompt 历史 当前消息跑 → Runner 循环调 LLM 和工具配 → tool_call_id 必须配对否则断链裁 → 超预算时裁旧历史和旧工具结果压 → Consolidator 让 LLM 把旧消息压成摘要记 → 稳定事实提炼到 MEMORY.md 长期保存复 → checkpoint 原子写入支持故障恢复面试时能围绕这十个字展开再举出 1-2 个具体机制比如孤儿消息为什么会报错、asyncio.Lock 怎么解决并发问题就已经比大多数人答得完整了。学AI大模型的正确顺序千万不要搞错了2026年AI风口已来各行各业的AI渗透肉眼可见超多公司要么转型做AI相关产品要么高薪挖AI技术人才机遇直接摆在眼前有往AI方向发展或者本身有后端编程基础的朋友直接冲AI大模型应用开发转岗超合适就算暂时不打算转岗了解大模型、RAG、Prompt、Agent这些热门概念能上手做简单项目也绝对是求职加分王给大家整理了超全最新的AI大模型应用开发学习清单和资料手把手帮你快速入门学习路线:✅大模型基础认知—大模型核心原理、发展历程、主流模型GPT、文心一言等特点解析✅核心技术模块—RAG检索增强生成、Prompt工程实战、Agent智能体开发逻辑✅开发基础能力—Python进阶、API接口调用、大模型开发框架LangChain等实操✅应用场景开发—智能问答系统、企业知识库、AIGC内容生成工具、行业定制化大模型应用✅项目落地流程—需求拆解、技术选型、模型调优、测试上线、运维迭代✅面试求职冲刺—岗位JD解析、简历AI项目包装、高频面试题汇总、模拟面经以上6大模块看似清晰好上手实则每个部分都有扎实的核心内容需要吃透我把大模型的学习全流程已经整理好了抓住AI时代风口轻松解锁职业新可能希望大家都能把握机遇实现薪资/职业跃迁这份完整版的大模型 AI 学习资料已经上传CSDN朋友们如果需要可以微信扫描下方CSDN官方认证二维码免费领取【保证100%免费】

关于恒美微站

恒美微站专注于为个体商户、工作室提供极简自助建站服务,让每个人都能轻松拥有专业网站。

快速链接

  • 关于我们
  • 建站服务
  • 主题模板
  • 案例展示
  • 资讯中心

服务项目

  • 可视化建站
  • 拖拽编辑
  • 主题定制
  • SEO 优化
  • 网站托管

联系方式

  • 📍 地址:北京市朝阳区建国路 88 号
  • 📞 电话:400-888-8888
  • ✉️ 邮箱:info@hmyw.cn
  • 🕐 时间:周一至周日 9:00-18:00

© 2024 恒美微站 hmyw.cn 版权所有 | 京 ICP 备 12345678 号