Skip to content
掌握度

按简历四条核心职责组织的专项题库,每题带完整答案与演练状态。(演练状态见文末总览表)。配套:专项 · 实习题库、自我介绍。

第一部分 · Bullet 1:执行引擎与代码检索 ​

1. 「P95 < 200ms 这个数字怎么测的?测的是什么口径?」 ​

完整答案:

测的是 grep_code 工具调用的端到端耗时——包含 rg 进程 spawn、扫描、结果格式化和截断,不只是 rg 本身的扫描时间,这个口径和用户体感一致。方法:System.nanoTime 包住调用,先预热 15 次触发 JIT 和文件缓存,再连续采样 100 次、5 组代表性 pattern 轮换,取分位数。实测主路径 P50 约 12ms、P95 约 23ms,对简历的 200ms 有近十倍余量。仓库是本项目源码约 3.3 万行复制四份组成的 13 万行、约一千个 Java 文件——文件分布和真实项目一致,不是极端构造。

复盘要点:被追问「为什么报 P95 不报平均」——平均会被大量快查询拉低,工具调用体验取决于最差那一次,P95 是对上限体验的承诺。

2. 「为什么封装 ripgrep 而不自研?目标机器没装 rg 怎么办?」 必复检(第三场不知道) ​

完整答案:

自研不划算:rg 快在四件事——Rust 正则引擎 NFA 状态机没有回溯爆炸、字面量前缀用 memchr/SIMD 在字节层预过滤、多线程目录遍历吃满多核、感知 .gitignore 跳过构建产物还检测二进制文件。这些自己重写等于把人家十年打磨重做一遍还做不对,而且 Java 的 Pattern 有回溯灾难,单线程遍历也吃不满核。所以封装 rg 做主路径,留一个纯 Java 遍历加正则的兜底:触发条件是 rg 未安装、进程启动失败、执行超时——语义一致但慢,实测 P95 是主路径的三倍、P99 差近八倍。兜底的价值是裸环境(无 rg 的 CI 或容器)工具不失效;rg 的探测在启动阶段做一次,不在热路径反复探测。

3. 「检索工具有哪几种?Agent 什么时候用哪个?」 必复检(第三场不知道) ​

完整答案:

三种,互补不替代。grep_code:rg 封装的精确检索,字面量或正则定位,结果就是行号,零索引零维护;search_code:RAG 语义检索,用自然语言找「大概在哪」,依赖离线向量索引;glob_files:按文件名模式找文件。关系是「精确 → 语义 → 文件名」:主路径是 grep 定位到行、再 read 读上下文,search_code 只在不知道关键词、按意思找的时候用。为什么 grep 不建索引:grep 的价值就是零状态——即时、永远新鲜,代码刚改完索引没更新,搜出旧结果比慢更致命;要「按意思找」才值得建索引,那是 search_code 的线。

记忆口诀:精确、语义、文件名,三把尺子各量各的;grep 零状态永远新鲜,要语义才配建索引。

4. 「模型怎么在本地工具和 MCP 工具里选?依据什么?」 部分考过 ​

完整答案:

每个工具是一个统一结构:名字、描述、JSON Schema 参数定义、执行器,分九组注册进同一个 ToolRegistry,目前 16 个内置工具。模型选工具完全靠 name + description + JSON Schema——这叫「描述即路由」,描述的措辞质量直接决定选中的命中率,所以改工具必须联动改提示词和文档。MCP 工具接进来时走初始化和工具发现,把 name、description、inputSchema 拉回来,包装成和本地工具一样的接口注册进同一张表,模型侧完全无差别;mcp__ 前缀一物两用:命名空间隔离防覆盖,同时是审批路由的 key——带前缀的默认全部过人工审批。选错或参数不合法也有防线:schema 校验不过打回让模型修正,值越界被 PathGuard 拦,危险操作还有人审。

第二部分 · Bullet 2:Plan-and-Execute ​

5. 「DAG 里某个子任务失败了怎么办?什么条件重规划,什么条件不触发?」 新角度(拓扑排序 / 屏障可见性已考,见第二轮面经) ​

完整答案:

分两种情况。任务失败且整体进度不到 50%:说明计划可能有大问题,把已完成任务清单、各自结果和失败原因一起喂回 LLM 重新规划——prompt 里明确告知「这些已达成,只覆盖剩余目标」,防止把做过的事重做一遍。进度已过半:推翻重来的代价大于收益,记录失败继续跑,最后按「部分完成」收尾,把失败原因拼进结果汇报给人决定。另外如果某个失败导致下游永远等不到依赖,有「依赖未满足」的兜底,直接标记计划失败,不会死循环空转。执行主循环本身:每轮找出依赖全部完成的任务、按拓扑序排好、固定线程池四并发跑,invokeAll 等整批完成再提交下一批,找不到可执行任务就退出,按全完成、部分失败、依赖卡死三态收尾。

