【AI Agent开发】相关知识整理

1. AI Agent 核心概念与架构

AI Agent是2026年最热门的技术方向,也是面试必问的核心模块。

一、基础概念

1. 什么是AI Agent?与普通大模型调用有什么本质区别?

AI Agent定义:能够自主感知环境、做出决策、执行动作并通过反馈迭代优化的智能体。它是大模型的"执行器",让大模型从"只能聊天"变成"能真正做事"。

本质区别

对比项 普通大模型调用 AI Agent
交互模式 单轮问答,一问一答 多轮自主循环,不需要人类干预
能力边界 只能输出文本 可以调用工具、操作文件、执行命令、访问网络
决策能力 被动响应,没有自主决策 主动规划、拆分任务、选择工具、反思优化
记忆能力 无状态,每次调用都是新的 有短期和长期记忆,能记住历史对话和执行结果
目标导向 完成单次请求 为了达成一个复杂目标,自主执行多步操作

2. Agent的基本架构由哪些核心组件构成?

一个完整的Agent架构包含以下6个核心组件:

  1. LLM大脑:Agent的核心,负责思考、决策、规划、生成文本
  2. 工具集:Agent可以调用的外部能力(搜索、文件、命令、数据库等)
  3. 记忆系统:存储历史对话、执行结果、长期知识
  4. 规划器:将复杂目标拆分为多个可执行的子任务
  5. 执行器:调用工具执行具体的动作
  6. 反思器:评估执行结果,调整计划,优化后续步骤

3. Workflow、Agent、Tools三个概念的区别是什么?

概念 定义 特点 适用场景
Tools 单一的原子能力,完成一个具体的动作 无状态、无决策能力、输入输出明确 读取文件、搜索网页、执行命令
Workflow 固定的、预定义的步骤流程 顺序执行、没有自主决策、流程不可变 数据处理流水线、自动化脚本
Agent 自主决策的智能体,能够动态调整执行路径 有状态、有决策能力、可以根据结果调整计划 复杂任务、不确定流程、需要推理的场景

核心区别:Workflow是"人告诉它怎么做",Agent是"人告诉它做什么,它自己想怎么做"。

二、核心能力

4. Agent的核心能力有哪些?

  1. 工具调用能力:能够识别何时需要调用工具,以及如何正确调用工具
  2. 任务规划能力:将复杂的目标拆分为多个可执行的子任务
  3. 记忆能力:记住历史对话、执行结果和长期知识
  4. 反思优化能力:评估执行结果,发现问题并调整计划
  5. 多轮迭代能力:能够自主执行多步操作,直到达成目标

5. 为什么Agent需要工具调用能力?

大模型本身存在以下局限性:

  • 知识截止日期:无法获取训练数据之后的最新信息
  • 实时数据:无法获取实时的天气、股票、新闻等数据
  • 计算能力:数学计算、逻辑推理能力弱
  • 操作能力:无法操作外部系统、文件、数据库

工具调用能力让Agent突破了这些局限性,能够连接到真实世界,完成各种实际任务。

2. Agent 设计范式

Agent设计范式是面试最高频的考点,必须掌握三种主流范式的区别和选型。

一、主流设计范式

1. ReAct 范式(最基础、最常用)

核心思想:Reasoning + Acting,将推理和动作交替进行。

执行流程

  1. 思考(Thought):我现在需要做什么
  2. 动作(Action):调用某个工具,传入参数
  3. 观察(Observation):获取工具执行的结果
  4. 重复以上步骤,直到达成目标

优点:简单易懂、容易实现、适合大多数场景
缺点:容易陷入循环、规划能力弱、不适合复杂任务

2. Plan-and-Execute 范式

核心思想:先制定完整的计划,再分步骤执行。

执行流程

  1. 规划(Plan):将目标拆分为多个步骤的执行计划
  2. 执行(Execute):按照计划逐个执行步骤
  3. 重新规划(Replan):如果执行失败或遇到意外,重新调整计划

优点:规划能力强、适合复杂任务、执行效率高
缺点:实现复杂、灵活性不如ReAct

3. Reflection 范式

核心思想:在执行过程中加入反思步骤,评估结果并优化。

执行流程

  1. 执行任务
  2. 反思(Reflection):评估执行结果是否符合预期
  3. 修正(Correction):如果有问题,修正错误并重新执行
  4. 总结(Summary):任务完成后总结经验教训

优点:准确率高、能够自我修正、适合需要高精度的任务
缺点:token消耗大、执行速度慢

二、范式对比与选型

4. ReAct、Plan-and-Execute、Reflection三种范式的核心区别是什么?

对比项 ReAct Plan-and-Execute Reflection
执行模式 边想边做 先想后做 做了再想
规划粒度 单步 多步 全程
灵活性
执行效率
准确率
实现难度

5. 实际项目中如何选择Agent设计范式?

  • 简单任务:使用ReAct范式,实现简单,足够用
  • 复杂任务:使用Plan-and-Execute范式,规划能力强
  • 高精度任务:使用Reflection范式,准确率高
  • 混合场景:组合使用,先用Plan-and-Execute制定计划,每个步骤用ReAct执行,关键步骤用Reflection验证

3. Agent 记忆系统

记忆系统是Agent区别于普通大模型的核心特征,也是面试必问的重点。

一、记忆分类

1. Agent的记忆系统分为哪几类?

记忆类型 定义 存储位置 生命周期 作用
短期记忆 当前会话的上下文 内存 会话期间 记住当前对话的历史和执行过程
长期记忆 跨会话的知识和经验 向量数据库 永久 记住用户的偏好、历史经验、通用知识
工作记忆 当前正在处理的信息 上下文窗口 单步执行 存储当前思考和决策所需的信息

二、短期记忆实现

2. 短期记忆的滑动窗口机制是如何实现的?

滑动窗口机制是为了解决大模型上下文窗口有限的问题:

  1. 当对话历史超过窗口大小时,自动删除最早的消息
  2. 保留最新的N条消息,确保总token数不超过上下文窗口限制
  3. 可以保护系统提示词和重要的工具执行结果不被删除

窗口大小:通常设置为上下文窗口的70%-80%,预留足够的空间给当前思考和生成内容。

3. 哪些消息需要被保护不被截断?

  1. 系统提示词(System Prompt)
  2. 工具定义(Tool Definitions)
  3. 重要的工具执行结果
  4. 用户的原始问题
  5. 最终的回答

三、长期记忆实现

4. 长期记忆的存储引擎是什么?

长期记忆通常使用向量数据库存储,如Chroma、Pinecone、Milvus等。

存储流程

  1. 将记忆内容转换为向量(Embedding)
  2. 将向量和原始文本一起存入向量数据库
  3. 给每个记忆添加元数据(时间戳、类型、标签等)

5. 长期记忆的提取流程是怎样的?

  1. 将当前的问题或上下文转换为向量
  2. 在向量数据库中进行相似度搜索,找到最相关的N条记忆
  3. 对搜索结果进行重排,过滤掉不相关的内容
  4. 将提取到的记忆注入到当前的上下文中

6. 记忆提取时的评分公式是什么?

通常结合语义相似度时间新鲜度进行评分:

最终得分 = 语义相似度 * 0.7 + 时间新鲜度 * 0.3
  • 语义相似度:向量之间的余弦相似度,范围0-1
  • 时间新鲜度:根据时间衰减函数计算,越新的记忆得分越高

四、记忆优化

7. Agent记忆压缩通常有哪些方法?

  1. 摘要压缩:使用大模型将多条历史消息总结为一条摘要
  2. 重要性过滤:只保留重要的记忆,删除无关紧要的内容
  3. 分块存储:将长记忆分成多个小块,只提取相关的块
  4. 分层记忆:将记忆分为不同的层次,常用的记忆放在上层,不常用的放在下层

