1. 先搞清楚这套面试题到底在考什么
看到“Langchain+Milvus+RAG+Agent+FDE”这个组合,很多准备面试的朋友第一反应可能是“要学的东西好多”。别慌,这套组合拳在2026年的AI大模型面试里,考的不是你每个工具都精通,而是看你有没有能力把几个核心组件串起来,解决一个真实的、端到端的AI应用问题。它本质上是一个RAG(检索增强生成)系统的生产级实现方案。
简单拆解一下:
- Langchain:负责流程编排和工具调用,是系统的“大脑”和“调度中心”。
- Milvus:负责存储和检索向量,是系统的“记忆库”。
- RAG:是核心架构模式,解决大模型“幻觉”和知识更新问题。
- Agent:是系统的“执行者”,让AI能自主决策、使用工具。
- FDE:这通常指Feature Development Engineer或类似角色,考察的是你如何从工程化、产品化角度去设计、实现和优化这套系统。
所以,面试官想看到的不是你背下了多少API,而是你能否清晰地回答:“如果让你从零搭建一个基于私有知识库的智能问答系统,并让它能处理复杂任务,你会怎么做?”下面,我就按一个真实项目从设计到落地的顺序,把这套技术栈拆开揉碎了讲。
2. 环境与核心组件选型:为什么是它们?
在动手写一行代码之前,你得能说清楚技术选型的理由。这比单纯罗列组件名字重要得多。
2.1 Langchain:为什么选它做编排框架?
Langchain的核心价值是标准化和模块化。它把与大模型交互、数据加载、文本分割、向量化、记忆管理、工具调用这些琐碎但必需的步骤,都封装成了可插拔的组件(Chains, Agents, Tools)。对于面试,你需要理解:
- 它解决了什么:避免了每个项目都从零开始写prompt模板、处理上下文窗口、管理对话历史。它提供了一个高层抽象,让开发者能快速搭建原型。
- 关键组件面试点:
- Chains:如何将检索器(Retriever)、大模型(LLM)、记忆(Memory)组合成一个流水线?
LCEL(LangChain Expression Language)的语法和优势是什么? - Agents:
ReAct框架是如何工作的?Agent如何根据LLM的思考(Thought)来决定使用哪个工具(Action)?initialize_agent函数里agent_type(如ZERO_SHOT_REACT_DESCRIPTION)的区别是什么? - Tools:如何自定义一个Tool?比如,写一个查询数据库的Tool,或者调用一个外部API的Tool。
- Chains:如何将检索器(Retriever)、大模型(LLM)、记忆(Memory)组合成一个流水线?
- 避坑提示:Langchain版本迭代快,API变动频繁。面试时要说清楚你用的版本和对应写法,并指出社区也有
LlamaIndex等替代方案,但Langchain的Agent生态目前更活跃。
2.2 Milvus:为什么选它做向量数据库?
当知识库文档达到万、十万级时,用Python列表做相似度搜索是不现实的。你需要一个专业的向量数据库。Milvus是其中的佼佼者。
- 它解决了什么:海量高维向量的近似最近邻搜索(ANN)问题,支持毫秒级检索。
- 关键概念面试点:
- 集合(Collection)与分区(Partition):如何设计集合的Schema(包含向量字段和标量字段)?分区如何用于数据隔离(如按部门、按时间)?
- 索引(Index):
IVF_FLAT、HNSW、SCANN这些索引类型有什么区别?如何根据数据规模、精度要求、内存和磁盘资源来选型?创建索引的参数(如nlist,M/efConstruction)如何影响性能和精度? - 标量过滤(Scalar Filter):这是Milvus的强项。如何实现“在2023年的产品文档中,搜索与‘退款政策’最相关的内容”?这需要结合向量相似度和元数据过滤。
- Segment:理解Milvus底层数据管理单元(Segment)的概念,有助于回答数据一致性、压缩和查询性能相关问题。
- 部署方式:面试官可能会问部署经验。你需要知道:
- 单机Docker部署:最快的学习和测试方式。
docker-compose up -d一键启动。 - 集群化部署:涉及
root coord、query coord、data node、index node等微服务组件。要能说出基本架构和扩容思路。 - 客户端:熟悉
pymilvus这个Python SDK的基本操作(连接、建表、插数据、建索引、搜索)。
- 单机Docker部署:最快的学习和测试方式。
2.3 RAG:如何构建一个健壮的知识库?
RAG是灵魂。但很多项目只做到了“能用”,离“好用”和“稳定”还差得远。面试时要展现出你对全链路的深度思考。
- 文档加载(Loading):能否处理多种格式?
Langchain的DocumentLoaders支持PDF、Word、PPT、HTML、Markdown甚至Notion。要提到编码、网络超时等常见问题。 - 文本分割(Splitting):这是效果的关键。不要只会用
RecursiveCharacterTextSplitter。- 为什么分割重要:分割得太碎,上下文不完整;分割得太长,检索精度下降且可能超出模型上下文。
- 高级策略:按标题分割、按句子分割、重叠(Overlap)窗口设置多少合适?可以提到
Langchain的MarkdownHeaderTextSplitter、TokenTextSplitter等。
- 向量化(Embedding):选哪个模型?
text-embedding-ada-002(OpenAI)效果好但收费;BGE、M3E等开源模型如何本地部署?向量维度是多少(如1536, 1024)?这直接影响Milvus集合的Schema定义。 - 检索(Retrieval):
- 简单检索:基于向量相似度的
similarity_search。 - 进阶检索:多路召回(Hybrid Search)= 向量相似度 + 关键词(BM25)分数。Milvus直接支持。重排序(Re-ranking):用更精细的模型(如
bge-reranker)对召回结果重新排序,提升Top1准确率。这是拉开差距的点。
- 简单检索:基于向量相似度的
- 生成(Generation):如何设计Prompt?至少要知道以下结构:
更高级的会涉及你是一个专业的助手,请根据以下上下文回答问题。 上下文:{context} 问题:{question} 如果上下文不包含答案,请直接说“根据已知信息无法回答”。 答案:Refine、Map-Reduce等文档汇总方式。
2.4 Agent:如何让系统“自主”完成任务?
RAG解决了知识问题,Agent解决行动问题。面试核心是ReAct模式和工具使用。
- ReAct模式:
Reason + Act。模型先“思考”(分析现状、制定计划),再“行动”(调用工具),根据工具返回结果再进行下一步思考,循环直到完成任务。 - 自定义工具(Tools):这是必考题。你需要现场构思或描述一个你实现过的Tool。
from langchain.tools import BaseTool from pydantic import BaseModel, Field class WeatherCheckInput(BaseModel): location: str = Field(description="城市名,例如:北京") class WeatherTool(BaseTool): name = "get_current_weather" description = "获取指定城市的当前天气情况" args_schema = BaseModel = WeatherCheckInput def _run(self, location: str): # 这里模拟调用一个天气API # 实际项目中会是 requests.get(...) return f"{location}的天气是晴朗,25摄氏度。" async def _arun(self, location: str): raise NotImplementedError("异步调用未实现") - Agent类型:
ZERO_SHOT_REACT_DESCRIPTION(零样本,最常用)、OPENAI_FUNCTIONS(适配OpenAI函数调用)、STRUCTURED_CHAT_ZERO_SHOT_REACT_DESCRIPTION(支持复杂多参数工具)。要能说出区别。 - 记忆(Memory):如何让Agent在长对话中记住之前的事情?
ConversationBufferMemory、ConversationSummaryMemory各自适用场景是什么?
2.5 FDE视角:工程化与系统设计
这是区分普通开发者和高级/架构师候选人的关键。FDE角度要求你跳出单点技术,思考整个系统。
- 系统架构图:能画出清晰的架构图,标明数据流(文档->向量化->Milvus;用户问题->检索->Agent调度->生成答案)、服务模块(加载服务、嵌入服务、检索服务、Agent服务)和依赖关系。
- 非功能性需求:
- 性能:检索的P99延迟是多少?如何通过索引优化、缓存(缓存Embedding结果、缓存检索结果)来提升?
- 可扩展性:知识库每天新增百万文档怎么办?Milvus集群如何扩容?Embedding服务如何横向扩展?
- 可用性:Milvus集群如何保证高可用?如何做监控(Prometheus + Grafana)和告警?
- 数据一致性:文档更新后,如何同步更新Milvus中的向量?是实时、定时还是手动触发?这涉及到源数据与向量数据的一致性问题,是面试高频题。
- 评估与迭代:如何评估RAG系统的效果?不能只靠人工看。要设计评估指标:检索相关性(Hit Rate, MRR)、答案准确性(基于GPT-4等模型评判)、答案忠实度(是否基于上下文)。建立评估集,持续迭代分割策略、检索模型和Prompt。
3. 从零搭建:一个可运行的实战Demo
光说不练假把式。我们用一个最小化的例子,把上述流程串起来。假设我们要构建一个“公司内部知识库问答助手”。
3.1 第一步:环境准备与Milvus启动
1. 启动Milvus(单机Docker版,用于测试)
# 下载 docker-compose 配置文件 wget https://github.com/milvus-io/milvus/releases/download/v2.4.0/milvus-standalone-docker-compose.yml -O docker-compose.yml # 启动服务 docker-compose up -d # 检查状态 docker-compose ps看到所有服务(standalone,etcd,minio)状态为Up即可。
2. 安装Python依赖
pip install langchain langchain-openai pymilvus python-dotenv # 如果你用开源Embedding模型,比如BGE # pip install sentence-transformers3.2 第二步:构建向量知识库(Indexing Pipeline)
这是离线预处理流程,通常作为一个独立脚本或服务运行。
import os from langchain.document_loaders import TextLoader # 示例用Text,实际可用PyPDF2等 from langchain.text_splitter import RecursiveCharacterTextSplitter from langchain.embeddings import OpenAIEmbeddings # 或使用开源Embedding # from langchain.embeddings import HuggingFaceEmbeddings from langchain.vectorstores import Milvus from pymilvus import connections, utility # 1. 连接Milvus connections.connect(host='localhost', port='19530') # 2. 加载文档(示例:假设有个knowledge.txt) loader = TextLoader("./knowledge.txt", encoding='utf-8') documents = loader.load() # 3. 分割文本 text_splitter = RecursiveCharacterTextSplitter( chunk_size=500, # 每个片段长度 chunk_overlap=50, # 重叠部分,保证上下文连贯 separators=["\n\n", "\n", "。", "!", "?", ",", " ", ""] # 分割符优先级 ) docs = text_splitter.split_documents(documents) print(f"原始文档分割为 {len(docs)} 个片段") # 4. 初始化Embedding模型(这里用OpenAI,需设置环境变量OPENAI_API_KEY) embeddings = OpenAIEmbeddings(model="text-embedding-ada-002") # 5. 定义Milvus集合参数 collection_name = "company_knowledge" vector_field = "embedding" text_field = "text" # 如果集合已存在,先删除(生产环境慎用) if utility.has_collection(collection_name): utility.drop_collection(collection_name) # 6. 创建向量库并插入数据 # 这一步会完成:创建集合、定义Schema、将docs转为向量、插入Milvus、创建索引 vector_db = Milvus.from_documents( documents=docs, embedding=embeddings, collection_name=collection_name, connection_args={"host": "localhost", "port": "19530"}, # 定义集合Schema drop_old=True, # 覆盖旧的 # 可以添加额外字段,比如 source, page 等元数据,用于标量过滤 # 这里我们添加一个 source 字段 # 注意:Milvus的from_documents会自动处理text和vector字段,额外字段需要通过`doc.metadata`传入 ) print("知识库构建完成!")关键点:
chunk_size和chunk_overlap需要根据你的文档类型(技术文档、会议纪要、QA对)反复调试。- 生产环境中,
drop_old=True要改为更精细的数据更新策略。
3.3 第三步:搭建RAG查询链(RetrievalQA)
from langchain.chains import RetrievalQA from langchain_openai import ChatOpenAI from langchain.vectorstores import Milvus from langchain.embeddings import OpenAIEmbeddings # 1. 重新连接Milvus和Embedding模型(与索引时一致) embeddings = OpenAIEmbeddings(model="text-embedding-ada-002") vector_db = Milvus( embedding_function=embeddings, collection_name="company_knowledge", connection_args={"host": "localhost", "port": "19530"}, ) # 2. 将向量库转为检索器(Retriever) # 可以设置搜索参数:search_kwargs={"k": 5} 表示返回最相似的5个片段 retriever = vector_db.as_retriever(search_kwargs={"k": 3}) # 3. 初始化大语言模型 llm = ChatOpenAI(model="gpt-4o", temperature=0) # temperature=0让输出更确定 # 4. 创建RAG链 qa_chain = RetrievalQA.from_chain_type( llm=llm, chain_type="stuff", # 最常用的类型,将所有检索到的上下文塞进prompt retriever=retriever, return_source_documents=True, # 返回源文档,便于调试和展示 chain_type_kwargs={ "prompt": YOUR_CUSTOM_PROMPT # 可以传入自定义的PromptTemplate,提升效果 } ) # 5. 进行查询 query = "我们公司的年假政策是怎样的?" result = qa_chain.invoke({"query": query}) print("答案:", result["result"]) print("\n来源文档:") for i, doc in enumerate(result["source_documents"]): print(f"[{i+1}] {doc.page_content[:200]}...") # 打印前200字符3.4 第四步:升级为具备工具调用能力的Agent
现在,我们让这个系统不仅能回答问题,还能执行任务,比如“查一下北京天气,然后根据公司出差政策,写一份出差申请草稿”。
from langchain.agents import initialize_agent, AgentType from langchain.tools import Tool from langchain.memory import ConversationBufferMemory # 1. 将刚才的RAG链包装成一个Tool rag_tool = Tool( name="Company_Knowledge_Base", func=qa_chain.run, # 注意这里直接调用.run方法 description="当需要查询公司内部政策、产品信息、规章制度等知识时,使用此工具。输入应为一个明确的问题。" ) # 2. 再定义几个其他工具(示例:天气、计算器) # 天气工具(模拟) def get_weather(location: str) -> str: return f"{location}的天气是模拟数据:晴,22度。" weather_tool = Tool( name="Get_Weather", func=get_weather, description="获取某个城市的当前天气。输入应为城市名,例如:北京。" ) # 3. 创建记忆,让Agent有上下文 memory = ConversationBufferMemory(memory_key="chat_history", return_messages=True) # 4. 初始化Agent # 需要更强的模型来驱动复杂的Agent推理,比如gpt-4 agent_llm = ChatOpenAI(model="gpt-4o", temperature=0) tools = [rag_tool, weather_tool] agent = initialize_agent( tools=tools, llm=agent_llm, agent=AgentType.ZERO_SHOT_REACT_DESCRIPTION, # 零样本ReAct代理 verbose=True, # 打印详细的思考过程,面试时可以展示这个! memory=memory, handle_parsing_errors=True # 优雅处理解析错误 ) # 5. 运行一个复杂任务 result = agent.run("我想去北京出差,那边天气怎么样?另外,根据公司的出差报销政策,我需要注意什么?") print(result)当verbose=True时,你会看到Agent的完整思考链:
Thought: 用户问了两个问题:北京的天气和公司的出差报销政策。我需要分别使用两个工具。 Action: Get_Weather Action Input: 北京 Observation: 北京的天气是模拟数据:晴,22度。 Thought: 我已经获得了天气信息。现在需要查询公司政策。 Action: Company_Knowledge_Base Action Input: 公司的出差报销政策是什么? Observation: 根据公司政策,出差需提前在OA系统提交申请... Thought: 我现在有了所有信息,可以回答用户了。 Final Answer: 北京目前天气晴朗,22度。关于出差报销,公司政策要求...这就是面试官想看到的:系统能理解复杂意图、自主规划、调用正确工具、整合信息并生成最终回答。
4. 面试高频问题与深度解析
掌握了基本流程,我们来看看面试官会从哪些角度深入提问。
4.1 Langchain与Agent相关
Q:Langchain中的Chain和Agent有什么区别?
- A:
Chain是预定义的、确定性的执行流程(如RetrievalQA)。给定输入,它的执行路径是固定的。Agent则引入了决策能力。它依赖LLM(大脑)根据当前状态和可用工具(Tools)来决定下一步做什么,是动态的、非确定性的。简单说,Chain是“流水线”,Agent是“智能调度员”。
- A:
Q:ReAct框架的具体步骤是什么?在Langchain中如何体现?
- A:ReAct是一个循环:Thought -> Action -> Observation。
- Thought:LLM分析当前情况(包括历史记录和用户问题),决定下一步该做什么。
- Action:LLM选择一个工具,并生成该工具所需的输入参数。在Langchain中,这对应一个格式化的字符串,如
Action: Get_Weather\nAction Input: 北京。 - Observation:工具执行并返回结果。这个结果被反馈给LLM。
- 重复1-3,直到LLM认为可以给出最终答案(
Final Answer)。
- 在
initialize_agent时设置verbose=True,就能在控制台看到这个循环的完整日志。
- A:ReAct是一个循环:Thought -> Action -> Observation。
Q:如何解决Agent在复杂任务中出现的“循环调用”或“幻觉调用”问题?
- A:这是实战中的难点。解决方案包括:
- 工具描述精细化:
description字段要极其精确,限定工具的用途、输入格式和边界。 - 设置最大迭代次数:
initialize_agent的max_iterations参数,防止无限循环。 - 使用更强大的LLM:
gpt-4在规划和工具选择上远强于gpt-3.5-turbo。 - 后处理与验证:对Agent的最终输出,可以再用一个简单的Chain或规则进行合理性校验。
- 工具描述精细化:
- A:这是实战中的难点。解决方案包括:
4.2 Milvus与向量检索相关
Q:Milvus的标量过滤(Scalar Filter)是怎么工作的?举个例子。
- A:标量过滤在向量相似度搜索之前或之后,对元数据字段进行过滤。例如,集合中有
年份(year)和部门(dept)字段。查询可以是:“在技术部2023年的文档中,搜索与‘微服务架构’最相关的内容”。在pymilvus中,查询表达式(expr)可以写为:expr='dept == "技术部" and year == 2023'。Milvus会先过滤出符合条件的数据,再在这些数据上做向量搜索,效率很高。
- A:标量过滤在向量相似度搜索之前或之后,对元数据字段进行过滤。例如,集合中有
Q:Milvus的索引类型
IVF_FLAT和HNSW如何选择?- A:这是一个经典的权衡问题。
- IVF_FLAT:基于聚类的索引。需要训练(
nlist参数决定聚类中心数)。查询速度快,内存占用相对低,但精度是近似值。适合数据量较大(百万级)、对精度要求不是100%的在线检索场景。 - HNSW:基于图结构的索引。不需要训练,插入即构建。在相同召回率下,通常比IVF_FLAT更快,但内存占用非常高。适合数据规模中等(千万以下)、对延迟极度敏感、内存充足的场景。
- 选择建议:数据量小(<100万)或追求极致速度选HNSW;数据量大、考虑内存成本选IVF_FLAT。一定要在自己的数据集上做基准测试。
- IVF_FLAT:基于聚类的索引。需要训练(
- A:这是一个经典的权衡问题。
Q:如何保证源文档更新后,Milvus中的向量数据也能同步更新?
- A:这是生产环境的核心问题。没有银弹,常见策略有:
- 双写:在业务系统更新源文档时,同步调用向量化服务更新Milvus。一致性最强,但业务耦合高。
- 异步队列:源文档更新后,发送一个消息到MQ(如Kafka)。有一个独立的消费者服务监听MQ,负责向量化并更新Milvus。解耦性好,但有一定延迟。
- 定时全量/增量同步:定期扫描源文档存储(如S3、数据库),通过比对哈希值或更新时间戳,找出变化的文档进行更新。实现简单,但延迟高,可能漏掉频繁更新。
- 标记删除+重新插入:对于更新,通常的做法是先根据文档ID删除旧向量,再插入新向量。Milvus支持通过主键(如文档ID)进行删除。
- A:这是生产环境的核心问题。没有银弹,常见策略有:
4.3 RAG效果优化相关
Q:RAG效果不好(答非所问或幻觉),你的排查和优化步骤是什么?
- A:这是一个系统性排查题,体现工程思维。
- 第一步:检查检索(70%的问题出在这里)
- 检索到的文档真的相关吗?手动执行检索器,看返回的
source_documents。 - 文本分割是否合理?检查
chunk_size和chunk_overlap。尝试按标题、按段落分割。 - Embedding模型是否合适?对于中文,
text-embedding-ada-002对某些专业领域可能不够好,可以尝试BGE或M3E。 - 是否用了多路召回+重排序?这是提升召回相关性的有效手段。
- 检索到的文档真的相关吗?手动执行检索器,看返回的
- 第二步:检查生成
- Prompt设计得好吗?是否明确要求模型“基于上下文”?是否设置了拒绝回答的指令?
- 上下文是否过长导致模型“注意力分散”?尝试
Map-Reduce或Refine等处理长上下文的方法。 - 换用更强的LLM(如从
gpt-3.5-turbo换到gpt-4)是否有改善?
- 第三步:评估量化
- 构建一个包含
(问题, 标准答案, 相关文档)的测试集。 - 定义评估指标:检索命中率、答案准确性(可以用GPT-4当裁判)。
- 任何优化前后,都用这个测试集跑一遍,用数据说话。
- 构建一个包含
- 第一步:检查检索(70%的问题出在这里)
- A:这是一个系统性排查题,体现工程思维。
Q:如何处理超长文档(如一本几百页的PDF)的RAG?
- A:不能简单分割。
- 分层索引:建立两层索引。第一层是“章节摘要”向量,用于快速定位相关章节。第二层是“章节内详细内容”向量。先检索章节,再在章节内检索细节。
- 摘要嵌入:为每个长文档或章节生成一个摘要,将摘要向量化存入Milvus。用户提问时,先找到相关摘要,再定位到原文的详细内容进行精读。
- Graph-based RAG:使用
Langchain的ParentDocumentRetriever。小块文本用于检索(保证精度),检索到后,返回其所属的更大父文档块给LLM(保证上下文完整)。
- A:不能简单分割。
4.4 FDE系统设计相关
Q:如果这个系统的QPS(每秒查询量)从10增长到1000,你会如何设计架构?
- A:考察可扩展性设计。
- 服务拆分与无状态化:
- 将系统拆分为微服务:
文档处理服务、向量化服务、检索服务、Agent/LLM服务。 - 每个服务无状态,方便水平扩展。
- 将系统拆分为微服务:
- 关键组件扩容:
- Milvus:从单机部署升级为分布式集群,增加
Query Node和Data Node。 - Embedding服务:部署多个模型实例,通过负载均衡(如Nginx)分发请求。可以考虑使用GPU实例加速。
- LLM服务:如果使用开源模型,同样需要部署多个实例。如果使用OpenAI API,需关注其速率限制,考虑使用代理池或请求队列。
- Milvus:从单机部署升级为分布式集群,增加
- 引入缓存:
- 查询缓存:对完全相同的用户查询,缓存最终的答案。
- 向量缓存:对常见的文档块,缓存其Embedding向量,避免重复计算。
- LLM响应缓存:对常见问题,缓存LLM的生成结果。
- 异步与队列:文档更新、向量化等耗时操作,全部通过消息队列(如Kafka, RabbitMQ)异步处理,避免阻塞主查询链路。
- 数据库与存储:元数据(文档信息、用户记录)使用传统关系型数据库(如PostgreSQL)或云服务。向量数据由Milvus集群管理。
- 服务拆分与无状态化:
- A:考察可扩展性设计。
Q:如何监控这个系统的健康状态和性能?
- A:考察运维和可观测性思维。
- 指标监控(Metrics):
- 应用层:各服务的QPS、响应时间(P50, P99)、错误率。
- 组件层:Milvus集群的CPU/内存/磁盘使用率、查询延迟、索引状态。LLM API的调用延迟、Token消耗、费用。
- 业务层:检索平均召回率、用户问题响应满意度(可通过埋点收集)。
- 日志(Logging):集中式日志(如ELK Stack),记录每次请求的详细信息:用户ID、查询内容、检索到的文档ID、Agent思考过程、最终答案、耗时。便于问题追溯和效果分析。
- 链路追踪(Tracing):使用
OpenTelemetry等工具,追踪一个用户请求在所有微服务间的调用链路,快速定位性能瓶颈。 - 告警(Alerting):基于上述指标设置告警规则(如错误率>1%, P99延迟>5s),及时通知运维人员。
- 指标监控(Metrics):
- A:考察运维和可观测性思维。
5. 总结:从面试题到真实项目
面对“Langchain+Milvus+RAG+Agent+FDE”这套组合,我的建议是分层准备,聚焦链路。
第一层(基础):能跑通一个Demo。理解每个组件的基本作用,能说出Langchain的Chain和Agent区别,能解释Milvus的Collection和Index是什么。
第二层(进阶):能解决实际问题。能设计文本分割策略,能进行多路召回和重排序优化,能自定义Tool,能处理Agent的循环问题,能说清楚IVF_FLAT和HNSW的选型。
第三层(高级/FDE):具备系统思维。能设计高可用、可扩展的系统架构,能规划数据一致性方案,能设计监控和评估体系,能对系统瓶颈进行性能分析和优化。
最后,记住面试的本质是沟通。在回答时,多用“我当时的项目是这样处理的…”、“我一般会先排查…”、“这里有个常见的坑…”这样的表达,将知识点融入你的项目经验和个人思考中,远比干巴巴地背诵概念要强得多。