抛开大厂的架构调整不说。
毫无疑问地,我将用最直白最不绕弯子的话告诉你。
我个人是飞书的重度用户,从今年一月份开始用。因为很多博主推荐飞书的多维表格,比如说我的好朋友苍何。所以后来我修改简历时的教育背景、实习经历、项目经历都会记录下来,目前已经 1000 多条了。

但如你所见,飞书的 AI 能力做的很差劲,让识别个 985、211、海外硕这种经常识别错,所以这次合并我个人觉得飞书的 AI 能力或许能再上升一个台阶。
另外,我必须得友好的提醒一句,你们评论的时候尽量克制一点,我会删的。😄
毕竟大厂的法务我可是惹不起的。
对于 Agent 来说,ToB 的场景我觉得确实比 ToC 的好挣钱。
B 端的用户至少是有付费意愿的,C 端能白嫖他不香吗?想收费变现,除非是你的 Agent 无可替代,做得像 Codex 和 Claude Code 那样。
所以大家也看到了,大厂的 Agent 都在发力两个方向,一个是 Coding,一个是 Work。
豆包和飞书合并,肯定也是想在 Work 层面更进一步。
大家也尽量往这两个方向靠,只有靠近最热门的方向,你的价值才能最大化,才能在 AI 时代分一杯羹喝。
如果你是一位愿意相信努力、相信过程、相信一步一个脚印、相信自己能在 AI 时代分一杯羹的人,那接下来这份硬核的面经,希望你能认真读一读。

(全文比较肝,保证大家能学到很多很多,系好安全带,我们粗粗粗粗发~)
content
01、讲一下 Claude Code 的架构?
老王推了推眼镜,低头扫了一眼简历,抬起头来的时候带着一股年轻面试官特有的好奇劲。“先聊点轻松的,你平时调试代码一般怎么调?”
“终端 Agent 主要靠日志和 trace 记录。每个节点的输入输出、工具调用结果、耗时都有快照,出了问题从 trace 里一步步回溯。”
“行。”老王端起茶杯喝了一口。“最近有没有关注什么新的 AI 内容?”
“AI 圈热闹啊,DeepSeek V4 正式版发布了,GLM-5.2 可以订阅了,Seedance 2.5 又进化了,GPT-5.6 也降价了,总之热闹的很。我个人也一直在做终端Agent,一直在升级迭代,类似 Claude Code,挺有意思的。”

老王眼睛亮了一下。“Claude Code 的架构你能讲讲吗?”

“最上面是 Harness,控制层。它管的是 Agent 能做什么、不能做什么——权限控制、上下文管理、文件系统访问、MCP 协议连接,都归 Harness。Harness 的设计决定了整个 Agent 的安全边界和能力边界。”
“中间是 Agent Loop,就是 ReAct 循环。LLM 接收上下文,决定下一步是调工具还是直接回复用户。每一轮循环就是一次思考、行动、观察。”
“最底层是 Tools,具体的执行能力。读文件、写文件、跑命令、搜索代码,每个工具有独立的输入输出定义。”
“三层之间分工清晰。Harness 管准入,Agent Loop 管决策,Tools 管执行。”
老王无名指上的戒指在灯光下晃了一下,他翻了翻简历。“Harness 这一层工程上的东西非常多,建议你下去之后再深入补一下。你简历上写了两个 Agent 项目,挑一个讲讲?”
02、简单讲讲你的Agent项目?
“三个项目,一个是 PaiCLI,一个是 PaiAgent,一个是派聪明。”
“PaiAgent 是一个 AI Agent 工作流编排平台,基于 LangGraph4j 和 Spring AI。核心是两个执行引擎——DAG 引擎走顺序节点执行,适合步骤固定的流程;LangGraph 引擎走状态图,支持条件分支和循环,适合需要动态决策的场景。”