4. 多Agent协作

多Agent是复杂系统的必然选择,也是面试中区分高级工程师的考点。

一、基础概念

1. 什么是Multi-Agent(多Agent)系统?

多Agent系统是指由多个相互协作的Agent组成的系统,每个Agent负责一个特定的角色或任务,通过通信和协作共同完成一个复杂的目标。

2. Single-Agent和Multi-Agent的设计方案有什么区别?

对比项 Single-Agent Multi-Agent
复杂度
可扩展性
分工明确度
执行效率
调试难度
适用场景 简单任务、个人助理 复杂项目、团队协作、企业级应用

二、多Agent核心机制

3. 多Agent之间的通信方式有哪些?

  1. 消息传递:Agent之间直接发送消息进行通信,最常用的方式
  2. 共享状态:所有Agent共享一个全局的状态空间,通过读写状态进行通信
  3. 黑板模式:有一个公共的黑板,Agent将结果写在黑板上,其他Agent可以读取

4. 多Agent的路由机制有哪些?

  1. 静态路由:预定义好每个Agent的职责和调用顺序,固定不变
  2. 动态路由:由一个路由Agent根据当前的任务动态选择合适的Agent执行
  3. 混合路由:结合静态和动态路由,核心流程固定,细节动态调整

5. 常见的多Agent协作模式有哪些?

  1. 主从模式:一个主Agent负责规划和协调,多个从Agent负责执行具体任务
  2. 流水线模式:每个Agent负责一个环节,任务在Agent之间顺序传递
  3. 团队模式:多个Agent平等协作,共同讨论和决策
  4. 竞争模式:多个Agent同时解决同一个问题,选择最好的结果

5. RAG 检索增强生成

RAG是将外部知识接入大模型的最主流方案,几乎所有AI应用都会用到。

一、基础概念

1. 什么是RAG?详细描述一个完整RAG系统的工作流程。

RAG定义:Retrieval-Augmented Generation(检索增强生成),通过检索外部知识库的相关信息,将其注入到大模型的上下文中,让大模型能够生成基于外部知识的准确回答。

完整工作流程

  1. 索引构建阶段

    • 文档加载:读取各种格式的文档(PDF、Word、Markdown等)
    • 文档切割:将长文档切成多个小块(Chunk)
    • 向量化:将每个Chunk转换为向量(Embedding)
    • 存储:将向量和原始文本存入向量数据库
  2. 检索生成阶段

    • 查询向量化:将用户的问题转换为向量
    • 向量检索:在向量数据库中搜索最相似的N个Chunk
    • 上下文构建:将检索到的Chunk和用户的问题组合成提示词
    • 大模型生成:大模型根据提示词生成回答

2. RAG主要用来解决大模型的哪些问题?

  1. 知识截止问题:大模型的知识截止到训练数据的日期,无法获取最新信息
  2. 幻觉问题:大模型会编造不存在的事实,RAG提供事实依据
  3. 私有知识问题:大模型无法获取企业内部的私有知识
  4. 长文本处理问题:大模型的上下文窗口有限,无法处理超长文档

3. RAG和微调的优劣势对比是什么?

对比项 RAG 微调
知识更新 实时更新,只需要更新知识库 需要重新训练,周期长、成本高
事实准确性 高,有明确的来源依据 中,仍然可能产生幻觉
实现成本 低,不需要训练数据 高,需要大量高质量的训练数据
部署成本 低,只需要向量数据库 高,需要GPU资源
知识规模 大,可以接入无限多的知识 小,受限于模型参数量
风格适配 差,只能改变内容,不能改变风格 好,可以改变模型的说话风格和行为

选型建议

  • 需要更新频繁的事实性知识 → 用RAG
  • 需要改变模型的风格和行为 → 用微调
  • 复杂场景 → RAG + 微调结合使用

二、索引构建

4. RAG中的文档切割(Chunking)策略有哪些?

  1. 固定长度切割:按固定的字符数或token数切割,最简单但效果最差
  2. 语义切割:根据语义段落切割,保留完整的语义单元
  3. 递归切割:先按大的分隔符切割,再递归切割成小块
  4. 重叠切割:相邻的Chunk之间有一定的重叠,避免语义被切断
  5. 结构化切割:根据文档的结构(标题、段落、列表)切割

5. 如何确定文档切割的粒度?

切割粒度的选择是RAG效果的关键:

  • 粒度太小:每个Chunk的语义不完整,检索到的信息无法回答问题
  • 粒度太大:包含太多无关信息,引入噪音,影响大模型生成

最佳实践

  • 通用场景:512-1024 token
  • 问答场景:256-512 token
  • 长文档场景:1024-2048 token
  • 代码场景:1024-4096 token

6. 怎么规避语义被切割掉的问题?

  1. 重叠切割:相邻Chunk之间保留10%-20%的重叠
  2. 语义切割:使用语义切割工具,在语义边界处切割
  3. 父文档检索:先检索小块,再返回对应的父文档
  4. 上下文窗口扩展:检索到小块后,扩展前后的上下文

三、检索优化

7. 什么是Query Rewrite(查询改写)?目的是什么?

定义:使用大模型将用户的原始问题改写为更适合检索的查询语句。

目的

  1. 解决用户表达不清晰、不完整的问题
  2. 将复杂问题拆分为多个简单问题
  3. 扩展同义词和相关词,提高召回率
  4. 消除歧义,明确查询意图

8. 什么是多路召回?具体怎么做?

定义:使用多种不同的检索方式,分别召回结果,然后合并去重。

常见的检索方式

  1. 向量检索:基于语义相似度检索
  2. 关键词检索:基于BM25算法的全文检索
  3. 结构化检索:基于元数据的过滤检索

流程

  1. 分别使用多种检索方式召回结果
  2. 对所有结果进行去重
  3. 使用重排模型对结果进行排序
  4. 选择Top-N结果作为最终的上下文

9. 了解哪些更复杂的RAG范式?

  1. Self-RAG:大模型自己决定是否需要检索,以及检索什么内容
  2. Corrective RAG:检索到的信息如果不正确,自动纠正或重新检索
  3. Adaptive RAG:根据问题的复杂程度自适应选择检索策略
  4. Graph RAG:使用图数据库存储知识,支持关系检索和多跳推理

四、生产落地

10. 如何规避RAG系统中大模型的幻觉?

  1. 提高检索精度:优化切割策略和检索算法,确保检索到的信息准确相关
  2. 强制引用来源:要求大模型在回答中引用检索到的来源
  3. 事实校验:使用大模型对生成的回答进行事实校验
  4. 限制回答范围:明确告诉大模型只能使用检索到的信息回答问题
  5. 添加免责声明:对于不确定的内容,明确告知用户

11. 怎么量化RAG的效果?

常用指标

  1. 召回率(Recall):检索到的相关文档占所有相关文档的比例
  2. 精确率(Precision):检索到的文档中相关文档的比例
  3. F1值:召回率和精确率的调和平均
  4. BLEU/ROUGE:评估生成回答和标准答案的相似度
  5. 人工评估:由人来评估回答的准确性、相关性、完整性

12. RAG知识库如何实现动态与持续更新?

  1. 增量更新:只更新新增或修改的文档,不需要重新构建整个索引
  2. 定时更新:定期从数据源同步最新的文档
  3. 实时更新:当文档发生变化时,立即更新索引
  4. 版本管理:保留知识库的历史版本,支持回滚

6. LLM 工具调用体系

工具调用是Agent"能做事"的基础,也是面试中区分理论和实战的关键。

一、Function Calling基础

1. 什么是Function Calling?原理是什么?

