跳转至

一面面试记录整理

说明:本文根据语音转录整理,已修正明显的 ASR 识别错误、口癖和重复表达。

1. 开场与自我介绍

面试官: 喂,你好,可以听见吗?

候选人: 嗯,可以。

面试官: OK,咱们本次面试大概会持续 30 分钟。你这边先做一个自我介绍。

候选人: 面试官你好,我叫刘玄昊,现在就读于瑞典查尔姆斯理工大学,专业方向是计算机系统与网络,预计 2027 年毕业。本科就读于哈尔滨工业大学(深圳),专业是计算机科学与技术。

我目前主要的项目,也是硕士论文相关项目,是一个多阶段 agent 工作流。它面向一个比较垂直的领域:对代码库进行漏洞审查、修复和验证。具体来说,我使用 LangGraph 和 LangChain 构建了这个工作流,最终效果和市面上通用的 coding agent 接近。这里说的通用 coding agent 包括 Claude Code、SWE-agent、OpenCode 这一类工具。

目前在专门的漏洞数据集 PatchEval 上,230 个 CVE 任务中能达到 78/230 的成功率,已经接近目前最高的 79/230。

2. 项目效果与模型评测对比

面试官: OK,那如果不用你这个东西,它能达到多少?

候选人: 这里需要区分 agent 和 model。如果用 Claude Code 搭配 GPT-5,能达到 79/230。我这边是用自己的工作流搭配 DeepSeek V4 Pro,能达到 78/230。

如果考虑模型本身没有完全控制变量,这一点确实没办法完全比较,因为 GPT-5 现在比较难获得。但就我的观察来看,DeepSeek V4 Pro 可能没有 GPT-5 那么强,所以我认为我的工作流在这个垂直任务上表现相对更好。

另外还有 token 消耗方面。整体来看,我这个工作流的 token 消耗比 Claude Code 这一类工具略低一些。不过这一点没有写在简历里,也还没有做非常完整的对照实验。

面试官: 嗯,因为要控制变量的话,肯定是说用你这个工作流和其他 agent 搭配同一个模型比较。

候选人: 对,无论是都用 GPT-5,还是都用 DeepSeek V4 Pro,这样控制变量肯定更严谨。但当时主要是成本限制。我们 5 月份跑 DeepSeek V4 Pro 的时候,成本正好比较低;如果再去跑 Claude Code + DeepSeek V4 Pro,或者全 GPT-5 的对照实验,消耗会比较大。当然如果要进一步做,这个实验肯定是可以补的。

面试官: 嗯,比如说你可以用 Claude Code 搭配 DeepSeek V4 Pro。

候选人: 对。目前如果没有这个控制变量,确实很难完全说明效果到底体现在模型上还是工作流上。

3. 项目亮点与端到端架构

面试官: OK,那你讲一下这个项目里的一个亮点吧。

候选人: 我大概从两个方面来说。

第一个方面是论文背景和项目背景。漏洞修复这个领域,早期从深度学习开始,通常需要自己构建数据集、训练模型,再进行评估。它的局限性有两个:一是需要自己准备数据并训练模型;二是模型容易局限在某一类语言或场景里,比如只在 C++ 或 Java 上收集数据,泛化到其他技术栈时效果可能不好。

后来这个领域进入大模型阶段。早期大模型方法还没有明显使用 agent,更多是把相关的漏洞代码片段、提示信息交给 LLM,让它生成修改,或者做类似代码填空的任务。但现在我们知道,大模型可能会产生幻觉;如果只是简单地基于片段生成补丁,最后产出的代码可能连编译都过不了,或者有很多显而易见的问题。因此后续就发展到了使用 agent 来处理这个任务。

在 agent 阶段,还可以再细分为两个方向:一个是用 agent 处理一般 bug,另一个是用 agent 专门处理漏洞。前者可以叫自动代码修复,后者则更接近自动漏洞修复,是更细分的领域。

我们调研相关论文时发现,真正做这个垂直领域的并不多。少数相关工作比如 2023、2024 年左右的 PatchAgent,也是专门做漏洞修复,但它的问题是比较局限于 C/C++ 技术栈,同时还依赖很多专门设计的编译链工具和检查工具,比较难泛化到其他领域。

而我们的项目更容易泛化到不同技术栈,比如 Java、JavaScript、Python、Go 等。

第二个亮点是端到端。很多漏洞修复或代码修复 agent,即使用 Claude Code、OpenCode 这类工具,也没有完全解决端到端问题。

