diff --git a/docs/interview/qunar-ai-fullstack.md b/docs/interview/qunar-ai-fullstack.md index 396e984..ff0e45f 100644 --- a/docs/interview/qunar-ai-fullstack.md +++ b/docs/interview/qunar-ai-fullstack.md @@ -9,59 +9,239 @@ 常规开场,简要介绍个人背景、技术栈和项目经历。 +!!! tip "回答框架" + - **Who**:姓名、学历、工作年限 + - **What**:核心技术栈(如 Go/TypeScript + AI Agent) + - **Highlight**:1-2 个最有亮点的项目,用数据说话 + - **Why**:为什么投这个岗位,和 AI 全栈方向的契合点 + --- ## 2. 语言选择(Java / TypeScript) 选项只有 Java 和 TypeScript 两个,后续问题会根据选择的语言侧重点展开。 +**选择 Java 的考察方向**:JVM 原理、GC、并发编程、Spring 生态 + +**选择 TypeScript 的考察方向**:类型系统、异步模型、Node.js 运行时、前端工程化 + --- ## 3. 垃圾回收 GC 过程 -!!! note "💡 关键点" - - 对象从新生代 Eden → Survivor → 老年代的晋升路径 - - Minor GC / Major GC / Full GC 的触发条件 - - 分代收集模型:新生代(复制算法)、老年代(标记-清除 / 标记-整理) +### 3.1 内存分代模型 + +JVM 堆内存分为新生代(Young Generation)和老年代(Old Generation),新生代又细分为: + +```mermaid +graph LR + subgraph 新生代 + E[Eden 区] -->|对象优先分配| S0[Survivor 0] + E --> S1[Survivor 1] + S0 -->|Minor GC 后存活| S1 + S1 -->|Minor GC 后存活| S0 + end + subgraph 老年代 + O[Old Generation] + end + S0 -->|年龄达到阈值| O + S1 -->|年龄达到阈值| O + E -->|大对象直接分配| O +``` + +### 3.2 对象分配与晋升路径 + +1. **对象优先在 Eden 区分配**:大多数对象朝生夕灭,Eden 区采用指针碰撞(Bump the Pointer)分配 +2. **大对象直接进入老年代**:通过 `-XX:PretenureSizeThreshold` 设置阈值,避免大对象在 Eden 和 Survivor 之间来回复制 +3. **长期存活对象晋升老年代**:对象每经历一次 Minor GC 仍然存活,年龄计数器 +1,达到 `-XX:MaxTenuringThreshold`(默认 15)后晋升 +4. **动态年龄判定**:Survivor 空间中相同年龄所有对象大小总和大于 Survivor 空间一半时,年龄大于等于该年龄的对象直接进入老年代 + +### 3.3 三种 GC 类型 + +| GC 类型 | 触发条件 | 回收区域 | 停顿时间 | +|---------|---------|---------|---------| +| **Minor GC** | Eden 区满 | 新生代 | 短(复制算法,存活对象少) | +| **Major GC** | 老年代空间不足 | 老年代 | 较长 | +| **Full GC** | 老年代满 / 方法区满 / `System.gc()` | 整个堆 + 方法区 | 最长 | + +!!! warning "Full GC 触发的常见场景" + - 老年代空间不足且无法扩展 + - 方法区(元空间)不足 + - CMS GC 出现 Concurrent Mode Failure + - 显式调用 `System.gc()`(可通过 `-XX:+DisableExplicitGC` 禁用) + +### 3.4 各代回收算法 + +**新生代 — 复制算法(Copying)**: + +- Eden:S0:S1 = 8:1:1(默认,通过 `-XX:SurvivorRatio` 调整) +- Minor GC 时将 Eden 和一个 Survivor 中存活对象复制到另一个 Survivor +- 优点:无内存碎片,分配效率高 +- 缺点:浪费 10% 的 Survivor 空间;如果 Survivor 空间不够,需要依赖老年代的分配担保(Handle Promotion) + +**老年代 — 标记-清除(Mark-Sweep)**: + +- 标记所有存活对象,清除未标记对象 +- 优点:不需要移动对象 +- 缺点:产生内存碎片,大对象分配可能触发 Full GC + +**老年代 — 标记-整理(Mark-Compact)**: + +- 标记存活对象后,将所有存活对象向一端移动,然后清理边界外的内存 +- 优点:无内存碎片 +- 缺点:移动对象需要更新引用,STW 时间更长 + +### 3.5 经典垃圾收集器 + +| 收集器 | 算法 | 区域 | 特点 | +|-------|------|------|------| +| **Serial** | 复制 / 标记-整理 | 新生代 / 老年代 | 单线程,Client 模式默认 | +| **ParNew** | 复制 | 新生代 | Serial 的多线程版本,配合 CMS | +| **Parallel Scavenge** | 复制 | 新生代 | 关注吞吐量(`-XX:MaxGCPauseMillis`) | +| **CMS** | 标记-清除 | 老年代 | 低停顿,但有碎片 | +| **G1** | 分区 + 标记-整理 | 整个堆 | 可预测停顿,JDK 9+ 默认 | +| **ZGC** | 着色指针 + 读屏障 | 整个堆 | 停顿 < 10ms,JDK 15+ 生产就绪 | --- ## 4. 三色标记的第一阶段 STW 在干什么 -三色标记法将对象标记为白色(未访问)、灰色(已访问但子对象未全部访问)、黑色(已访问且子对象已全部访问)。 +### 4.1 三色标记法基础 -第一阶段 STW(Stop The World)的主要工作: +三色标记法是并发 GC 的核心算法,将堆中对象分为三类: -- **根节点枚举**:暂停所有应用线程,扫描 GC Roots(栈帧中的局部变量、静态变量、常量池引用等) -- **建立初始引用关系**:确保在并发标记开始前,堆中对象的引用关系是一个一致的快照 -- **防止并发标记期间的遗漏**:如果没有这个 STW,并发标记可能会漏掉某些从 GC Roots 新建立的引用 +| 颜色 | 含义 | +|------|------| +| **白色** | 尚未被扫描的对象。GC 结束后仍为白色的对象将被回收 | +| **灰色** | 已被扫描,但其引用的子对象尚未全部扫描完成 | +| **黑色** | 已被扫描,且其所有子引用都已扫描完成 | -!!! tip "追问方向" - - 为什么需要 STW?不 STW 会怎样? - - CMS 和 G1 在三色标记上的差异 - - 写屏障(Write Barrier)如何解决并发标记期间的引用变更问题 +### 4.2 CMS 的四阶段与第一阶段 STW + +CMS(Concurrent Mark Sweep)的完整 GC 流程: + +```mermaid +graph TD + A[初始标记 Initial Mark
⚡ STW] --> B[并发标记 Concurrent Mark] + B --> C[重新标记 Remark
⚡ STW] + C --> D[并发清除 Concurrent Sweep] +``` + +**第一阶段「初始标记」(Initial Mark)的 STW 做了什么:** + +1. **枚举 GC Roots 直接可达的对象**:扫描以下根节点集合 + - 虚拟机栈(栈帧中的局部变量表)中引用的对象 + - 方法区中类静态属性(`static` 字段)引用的对象 + - 方法区中常量(`final static`)引用的对象 + - 本地方法栈中 JNI(Native 方法)引用的对象 + - JVM 内部引用(如基本类型对应的 Class 对象、常驻异常对象、系统类加载器) + - 被同步锁(`synchronized`)持有的对象 + +2. **标记这些直接可达对象为灰色**:只标记 GC Roots 的直接引用,不递归遍历整个引用链 + +3. **建立并发标记的起点**:为后续并发标记阶段提供一个一致的、从 GC Roots 出发的起始快照 + +!!! note "为什么需要 STW" + 如果初始标记不 STW,在扫描 GC Roots 的过程中,应用线程可能修改引用关系(比如栈帧中的局部变量被赋值为新对象),导致某些 GC Roots 引用的对象被遗漏。初始标记只需要扫描 GC Roots,存活对象少,STW 时间通常很短(毫秒级)。 + +### 4.3 并发标记期间的问题与写屏障 + +并发标记阶段应用线程和 GC 线程同时运行,可能产生两个问题: + +**问题一:白色对象被黑色对象新增引用(漏标)** + +``` +初始状态:A(黑) → B(灰) → C(白) +并发修改:A(黑) → C(白) (B 不再引用 C) +结果:C 仍为白色,但被黑色对象 A 引用,会被错误回收 +``` + +**问题二:灰色对象删除了对白色对象的引用(误保留不算问题,只是多活一轮)** + +**CMS 的解决方案 — 增量更新(Incremental Update)**: + +通过写屏障(Write Barrier)在引用赋值时记录变化: + +```java +// 写屏障伪代码:当黑色对象新增引用时 +void write_barrier(Object* slot, Object* new_ref) { + if (current_phase == CONCURRENT_MARK) { + if (is_black(slot_object) && is_white(new_ref)) { + remark_set.add(slot); // 记录这个写入 + } + } + *slot = new_ref; // 执行实际赋值 +} +``` + +重新标记阶段(Remark,第二次 STW)处理这些记录,将被黑色对象新引用的白色对象重新扫描。 + +**G1 的解决方案 — SATB(Snapshot At The Beginning)**: + +通过写屏障在引用被覆盖前记录旧值: + +```java +// SATB 写屏障伪代码 +void write_barrier(Object* slot, Object* old_ref, Object* new_ref) { + if (current_phase == CONCURRENT_MARK) { + satb_queue.push(old_ref); // 记录被覆盖的旧引用 + } + *slot = new_ref; +} +``` + +SATB 保证并发标记开始时的引用快照中所有存活对象都会被标记,可能多标记(浮动垃圾),但不会漏标。 + +### 4.4 G1 与 CMS 的关键差异 + +| 维度 | CMS | G1 | +|------|-----|-----| +| 算法 | 标记-清除(有碎片) | 标记-整理(无碎片) | +| 区域 | 连续的新生代 / 老年代 | 将堆划分为等大的 Region | +| 并发标记策略 | 增量更新(Incremental Update) | SATB(Snapshot At The Beginning) | +| 停顿预测 | 不支持 | 支持(`-XX:MaxGCPauseMillis`) | +| Mixed GC | 不支持 | 支持(选择回收价值最高的 Region) | +| 碎片处理 | Full GC 时压缩 | 每次 GC 都做整理 | --- ## 5. 最有成就感的项目 -讲述一个完整的项目经历,重点包括: +!!! tip "STAR 法则回答框架" + - **Situation**:项目的背景和业务上下文 + - **Task**:你负责的具体任务和目标 + - **Action**:你采取的技术方案和关键决策 + - **Result**:量化的成果(性能提升 X%、成本降低 X%、效率提升 X 倍) -- **背景与目标**:为什么做这个项目,要解决什么问题 -- **技术选型与架构设计**:为什么选择当前方案 -- **关键难点与突破**:遇到了什么挑战,如何解决的 -- **最终成果**:量化的业务收益或技术指标 +**回答要点:** + +- **背景与目标**:为什么做这个项目,要解决什么业务痛点,目标指标是什么 +- **技术选型与架构设计**:为什么选择当前方案,对比过哪些替代方案,取舍的依据 +- **关键难点与突破**:遇到了什么技术挑战(如性能瓶颈、一致性问题、高可用保障),如何分析和解决的 +- **最终成果**:用数据说话,如 QPS 从 X 提升到 Y、延迟从 Xms 降低到 Yms、故障率降低 X% --- ## 6. AI 提效成果 -在项目开发过程中,AI 工具对效率的提升: +在项目开发过程中,AI 工具对效率的提升,需要有具体的量化数据和使用场景: -- **代码生成与补全**:减少重复性编码工作 -- **文档与注释生成**:自动化的文档维护 -- **问题排查与调试**:利用 AI 分析日志和定位问题 -- **设计与架构讨论**:作为技术方案的验证伙伴 +### 6.1 具体提效场景 + +| 场景 | 传统方式耗时 | AI 辅助耗时 | 提效倍数 | +|------|------------|-----------|---------| +| 重复性 CRUD 代码 | 2h | 20min | 6x | +| 单元测试编写 | 1h | 15min | 4x | +| 代码 Review(首轮) | 30min | 5min | 6x | +| 文档编写 | 2h | 30min | 4x | +| 问题排查与定位 | 1h | 15min | 4x | + +### 6.2 提效方法论 + +- **Context 工程**:给 AI 提供精准的上下文(项目结构、依赖关系、编码规范),而非泛泛的提示 +- **任务拆解**:将大任务拆成小的、可验证的子任务,每个子任务交给 AI 完成后人工验收 +- **迭代式开发**:AI 生成初稿 → 人工 Review → 反馈修改 → 再次验收,而非一步到位 +- **模板化 Prompt**:对高频场景(如 API 接口、数据模型)沉淀为可复用的 Prompt 模板 --- @@ -69,118 +249,628 @@ 生成 JSON 等结构化内容时,确保键的准确性和嵌套层级的正确性: -- **Schema 约束**:提供明确的 JSON Schema 或类型定义,约束输出格式 -- **结构化输出(Structured Output)**:利用模型的结构化输出能力,强制符合预定义 schema -- **分步生成**:先生成骨架,再填充内容,降低单次生成的复杂度 -- **后处理校验**:解析 JSON 进行 schema 校验,不通过则重试或修正 -- **Few-shot 示例**:提供目标格式的示例,让模型学习结构模式 +### 7.1 技术方案对比 + +| 方案 | 原理 | 可靠性 | 灵活性 | 延迟 | +|------|------|--------|--------|------| +| **JSON Mode** | 模型强制输出合法 JSON | 中(格式对,内容可能错) | 高 | 低 | +| **Structured Output** | 基于 JSON Schema 约束输出 | 高 | 中 | 低 | +| **Function Calling** | 模型输出工具调用参数 | 高 | 中 | 低 | +| **分步生成** | 先生成骨架再填充 | 高 | 高 | 高 | +| **后处理校验 + 重试** | 解析校验失败则重试 | 中 | 高 | 不确定 | + +### 7.2 Structured Output 实现原理 + +OpenAI 的 Structured Output 基于 **Constrained Decoding**(受限解码): + +1. 将 JSON Schema 转换为 **有限状态自动机(FSA)** 或 **上下文无关文法(CFG)** +2. 在每一步 token 生成时,根据当前状态和 schema 约束,**屏蔽不合法的 token** +3. 模型只能从合法 token 中采样,保证输出 100% 符合 schema + +```mermaid +graph LR + A[JSON Schema] --> B[转换为 CFG/FSA] + B --> C[受限解码引擎] + D[模型输出 logits] --> C + C --> E[屏蔽非法 token] + E --> F[采样合法 token] + F --> G[符合 Schema 的 JSON] +``` + +### 7.3 实践建议 + +- **提供严格的 JSON Schema**:定义 `required` 字段、`enum` 约束、`additionalProperties: false` +- **Few-shot 示例**:提供 2-3 个目标格式的完整示例,让模型学习结构模式 +- **分步生成复杂结构**:对于深层嵌套 JSON,先生成顶层结构,再逐层填充 +- **后处理兜底**:即使用了 Structured Output,仍需对内容语义进行校验(格式对不等于内容对) --- ## 8. Agent 场景与目标达成 -讲述实际构建的 Agent 场景: +### 8.1 Agent 核心架构模式 -- **场景定义**:Agent 要解决的具体问题 -- **工具链设计**:Agent 可调用的工具和能力 -- **任务分解与规划**:如何将复杂任务拆解为可执行步骤 -- **执行与反馈循环**:ReAct / Plan-and-Execute 等模式的应用 -- **目标达成评估**:如何判断 Agent 完成了任务 +```mermaid +graph TD + U[用户输入] --> P[Planning 规划] + P --> E[Execution 执行] + E --> O[Observation 观察] + O -->|未完成| P + O -->|已完成| R[最终结果] + + E --> T1[工具调用 1] + E --> T2[工具调用 2] + E --> T3[工具调用 N] +``` + +**主流 Agent 架构模式:** + +| 模式 | 原理 | 适用场景 | +|------|------|---------| +| **ReAct** | Reasoning + Acting 交替进行 | 通用任务,步骤不确定 | +| **Plan-and-Execute** | 先规划完整计划,再逐步执行 | 复杂任务,需要全局规划 | +| **Reflexion** | 执行后自我反思,失败时调整策略 | 需要试错的任务 | +| **Multi-Agent** | 多个 Agent 协作,各司其职 | 复杂系统,需要分工 | +| **Critic/Verifier** | 执行 Agent + 审查 Agent | 需要高可靠性的任务 | + +### 8.2 ReAct 模式详解 + +``` +Thought: 我需要查询用户的订单信息,首先需要调用订单查询 API +Action: query_orders(user_id="12345", status="pending") +Observation: 返回了 3 笔待处理订单 +Thought: 我需要对这 3 笔订单进行金额汇总 +Action: calculate_total(orders=[...]) +Observation: 总金额为 ¥15,000 +Thought: 任务已完成,可以给出最终回答 +Answer: 用户共有 3 笔待处理订单,总金额 ¥15,000 +``` + +### 8.3 工具链设计原则 + +- **单一职责**:每个工具只做一件事,通过组合实现复杂功能 +- **幂等性**:相同输入产生相同结果,支持安全重试 +- **错误处理**:工具返回结构化错误信息,Agent 可据此调整策略 +- **权限控制**:敏感操作(如删除、支付)需要人工确认(Human-in-the-Loop) --- ## 9. Agent 长期记忆管理 -对于 Agent 长期记忆,应该放什么以及如何管理: +### 9.1 记忆分层架构 -**哪些东西应该放进来:** +```mermaid +graph TD + subgraph 短期记忆 + W[工作记忆 Working Memory
当前会话上下文] + end + subgraph 中期记忆 + E[情景记忆 Episodic Memory
历史交互记录] + end + subgraph 长期记忆 + S[语义记忆 Semantic Memory
知识、偏好、经验] + P[程序性记忆 Procedural Memory
技能和操作流程] + end + W -->|会话结束| E + E -->|提炼总结| S + S -->|指导行为| P +``` -- 用户偏好与习惯 -- 历史交互中的关键决策和结论 -- 领域知识和经验 -- 任务上下文与状态 +### 9.2 记忆淘汰机制 -**管理策略:** +**LRU(Least Recently Used)— 最近最少使用**: -- **淘汰机制**:类似 LRU(最近最少使用)/ LFU(最不经常使用),对记忆条目按访问频率和时间进行淘汰 -- **优先级判定**:高优先级记忆(用户明确要求记住的、频繁使用的)不易被淘汰 -- **分层存储**:短期记忆(当前会话)→ 中期记忆(近期交互)→ 长期记忆(持久化知识) +``` +记忆队列:[A, B, C, D, E] (A 最近使用,E 最久未使用) +访问 C 后:[C, A, B, D, E] +新记忆 F 加入:[F, C, A, B, D] (E 被淘汰) +``` + +- 实现:双向链表 + 哈希表,O(1) 访问和淘汰 +- 优点:适合有时间局部性的场景 +- 缺点:不考虑访问频率,偶尔访问一次就能"续命" + +**LFU(Least Frequently Used)— 最不经常使用**: + +``` +访问计数:A=10, B=3, C=7, D=1, E=2 +淘汰:D(计数最低) +新记忆 F 加入,计数=1 +``` + +- 实现:最小堆或双链表 + 频率桶 +- 优点:考虑了访问频率,高频记忆不易被淘汰 +- 缺点:存在"历史热点"问题,早期高频但后期不再使用的记忆难以淘汰 + +**实际推荐 — 混合策略**: + +``` +score = α × recency(t) + β × frequency(f) + γ × importance(i) +``` + +- `recency`:时间衰减函数,如 `e^(-λt)`,t 为距上次访问的时间 +- `frequency`:访问频率,可用 log 平滑 +- `importance`:人工标注的重要性等级(如用户明确要求记住的 = 1.0,自动生成的 = 0.5) +- `α, β, γ`:权重参数,根据场景调优 + +### 9.3 记忆存储结构 + +```json +{ + "memory_id": "mem_001", + "content": "用户偏好使用 Go 语言开发后端服务", + "type": "semantic", + "source": "user_explicit", + "created_at": "2026-01-15T10:30:00Z", + "last_accessed": "2026-08-30T14:20:00Z", + "access_count": 42, + "importance": 0.9, + "confidence": 0.95, + "tags": ["preference", "language", "backend"], + "embedding": [0.12, -0.34, ...] +} +``` --- ## 10. 记忆部分冲突处理 -当多条记忆之间存在部分冲突时: +当多条记忆之间存在部分冲突(如两条记忆描述同一事物但细节不一致): -- **建立知识图谱**:将记忆中的实体和关系组织成图结构,便于推理和综合判断 -- **综合判断**:结合多条相关记忆的上下文、时间、来源进行加权分析 -- **置信度评估**:对每条记忆赋予置信度,冲突时优先采信置信度更高的记忆 -- **主动澄清**:当无法自动判断时,向用户确认 +### 10.1 知识图谱辅助判断 + +将记忆中的实体和关系组织为知识图谱: + +```mermaid +graph LR + M1[记忆1: 用户使用 MySQL 8.0] -->|存储| DB[(数据库)] + M2[记忆2: 用户使用 PostgreSQL 15] -->|存储| DB + M3[记忆3: 项目 QData 使用 MySQL] -->|项目| P[QData] + M4[记忆4: 项目 OpenAPI 使用 PostgreSQL] -->|项目| P2[OpenAPI] + + DB -->|推理| R[结论: 用户在不同项目中使用不同数据库] +``` + +### 10.2 冲突消解策略 + +1. **上下文化**:判断冲突是否因上下文不同导致(不同项目、不同时期),若上下文不同则两条记忆都保留 +2. **时间衰减**:更新的记忆通常更准确,赋予更高权重 +3. **来源可信度**:用户明确告知 > 从对话中推断 > 自动生成 +4. **置信度加权**:每条记忆有置信度评分,冲突时取置信度更高的 + +```python +def resolve_conflict(mem_a, mem_b): + # 1. 检查是否真正冲突(上下文不同则不冲突) + if mem_a.context != mem_b.context: + return [mem_a, mem_b] # 都保留 + + # 2. 时间加权 + time_score_a = exp(-lambda_ * (now - mem_a.created_at)) + time_score_b = exp(-lambda_ * (now - mem_b.created_at)) + + # 3. 来源可信度 + source_weight = {"user_explicit": 1.0, "inferred": 0.7, "auto": 0.5} + + # 4. 综合评分 + score_a = time_score_a * source_weight[mem_a.source] * mem_a.confidence + score_b = time_score_b * source_weight[mem_b.source] * mem_b.confidence + + return mem_a if score_a > score_b else mem_b +``` + +### 10.3 无法自动消解时 + +当置信度差异不大(如 score 差值 < 0.1),主动向用户澄清: + +> "我发现两条关于数据库选择的记忆存在冲突: +> - 记忆 A(2026-01-15):你提到项目使用 MySQL +> - 记忆 B(2026-06-20):你提到项目使用 PostgreSQL +> +> 请问哪条是正确的,或者它们分别适用于不同的场景?" --- ## 11. 两条记忆完全冲突 -当两条记忆完全矛盾时,根据环境风险等级采取不同策略: +当两条记忆完全矛盾(同一实体、同一上下文、相反的结论),根据环境风险等级采取不同策略: -| 环境类型 | 策略 | -|---------|------| -| **危险环境** | 直接输出两条冲突记忆,不做自动选择,由人工决策 | -| **安全环境** | 可配置优先级规则:按时间(新的优先)、按来源(权威来源优先)自动采纳 | +### 11.1 风险等级分类 -!!! warning "核心原则" - 在高风险场景下,宁可暴露冲突也不做错误的自动选择。安全第一。 +| 风险等级 | 场景示例 | 策略 | +|---------|---------|------| +| **危险(Critical)** | 医疗用药、金融操作、生产环境配置、权限变更 | 不做自动选择,暴露冲突,人工决策 | +| **安全(Safe)** | 代码风格偏好、文档格式、非关键配置 | 按优先级规则自动采纳 | + +### 11.2 危险环境处理 + +```mermaid +graph TD + A[检测到完全冲突] --> B{环境风险等级?} + B -->|危险| C[停止自动决策] + C --> D[输出两条冲突记忆] + D --> E[说明冲突内容和来源] + E --> F[等待人工决策] + F --> G[将决策结果写入记忆] +``` + +**原则**:宁可暴露冲突,也不做错误的自动选择。在医疗、金融、生产环境等高风险场景下,错误的自动选择可能造成不可逆的损失。 + +### 11.3 安全环境处理 + +可配置的优先级规则体系: + +```yaml +conflict_resolution: + rules: + - dimension: time + strategy: newer_wins # 新记忆优先 + weight: 0.4 + - dimension: source + priority: + - user_explicit # 用户明确告知 + - user_confirmed # 用户确认过的推断 + - inferred # 从对话推断 + - auto_generated # 自动生成 + weight: 0.4 + - dimension: access_count + strategy: higher_wins # 高频访问优先 + weight: 0.2 + fallback: ask_user # 规则无法判定时询问用户 +``` + +### 11.4 冲突检测机制 + +- **语义相似度**:使用 embedding 计算余弦相似度,相似度 > 0.8 的记忆对进入冲突检测 +- **矛盾检测**:对相似记忆进行 NLI(自然语言推理)判断,如果蕴含关系为"矛盾"则标记为冲突 +- **定期巡检**:后台定期扫描记忆库,检测新增记忆与已有记忆的冲突 --- ## 12. 如何评价是否达成目标 -评估 Agent 目标达成情况的方法: +### 12.1 Critic 架构详解 -- **打分量化**:定义评分维度(准确性、完整性、效率等),对结果进行 1-5 分量化评估 -- **Critic 架构**:引入独立的评估 Agent(Critic),对执行 Agent 的输出进行审查和打分 -- **参考标准对比**:将输出与预期标准进行对比,计算相似度或匹配度 -- **多轮迭代评估**:通过多轮交互逐步收敛,评估是否达到满意的最终状态 +```mermaid +graph TD + U[用户目标] --> A[执行 Agent] + A -->|输出| C[Critic Agent] + C -->|评分 + 反馈| J{达标?} + J -->|是| R[返回最终结果] + J -->|否| F[反馈修改建议] + F --> A +``` + +**Critic Agent 的评估维度:** + +| 维度 | 评分标准 | 权重 | +|------|---------|------| +| **准确性** | 输出内容是否事实正确 | 0.3 | +| **完整性** | 是否覆盖了所有要求 | 0.25 | +| **格式合规** | 是否符合预期格式和规范 | 0.15 | +| **效率** | 是否用最少步骤完成 | 0.1 | +| **可读性** | 输出是否清晰易懂 | 0.1 | +| **安全性** | 是否包含有害或不当内容 | 0.1 | + +### 12.2 多层评估体系 + +```mermaid +graph LR + subgraph 自动评估 + L1[格式校验 Schema Check] + L2[单测通过率] + L3[Lint 零告警] + end + subgraph AI 评估 + L4[Critic Agent 评分] + L5[多 Agent 投票] + L6[Adversarial Verify] + end + subgraph 人工评估 + L7[Code Review] + L8[用户验收] + end + L1 --> L4 --> L7 + L2 --> L5 --> L8 + L3 --> L6 +``` + +### 12.3 打分量化实现 + +```python +class GoalEvaluator: + def evaluate(self, task, output) -> dict: + scores = {} + + # 自动评估 + scores["format"] = self.check_format(output, task.schema) # 0-1 + scores["tests"] = self.run_tests(output, task.test_cases) # 0-1 + scores["lint"] = self.run_lint(output, task.lint_config) # 0-1 + + # AI 评估 + scores["accuracy"] = self.critic.evaluate( + prompt=f"评估以下输出的准确性,目标:{task.goal},输出:{output}", + rubric=ACCURACY_RUBRIC + ) # 1-5 + scores["completeness"] = self.critic.evaluate( + prompt=f"评估以下输出的完整性,要求:{task.requirements},输出:{output}", + rubric=COMPLETENESS_RUBRIC + ) # 1-5 + + # 加权总分 + weights = {"format": 0.15, "tests": 0.2, "lint": 0.1, + "accuracy": 0.3, "completeness": 0.25} + total = sum(scores[k] * weights[k] for k in weights) + + return {"scores": scores, "total": total, "passed": total >= 0.8} +``` --- ## 13. 如何应对 AI 幻觉 -在项目中应对 AI 幻觉的策略: +### 13.1 幻觉的分类 -- **Context 工程**:提供精准、充分的上下文信息,减少模型需要"猜测"的空间 -- **Sub-agent 评估**:引入独立的子 Agent 对主 Agent 的输出进行事实核查 -- **Hook 机制**:基于 hook 进行必要的 CI 检查,在关键节点验证输出的正确性 -- **Skill 补充背景**:在未知领域使用 skill 注入领域知识,降低幻觉风险 -- **检索增强(RAG)**:将回答基于检索到的实际文档,而非模型的参数记忆 +| 类型 | 描述 | 示例 | +|------|------|------| +| **事实性幻觉** | 生成与客观事实不符的内容 | 编造不存在的 API 或函数 | +| **忠实性幻觉** | 生成与输入上下文不一致的内容 | 检索到文档说 A,回答说 B | +| **推理幻觉** | 逻辑推理过程出错 | 数学计算错误、因果倒置 | +| **指令幻觉** | 偏离用户指令要求 | 要求生成 JSON 却输出 YAML | + +### 13.2 Context 工程 + +**核心思想**:减少模型需要"猜测"的空间,提供精准、充分的上下文。 + +```mermaid +graph TD + subgraph Context 构成 + S[System Prompt
角色、规则、输出格式] + K[Knowledge Base
项目文档、API 文档、规范] + H[History
对话历史、工具调用结果] + R[Retrieved Context
RAG 检索的相关文档] + end + S --> LLM + K --> LLM + H --> LLM + R --> LLM + LLM --> O[输出] +``` + +**关键实践:** + +- **项目规范注入**:将 CLAUDE.md 中的编码规范、命名约定、返回格式等注入 system prompt +- **实时上下文获取**:通过工具调用获取最新的代码状态、文件内容,而非依赖模型的参数记忆 +- **约束明确化**:明确告诉模型"不要猜测,不确定时说不知道" + +### 13.3 Sub-agent 评估(Adversarial Verify) + +引入独立的审查 Agent 对主 Agent 的输出进行事实核查: + +```mermaid +graph LR + A[主 Agent 输出] --> V1[验证 Agent 1
事实核查] + A --> V2[验证 Agent 2
逻辑检查] + A --> V3[验证 Agent 3
一致性检查] + V1 --> J{多数通过?} + V2 --> J + V3 --> J + J -->|是| R[接受输出] + J -->|否| F[要求重新生成] +``` + +**验证 Prompt 示例:** + +``` +你是一个严格的事实核查员。请验证以下输出中的每个事实声明: +1. 检查是否存在编造的函数名、API、类名 +2. 检查代码逻辑是否正确 +3. 检查与提供的上下文是否一致 +对于每个声明,给出 verdict: CONFIRMED / REFUTED / UNCERTAIN +``` + +### 13.4 Hook 机制 + +在关键节点插入自动化检查: + +```mermaid +graph TD + A[AI 生成代码] --> H1[Pre-commit Hook] + H1 -->|类型检查| C1{通过?} + C1 -->|是| H2[Lint Hook] + C1 -->|否| F1[修复] + H2 -->|代码风格| C2{通过?} + C2 -->|是| H3[单测 Hook] + C2 -->|否| F2[修复] + H3 -->|测试通过| C3{通过?} + C3 -->|是| M[合并] + C3 -->|否| F3[修复] +``` + +### 13.5 Skill 补充背景信息 + +在未知领域,通过 Skill 注入领域知识: + +- **场景**:AI 不了解项目的特定技术栈或业务领域 +- **方案**:将领域文档、最佳实践、常见陷阱封装为 Skill,在相关任务时自动加载 +- **效果**:AI 基于真实的领域知识回答,而非猜测 + +### 13.6 检索增强生成(RAG) + +```mermaid +graph LR + Q[用户问题] --> E[Embedding] + E --> S[向量检索] + S -->|Top-K 文档| C[Context 组装] + C --> LLM[大模型] + LLM --> A[基于文档的回答] +``` + +**降低幻觉的关键**:回答基于检索到的实际文档,而非模型的参数记忆。模型的角色从"知识库"转变为"文档阅读理解"。 --- ## 14. 如何遵守项目规范 -确保 AI 遵守项目规范的方法: +### 14.1 规范的层次结构 -- **明确的规范文档**:将项目规范写入 CLAUDE.md 或类似配置文件 -- **软件工程实践**:瀑布模型、敏捷开发等流程规范的约束 -- **统一约定**:如统一返回类、命名规范、代码风格等,通过配置和示例固化 -- **自动化检查**:Lint、类型检查、测试等自动化手段兜底 +```mermaid +graph TD + subgraph 第一层: 全局规范 + G1[语言规范 Go/TS] + G2[通用工程规范] + end + subgraph 第二层: 项目规范 + P1[命名约定] + P2[返回类格式] + P3[错误处理模式] + P4[目录结构] + end + subgraph 第三层: 团队规范 + T1[Git 提交规范] + T2[Code Review 标准] + T3[文档要求] + end + G1 --> P1 --> T1 + G2 --> P2 --> T2 + G2 --> P3 --> T3 +``` + +### 14.2 Claude Code 的规范实践 + +**CLAUDE.md 配置示例:** + +```markdown +# 项目规范 + +## 代码风格 +- Go: 遵循 Uber Go Style Guide +- TypeScript: 使用 ESLint + Prettier,严格模式 + +## 命名规范 +- 接口以 I 开头:IUserService +- 错误类型以 Error 结尾:NotFoundError +- 数据库模型以 Model 结尾:UserModel + +## 返回类格式 +统一使用 Result 包装: +{ + "code": 0, + "message": "success", + "data": T +} + +## Git 提交 +使用 Conventional Commits 格式 +``` + +### 14.3 软件工程实践约束 + +**瀑布模型(Waterfall)在 AI 辅助开发中的应用:** + +1. **需求分析**:AI 辅助梳理需求文档、生成用户故事 +2. **设计**:AI 辅助生成架构设计、数据库 ER 图、API 文档 +3. **实现**:AI 辅助生成代码,但严格遵循设计文档 +4. **测试**:AI 辅助生成单元测试、集成测试 +5. **部署**:AI 辅助生成 CI/CD 配置、部署脚本 +6. **维护**:AI 辅助日志分析、问题排查 + +**关键点**:每个阶段都有明确的输入和输出标准,AI 在每个阶段的工作需要经过人工验收才能进入下一阶段。 + +### 14.4 自动化检查兜底 + +| 检查类型 | 工具示例 | 作用 | +|---------|---------|------| +| 类型检查 | `tsc --noEmit`、`go vet` | 编译期错误捕获 | +| 代码风格 | ESLint、golangci-lint | 统一代码风格 | +| 安全扫描 | gosec、npm audit | 安全漏洞检测 | +| 测试覆盖 | `go test -cover`、Jest | 确保测试覆盖 | +| 提交规范 | commitlint | Git 提交信息规范 | --- ## 15. AI 工具选择与可靠性保障 -**使用的 AI 工具及原因:** +### 15.1 AI 工具生态 -- 选择标准:能力匹配、生态完善、可靠性高 -- 工具链搭配:不同工具在不同场景下的互补使用 +| 工具 | 定位 | 核心优势 | 适用场景 | +|------|------|---------|---------| +| **Claude Code** | CLI Agent | 深度代码理解、工具调用、多文件编辑 | 复杂编码任务、项目级重构 | +| **Cursor** | IDE 集成 | 内联补全、上下文感知 | 日常编码、快速原型 | +| **GitHub Copilot** | 代码补全 | 广泛的语言支持、低延迟 | 代码补全、单元测试 | +| **ChatGPT/Claude** | 通用对话 | 强推理、多模态 | 技术方案讨论、文档编写 | -**可靠性保障措施:** +### 15.2 Harness(执行框架) -- **好的 Harness**:构建可靠的执行框架,管理工具调用和状态流转 -- **达成目标的标准**:明确的任务完成标准和验收条件 -- **Hooks 机制**:在关键节点插入检查和干预逻辑 -- **Sub-agent 审查**:独立的子 Agent 进行交叉验证 -- **Code Review**:人工或自动化的代码审查,确保输出质量 +Harness 是管理 AI Agent 执行的核心框架: + +```mermaid +graph TD + subgraph Harness 核心组件 + PM[Permission Manager
权限管理] + CM[Context Manager
上下文管理] + TM[Tool Manager
工具管理] + SM[State Manager
状态管理] + HM[Hook Manager
钩子管理] + end + U[用户输入] --> HM + HM --> CM + CM --> LLM[大模型] + LLM --> TM + TM -->|工具调用| PM + PM -->|授权| EX[执行] + EX --> SM + SM -->|状态更新| CM +``` + +**Harness 的关键职责:** + +- **权限管理**:哪些操作需要用户确认,哪些可以自动执行 +- **上下文管理**:维护对话历史、工具结果、文件状态 +- **工具管理**:注册、调用、结果处理 +- **状态管理**:任务状态、进度追踪、错误恢复 +- **Hook 管理**:在关键节点插入自定义逻辑 + +### 15.3 可靠性保障体系 + +```mermaid +graph TD + subgraph 预防 + H1[明确的目标定义] + H2[详细的规范约束] + H3[充分的上下文] + end + subgraph 检测 + D1[Sub-agent 交叉验证] + D2[Hook 自动检查] + D3[Critic 评分] + end + subgraph 纠正 + F1[自动重试] + F2[人工介入] + F3[回滚机制] + end + H1 --> D1 --> F1 + H2 --> D2 --> F2 + H3 --> D3 --> F3 +``` + +**具体措施:** + +1. **达成目标的标准**:在任务开始前明确定义"完成"的条件(Definition of Done),避免主观判断 +2. **Hooks 机制**: + - `preToolUse`:工具调用前检查参数合理性 + - `postToolUse`:工具调用后验证结果正确性 + - `preCommit`:提交前运行 lint、测试、类型检查 +3. **Sub-agent 审查**:独立的子 Agent 从不同角度(正确性、安全性、性能)验证输出 +4. **Code Review**:AI 生成的代码必须经过人工 Review,重点关注边界条件和异常处理 +5. **渐进式信任**:从简单任务开始验证 AI 能力,逐步增加任务复杂度 + +### 15.4 工具选择原则 + +- **能力匹配**:工具的核心能力要与任务需求匹配 +- **可控性**:优先选择有良好权限控制和审计能力的工具 +- **可组合性**:工具之间可以组合使用,形成完整的工具链 +- **成本效益**:在质量和成本之间取得平衡 --- @@ -188,11 +878,18 @@ 这次去哪儿的 AI 面试整体考察深度不错,涵盖了: -| 考察维度 | 题目 | -|---------|------| -| 语言基础 | GC 过程、三色标记 | -| 项目经验 | 有成就感的项目、AI 提效 | -| AI 工程实践 | 结构化输出、Agent 设计、记忆管理、幻觉应对 | -| 系统设计思维 | 冲突处理、目标评估、规范遵守、可靠性保障 | +| 考察维度 | 题目 | 核心考察点 | +|---------|------|-----------| +| 语言基础 | GC 过程、三色标记 | JVM 底层原理理解深度 | +| 项目经验 | 有成就感的项目、AI 提效 | 实战经验和量化思维 | +| AI 工程实践 | 结构化输出、Agent 设计 | AI 集成的技术深度 | +| 记忆管理 | 记忆存储、冲突处理 | 系统设计和边界处理 | +| 可靠性工程 | 幻觉应对、规范遵守、工具保障 | 工程化思维和质量意识 | 核心考察点在于 **AI 工程化能力** — 不只是会用 AI,而是如何可靠地将 AI 集成到实际项目中。 + +!!! tip "面试准备建议" + - GC 和三色标记是 Java 面试的高频考点,需要理解到源码级别 + - AI 相关问题需要有实际项目经验支撑,不能只谈理论 + - 记忆管理和冲突处理是 Agent 系统的核心难点,需要有具体的方案设计 + - 可靠性保障是区分"会用 AI"和"能工程化 AI"的关键