定义:大模型的一种能力,能够识别用户的问题需要调用外部工具,并输出符合特定格式的工具调用请求。

原理

  1. 在提示词中告诉大模型有哪些工具可以调用,以及每个工具的参数格式
  2. 大模型根据用户的问题,决定是否需要调用工具
  3. 如果需要调用,大模型输出JSON格式的工具调用请求
  4. 后端解析JSON,调用对应的工具
  5. 将工具的返回结果返回给大模型
  6. 大模型根据工具的返回结果生成最终回答

2. LLM是如何学会调用外部工具的?

大模型的工具调用能力是通过微调学会的:

  1. 收集大量的工具调用示例数据
  2. 使用这些数据对大模型进行监督微调(SFT)
  3. 训练大模型学习工具调用的格式和逻辑
  4. 通过RLHF进一步优化工具调用的准确性

二、工具调用体系对比

3. Function Calling、Skill、MCP三者的区别是什么?

概念 定义 层级 作用
Function Calling 大模型输出JSON格式调用请求的能力 语言层 定义了大模型和工具之间的通信语言
MCP 模型上下文协议,统一的工具接入标准 接口层 定义了工具的注册、发现和调用接口
Skill 将使用工具完成任务的知识和流程打包成可复用模块 应用层 定义了如何使用工具完成一个复杂任务

三者关系:Function Calling是语言,MCP是工具箱,Skill是操作手册。

4. 什么场景下使用Function Calling,什么场景下使用MCP?

  • Function Calling适用场景

    • 简单的工具调用,只需要调用一两个工具
    • 项目早期,工具数量少
    • 不需要跨项目共享工具
  • MCP适用场景

    • 复杂的工具调用,需要调用多个工具
    • 工具数量多,需要统一管理
    • 需要跨项目、跨语言共享工具
    • 希望接入生态中已有的MCP工具

7. MCP 模型上下文协议

MCP是2026年AI工具生态最热门的话题,也是你正在使用的技术。

一、基础概念

1. 什么是MCP(模型上下文协议)?

MCP(Model Context Protocol)是由Anthropic推出的开放标准,定义了大模型和外部工具之间的统一通信协议。它允许大模型无缝接入各种外部工具和服务,而不需要为每个工具编写专门的集成代码。

2. MCP由哪几部分组成?

  1. MCP服务器:提供工具能力的服务,每个服务器可以提供多个工具
  2. MCP客户端:集成在Agent中的客户端,负责与MCP服务器通信
  3. 传输协议:定义了客户端和服务器之间的通信方式(Stdio、HTTP、WebSocket)
  4. 消息格式:定义了工具注册、调用、返回的JSON消息格式

3. MCP的通信方式有哪些?

  1. Stdio(本地子进程):最常用的方式,MCP服务器作为子进程运行,通过标准输入输出通信
  2. HTTP(远程服务器):MCP服务器运行在远程,通过HTTP接口通信
  3. WebSocket:支持双向实时通信,适合需要持续交互的工具

二、MCP实战

4. Docker环境下部署MCP需要注意哪些问题?

  1. 路径映射:所有路径必须使用容器内的路径,不能使用宿主机路径
  2. 命令路径:必须使用完整的命令路径,不能使用npx/uvx等短命令
  3. 依赖预装:所有MCP服务器的依赖必须在Dockerfile中预装
  4. 卷映射:需要访问宿主机文件时,必须配置Docker卷映射

5. 如何解决MCP文件系统工具的路径不匹配问题?

  1. 在系统提示词中明确告诉Agent运行在Docker环境中,只能访问容器内的路径
  2. 实现路径自动转换,将宿主机路径自动转换为容器内的路径
  3. 添加错误处理,当访问不存在的路径时,提示用户使用容器内的路径

8. LangChain 框架核心

LangChain是最流行的Agent开发框架,几乎所有AI工程师都用过。

一、核心组件

1. LangChain的核心组件有哪些?

  1. LLM:大语言模型的抽象,支持各种主流大模型
  2. Prompt Template:提示词模板,方便复用和管理提示词
  3. Chain:将多个组件组合成一个执行流程
  4. Agent:自主决策的智能体
  5. Tool:外部工具的抽象
  6. Memory:记忆系统的抽象
  7. Retriever:检索器的抽象,支持各种检索方式
  8. Document Loader:文档加载器,支持各种格式的文档
  9. Text Splitter:文本切割器,支持各种切割策略
  10. Vector Store:向量数据库的抽象,支持各种主流向量数据库

二、Agent框架

2. LangChain支持哪些Agent类型?

  1. ReAct Agent:实现ReAct范式的Agent,最常用
  2. Plan-and-Execute Agent:实现Plan-and-Execute范式的Agent
  3. OpenAI Functions Agent:专门针对OpenAI Function Calling优化的Agent
  4. Structured Chat Agent:支持结构化输出的Agent
  5. Multi-Agent:支持多Agent协作

3. 在工程实践中,为什么有时候选择"手搓"Agent,而不是直接用LangChain?

  1. 灵活性:LangChain的封装太死,难以定制化修改
  2. 性能:LangChain有很多额外的开销,性能不如手搓的
  3. 调试难度:LangChain的执行流程不透明,调试困难
  4. 依赖问题:LangChain的版本更新快,兼容性差
  5. 功能冗余:很多功能用不到,增加了项目的复杂度

选型建议

  • 快速原型验证 → 用LangChain
  • 生产环境部署 → 手搓Agent,只使用LangChain的部分组件

9. 大模型工程基础

大模型工程是AI应用的地基,了解基础原理能让你更好地优化Agent性能。

一、推理与生成

1. 大模型生成文本时的解码策略有哪些?

  1. 贪心解码:每次选择概率最高的token,速度快但容易重复
  2. Beam Search:同时保留多个候选路径,选择概率最高的路径,生成质量高但速度慢
  3. 采样解码:根据概率分布随机选择token,生成更有多样性
    • Top-K采样:只从概率最高的K个token中选择
    • Top-P采样:只从概率和为P的token中选择

2. 大模型的采样参数:温度值、Top-P、Top-K分别是什么?

  • 温度值(Temperature):控制生成的随机性,值越高越随机,值越低越确定。常用值:0.1-1.0
  • Top-K:只考虑概率最高的K个token,过滤掉低概率的token。常用值:20-100
  • Top-P:只考虑概率和为P的最小token集合。常用值:0.7-0.9

3. KV Cache是什么?原理是什么?

定义:一种优化大模型推理速度的技术,缓存注意力计算的中间结果。

原理

  1. 在生成每个token时,注意力机制需要计算所有之前token的Key和Value
  2. KV Cache将这些Key和Value缓存起来,不需要每次都重新计算
  3. 生成第N个token时,只需要计算第N个token的Key和Value,然后和之前缓存的结果合并

效果:推理速度提升10倍以上,内存占用增加约2倍。

4. 大模型量化是什么?常见的量化方式有哪些?

定义:将大模型的参数从高精度(FP16/BF16)转换为低精度(INT8/INT4),减少内存占用和计算量。

常见量化方式

  • INT8量化:精度损失小,速度提升中等,适合大多数场景
  • INT4量化:精度损失中等,速度提升大,内存占用小
  • AWQ:专门针对大模型优化的量化方法,精度损失比普通INT4小
  • GPTQ:基于训练的量化方法,精度损失最小,但量化过程慢

10. SSE 协议

2026年AI大模型行业标准面试题大全,按难度分级整理,覆盖从基础概念到生产级实战的所有核心考点。

一、初级题(基础概念·必问)

1. 什么是SSE?全称是什么?