“Agent 节点支持 ReAct 循环,可以挂载工具、接入知识库、读写记忆。多节点之间通过状态流转传递数据。”
“派聪明是一个 RAG 知识库,基于 Elasticsearch 的混合搜索,支持向量检索和关键词检索的组合打分,用来给 Agent 提供外部知识。”
03、短期记忆的具体实现方式是什么?
老王往前靠了靠。“你刚才说 Agent 支持记忆,短期记忆具体是怎么实现的?”
“短期记忆的核心就是对话历史列表。每一轮对话产生三部分内容——用户输入、模型响应、工具调用结果。这三部分按时间顺序存在一个列表里,每次调用 LLM 的时候,把这个列表拼进提示词的对话历史区域。”

“在 ReAct Agent 里还多了一层,就是 trace 列表。每一步推理的思考过程、选择的工具、工具输入参数、执行结果,都作为一条 trace 记录追加进去。下一步推理的时候,模型能看到之前所有步骤的完整轨迹,知道自己做过什么、还差什么没做。”
什么叫“快到上限了”?对话是怎么逐步叠加的?
“每一轮对话都会往上下文窗口里追加内容。模型回一段话,可能几百到上千 token。如果中间还调了工具,工具的返回结果也要追加进去,一次文件读取就可能几千 token。”

“一轮对话下来,差不多增加两三千 token。8 到 10 轮之后,上下文就轻松超过两三万 token,甚至更多。”
“‘快到上限’是相对的,要看系统提示词占了多少、模型的上下文窗口有多大,比如说DeepSeek V4 就是 1M 上下文,一个窗口就能完成很多任务。”
04、如果对话轮次过多,你怎么做优化?
老王摘下眼镜擦了擦,重新戴上。“假设现在已经聊了二十多轮,上下文快满了,你怎么处理?”
“三个策略配合用。”
“第一个是滑动窗口。只保留最近 N 轮对话,早期的对话直接移出上下文。这是最简单的方式,优点是实现成本低,缺点是早期信息直接丢了。”
“第二个是总结压缩。不是直接丢掉早期对话,而是让 LLM 把早期对话总结成一段摘要。原来十轮对话可能两万 token,压缩成一段摘要可能就一两千 token。信息密度提高了,空间占用降下来了。”
“第三个是分层管理。把上下文分成三个区域——最近两三轮保留原文,中期对话压缩成摘要,更早的内容如果有价值就写入长期记忆。三层各管各的,既保证近期对话的细节,又不丢失早期的关键信息。”

什么时候触发总结动作?
“两种触发条件。一种是按 token 计数,当前上下文的 token 数达到上下文窗口的某个比例,比如 80%,就触发一轮总结。另一种是按轮次,每隔几轮做一次。”

“实际工程里一般两种结合用。轮次是兜底策略,token 计数是精确策略。有时候一轮对话就带了大量工具返回结果,可能两三轮就达到阈值了。”
是每一轮对话都要做总结吗?
“不是。总结本身也要消耗一次 LLM 调用,有成本的。每一轮都总结,延迟上去了,而且频繁总结反而可能丢信息——每次总结都是一次信息压缩,压得太频繁,细节越丢越多。”

“所以是按阈值触发,够了才做。”
05、做了总结后,新一轮怎么处理?是重算前面所有轮还是累加?
“累加,不重算。”
“做法是这样的。第 10 轮触发了总结,前 10 轮的对话被压缩成一段摘要。第 11 轮开始,上下文里放的是这段摘要加上第 11 轮的原文。第 12 轮进来,上下文就是摘要加上第 11 和第 12 轮的原文。”

“等到第 18 轮,摘要加上后面 8 轮的原文又快到阈值了,再触发一轮总结。这次总结的输入是上一轮的摘要加上第 11 到 18 轮的原文,压缩成一段新摘要。”
“所以是滚动累加的,每次只总结增量部分,不回头重算全部历史。Claude Code 的上下文压缩就是这个思路。”
原始上下文就不需要了吗?
“不能完全丢。”
“最好的做法是保留三样东西。初始任务描述,就是用户最开始想要做什么。最近两三轮的原文,保证上下文连贯性。加上压缩后的摘要。”