追问预案:「重规划怎么避免把已完成的再做一遍?」——靠注入不靠标记:重新规划的 prompt 里带上已完成任务清单和各自结果,明确告知只覆盖剩余目标。

第三部分 · Bullet 3:分层记忆与上下文 ​

6. 「动态阈值压缩:阈值怎么算?怎么压?摘要失败怎么办?」 必复检(第一场串台) ​

完整答案:

压缩的对象是真正发给 LLM 的消息历史——每轮调模型前评估它的 token 数。阈值不是固定比例,是从模型窗口算的:窗口减摘要输出预留、减安全缓冲,200k 窗口约 167k 触发,83% 左右。预留的道理:压缩本身要调一次 LLM 生成摘要,得给它留输出空间;缓冲是因为 token 是字符折算的启发式估算,不精确。压缩两条硬规则:最近三个用户轮次原样不动;切割点强制落在 user 消息边界——历史里 tool_call 和 tool_result 成对出现,从中间切开下一轮请求就是协议违约。切下来的旧消息整体摘要,重建成「system + 摘要 + 确认 + 最近三轮」,摘要要求保留用户目标、已完成操作、已确认结论和未完成事项。失败就跳过本次压缩、保留原历史,下一轮重新评估——重试是拿用户等待赌大概率还失败,硬截断保不住工具对和关键信息,半截历史比完整略超限更危险,只有跳过是零代价的。

串台警戒:滑窗保留最近 20 条是 RAG 项目的机制;CLI 的口径是「跳过压缩保留原历史」——两场面试已在此混淆过一次。

7. 「为什么用 JSONL 持久化会话?跨会话恢复怎么做的?」 ​

完整答案:

会话数据存在四个地方,各管一段:对话历史运行时在 JVM 堆内,同时以 JSONL 逐行落盘到用户目录的 history 下,跨会话可恢复;短期记忆在内存里,有独立 token 预算;长期记忆是 JSON 文件同步刷盘;代码向量索引在 SQLite 里,属于离线索引不算对话记忆。选 JSONL 三个理由:追加写便宜——每轮一条 append,不改历史文件;逐行可解析——某一行坏了不影响整个文件,容错好;人可读可审计——出问题能直接打开看。启动时读回内存,会话就能接着上次的上下文继续。

8. 「project/global 作用域怎么隔离?召回打分公式?」 后端岗考过 8 分 ​

完整答案:

先分两层:静态记忆是 CODEAGENT.md,项目规范启动注入 system prompt,跟 Git 走团队共享;动态是长期事实库,JSON 文件存盘。作用域隔离说的是动态库:每条记忆带 scope 字段,project 的只在绑定项目可见,global 的跨项目共享,检索时按当前项目路径过滤——A 项目的约定不会污染 B 项目。召回打分:查询先 jieba 分词,整句被记忆包含直接满分,否则算命中词占比,乘时间衰减——24 小时内从 1.0 线性降到 0.5、之后兜底 0.5——长期记忆整体再乘 1.2,因为比短期对话更精炼可信。排序取 top 10,按 token 预算截断注入,注入上限是窗口的千分之五、封顶 5000 token。

9. 「短期记忆和长期记忆为什么分开存?短期记忆超预算怎么处理?」 新题 ​

完整答案:

两者的数据形态和生命周期完全不同。短期记忆是会话内的原始记录——用户消息、助手回复、工具结果,有独立的 token 预算;超预算时不是直接丢:被淘汰的最旧条目先挪进待压缩区,等压缩触发时再由 LLM 摘要成 SUMMARY 回注——「先缓存、后丢失」。长期记忆是跨会话的精炼事实,JSON 文件同步刷盘、ConcurrentHashMap 加载,只存用户显式要求保存的内容。分开的理由:原始对话体积大、只服务当前任务;事实小而稳定、要跨会话即时可用——混在一起,既撑不住检索质量也管不住预算。另外项目里有两道压缩要分清:一道压短期记忆条目(Map-Reduce 分片摘要),一道压真正发给 LLM 的对话历史(一次性摘要)——前者管记忆系统内部,后者管实际请求的 token。

10. 「CODEAGENT.md 和长期记忆什么区别?加载流程是什么?」 新题(针对已知混淆点:长期记忆启动加载进的是内存,不是系统提示词) ​

完整答案:

这是静态记忆和动态记忆的区分。CODEAGENT.md 是静态层:项目规范、构建命令、代码约定——变化频率低、跟 Git 走、团队共享一份,由开发者维护。加载按优先级合并:用户全局目录下的 CODEAGENT.md → 项目根或 .code-agent-cli 目录下的项目级 → CODEAGENT.local.md 本地覆盖(不进版本库),支持 @path 导入其他文件,导入深度上限 3 层、总预算 24000 字符,防止记忆把窗口吃穷。长期记忆是动态层:运行中学到的用户事实和偏好,JSON 存用户目录、按 project/global 作用域隔离、检索召回 top 10 才注入。分开的理由:静态的由人维护、走版本控制,动态的由 Agent 管理、不能污染代码仓库;两者拼 system prompt 时静态先加载、动态后加载。