SSE全称是Server-Sent Events(服务器发送事件),是HTML5标准定义的一种服务器主动向客户端推送数据的单向通信协议。它基于HTTP协议,允许服务器在建立连接后持续向客户端发送流式数据,客户端通过事件监听的方式接收数据。

2. SSE和WebSocket的核心区别是什么?

对比项 SSE WebSocket
通信方向 单向(仅服务器→客户端) 双向全双工
协议基础 基于HTTP/1.1或HTTP/2 独立的WebSocket协议(ws/wss)
连接建立 标准HTTP握手 专用的WebSocket握手
数据格式 仅支持文本(UTF-8) 支持文本和二进制
自动重连 原生支持 需要手动实现
浏览器兼容性 所有现代浏览器 所有现代浏览器
使用场景 大模型流式输出、日志推送、实时通知 聊天、游戏、实时协作

3. 为什么现在AI大模型几乎都用SSE而不是WebSocket?

  1. 简单性:SSE基于标准HTTP,不需要额外的协议支持,部署和调试更简单
  2. 兼容性:完美兼容所有现有的HTTP代理、防火墙、负载均衡器
  3. 功能匹配:大模型生成回答是服务器单向流式输出,SSE的单向通信完全满足需求
  4. 生态成熟:OpenAI的SSE格式已经成为行业事实标准,所有客户端和工具链都已支持
  5. 自动重连:SSE原生支持断线自动重连,不需要额外开发

4. SSE和长轮询(Long Polling)的区别?

  • 长轮询:客户端发送请求,服务器保持连接直到有数据返回,然后关闭连接,客户端立即发送下一个请求。本质上是多个短连接的循环。
  • SSE:建立一次持久连接,服务器可以持续多次向客户端发送数据,连接一直保持直到主动关闭。
  • 性能:SSE的延迟更低,服务器开销更小,没有频繁的连接建立和断开开销。

二、中级题(协议细节与实现)

5. SSE标准响应头必须包含哪几个?缺一不可的是哪个?

标准响应头:

Content-Type: text/event-stream
Cache-Control: no-cache
Connection: keep-alive
X-Accel-Buffering: no

缺一不可的是Content-Type: text/event-stream,浏览器只有识别到这个头才会将响应作为SSE流处理。其中X-Accel-Buffering: no是生产环境最容易遗漏的,它强制Nginx和FastCGI不缓冲响应,确保数据立即发送到客户端。

6. SSE的标准数据格式是什么?

每个SSE事件由一行或多行组成,每个事件之间用**两个换行符\n\n**分隔:

# 普通数据事件
data: 这是一条数据\n\n

# 带ID的事件
id: msg_001\n
data: 这是带ID的事件\n\n

# 自定义事件类型
event: step\n
data: {"content":"正在检索知识库"}\n\n

# 重连间隔设置
retry: 3000\n\n

# 结束标记(OpenAI标准)
data: [DONE]\n\n

7. 什么是SSE的粘包问题?如何解决?

粘包问题是指:由于TCP协议的流特性,多个SSE事件可能会被合并成一个TCP数据包发送,客户端收到时是多个事件连在一起的字符串。

解决方法

  1. 客户端维护一个缓冲区,将每次收到的数据追加到缓冲区
  2. 以两个换行符\n\n为分隔符,将缓冲区分割成多个完整的事件
  3. 处理所有完整的事件,将剩余的不完整部分留在缓冲区等待下一次数据

8. 原生EventSource API有哪些局限性?

  1. 仅支持GET请求,不支持POST、PUT等其他方法
  2. 不能自定义请求头,无法传递Authorization等认证信息
  3. 只能接收UTF-8文本,不支持二进制数据
  4. 错误处理能力弱,只能监听error事件,无法获取具体的错误状态码
  5. 重连逻辑不可控,原生重连间隔固定为3秒,无法自定义

这就是为什么2026年所有行业标准实现都改用fetch + ReadableStream替代原生EventSource的原因。

9. OpenAI的SSE格式为什么成为了行业事实标准?

  1. 生态完整:几乎所有的大模型提供商(Anthropic、Google、字节、百度)都兼容OpenAI的SSE格式
  2. 工具链丰富:有大量的开源客户端、SDK和调试工具支持
  3. 设计合理:格式简洁,易于解析,同时支持扩展字段
  4. 向后兼容:可以很容易地在现有SSE实现的基础上改造

OpenAI标准格式示例:

data: {"id":"chatcmpl-xxx","object":"chat.completion.chunk","created":1718000000,"model":"gpt-4o","choices":[{"index":0,"delta":{"content":"你"},"finish_reason":null}]}\n\n

三、高级题(生产环境与性能优化)

10. 生产环境中SSE连接为什么会被网关断开?如何解决?

断开原因

  1. Nginx、Apache等反向代理服务器默认有连接超时时间(通常60秒)
  2. 防火墙和负载均衡器会自动关闭长时间没有数据传输的连接
  3. 浏览器和操作系统也有自己的连接超时限制

解决方法

  1. 心跳包机制:服务器每15秒发送一个注释行心跳: ping\n\n,浏览器会忽略注释行,但会重置连接超时计时器
  2. 延长代理超时:在Nginx配置中设置proxy_read_timeout 300s;,将超时时间延长到5分钟
  3. 禁用缓冲:设置proxy_buffering off; proxy_cache off;,确保数据立即发送

11. 什么是伪流式SSE?它有什么问题?

伪流式是指:服务器先完整生成所有数据,然后再将数据分成多个块发送给客户端。

问题

  1. 用户体验差:用户需要等待所有内容生成完成后才能看到第一个字
  2. 服务器内存占用高:需要在内存中缓存完整的响应内容
  3. 延迟高:第一个字节的延迟等于整个响应的生成时间

真流式:服务器每生成一个token就立即发送给客户端,第一个字节的延迟<100ms。

12. SSE如何支持请求取消?

使用fetch + ReadableStream配合AbortController实现:

const controller = new AbortController();

// 发起请求
const response = await fetch('/api/chat/stream', {
  method: 'POST',
  signal: controller.signal
});

// 取消请求
controller.abort();

当调用abort()时,浏览器会关闭连接,服务器会收到一个断开事件,可以停止生成内容释放资源。

13. HTTP/2和HTTP/3对SSE有什么优化?

  1. 多路复用:HTTP/2和HTTP/3支持在一个TCP/QUIC连接上同时进行多个SSE流,不需要建立多个TCP连接
  2. 头部压缩:HPACK/QPACK压缩请求和响应头,减少额外开销
  3. 服务器推送:可以主动推送相关资源,进一步降低延迟
  4. 连接复用:同一个域名的所有请求都复用同一个连接,减少握手开销

注意:HTTP/2和HTTP/3只支持HTTPS,这也是现在所有生产环境必须使用HTTPS的原因之一。

14. 如何实现SSE的断点续传?

使用SSE的id字段实现:

  1. 服务器在每个事件中都包含一个唯一的id
  2. 当连接断开时,浏览器会自动在重连请求的Last-Event-ID头中带上最后收到的事件ID
  3. 服务器收到Last-Event-ID头后,从该ID之后的事件开始继续发送

示例:

# 服务器发送
id: msg_005\n
data: 第5条消息\n\n

# 连接断开后浏览器重连
GET /api/stream HTTP/1.1
Last-Event-ID: msg_005

四、实战综合题(项目经验考察)

15. 现有一个伪流式的SSE实现,如何将其升级为真流式?

  1. 移除所有手动分块代码:删除按固定字符数分块的逻辑
  2. 直接迭代大模型的原生流:调用大模型的astream()方法,每个token生成后立即yield
  3. 修改响应格式:改为OpenAI兼容的标准SSE格式
  4. 添加心跳包机制:每15秒发送一个心跳包
  5. 前端升级:从EventSource改为fetch + ReadableStream
  6. 添加请求取消支持:使用AbortController实现取消功能