“初始任务描述之所以要保留,是因为长对话容易跑偏。模型聊着聊着就忘了最初的目标,有了初始任务描述,模型每一轮都能对照,不至于偏太远。”
“完全丢弃原始上下文的风险是信息丢失。总结毕竟是压缩,压缩就有损失。”
06、长期记忆在什么情况下需要检索?
老王喝了口茶,换了个方向。“短期记忆聊清楚了,长期记忆呢?什么时候需要从长期记忆里检索内容?”
“两种触发方式。”
“第一种是显式触发。用户主动说‘记住这个偏好’或者‘我之前跟你说过的那个方案’,这种情况下 Agent 明确知道需要去查长期记忆。”

“第二种是隐式触发。用户没有明说,但当前对话涉及的主题和已存储的记忆有关联。这时候用当前对话的内容生成 embedding 向量,去记忆库里做相似度检索,余弦相似度超过阈值的记忆就召回注入上下文。”
“PaiAgent 里用的是第二种方式,topK 设成 5,就是每次最多召回 5 条最相关的记忆。”
每轮对话都要注入记忆吗?长短期记忆是同时注入吗?
“长期记忆不是每轮都注入。只有检测到相关性的时候才注入,否则就是白白浪费 token。”
“短期记忆是常驻的,每轮都在。因为对话历史就是短期记忆本身,不注入的话模型连上一句说了什么都不知道。”

“注入的位置也不一样。短期记忆放在对话历史区,就是 messages 列表。长期记忆放在系统提示词的上下文补充区,格式类似‘相关记忆:以下是之前的对话中保存的信息……’。位置分开,模型能区分哪些是当前对话的内容,哪些是跨会话召回的背景信息。”
07、如何减少工具过多带来的 Token 消耗?
“渐进式披露,分层加载。”
“第一层是索引。只把工具的名称和一句话描述放进系统提示词,不放完整的参数定义。二十个工具的索引,差不多也就两三千 token。”
“第二层是正文。LLM 看到索引后,判断当前任务需要哪个工具,再把完整的 JSON Schema 定义加载进来。用不到的工具,完整定义根本不进上下文。”

“PaiAgent 的做法是选择性加载——节点配置里指定需要哪些工具,只有指定的工具才会出现在系统提示词里。比如一个知识库问答节点,只需要检索工具和搜索工具,其他六七个工具的定义都不会出现。”
“另外,工具的描述和参数定义要尽量精简。一个工具的描述一句话说清楚就行,不需要写一大段解释。参数只定义必填的,可选参数能省则省。看起来是小事,但工具一多,每个省几百 token,加起来就是几千 token 的差距。”
老王把简历翻了个面,低头看了一眼。“你另一个项目是 RAG 知识库,对吧?聊聊这个。”
08、你的 RAG 是用什么技术实现的?
“ES 混合搜索。整个 RAG 管线分三步——向量化、检索、生成。”
“向量化用的是千问 Text Embedding V4,生成 2048 维的向量,存在 Elasticsearch 的 dense_vector 字段里,相似度度量用余弦相似度。”

“检索是两阶段的。第一阶段是 KNN(K 最近邻)召回,用查询向量在 ES 里做近似最近邻搜索,召回窗口设成 topK 乘以 30,就是要 5 条结果的话,先拉 150 个候选。第二阶段是 BM25 重打分,在候选集上跑关键词匹配,KNN 分数的权重是 0.2,BM25 分数的权重是 1.0。”
“最终排序以 BM25 为主导,KNN 做补充。这样设计的原因是纯向量检索在语义上表现不错,但有时候会召回语义相关但主题偏了的文档。加上 BM25 关键词匹配,能把真正包含用户提问关键词的文档排上来。”
“分块策略是 512 字符一块,100 字符重叠。重叠是为了避免语义信息在分块边界被切断。”
09、如何判断向量的相似度?
“用余弦相似度。”
“两个向量之间的余弦值,衡量的是方向上的接近程度。值域是 -1 到 1,1 表示方向完全一致,0 表示正交没有相关性,-1 表示方向完全相反。”