第四部分 · Bullet 4:安全链路 ​

11. 「『按任务回滚』和『历史版本恢复』分别是什么?能恢复到任意时点吗?」 半考过(回滚机制已考,恢复语义没钻) ​

完整答案:

快照锚点打在回合边界,分三个相位:任务执行前 PRE_TURN、执行后 POST_TURN、恢复前 PRE_RESTORE,用空提交做相位标记。按任务回滚就是恢复到某个任务执行前的 PRE_TURN 快照;历史版本恢复是按偏移量选择更早的 pre-turn 快照,比如回到最近第三次任务开始前的状态。能不能恢复到任意时点:不能,粒度是回合不是任意时刻——这是刻意的设计选择:回合粒度语义清晰(回到某个任务开始前)、数量有上限(默认保留 50 个,可配置),而且只允许恢复 pre-turn,post-turn 里可能已经包含改坏的产物,不满足「回到干净状态」的语义。恢复动作全程文件操作,恢复前先拍 pre-restore 快照,回滚本身也可撤销。

12. 场景题:「Agent 改坏了用户文件,用户要求恢复——从发现到恢复的完整流程?」 新题 ​

完整答案:

四步。① 回滚动作本身是危险操作,revert_turn 在危险工具名单里,先过 HITL 人工确认;② 确认后定位快照——每个任务执行前都有 PRE_TURN 相位快照,按偏移量选到目标任务之前的那一张;③ 恢复前先给当前状态拍一张 PRE_RESTORE 快照——回滚本身也可能出错,必须留退路;④ 恢复是纯文件操作:从快照仓库读目标树,和当前工作区做差异,多出来的文件删掉、变化的写回、空目录清掉,全程不碰项目的 .git,不做 checkout 和 reset。如果用户想回到更早的状态,按偏移量选更早的 pre-turn 快照重复同样流程。

边界主动交代:只能恢复到「某个任务开始前」的相位,不能恢复任意时点——post-turn 快照可能已包含改坏的产物,不满足「回到干净状态」的语义;快照默认保留 50 个、可配置。

13. 「简历写了限制『网络访问』——具体怎么限制的?」 新题 ​

完整答案:

和文件、命令一样,网络是分级管控的。联网能力是三个 web 工具——网页搜索、网页抓取、浏览器三件套——它们都在审批名单里:外部网络内容不可预测,和写文件、跑命令同级,触发 HITL 人工确认;MCP 提供的带 mcp__ 前缀的外部工具默认也全部审批。审批支持粒度化减负:可以对单个工具或整个 MCP server「全部放行」,但放行的只是「不再逐条问你」,PathGuard 和 CommandGuard 在放行后依然生效;而且信任边界变化会自动收紧——切换浏览器模式时清空放行状态、重新逐条确认,微信这类非交互渠道反向收紧到只读白名单。审计日志按天滚动 JSONL,完整记录每次网络访问的工具、参数和审批结果,写入前敏感信息脱敏,事后可追溯。

第五部分 · 综合定位 ​

14. 「市面已有 Claude Code、Cursor,你的差异化和价值是什么?」 新题(口径需内化成自己的话) ​

完整答案:

不和商业产品比功能覆盖,我的定位是终端、本地、模型无关、安全内建的自研实现。四个差异点:一是终端本地运行,代码不出机器,适配隐私和内网场景;二是模型无关——LlmClient 接口声明能力,五家 OpenAI 兼容的瘦实现可切换,换模型只动接入层;三是三条执行路径共享同一套工具、记忆、快照能力——架构铁律是不为某个模式造孤立功能,能力改进对三种模式同时生效;四是安全链路内建:审批、围栏、黑名单、审计加 Side-Git 快照,改坏可退。做这个项目的价值在于把 Agent 的内部机制——上下文工程、工具路由、安全边界——完整趟了一遍,这些判断可以迁移到任何 Agent 框架上。

答题纪律:不贬低竞品,讲「学到了什么 + 哪些判断可迁移」,不吹功能覆盖。

演练状态总览 ​

题号主题状态
1200ms 测量口径未考
2rg 不自研 + 兜底必复检
3三种检索分工必复检
4描述即路由复检
5replan 条件新角度
6动态阈值压缩必复检(防串台)
7JSONL 持久化未考
8作用域 + 召回复检
9短期 vs 长期新题
10静态 vs 动态新题(混淆点)
11回滚 vs 历史版本复检
12改坏恢复流程新题
13网络访问限制新题
14差异化定位口径需内化

本站仅供个人学习使用,请勿外传