16. 设计一个支持工具调用的SSE流协议,需要包含哪些事件类型?

需要设计4种核心事件类型:

  1. token事件:大模型生成的文本token,使用标准data:事件
  2. step事件:状态更新事件,使用event: step,包含当前执行的步骤
  3. observation事件:工具执行结果事件,使用event: observation,包含工具名称和返回结果
  4. done事件:流结束事件,使用标准data: [DONE]标记

示例:

event: step
data: {"step_id":"plan","content":"正在制定执行计划"}\n\n

event: observation
data: {"tool_name":"tavily_web_search","content":"搜索结果..."}\n\n

data: {"choices":[{"delta":{"content":"根据搜索结果"}}]}\n\n

data: [DONE]\n\n

17. 生产环境部署SSE服务,Nginx需要做哪些特殊配置?

location /api/chat/stream {
    proxy_pass http://backend:8000;
    
    # SSE核心配置
    proxy_buffering off;          # 禁用代理缓冲
    proxy_cache off;              # 禁用缓存
    proxy_read_timeout 300s;      # 延长超时到5分钟
    proxy_set_header X-Accel-Buffering "no";  # 强制FastCGI不缓冲
    
    # 通用代理配置
    proxy_set_header Host $host;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header X-Forwarded-Proto $scheme;
    proxy_set_header Connection "";  # 保持长连接
}

18. 如何处理SSE流中的异常?

  1. 后端异常处理:捕获所有异常,发送标准错误事件并优雅关闭连接
    event: error
    data: {"code":500,"message":"服务器内部错误"}\n\n
    data: [DONE]\n\n
    
  2. 前端异常处理:监听fetch的error事件,实现指数退避自动重连
  3. 超时处理:设置全局请求超时,超时后发送finish_reason=“timeout”
  4. 资源清理:连接断开时,立即停止大模型生成,释放所有资源

五、陷阱题(考察细节)

19. SSE的retry字段单位是什么?

毫秒。例如retry: 3000表示重连间隔为3秒。

20. SSE的注释行有什么用?

以冒号:开头的行是注释行,浏览器会完全忽略。主要用于发送心跳包,防止连接被网关断开。

21. SSE可以发送二进制数据吗?

原生SSE协议只能发送UTF-8文本。如果需要发送二进制数据,可以先进行Base64编码,客户端收到后再解码。

22. 一个浏览器最多可以同时打开多少个SSE连接?

HTTP/1.1下,同一个域名最多同时打开6个SSE连接。HTTP/2和HTTP/3下没有这个限制,可以同时打开数百个连接。

11. 后端基础设施

2026年AI大模型后端面试核心模块,覆盖FastAPI、Redis、MySQL三大技术栈,包含生产环境实战和AI项目专属问题。

一、FastAPI 框架核心(Python后端必问)

1. 基础概念

1. FastAPI的核心优势是什么?为什么它能取代Flask成为Python后端首选?
  • 高性能:基于Starlette异步框架,性能接近Node.js和Go,是最快的Python Web框架之一
  • 自动文档:原生支持Swagger UI和ReDoc,代码即文档,自动生成交互式API文档
  • 类型安全:基于Python类型提示和Pydantic,自动进行数据验证和序列化
  • 异步原生:完整支持async/await语法,适合I/O密集型任务(如大模型调用)
  • 依赖注入:强大的依赖注入系统,代码解耦、可测试性强
  • 生态丰富:支持OAuth2、JWT、WebSocket、GraphQL等现代Web标准
2. FastAPI的底层依赖是什么?
  • Starlette:提供异步Web服务器和路由功能
  • Pydantic:提供数据验证、序列化和类型提示功能
  • Uvicorn:ASGI服务器,用于运行FastAPI应用
3. 路径参数和查询参数的区别是什么?
  • 路径参数:URL的一部分,用于标识资源,如/items/{item_id}
  • 查询参数:URL中?后面的键值对,用于过滤和排序,如/items?page=1&size=10

2. 核心机制

4. FastAPI的依赖注入系统是如何工作的?

依赖注入是FastAPI最强大的功能之一,它允许你声明依赖项,并由FastAPI自动解析和注入:

  1. 定义依赖函数,返回需要的对象
  2. 在路径操作函数中使用Depends()声明依赖
  3. FastAPI在调用路径操作函数之前,自动执行依赖函数并注入结果

示例

from fastapi import Depends, FastAPI

app = FastAPI()

async def get_db():
    db = Database()
    try:
        yield db
    finally:
        db.close()

@app.get("/items/")
async def read_items(db=Depends(get_db)):
    return db.query("SELECT * FROM items")
5. Pydantic模型在FastAPI中有什么作用?
  • 数据验证:自动验证请求体、查询参数、路径参数的类型和格式
  • 数据序列化:自动将Python对象转换为JSON响应
  • 自动生成文档:根据Pydantic模型自动生成API文档的请求和响应格式
  • 类型安全:提供编译时类型检查,减少运行时错误
6. FastAPI如何处理异步请求?和同步请求有什么区别?

FastAPI同时支持同步和异步路径操作函数:

  • 异步函数:使用async def定义,由Uvicorn的事件循环执行,适合I/O密集型任务
  • 同步函数:使用def定义,FastAPI会自动将其放到线程池中执行

关键区别

  • 异步函数不能调用阻塞操作,否则会阻塞整个事件循环
  • 同步函数可以调用阻塞操作,不会影响其他请求
  • 大模型调用、数据库查询、网络请求等I/O密集型任务优先使用异步

3. 生产环境实战

7. 如何优化FastAPI的性能?
  1. 使用异步函数:所有I/O密集型操作都使用异步版本
  2. 启用HTTP/2:在Nginx中配置HTTP/2,提高并发性能
  3. 使用连接池:数据库、Redis、大模型API都使用连接池
  4. 启用Gzip压缩:在Nginx中启用Gzip压缩,减少传输数据量
  5. 静态资源分离:静态资源由Nginx托管,不经过FastAPI
  6. 使用进程管理器:使用Gunicorn+Uvicorn部署,充分利用多核CPU
  7. 添加缓存:使用Redis缓存频繁访问的数据和大模型生成结果
8. FastAPI如何实现后台任务?

FastAPI提供了BackgroundTasks类,用于在请求返回后执行后台任务:

from fastapi import BackgroundTasks, FastAPI

app = FastAPI()

def write_notification(email: str, message: str = ""):
    with open("log.txt", mode="a") as email_file:
        email_file.write(f"notification for {email}: {message}\n")

@app.post("/send-notification/{email}")
async def send_notification(email: str, background_tasks: BackgroundTasks):
    background_tasks.add_task(write_notification, email, message="some notification")
    return {"message": "Notification sent in the background"}

注意:后台任务适合执行时间短的任务,长时间任务应该使用消息队列(如Celery、RabbitMQ)。

9. FastAPI如何实现限流?

使用slowapi库实现限流,基于Redis存储限流计数器:

from fastapi import FastAPI
from slowapi import Limiter, _rate_limit_exceeded_handler
from slowapi.util import get_remote_address
from slowapi.errors import RateLimitExceeded

limiter = Limiter(key_func=get_remote_address, storage_uri="redis://localhost:6379")
app = FastAPI()
app.state.limiter = limiter
app.add_exception_handler(RateLimitExceeded, _rate_limit_exceeded_handler)

@app.get("/chat")
@limiter.limit("10/minute")
async def chat(request: Request):
    return {"message": "Hello"}

4. AI项目专属问题