“计算方式是两个向量的点积除以各自模长的乘积。在 embedding 检索里,向量通常是归一化的,长度都是 1,这时候余弦相似度就等于点积,计算更快。”
除了余弦相似度,还了解其他相似度算法吗?
“了解几种。”
“欧几里得距离(Euclidean Distance),算的是两个向量在空间中的直线距离。距离越小越相似,和余弦相似度的方向相反。”
“曼哈顿距离(Manhattan Distance),也叫 L1 距离,是各维度差值绝对值的和。计算成本比欧几里得低,因为不需要开方。”

“点积(Dot Product),当向量已经归一化的时候,点积等价于余弦相似度。ES 里也支持配置为 dot_product。”
“还有 Jaccard 相似度,主要用在集合比较上,比如两个文档的关键词集合有多少重合。”
余弦相似度与欧几里得距离在工程应用中的具体区别是什么?
“核心区别是余弦看方向,欧几里得看位置。”
“余弦相似度对向量的长度不敏感。两段文本表达了同一个意思,但一段长一段短,embedding 向量的方向差不多但长度不同。用余弦相似度,方向接近就判定为相似。用欧几里得距离,长度不同会拉开距离,可能判定为不相似。”

“在文本 embedding 检索里,向量通常是归一化的,长度统一为 1。这种情况下余弦和欧几里得在排序上是等价的。但如果向量没有归一化,余弦更合适,因为我们关心的是语义方向,不是绝对大小。”
“欧几里得距离更适合特征值有实际物理意义的场景,比如推荐系统里的用户画像向量,每个维度代表一个具体的行为指标,这时候绝对值的差距是有意义的。”
10、项目中一共使用了几个模型?分别是什么?
老王眯着眼看了一下手表。“模型这块快速过一下,你一共用了几个模型?”
“两个。”
“第一个是千问 Text Embedding V4,负责文本向量化。把文档分块后的文本转成 2048 维的向量,存进 ES。检索的时候,用户的 query 也用同一个模型转成向量,和库里的向量做相似度计算。”
“第二个是 DeepSeek,负责最终的答案生成。把检索召回的文档块拼进提示词,让模型基于这些内容回答用户的问题。”

“没有单独的重排序模型。很多 RAG 系统会在向量召回之后加一个精排模型做二次排序,我们用的是 ES 的 BM25 重打分代替。好处是不需要额外部署模型,直接用 ES 原生能力,延迟也更低。”
11、如何控制模型的幻觉问题?
“四层控制。”
“第一层,系统提示词里强制要求调用搜索工具。在系统指令里明确写了,遇到任何非闲聊的问题,必须先调用搜索工具检索知识库,不搜就不允许回答。只有纯打招呼、纯翻译、通用编程数学题这几种情况可以跳过搜索。”
“第二层,低温度采样。生成参数的 temperature 设成 0.3,做摘要的时候甚至降到 0.2。温度越低,模型越倾向于选择概率最高的 token,减少随机性,也就减少了编造内容的可能。”

“第三层,来源标注。系统指令要求模型在回答时按引用编号标注信息来源。比如‘根据知识库内容 [1],这个接口的超时时间默认是 30 秒’。有了引用编号,用户可以点进去看原文,验证模型说的对不对。”
“第四层,显式兜底话术。如果搜索没有召回相关内容,系统要求模型明确说‘知识库中没有找到相关信息’,不允许自己编一个答案。”
12、如何观察模型召回了哪些块?
“做了一套引用追踪系统。”
“每次搜索工具返回结果的时候,每一条结果都会映射到一个引用编号——[1]、[2]、[3]。每个编号背后记录了一组元数据,包括来源文件名、PDF 页码、匹配到的原始文本、相似度分数、当时用的检索 query。”