比如现在代码库里有一个 issue,里面描述了某个问题。agent 可以基于这个 issue 结合代码库分析问题、修复问题。但这里有一个前提:你已经给了它一个起始方向。如果连这个起始方向都没有,就需要更前置的流程。

我们所谓的端到端,是指不仅能处理已经给定的问题,还可以直接给定一个代码库,在没有 issue 描述或其他触发信息的情况下,先由 agent 扫描代码库,寻找可能的问题;找到多个候选问题后,再分别把每个问题交给特定的问题分析和修复工作流。

除了前置发现流程,还需要后置交付流程。比如在 issue 评论区 at 这个 agent 或 GitHub App,让它进行分析和回复。agent 分析完问题后,还需要把结果整理成回复并上传。

再比如全量扫描代码库的场景:扫描后可能发现很多漏洞,并且针对每个漏洞生成了 patch。这些 patch 之间有些不相关,有些相关,甚至可能修改同一个代码文件。这时就需要对 patch 做合并,把相关修改整合成一个更大的 patch,再以 pull request 的形式交付到代码库,而不是给用户一堆零散的报告和 patch。

所以这个项目的亮点是:既覆盖了前置的漏洞发现过程,也覆盖了问题分析后的交付过程。基本上现有项目或论文较少完整做到这一点,因此我们的项目会更产品化一些。

4. 项目落地与实践方式

面试官: 那你们这个项目如果更产品化的话,是不是也会在一些仓库里实践过?

候选人: 对,已经实现过。现在主要实践方式是和 GitHub 连接。整个项目架构分为两部分:一部分是处理任务的 agent 端,另一部分是 GitHub App 端。

GitHub App 端会注册到代码库里,并获得一定权限,比如访问代码库、发布评论、修改代码等。产品场景主要有几类。

第一类是 issue 场景。比如代码库里有一个 issue,用户在下面 at 我们的 bot,系统会收到这个事件,然后拉取代码库,把 issue 描述一起交给 agent。agent 处理完后,会把结果整合成评论发送到 issue 页面。如果涉及代码修改,不仅会发布评论,还会创建一个相关联的 PR,并在评论中关联这个 PR。

第二类是 pull request 场景。比如有人提交了一个 PR,PR 本身有描述,也包含一些 commit 和修改文件。用户可以在 PR 下 at 这个 bot,请求会发送到系统这边。后续流程类似:系统处理后在 PR 下评论;如果有代码修改,也可以显示为 PR 上的建议修改。

第三类是代码库全量扫描。目前我是通过 GitHub Actions 来做的。用户可以写一个 action 来触发工作流,向系统发送 HTTP 请求。系统拿到权限后拉取代码库,然后让 agent 端执行全量扫描。

整体来说,这个项目比较容易迁移到其他平台。agent 端主要是 Python、LangChain 相关实现,GitHub App 端目前是 TypeScript 维护。如果之后想接入 GitLab 或其他平台,只需要替换 App 端的适配层,agent 端可以保持相对独立。

5. 任务平台与工具调用

面试官: 不知道你们有没有接触过那种任务平台,比如说 MotiaLinear 那种。

候选人: 您说的任务平台,尤其是您提到的这几个,我不是特别了解,也没有听说过。您具体指的是哪一类?

面试官: 比如我自己通过跟大模型对话,然后给它我的 CLI,是不是也能实现这个功能?

候选人: 我理解您的意思是:假设有一个单智能体,让它拿到一个 GitHub CLI token,或者临时 token,然后它通过这个 token 获取代码库,直接把代码库拉下来,进行分析,最后再调用 CLI 把 PR 或 description 发出去。

理论上是可以的。比如做 demo 的时候,完全可以给 agent 一个 CLI 权限,或者给它一个 MCP,再加一个专门教它如何使用 GitHub CLI 的 skill。

但问题是,这种方式的操作可控性比较弱。我目前的做法是 GitHub App 端拿到权限后,由系统负责把代码库拉下来,并通过 HTTP 方式准备任务。也就是说,把所有需要的东西,包括代码库、issue 描述、patch 以及相关信息,打包后交给 agent 后端。agent 后端拿到这些输入后再进行处理。

我认为 agent 可以做得很 demo,也可以做得很产品化。如果只是自己用,或者做一个临时工具,可以给 agent 很大的权限。但如果要进一步做成产品,我不太认为可以完全采用这种方式。权限、输入、输出和执行边界都需要更明确。

6. Agent 记忆机制