10. 为什么大模型后端必须使用异步接口?
  • 高并发:大模型生成响应需要几秒钟到几十秒钟,同步接口会导致服务器很快被占满
  • 资源利用率:异步接口可以在等待大模型响应的同时处理其他请求,提高CPU和内存利用率
  • 用户体验:异步接口配合SSE流式输出,可以实现打字机效果,提升用户体验
  • 容错性:异步接口更容易实现超时控制和重试机制
11. FastAPI中如何实现SSE流式输出?

使用EventSourceResponse返回流式响应:

from fastapi import FastAPI
from fastapi.responses import EventSourceResponse
import asyncio
import json

app = FastAPI()

async def generate_tokens():
    tokens = ["你", "好", ",", "我", "是", "BaseAgent"]
    for token in tokens:
        yield f"data: {json.dumps({'choices': [{'delta': {'content': token}}])}\n\n"
        await asyncio.sleep(0.1)
    yield "data: [DONE]\n\n"

@app.get("/chat/stream")
async def chat_stream():
    return EventSourceResponse(generate_tokens())
12. FastAPI项目的目录结构如何设计?(AI项目最佳实践)
backend/
├── app/
│   ├── api/
│   │   ├── v1/
│   │   │   ├── chat.py       # 聊天接口
│   │   │   ├── knowledge.py  # 知识库接口
│   │   │   ├── mcp.py        # MCP接口
│   │   │   └── __init__.py
│   │   └── __init__.py
│   ├── core/
│   │   ├── config.py         # 配置文件
│   │   ├── exceptions.py     # 异常处理
│   │   └── security.py       # 安全认证
│   ├── db/
│   │   ├── database.py       # 数据库连接
│   │   └── models.py         # 数据库模型
│   ├── schemas/
│   │   ├── chat.py           # 聊天相关Pydantic模型
│   │   └── knowledge.py      # 知识库相关Pydantic模型
│   ├── services/
│   │   ├── chat_service.py   # 聊天服务
│   │   ├── rag_service.py    # RAG服务
│   │   └── mcp_service.py    # MCP服务
│   ├── utils/
│   │   ├── logger.py         # 日志工具
│   │   └── stream.py         # 流式输出工具
│   └── main.py               # 应用入口
├── tests/                    # 测试用例
├── Dockerfile                # Docker构建文件
└── requirements.txt          # 依赖列表

二、Redis 核心原理与实战(高并发必问)

1. 基础原理

1. Redis为什么这么快?
  1. 内存存储:所有数据都存储在内存中,避免了磁盘I/O
  2. 高效数据结构:底层使用跳表、哈希表等高效数据结构,时间复杂度多为O(1)或O(logN)
  3. 单线程模型:避免了多线程的上下文切换和锁竞争
  4. I/O多路复用:使用epoll机制,单线程能高效处理大量并发连接
  5. 优化的代码:Redis是用C语言编写的,执行效率高
2. Redis有哪些核心数据类型?应用场景是什么?
数据类型 底层结构 应用场景
String SDS动态字符串 缓存、计数器、分布式锁、会话存储
Hash 哈希表 存储对象(用户信息、商品详情)
List 双向链表 消息队列、最新文章列表、任务队列
Set 哈希表 去重、共同好友、标签系统
ZSet 跳表+哈希表 排行榜、带权重的队列、延时队列
Bitmap 字符串 签到统计、用户在线状态
HyperLogLog 基数统计 UV统计、独立访客计数
Geo ZSet 地理位置查询、附近的人
Stream 消息队列 可靠消息队列、消费者组
3. Redis的过期键删除策略有哪些?
  1. 惰性删除:只有当访问一个键时,才检查它是否过期,如果过期就删除。优点是CPU开销小,缺点是内存浪费大。
  2. 定期删除:每隔一段时间,随机抽取一部分键进行检查,删除过期的键。优点是平衡了CPU和内存开销,缺点是可能有大量过期键没有被及时删除。
  3. 内存淘汰:当内存使用达到maxmemory限制时,执行内存淘汰策略,删除部分键释放内存。

Redis默认使用惰性删除+定期删除的组合策略。

4. Redis的内存淘汰策略有哪些?
策略 说明
noeviction 不淘汰,当内存满时,新的写操作会报错
allkeys-lru 淘汰所有键中最近最少使用的键(最常用)
allkeys-lfu 淘汰所有键中使用频率最低的键
allkeys-random 随机淘汰所有键中的一部分
volatile-lru 淘汰设置了过期时间的键中最近最少使用的键
volatile-lfu 淘汰设置了过期时间的键中使用频率最低的键
volatile-random 随机淘汰设置了过期时间的键中的一部分
volatile-ttl 淘汰设置了过期时间的键中最早过期的键

2. 缓存问题与解决方案

5. 什么是缓存穿透、缓存击穿、缓存雪崩?如何解决?
问题 现象 原因 解决方案
缓存穿透 大量请求查询不存在的数据,直接打到数据库 请求的数据在缓存和数据库中都不存在 1. 布隆过滤器
2. 缓存空值
3. 接口参数校验
缓存击穿 某个热点key过期,大量请求同时打到数据库 热点key过期,同时有大量并发请求 1. 热点key永不过期
2. 互斥锁
3. 提前更新缓存
缓存雪崩 大量key同时过期,数据库压力剧增甚至宕机 大量key在同一时间过期
Redis服务器宕机
1. 过期时间加随机值
2. 搭建Redis集群
3. 服务熔断和降级
4. 多级缓存
6. 如何保证缓存与数据库的双写一致性?

