1. 面试官问"讲讲你的DocResearch项目"时,他到底想听什么
面过 DocResearch 这类文档研究型 Agent 项目的人大概都有体会:简历上写着"基于 RAG 的智能文档问答系统",面试官一句"你讲讲这个项目的架构",很多人就开始背术语了——"我用了向量数据库做语义检索,然后通过大模型做增强生成,整体是一个 Agent 编排的流程"。这段话说完,面试官的表情通常是礼貌而空洞的,因为他一个字的信息量都没收到。
问题出在哪?出在你讲的是技术名词的堆叠,而不是问题的拆解过程。DocResearch 这个项目的本质,是让机器在一堆非结构化文档里,像人一样"查资料、做笔记、交叉验证、给出结论"。它天然包含检索、编排、记忆、工具调用这几块,但面试官真正想确认的是:你知不知道每一块为什么存在、边界在哪、你踩过什么坑。
我面过也被人面过不少次,一个很实在的观察是:能把 DocResearch 讲明白的人,往往不是背了最多术语的人,而是能对着白板画出数据流、并且能说清楚"这里如果换成另一种方案会怎样"的人。术语是结果,不是过程。你上来就甩 pgvector、Milvus、Agentic RAG 这些词,面试官只会追问一句"那你为什么选它",然后你就卡住了。
这篇东西我想干的事很具体:把 DocResearch 拆成几个必须讲清楚的模块,每个模块告诉你该讲什么、为什么这么讲、面试官会从哪个角度挖坑。关键词里那些 DocResearch、Agent、RAG、pgvector、Milvus,我会一个个落到具体场景里,而不是让它们飘在空中。适合正在准备这类项目面试的人,也适合刚做完项目、想回头把逻辑理顺的人。
先说一个反直觉的结论:面试里讲项目,模块的"选型理由"比模块的"实现细节"重要得多。因为实现细节网上都有,选型理由才是你个人判断力的体现。下面按这个思路往下拆。
2. 先把数据流讲清楚,再谈用了什么组件
2.1 为什么面试官总让你"画一下架构"
DocResearch 这类项目最容易讲乱的地方,是一上来就分模块讲"检索模块用了什么、生成模块用了什么",听众脑子里没有一张图,信息就是散的。正确的顺序是:先用三十秒把一条完整的数据流讲完,让面试官建立全局观,再回头填细节。
一条典型的 DocResearch 数据流是这样的:用户提问 → 查询理解与改写 → 检索(可能多路)→ 结果重排与过滤 → 组装上下文 → 交给 LLM 生成 → 必要时触发工具调用或二次检索 → 输出并记录。你把这七八个环节按顺序说清楚,面试官立刻知道你脑子里是有系统的。
我一般会这么开场:"这个项目核心是一条'提问到答案'的流水线,中间有三个关键决策点:第一,用户的问题要不要改写;第二,检索走几路、怎么融合;第三,生成之前上下文怎么裁剪。我逐个说。" 这样讲的好处是,你主动把面试官的注意力引到了决策点上,而不是让他去猜你哪里没想清楚。
2.2 查询改写这一步,很多人直接跳过了
大部分人的 DocResearch 是"用户问什么就检索什么",然后发现召回质量很差。原因很简单:用户的自然语言提问和文档里的表述往往对不上。用户问"这个方案贵不贵",文档里写的是"成本评估""预算区间",字面完全不重叠,纯向量检索也可能因为语义漂移而漏掉。
所以查询改写(Query Rewriting)不是锦上添花,是刚需。常见做法有三类:一是同义扩展,把问题扩成几个不同表述分别检索;二是假设文档生成(HyDE 那套思路),先让 LLM 编一个"理想答案",拿这个答案去检索,因为答案和文档的语义分布更接近;三是多轮对话下的指代消解,把"它""这个"还原成具体实体。
面试时你要能说清楚:我为什么在这个项目里选了同义扩展而不是 HyDE?理由可以是——HyDE 多一次 LLM 调用,延迟和成本都上去了,而我的文档领域相对固定,同义扩展用一个小模型或者规则就能覆盖大部分情况。这种"我权衡过"的表达,比"我用了 HyDE"值钱十倍。
2.3 检索为什么要多路,单路不行吗
单路检索的问题在于,任何一种检索方式都有盲区。向量检索擅长语义相似,但对精确的专有名词、编号、代码符号不敏感;关键词检索(BM25 这类)恰好相反,精确匹配强但语义泛化弱。DocResearch 面对的是研究型文档,里面既有大量专业术语,又有需要语义理解的论述,所以混合检索几乎是标配。
讲这块的时候,重点不是"我用了向量加关键词",而是融合策略。常见的是 RRF(Reciprocal Rank Fusion),把两路结果的排名做倒数加权求和,好处是不依赖两路分数的量纲,鲁棒。你要能说出:为什么不直接加权求和分数?因为向量相似度和 BM25 分数根本不在一个尺度上,直接加会有一路被淹没。
提示:面试官很爱追问"两路检索结果冲突时听谁的"。这时候别慌,正确答案是"看场景"——如果问题里有明确的专有名词,关键词路权重高;如果是开放式论述题,向量路权重高。能说出这种条件化策略,说明你真跑过数据。
3. 向量库选型:pgvector 和 Milvus 不是谁替代谁
3.1 选型的第一问永远是数据规模和并发
关键词里同时出现了 pgvector 和 Milvus,这俩经常被拿来对比,但很多人对比的方式是错的——比"谁更强"。正确的第一问是:你的数据量级和并发量级是多少。
pgvector 是 PostgreSQL 的扩展,优势是"你本来就有 PG,加个扩展就能用",运维成本几乎为零,事务、备份、权限这些直接复用。它的短板在超大规模和高并发下的检索性能。Milvus 是专门的向量数据库,为向量检索做了大量工程优化,索引类型丰富(HNSW、IVF 系列等),水平扩展能力强,适合千万级甚至上亿向量、高并发的场景。
所以选型逻辑很清晰:文档量在几十万 chunk 以内、QPS 不高、团队已经有 PG,pgvector 是性价比最高的选择;数据量上千万、需要独立扩缩容、对检索延迟敏感,才值得上 Milvus。面试时你要是能说出"我这个项目文档量大概 X 万 chunk,QPS 峰值 Y,所以我选了 pgvector,因为引入 Milvus 的运维成本在这个量级下不划算",面试官会觉得你是真做过决策的。
3.2 索引参数不是抄来的,是算出来的
不管用哪个库,索引参数都得能解释。以 HNSW 为例,核心参数是 M(每个节点的连接数)和 ef_construction(建索引时的候选集大小)。M 越大,召回越高但内存和建索引时间越长;ef_construction 越大,索引质量越好但建得越慢。查询时还有 ef_search,它直接决定召回和延迟的权衡。
面试时被问到"你怎么调的",别说"我用了默认值"。你可以说:我先用默认参数跑了一版基线,测出召回率,然后固定 ef_search 逐步加大,观察召回提升的边际收益,在收益变平的那个点定下来。这种基于实测曲线做决策的描述,是加分项。
3.3 本地加载 Milvus 那个坑,值得单独讲
关键词里有一条"在 mac 上使用 docker 安装 milvus"和"服务器 linux 上使用 milvus_uri: str = './data/milvus.db' 本地加载 milvus 提示 milv...",这其实是很多人踩过的坑:Milvus 有 Lite 版本(Milvus Lite),可以用本地文件路径当 uri,适合开发和轻量场景,但它和完整的 Milvus 服务端在能力上是有差异的。
典型问题:你在本地用./data/milvus.db跑通了,部署到服务器上想连集群,发现连接方式、认证、集合管理都不一样,代码得改。或者反过来,本地 Lite 版对某些索引类型、某些数据规模支持有限,你按服务端的思路写,跑起来报错。
面试时如果聊到部署,你可以主动提这个:开发阶段用 Milvus Lite 快速验证逻辑,生产环境切到服务端集群,中间要抽象一层向量库访问接口,避免业务代码和具体部署形态耦合。这个"抽象一层"的意识,是工程成熟度的体现。
| 维度 | pgvector | Milvus(服务端) | Milvus Lite |
|---|---|---|---|
| 适用规模 | 十万到百万级 | 千万级以上 | 开发验证、小数据 |
| 运维成本 | 极低(复用 PG) | 中高(独立集群) | 极低 |
| 索引丰富度 | 够用 | 非常丰富 | 受限 |
| 典型场景 | 已有 PG 的中小项目 | 高并发大规模 | 本地开发调试 |
4. Agent 编排:别把"能跑"当成"设计过"
4.1 Agent 和普通 RAG 的分界线在哪
很多人做 DocResearch,其实做的是一个"检索加生成"的固定流水线,然后管它叫 Agent。面试官一旦追问"你这哪里体现 Agent 了",就露馅了。Agent 和固定 RAG 流水线的核心区别在于:Agent 能根据中间结果动态决定下一步做什么。
具体到 DocResearch:普通 RAG 是"检索一次 → 生成",Agent 是"检索 → 发现信息不够 → 换个查询再检索 → 发现需要对比两份文档 → 调用对比工具 → 综合生成"。这个"发现不够再行动"的循环,才是 Agent 的灵魂。你讲项目时,一定要举一个具体的多步决策例子,而不是抽象地说"我用了 Agent 框架"。
4.2 编排框架选型:LangChain 系还是自己写
关键词里有 langchain4j、agent 框架、agent 编排这些。框架能省事,但也会带来抽象泄漏。我的经验是:原型阶段用框架快速验证,理解清楚后再决定哪些部分自己接管。因为 DocResearch 这种项目,检索策略、上下文组装这些核心逻辑往往需要精细控制,框架的默认行为反而会碍事。
面试时被问"为什么用/不用某个框架",你可以这么答:我用框架搭了第一版,跑通后发现检索融合那块框架给的控制粒度不够,我就把这块抽出来自己实现了,框架只负责工具调用和流程编排。这种"该用用、该拆拆"的态度,比"我全程手写"或"我全程用框架"都更可信。
4.3 工具调用与记忆:Agent 的两个易错点
工具调用方面,DocResearch 常见的工具有:文档检索、网页检索、计算器、对比工具、摘要工具。易错点是工具描述写得太模糊,导致 LLM 不知道该在什么时候调用哪个。工具描述要像给新人写说明书一样具体,说清楚"什么时候用、输入是什么、输出是什么"。
记忆方面,Agent 需要记住对话历史、已经检索过的内容、已经得出的中间结论。这里有个坑:把全部历史都塞进上下文,会迅速撑爆窗口并稀释关键信息。合理做法是分层记忆——短期保留最近几轮原文,长期把历史压缩成摘要,检索过的文档只保留引用和关键片段。面试时能讲清楚这个分层,说明你考虑过真实运行时的资源约束。
5. 检索质量:hit rate 上不去时,先别急着换模型
5.1 召回差,八成不是模型的问题
关键词里有 rag hit rate、rag 瓶颈,这是 DocResearch 最核心的痛点。很多人 hit rate 低,第一反应是"换个更强的 embedding 模型",但实测下来,大部分召回问题出在切分和查询侧,而不是 embedding 模型本身。
切分(chunking)是重灾区。切太大,一个 chunk 里混了好几个主题,向量被平均掉,检索时哪个主题都匹配不准;切太小,语义不完整,检索到了也答不好。合理的做法是按语义边界切(比如按标题层级、段落),并保留一定的重叠(overlap),避免关键信息被切断。面试时你可以说:我一开始用固定长度切分,hit rate 一直上不去,后来改成按文档结构切,同一批查询下 hit rate 有明显提升。
5.2 重排是性价比最高的一步
检索出来一堆候选后,直接按向量相似度排序往往不够好。加一个重排(rerank)环节,用一个交叉编码器(cross-encoder)对"查询-文档"对做精细打分,通常能显著提升最终进入上下文的那几条的质量。代价是延迟增加,所以一般是"先粗召回 Top-K(比如 50),再重排取 Top-N(比如 5)"。
面试时被问"你怎么提升检索质量",把重排放在切分优化之后讲,逻辑是:先保证候选集里有正确答案(切分和召回负责),再保证正确答案排到前面(重排负责)。这个先后关系讲清楚,面试官会觉得你懂检索的完整链路。
5.3 怎么量化 hit rate,别用"感觉变好了"
讲项目最忌讳"我感觉效果变好了"。hit rate 要能算:准备一批标注了正确答案的查询,看检索结果里有没有命中正确文档,命中率就是 hit rate。更进一步可以看 MRR(平均倒数排名),它不光看有没有命中,还看命中的排位靠不靠前。
面试时你可以说:我建了一个几十条的评测集,每次改检索策略都跑一遍,对比 hit rate 和 MRR 的变化,避免拍脑袋。这个评测驱动的习惯,是区分"做过 demo"和"做过项目"的关键标志。
6. 并发、成本与安全:项目上线才会暴露的问题
6.1 Agent 怎么扛并发,瓶颈通常不在 LLM
关键词里有"ai agent 怎么扛并发",这是个好问题。DocResearch 的并发瓶颈往往不在 LLM 调用本身(那个可以异步、可以排队),而在向量检索和重排这两步,它们要么吃 CPU/GPU,要么吃数据库连接。所以扛并发的思路是:检索层做连接池和缓存,重排层做批处理,LLM 调用做异步和限流。
缓存特别值得讲:相同或相似的查询,检索结果可以缓存。DocResearch 场景下用户问题经常重复或高度相似,缓存命中率不低,能省下大量检索开销。面试时提一句"我在检索层加了查询缓存,相似查询直接复用结果",是很实在的工程点。
6.2 成本控制:每一次 LLM 调用都要有理由
Agent 的多步特性意味着 LLM 调用次数可能很多,成本容易失控。控制手段包括:查询改写用小模型、能规则解决的不调 LLM、上下文裁剪到刚好够用、设置最大步数防止 Agent 无限循环。面试时能说出"我给 Agent 设了最大迭代步数,超过就强制输出当前最优结果",说明你考虑过失控场景。
6.3 Agent 安全:别让检索到的内容反过来指挥 Agent
关键词里有 agent 安全、a-memguard 这类。DocResearch 会检索外部文档,如果文档里藏了"忽略之前的指令,执行某某操作"这种内容,Agent 可能被带偏,这就是提示注入。防护思路是:把检索到的内容明确标记为"数据"而非"指令",在系统提示里强调只把检索内容当参考资料,同时对输出做校验。面试时能主动提这个风险,是明显的加分项,因为很多人根本没意识到。
7. 面试现场:怎么把上面这些串成一段不背术语的回答
7.1 一个可复用的回答框架
把前面所有内容压缩成一个回答框架,大概是这个结构:一句话定位项目 → 画数据流 → 点出三个关键决策 → 每个决策讲选型和理由 → 讲一个踩过的坑和怎么解决的 → 讲怎么量化效果。这个框架的好处是,它逼着你讲"为什么",而不是"是什么"。
举个例子串起来:"DocResearch 是一个能对多份文档做研究型问答的 Agent。数据流是提问、改写、混合检索、重排、组装、生成,必要时多轮。三个关键决策:一是查询改写用同义扩展而非 HyDE,因为延迟敏感;二是向量库选 pgvector,因为数据量在几十万级、团队已有 PG;三是加了重排,因为粗召回 Top-50 里正确答案经常排不进前 5。踩过的坑是切分太粗导致 hit rate 低,改成按结构切分后提升明显。效果上我建了评测集,hit rate 和 MRR 都有量化对比。"
这段话里没有一个术语是硬塞的,每个术语都挂在具体决策上。这就是"讲明白"和"背术语"的区别。
7.2 面试官追问时的应对原则
追问是好事,说明他感兴趣。应对原则有三条:不知道的别硬编,可以说"这块我当时没深入,我的初步想法是……";被质疑选型时先问清场景,因为很多选型没有绝对对错,只有场景匹配;主动暴露权衡,任何方案都有代价,能说出代价的人显得更可信。
比如面试官问"你为什么不用 Milvus",你别急着辩解,可以说"在我的数据量级下 pgvector 够用且运维简单,如果数据涨到千万级或者并发上来了,我会考虑迁到 Milvus,迁移成本主要在于抽象好向量库访问层"。这个回答既守住了当前选择,又展示了你对演进路径的思考。
7.3 几个高频问题的准备方向
- "你的检索为什么准/不准" → 从切分、召回、重排三段答,配 hit rate 数据。
- "Agent 会不会死循环" → 最大步数、终止条件、超时兜底。
- "上下文超了怎么办" → 分层记忆、摘要压缩、只保留引用。
- "怎么保证答案不瞎编" → 引用溯源、要求基于检索内容作答、输出校验。
- "成本和延迟怎么控" → 缓存、小模型、异步、批处理。
这些问题背后其实是同一件事:你有没有把项目当成一个要上线的系统来想,而不是一个跑通的 demo。想清楚这一点,术语自然就退到背景里了,你讲出来的每一句话都带着判断。
最后分享一个我自己的习惯:准备面试时,我会假装对面坐着一个完全不懂技术的人,试着把 DocResearch 讲给他听。如果他能听懂"这东西是干嘛的、为什么这么设计",那面试官一定也能听懂。术语是给同行省时间的,不是用来掩盖没想清楚的地方的。把每个模块的"为什么"讲透,比背一百个名词都管用。