候选人: 刚才其实我还少说了一个亮点,和论文主体关系不是很大,但我也做了一个 agent 记忆机制。

目前 agent 记忆有很多不同方案。最简单的,比如 Claude Code 和 Codex 的做法相对比较简单,类似 skills 机制。通常有一个 SKILL.md,可能还有 references、可使用的 scripts、templates 等。

Claude Code 和 Codex 的做法类似:有一个全量读取的 memory 文件,同时还有一些可以渐进式披露的 topic。topic 目录下会组织一些 Markdown 文件,类似 references。除此之外,机制里还可以包括:运行中的 agent 读取 memory、写 memory,以及后台从 agent 运行记录中提取经验,并对 memory 做整体整理,比如去重、把碎片化内容重新组织起来。

我这里的 memory 机制相当于把这几类能力整合起来。

一方面,我们会从 agent 整体运行轨迹中提取经验。运行轨迹包括一次任务里的所有 message,例如 LLM 调用、工具调用等。我们会把这些原始记录作为记忆提取来源,先做一轮初步提取,从中抽取可能有用的经验。

另一方面,提取出的经验还需要进一步整理到 memory 目录里。这一步由整理 agent 完成:它读取刚才生成的经验记录,并把这些经验整合进 memory,组织成 memory 加 topic 文件的形式。最后,这些文件可以供正在运行的 agent 读取。

如果想做得更复杂,也可以参考腾讯的 Tencent Agent Memory。它们的层级会更复杂。比如 skills 明显只有两层:第一层是 SKILL.md 开头的小段描述,第二层是 references;但腾讯的项目可能会有三级、四级、五级,不仅有层次,还会结合关键词检索、RAG 等。

不过我个人不是非常赞同把记忆做得过于复杂。记忆不应该庞大到必须依赖关键词检索、BM25 或 RAG 才能查找。它应该保持相对简短和可维护。

如果运行很长时间后积累了大量记忆,我认为更好的做法不是继续检索这些记忆,而是通过后台流程对记忆进行治理。比如把可复用经验提升成 skill,或者在你完全掌握产品的情况下,把关键内容提升为 system prompt。否则收集了大量经验,却只是静静躺在 memory 里等待 agent 去读,我认为是不好的。

有些现象也支持这个观点。比如 Hermes 宣称自己能够记忆用户偏好,但有用户反馈,一开始使用时它记忆收集得很好,会让人感觉它很懂自己;但越用到后面,反而感觉它更不懂自己了,很多东西很难找回来。这就是记忆太多的问题。记忆多到一定程度,即便有检索方案甚至 RAG,也可能不够用。

所以我认为,光有记忆还不够,还需要后续治理。无论是提升到 prompt,还是设计成 skills,这些步骤都是不可避免的。

面试官: 这种治理肯定是需要的。但如果像刚才说的,你完全掌握这个产品,然后在产品里把这些记忆提升到 prompt 或 skill,可能只适用于一个比较垂直的领域。如果是一个比较通用的场景呢?

候选人: 这个确实要分产品和个人使用。

比如 Hermes 宣称自己可以自动做提升,也就是把 memory 提升成 skills 或 prompt。这个可以理解为把经验升华,因为它是从 memory 到 skill。

腾讯的项目也类似,它们下一阶段目标也是把 memory 里最重要的东西提炼成 skills,形成一个 memory 闭环。

但我想说,这两类更多还是个人使用场景。说到底,memory 哪怕有多层结构,本质上也是以 prompt 或某种特定方式注入给 agent。

如果是真正上线的产品,我认为基本不会允许在用户正常使用过程中,自动调整 system prompt 或自动调整 skill 装载。这是不太可能的。

即使在 prompt engineering 阶段,我们对 prompt 做迭代,也至少需要在测试集上验证。测试集里要包含极端数据和常规数据,必须证明这个东西提升到 system prompt 或 skill 之后确实有用,才能真正合入。

所以这是产品和个人使用的区别。个人使用可以随意提升 skill 或修改 prompt;但产品场景一定需要验证。无论是修改 prompt、增加或修改 skills,还是给 agent 增加 MCP,都要证明它有效。通常需要在测试集上跑,也可能需要灰度一段时间,看用户反馈。这就涉及评估体系了。

7. 数据库选型与技术栈

面试官: 你对向量数据库的了解,比如说你能对现在的向量数据库做一下比较吗?

候选人: 最早发展比较早的应该是 FAISS。不过 FAISS 更偏小型化、学术化,也更倾向于本地使用。