最佳实践:Cache Aside Pattern(旁路缓存模式)

  • 读操作:先读缓存,命中返回;未命中读数据库,写入缓存后返回
  • 写操作:先更新数据库,再删除缓存(不是更新缓存

为什么删除缓存而不是更新缓存?

  1. 懒加载:避免无效更新,只有当数据被访问时才更新缓存
  2. 并发安全:防止并发更新时因顺序错乱导致的脏数据问题
  3. 幂等性:删除操作是幂等的,重复删除不会有问题

进阶方案

  • 延迟双删:先删缓存 → 更新数据库 → 延时1秒 → 再删缓存(解决更新期间的脏读)
  • 异步监听:通过Canal监听MySQL Binlog,自动删除/更新缓存

3. 分布式锁与高可用

7. 如何用Redis实现分布式锁?需要注意哪些问题?

基本实现

SET key value NX PX 30000
  • NX:键不存在才设置
  • PX:设置过期时间(防止死锁)

核心问题与解决方案

  1. 误删问题:解锁时需要校验Value(线程ID),且判断+删除操作必须用Lua脚本保证原子性
  2. 锁过期问题:业务未执行完锁就过期了。解决方案:Redisson的看门狗(Watch Dog)机制,自动续期
  3. 集群安全问题:Redlock算法(向半数以上节点申请锁),但争议较大,一般单机或主从+哨兵配合过期时间已足够
8. Redis主从复制的原理是什么?
  1. 从节点发送PSYNC命令给主节点
  2. 主节点执行BGSAVE生成RDB快照,并将快照发送给从节点
  3. 从节点清空自己的数据,加载RDB快照
  4. 主节点将快照生成期间的写命令发送给从节点,从节点执行这些命令
  5. 主节点后续的写命令都会异步复制给从节点
9. Redis哨兵(Sentinel)机制的作用是什么?

哨兵是Redis的高可用解决方案,主要作用:

  1. 监控:持续监控主节点和从节点的健康状态
  2. 自动故障转移:当主节点宕机时,自动将一个从节点提升为新的主节点
  3. 通知:当发生故障转移时,通知客户端新的主节点地址
  4. 配置管理:客户端通过哨兵获取主节点的地址

4. AI项目专属问题

10. Redis在AI Agent项目中有哪些应用场景?
  1. 会话存储:存储用户的会话信息和短期记忆
  2. 缓存:缓存大模型的生成结果、向量检索结果、嵌入结果
  3. 分布式锁:防止并发请求导致的重复生成和重复工具调用
  4. 消息队列:实现异步任务处理,如知识库构建、大模型批量生成
  5. 限流:限制用户的请求频率,防止滥用大模型API
  6. 计数器:统计用户的API调用次数、token使用量
  7. 滑动窗口限流:实现更精细的限流控制
  8. 分布式缓存:多实例部署时共享缓存数据
11. 如何用Redis实现滑动窗口限流?
import redis
import time

r = redis.Redis(host='localhost', port=6379, db=0)

def is_rate_limited(user_id: str, window_size: int = 60, max_requests: int = 10) -> bool:
    """
    滑动窗口限流
    :param user_id: 用户ID
    :param window_size: 窗口大小(秒)
    :param max_requests: 窗口内最大请求数
    :return: True表示被限流,False表示允许
    """
    now = int(time.time() * 1000)  # 毫秒级时间戳
    key = f"rate_limit:{user_id}"
    
    # 使用Lua脚本保证原子性
    lua_script = """
    local key = KEYS[1]
    local now = tonumber(ARGV[1])
    local window_size = tonumber(ARGV[2])
    local max_requests = tonumber(ARGV[3])
    
    -- 删除窗口外的记录
    redis.call('ZREMRANGEBYSCORE', key, 0, now - window_size * 1000)
    
    -- 统计当前窗口内的请求数
    local count = redis.call('ZCARD', key)
    
    if count >= max_requests then
        return 1
    else
        -- 添加当前请求
        redis.call('ZADD', key, now, now)
        redis.call('EXPIRE', key, window_size)
        return 0
    end
    """
    
    result = r.eval(lua_script, 1, key, now, window_size, max_requests)
    return result == 1
12. 如何用Redis实现Agent的短期记忆?
import redis
import json

r = redis.Redis(host='localhost', port=6379, db=0)

def add_message(conversation_id: str, role: str, content: str):
    """添加一条消息到短期记忆"""
    key = f"conversation:{conversation_id}"
    message = {"role": role, "content": content, "timestamp": int(time.time())}
    r.rpush(key, json.dumps(message))
    r.expire(key, 86400)  # 24小时过期

def get_messages(conversation_id: str, limit: int = 10) -> list:
    """获取最近的N条消息"""
    key = f"conversation:{conversation_id}"
    messages = r.lrange(key, -limit, -1)
    return [json.loads(msg) for msg in messages]

def clear_messages(conversation_id: str):
    """清空会话的短期记忆"""
    key = f"conversation:{conversation_id}"
    r.delete(key)

三、MySQL 核心原理与实战(数据存储必问)

1. 索引原理

1. MySQL InnoDB索引的底层数据结构是什么?为什么用B+树?

底层结构:B+树

为什么用B+树而不用其他结构?

  • 对比哈希索引:哈希索引只支持等值查询,不支持范围查询和排序
  • 对比二叉树:二叉树在数据量大时深度太大,磁盘I/O次数多
  • 对比B树:B+树的非叶子节点不存储数据,只存储索引,能存储更多的索引项,树的深度更小,磁盘I/O次数更少;B+树的叶子节点形成一个有序链表,方便范围查询和排序
2. 聚簇索引和非聚簇索引的区别是什么?
对比项 聚簇索引(主键索引) 非聚簇索引(二级索引)
叶子节点存储 整行数据 主键值
数量 一个表只能有一个聚簇索引 一个表可以有多个非聚簇索引
查询效率 高,一次查询就能得到数据 低,需要先查二级索引得到主键,再查聚簇索引(回表)
3. 什么是覆盖索引?有什么好处?

覆盖索引是指一个索引包含了查询需要的所有字段,不需要回表查询聚簇索引。

好处

  • 大大提高查询性能,减少磁盘I/O
  • 避免回表操作,减少锁竞争
  • 降低内存占用

示例

-- 创建联合索引
CREATE INDEX idx_name_age ON user(name, age);

-- 这个查询可以使用覆盖索引,不需要回表
SELECT name, age FROM user WHERE name = '张三';
4. 什么是最左前缀原则?

最左前缀原则是指联合索引按照最左优先的方式进行匹配,查询时会从联合索引的最左边开始匹配,直到遇到范围查询(>、<、between、like)就停止匹配。

示例
联合索引idx_a_b_c(a, b, c)

  • 可以匹配:aa,ba,b,c
  • 不能匹配:bb,cc
  • 部分匹配:a,c(只匹配a,c不会用到索引)

2. 事务与并发

5. 事务的ACID特性是什么?
  • 原子性(Atomicity):事务是一个不可分割的工作单位,事务中的操作要么全部成功,要么全部失败
  • 一致性(Consistency):事务执行前后,数据库的完整性约束没有被破坏
  • 隔离性(Isolation):多个事务并发执行时,一个事务的执行不能被其他事务干扰
  • 持久性(Durability):一个事务一旦提交,它对数据库的修改是永久性的
6. MySQL的事务隔离级别有哪些?分别解决了什么问题?
隔离级别 脏读 不可重复读 幻读
读未提交(Read Uncommitted)
读已提交(Read Committed)
可重复读(Repeatable Read) ❌(InnoDB通过MVCC解决)
串行化(Serializable)

MySQL InnoDB默认的隔离级别是可重复读(RR)

7. 什么是MVCC?原理是什么?

MVCC(多版本并发控制)是InnoDB实现隔离级别的基础,它允许多个事务同时读写数据库,而不会互相阻塞。

原理

  1. 每行数据都有两个隐藏字段:DB_TRX_ID(事务ID)和DB_ROLL_PTR(回滚指针)
  2. 事务修改数据时,会生成一个新版本的数据,旧版本的数据会被保留在undo log中
  3. 事务读取数据时,根据事务的启动时间和数据的版本号,读取符合条件的版本
  4. 不同的事务可以看到不同版本的数据,实现了读写不阻塞
8. InnoDB是如何解决幻读问题的?

InnoDB在可重复读隔离级别下,通过MVCC+间隙锁解决了幻读问题:

  • 快照读:使用MVCC,读取数据的历史版本,不会看到其他事务插入的新数据
  • 当前读:使用间隙锁(Gap Lock),锁定索引之间的间隙,防止其他事务在间隙中插入新数据

3. 性能优化与架构

9. 如何定位和优化慢查询?

定位慢查询

  1. 开启慢查询日志:slow_query_log = ONlong_query_time = 1(超过1秒的查询记录下来)
  2. 使用EXPLAIN分析查询计划,查看索引使用情况
  3. 使用SHOW PROFILE查看查询的执行时间分布

优化方法

  1. 添加合适的索引:避免全表扫描
  2. 优化SQL语句:避免SELECT *,避免在WHERE子句中使用函数和运算
  3. 分页优化:使用游标分页替代OFFSET分页
  4. 避免大事务:将大事务拆分为小事务
  5. 读写分离:主库写,从库读
  6. 分库分表:单表数据量超过5000万行时考虑分库分表
10. 什么是分库分表?什么时候需要分库分表?

分库分表:将一个大的数据库拆分为多个小的数据库,将一个大的表拆分为多个小的表,以提高数据库的性能和可扩展性。

什么时候需要分库分表?

  1. 单表数据量超过5000万行且持续快速增长
  2. 单库并发量(QPS)超过数据库承载能力(通常写QPS>1000)
  3. 业务数据有明显的冷热区分
  4. 未来有明确的大规模扩容需求
  5. 单库磁盘使用率超过80%且无法通过清理数据解决

拆分策略

  • 垂直分库:根据业务模块拆分,如用户库、订单库、商品库
  • 垂直分表:根据字段拆分,将大字段和不常用字段拆分到单独的表中
  • 水平分库:将一个库的数据按某个字段(如用户ID)拆分到多个库中
  • 水平分表:将一个表的数据按某个字段拆分到多个表中
11. MySQL的备份策略有哪些?
备份方式 类型 优点 缺点 适用场景
mysqldump 逻辑备份 简单、灵活、兼容性强 大库备份慢 中小库、单库单表恢复、数据迁移
Percona XtraBackup 物理备份 快、不锁表、支持增量备份 粒度粗、跨平台差 大库、全量/增量备份、灾难恢复
主从复制 - 快速回滚 需要主从架构 有主从的环境
binlog时间点恢复 - 精确到时间/位置 依赖binlog 数据误删应急恢复

生产环境最佳实践

  • 中小库:每天凌晨用mysqldump做全量压缩备份,保留7天
  • 大库:每周日用XtraBackup做全量备份,周一到周六做增量备份,保留2周
  • 必须开启binlog:用于误删后的时间点恢复

4. AI项目专属问题

12. MySQL在AI Agent项目中有哪些应用场景?
  1. 用户管理:存储用户信息、权限、角色
  2. 会话管理:存储永久的对话历史记录
  3. 知识库管理:存储知识库的元信息、文档信息、分片信息
  4. MCP配置管理:存储MCP服务器的配置信息
  5. 工具调用日志:存储工具调用的日志和统计信息
  6. 模型配置管理:存储大模型的配置信息和API密钥
  7. 用户配额管理:存储用户的API调用配额和使用量
  8. 系统日志:存储系统的运行日志和错误日志
13. 如何设计Agent项目的MySQL表结构?
-- 用户表
CREATE TABLE users (
    id INT PRIMARY KEY AUTO_INCREMENT,
    username VARCHAR(50) NOT NULL UNIQUE,
    email VARCHAR(100) NOT NULL UNIQUE,
    password_hash VARCHAR(255) NOT NULL,
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
);

-- 对话表
CREATE TABLE conversations (
    id INT PRIMARY KEY AUTO_INCREMENT,
    user_id INT NOT NULL,
    title VARCHAR(255) NOT NULL,
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
    FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE
);

-- 消息表
CREATE TABLE messages (
    id INT PRIMARY KEY AUTO_INCREMENT,
    conversation_id INT NOT NULL,
    role ENUM('user', 'assistant', 'system', 'tool') NOT NULL,
    content TEXT NOT NULL,
    tool_name VARCHAR(100),
    tool_args JSON,
    tool_result JSON,
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    FOREIGN KEY (conversation_id) REFERENCES conversations(id) ON DELETE CASCADE
);

-- 知识库表
CREATE TABLE knowledge_bases (
    id INT PRIMARY KEY AUTO_INCREMENT,
    user_id INT NOT NULL,
    name VARCHAR(100) NOT NULL,
    description TEXT,
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
    FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE
);

-- 文档表
CREATE TABLE documents (
    id INT PRIMARY KEY AUTO_INCREMENT,
    knowledge_base_id INT NOT NULL,
    name VARCHAR(255) NOT NULL,
    file_type VARCHAR(50) NOT NULL,
    file_size INT NOT NULL,
    status ENUM('uploading', 'processing', 'completed', 'failed') NOT NULL,
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
    FOREIGN KEY (knowledge_base_id) REFERENCES knowledge_bases(id) ON DELETE CASCADE
);

-- MCP服务器表
CREATE TABLE mcp_servers (
    id INT PRIMARY KEY AUTO_INCREMENT,
    user_id INT NOT NULL,
    name VARCHAR(100) NOT NULL,
    type ENUM('stdio', 'http') NOT NULL,
    command TEXT,
    args JSON,
    env JSON,
    url VARCHAR(255),
    status ENUM('stopped', 'running', 'error') NOT NULL DEFAULT 'stopped',
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
    FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE
);
14. 如何处理大模型项目中的长文本存储?
  • 短文本(<65535字符):使用VARCHAR或TEXT类型
  • 中长文本(<16MB):使用MEDIUMTEXT类型
  • 超长文本(>16MB):不要存储在MySQL中,使用文件系统或对象存储(如S3、OSS),MySQL中只存储文件路径
  • 聊天记录:使用TEXT类型,单条消息一般不会太长
  • 知识库文档:文档内容存储在文件系统或向量数据库,MySQL中只存储元信息

四、生产环境部署与运维

1. Docker与容器化

1. 为什么AI项目必须使用Docker部署?
  1. 环境一致性:开发、测试、生产环境完全一致,避免"在我电脑上能跑"的问题
  2. 部署简单:一键部署,不需要手动安装依赖和配置环境
  3. 隔离性:不同服务之间相互隔离,不会互相影响
  4. 可移植性:可以在任何支持Docker的平台上运行
  5. 扩缩容方便:配合Kubernetes可以轻松实现水平扩缩容
  6. 版本管理:镜像版本化,方便回滚和升级
2. 你的BaseAgent项目的Docker Compose配置应该是什么样的?
version: '3.8'

services:
  frontend:
    build: ./frontend
    ports:
      - "3000:80"
    depends_on:
      - backend
    restart: always

  backend:
    build: ./backend
    ports:
      - "8000:8000"
    environment:
      - DATABASE_URL=mysql+pymysql://user:password@mysql:3306/baseagent
      - REDIS_URL=redis://redis:6379/0
      - OPENAI_API_KEY=${OPENAI_API_KEY}
      - TAVILY_API_KEY=${TAVILY_API_KEY}
    volumes:
      - ./uploads:/app/uploads
      - ./mcp-test-files:/mcp-test-files
    depends_on:
      - mysql
      - redis
    restart: always

  mysql:
    image: mysql:8.0
    ports:
      - "3306:3306"
    environment:
      - MYSQL_ROOT_PASSWORD=rootpassword
      - MYSQL_DATABASE=baseagent
      - MYSQL_USER=user
      - MYSQL_PASSWORD=password
    volumes:
      - mysql_data:/var/lib/mysql
    restart: always

  redis:
    image: redis:7-alpine
    ports:
      - "6379:6379"
    volumes:
      - redis_data:/data
    restart: always

volumes:
  mysql_data:
  redis_data:

2. Nginx反向代理

3. 生产环境中Nginx需要做哪些配置?

完整的Nginx配置参考之前的SSE部分,核心要点:

  1. HTTPS配置:使用Let’s Encrypt免费证书,自动续期
  2. HTTP重定向:将所有HTTP请求重定向到HTTPS
  3. 静态资源托管:前端静态资源由Nginx直接托管
  4. 反向代理:API请求转发到FastAPI后端
  5. SSE专属配置:禁用缓冲,延长超时时间
  6. Gzip压缩:启用Gzip压缩,减少传输数据量
  7. 安全头:添加X-Frame-Options、X-Content-Type-Options等安全头
  8. 限流:配置Nginx限流,防止恶意攻击

3. 监控与告警

4. AI项目需要监控哪些指标?
  1. 业务指标
    • 对话次数、活跃用户数
    • 平均响应时间、首字延迟
    • 工具调用成功率、错误率
    • token使用量、API调用次数
  2. 系统指标
    • CPU使用率、内存使用率、磁盘使用率
    • 网络带宽、连接数
    • 数据库QPS、慢查询数
    • Redis命中率、内存使用率
  3. 大模型指标
    • 大模型API响应时间、错误率
    • 并发请求数、排队数
    • token消耗速度、成本

需要我帮你把这些面试题整理成一页纸速记版,方便你面试前快速复习吗?

Logo

AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。

更多推荐