“这些映射关系存在一个 Map 里,key 是引用编号,value 是完整的元数据对象。生成完成后,这个映射关系会和回答内容一起持久化。”
“前端拿到回答之后,发现文本里有 [1]、[2] 这样的标记,就渲染成可点击的引用链接。用户点击之后,调接口拿到这条引用的完整元数据,能看到原始文档的名称、具体第几页、匹配到的原文内容、相似度分数。”
“这个设计的好处是可追溯。用户发现模型的回答有问题,可以点引用看看是检索召回的内容本身就有问题,还是模型在生成环节出了偏差。开发的时候也方便调试,直接看引用信息就知道召回质量怎么样。”
PaiAgent 如何写到简历上?
项目名称:PaiAgent — AI Agent 工作流编排平台
项目简介:基于 LangGraph4j + Spring AI 的工作流编排平台,支持 DAG 顺序执行和状态图条件分支两种引擎模式,集成 ReAct 循环、多角色协作、记忆管理和知识库检索能力。
技术栈:Java 21 + Spring AI + LangGraph4j + MySQL + Redis + Elasticsearch

核心职责:
- 设计双引擎执行架构,DAG 引擎支持拓扑排序的顺序节点执行,LangGraph 引擎支持状态图条件分支和循环决策,根据任务特征自动选择引擎模式
- 实现 Agent 记忆管理系统,短期记忆通过对话历史列表和 ReAct trace 追踪当前任务状态,长期记忆通过 embedding 向量化持久存储并按余弦相似度检索召回,topK 默认 5 条
- 构建渐进式工具加载机制,节点配置指定所需工具集合,只加载指定工具的 JSON Schema 定义到系统提示词,避免全量工具占满上下文窗口
- 集成知识库检索能力,LLM 节点可绑定知识库 ID,运行时按可配置的 topK 和相似度阈值检索外部知识并注入上下文
- 设计节点快照和断点恢复机制,每个节点执行完成后持久化状态快照,支持从任意节点恢复执行,保障长流程任务的容错能力
派聪明如何写到简历上?
项目名称:派聪明 — 基于 ES 混合搜索的 RAG 知识库
项目简介:企业级 RAG 知识库系统,采用 Elasticsearch 混合检索(KNN + BM25)实现高精度文档召回,支持多格式文件解析、异步向量化管线和多租户权限隔离。
技术栈:Java + Spring Boot + Elasticsearch 8.x + Kafka + MinIO + 千问 Embedding V4 + DeepSeek Chat

核心职责:
- 实现混合检索管线,KNN 向量检索召回 topK×30 候选集,BM25 关键词重打分(KNN 权重 0.2 / BM25 权重 1.0)精排,替代独立重排序模型降低部署成本
- 设计幻觉控制流程,集成系统提示词强制搜索、低温度采样(0.2-0.3)、来源引用编号标注、显式兜底话术四层控制机制,减少模型编造内容
- 构建引用追踪系统,每条检索结果映射引用编号并记录文件名、页码、匹配文本、相似度分数等元数据,支持用户点击引用验证来源
- 实现多租户权限过滤,检索阶段在 ES 查询中注入用户权限条件(个人文档 / 公开文档 / 组织标签),保障数据隔离
- 设计异步文件处理管线,通过 Kafka 异步解析上传文件、分块(512 字符 / 100 字符重叠)、调用千问 Embedding 生成 2048 维向量并写入 ES 索引
ending
记忆管理、上下文压缩、混合检索、幻觉控制——这些词两年前在面试里基本不会出现。
新技术带来新问题,但解题的思路和以前一样:搞清楚原理,动手做出来,细节经得起追问。
加油吧,兄弟姐妹们。
下期见。
回复