我在做项目时也换过不少方案。最终考虑到希望更接近生产环境,所以用了 Milvus。目前还是以 standalone 形式跑,但 Milvus 本身可以扩展到分布式。

面试官: 我看到你有用 PostgreSQL。

候选人: 对,这涉及文档切 chunk 后怎么存的问题。

如果只是考虑分 chunk,可能存下来就可以。但如果在线检索阶段还需要关键词检索,就需要维护一个倒排索引或者分词后的检索系统。我们这里用的是 OpenSearch,企业项目里也可能用 Elasticsearch,用来做关键词检索。

PostgreSQL 的作用是维护文档和 chunk 的元数据。比如我们用了父子切割,那么除了每个 chunk 本身,还需要存文档元数据、parent chunk、children chunk 等信息。这些东西不太适合只存到向量数据库里。向量数据库主要存向量,但还有很多结构化信息需要其他数据库配合检索。

面试官: 你是对 Java 比较了解,还是对 Python 比较熟?

候选人: 相对来说我对 Java 更了解一些。如果对比 Python 和 Go,我可能对 Go 也比较了解。整体来说各方面都有涉猎。

最近主要在用 Python,因为 agent 项目和相关研究大部分都用 Python 写。比如 LangChain 生态里,最发达的是 Python,其次可能是 JavaScript;Java、Go 相关生态就少很多。

8. LangChain 与 LangGraph 对比

面试官: 你说一下 LangChain 和 LangGraph 的区别吧。

候选人: 最开始可以从 LangGraph 说起。LangGraph 本质上是在构建一个图,图上有节点。比如从 start 开始,接一个 LLM 节点,再接一个 tool 节点,再接一些其他自定义处理节点。它的好处是可以把工作流设计得很严谨,但问题是比较底层。如果要快速做产品或 demo,直接用 LangGraph 会比较费时间。

LangChain 则更高一层。它最核心的能力之一是 create_agent,大概是去年年底或今年 1 月份正式推出的。它相当于封装了一个基本的 ReAct agent。如果直接用 LangGraph,当然也可以自己实现一个,但会更耗时间,也需要自己管理很多东西。用 LangChain 的 create_agent 可以更快地搭出一个 ReAct agent。

LangChain 还有一个重要能力是 middleware。比如可以添加 filesystem middleware,让 agent 获得访问文件系统的一套工具和 prompt,也可以理解成一种插件机制。再比如 summary middleware,在上下文过长时保存最近几轮对话,并压缩更早之前的对话。还有很多其他 middleware。它的优势是你不需要从底层开始搭,而是可以拼装组件。

如果从层级上看,底层是 LangGraph,往上一层是 LangChain,再往上一层现在还有 DeepAgents。DeepAgents 基于 LangChain,给 create_agent 默认加了一些组件,比如 skills、文件系统访问、summary 等。整体上是一层一层封装上去的。

具体项目怎么选,主要看项目阶段和需要的控制力度。

我的项目一开始尝试过用 DeepAgents,但我发现它的控制力度太粗了。有些地方我需要自己设计,就不能完全依赖 DeepAgents。它很适合作为快速跑 demo 的工具,但如果要进一步调优,就需要切换到 LangChain。

至于为什么还没有从 LangChain 直接切换到 LangGraph,是因为 LangGraph 层级太低,需要自己控制的东西太多。至少对我这个项目来说,还没有到必须用 LangGraph 控制这么细的程度。

当然,我也知道有些文章会说 LangGraph 的控制能力更好。但我认为有些文章对 LangGraph 和 LangChain 的判断已经有点过时了,因为 LangChain 本身也在持续发展。

9. 反问环节与结束语

面试官: 那我这边暂时没有别的问题,看你这边有没有什么问题想咨询一下。

候选人: 我想问一下,贵司的 AI 技术栈大概是什么?比如基础技术栈、框架,或者一些提示都可以。

面试官: 技术栈主要还是 Python、LangGraph、Neo4j 这些。

候选人: 大概了解。其实有些人会说,LangChain 已经不太适合个人开发者拿来开发自己用的项目,这一点我比较认同。

我刚才一直在强调产品和个人使用的区别。如果是做真正用于产品的项目,用 LangChain、LangGraph,甚至是正在快速迭代的 DeepAgents,都是比较合理的。因为产品场景最终需要更多地控制这些东西。所以从这个角度看,很多地方使用 LangChain 或 LangGraph 是很正常的。谢谢您。

面试官: 那我们今天的面试就先到这里,感谢你的时间。

候选人: 好,谢谢您,再见。