跳转至

去哪儿 AI 面 — AI 全栈方向

面试形式:双机位(手机也要开摄像头),共 8 轮问答,每轮内会提一个问题并根据回答进行追问 以下内容仅根据回忆记录,未录音


1. 自我介绍

常规开场,简要介绍个人背景、技术栈和项目经历。

回答框架

  • 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 过程

3.1 内存分代模型

JVM 堆内存分为新生代(Young Generation)和老年代(Old Generation),新生代又细分为:

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() 整个堆 + 方法区 最长

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 三色标记法基础

三色标记法是并发 GC 的核心算法,将堆中对象分为三类:

颜色 含义
白色 尚未被扫描的对象。GC 结束后仍为白色的对象将被回收
灰色 已被扫描,但其引用的子对象尚未全部扫描完成
黑色 已被扫描,且其所有子引用都已扫描完成

4.2 CMS 的四阶段与第一阶段 STW

CMS(Concurrent Mark Sweep)的完整 GC 流程:

graph TD
    A[初始标记 Initial Mark<br/>⚡ STW] --> B[并发标记 Concurrent Mark]
    B --> C[重新标记 Remark<br/>⚡ 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 出发的起始快照

为什么需要 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)在引用赋值时记录变化:

// 写屏障伪代码:当黑色对象新增引用时
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):

通过写屏障在引用被覆盖前记录旧值:

// 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. 最有成就感的项目

STAR 法则回答框架

  • Situation:项目的背景和业务上下文
  • Task:你负责的具体任务和目标
  • Action:你采取的技术方案和关键决策
  • Result:量化的成果(性能提升 X%、成本降低 X%、效率提升 X 倍)

回答要点:

  • 背景与目标:为什么做这个项目,要解决什么业务痛点,目标指标是什么
  • 技术选型与架构设计:为什么选择当前方案,对比过哪些替代方案,取舍的依据
  • 关键难点与突破:遇到了什么技术挑战(如性能瓶颈、一致性问题、高可用保障),如何分析和解决的
  • 最终成果:用数据说话,如 QPS 从 X 提升到 Y、延迟从 Xms 降低到 Yms、故障率降低 X%

6. 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 模板

7. 如何确保 AI 生成格式化内容的可靠性

生成 JSON 等结构化内容时,确保键的准确性和嵌套层级的正确性:

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
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 场景与目标达成

8.1 Agent 核心架构模式

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 长期记忆管理

9.1 记忆分层架构

graph TD
    subgraph 短期记忆
        W[工作记忆 Working Memory<br/>当前会话上下文]
    end
    subgraph 中期记忆
        E[情景记忆 Episodic Memory<br/>历史交互记录]
    end
    subgraph 长期记忆
        S[语义记忆 Semantic Memory<br/>知识、偏好、经验]
        P[程序性记忆 Procedural Memory<br/>技能和操作流程]
    end
    W -->|会话结束| E
    E -->|提炼总结| S
    S -->|指导行为| P

9.2 记忆淘汰机制

LRU(Least Recently Used)— 最近最少使用:

记忆队列:[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 记忆存储结构

{
  "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 知识图谱辅助判断

将记忆中的实体和关系组织为知识图谱:

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. 置信度加权:每条记忆有置信度评分,冲突时取置信度更高的
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 风险等级分类

风险等级 场景示例 策略
危险(Critical) 医疗用药、金融操作、生产环境配置、权限变更 不做自动选择,暴露冲突,人工决策
安全(Safe) 代码风格偏好、文档格式、非关键配置 按优先级规则自动采纳

11.2 危险环境处理

graph TD
    A[检测到完全冲突] --> B{环境风险等级?}
    B -->|危险| C[停止自动决策]
    C --> D[输出两条冲突记忆]
    D --> E[说明冲突内容和来源]
    E --> F[等待人工决策]
    F --> G[将决策结果写入记忆]

原则:宁可暴露冲突,也不做错误的自动选择。在医疗、金融、生产环境等高风险场景下,错误的自动选择可能造成不可逆的损失。

11.3 安全环境处理

可配置的优先级规则体系:

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. 如何评价是否达成目标

12.1 Critic 架构详解

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 多层评估体系

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 打分量化实现

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 幻觉

13.1 幻觉的分类

类型 描述 示例
事实性幻觉 生成与客观事实不符的内容 编造不存在的 API 或函数
忠实性幻觉 生成与输入上下文不一致的内容 检索到文档说 A,回答说 B
推理幻觉 逻辑推理过程出错 数学计算错误、因果倒置
指令幻觉 偏离用户指令要求 要求生成 JSON 却输出 YAML

13.2 Context 工程

核心思想:减少模型需要"猜测"的空间,提供精准、充分的上下文。

graph TD
    subgraph Context 构成
        S[System Prompt<br/>角色、规则、输出格式]
        K[Knowledge Base<br/>项目文档、API 文档、规范]
        H[History<br/>对话历史、工具调用结果]
        R[Retrieved Context<br/>RAG 检索的相关文档]
    end
    S --> LLM
    K --> LLM
    H --> LLM
    R --> LLM
    LLM --> O[输出]

关键实践:

  • 项目规范注入:将 CLAUDE.md 中的编码规范、命名约定、返回格式等注入 system prompt
  • 实时上下文获取:通过工具调用获取最新的代码状态、文件内容,而非依赖模型的参数记忆
  • 约束明确化:明确告诉模型"不要猜测,不确定时说不知道"

13.3 Sub-agent 评估(Adversarial Verify)

引入独立的审查 Agent 对主 Agent 的输出进行事实核查:

graph LR
    A[主 Agent 输出] --> V1[验证 Agent 1<br/>事实核查]
    A --> V2[验证 Agent 2<br/>逻辑检查]
    A --> V3[验证 Agent 3<br/>一致性检查]
    V1 --> J{多数通过?}
    V2 --> J
    V3 --> J
    J -->|是| R[接受输出]
    J -->|否| F[要求重新生成]

验证 Prompt 示例:

你是一个严格的事实核查员。请验证以下输出中的每个事实声明:
1. 检查是否存在编造的函数名、API、类名
2. 检查代码逻辑是否正确
3. 检查与提供的上下文是否一致
对于每个声明,给出 verdict: CONFIRMED / REFUTED / UNCERTAIN

13.4 Hook 机制

在关键节点插入自动化检查:

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)

graph LR
    Q[用户问题] --> E[Embedding]
    E --> S[向量检索]
    S -->|Top-K 文档| C[Context 组装]
    C --> LLM[大模型]
    LLM --> A[基于文档的回答]

降低幻觉的关键:回答基于检索到的实际文档,而非模型的参数记忆。模型的角色从"知识库"转变为"文档阅读理解"。


14. 如何遵守项目规范

14.1 规范的层次结构

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 配置示例:

# 项目规范

## 代码风格
- Go: 遵循 Uber Go Style Guide
- TypeScript: 使用 ESLint + Prettier,严格模式

## 命名规范
- 接口以 I 开头:IUserService
- 错误类型以 Error 结尾:NotFoundError
- 数据库模型以 Model 结尾:UserModel

## 返回类格式
统一使用 Result<T> 包装:
{
  "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 工具选择与可靠性保障

15.1 AI 工具生态

工具 定位 核心优势 适用场景
Claude Code CLI Agent 深度代码理解、工具调用、多文件编辑 复杂编码任务、项目级重构
Cursor IDE 集成 内联补全、上下文感知 日常编码、快速原型
GitHub Copilot 代码补全 广泛的语言支持、低延迟 代码补全、单元测试
ChatGPT/Claude 通用对话 强推理、多模态 技术方案讨论、文档编写

15.2 Harness(执行框架)

Harness 是管理 AI Agent 执行的核心框架:

graph TD
    subgraph Harness 核心组件
        PM[Permission Manager<br/>权限管理]
        CM[Context Manager<br/>上下文管理]
        TM[Tool Manager<br/>工具管理]
        SM[State Manager<br/>状态管理]
        HM[Hook Manager<br/>钩子管理]
    end
    U[用户输入] --> HM
    HM --> CM
    CM --> LLM[大模型]
    LLM --> TM
    TM -->|工具调用| PM
    PM -->|授权| EX[执行]
    EX --> SM
    SM -->|状态更新| CM

Harness 的关键职责:

  • 权限管理:哪些操作需要用户确认,哪些可以自动执行
  • 上下文管理:维护对话历史、工具结果、文件状态
  • 工具管理:注册、调用、结果处理
  • 状态管理:任务状态、进度追踪、错误恢复
  • Hook 管理:在关键节点插入自定义逻辑

15.3 可靠性保障体系

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 工具选择原则

  • 能力匹配:工具的核心能力要与任务需求匹配
  • 可控性:优先选择有良好权限控制和审计能力的工具
  • 可组合性:工具之间可以组合使用,形成完整的工具链
  • 成本效益:在质量和成本之间取得平衡

面试总结

这次去哪儿的 AI 面试整体考察深度不错,涵盖了:

考察维度 题目 核心考察点
语言基础 GC 过程、三色标记 JVM 底层原理理解深度
项目经验 有成就感的项目、AI 提效 实战经验和量化思维
AI 工程实践 结构化输出、Agent 设计 AI 集成的技术深度
记忆管理 记忆存储、冲突处理 系统设计和边界处理
可靠性工程 幻觉应对、规范遵守、工具保障 工程化思维和质量意识

核心考察点在于 AI 工程化能力 — 不只是会用 AI,而是如何可靠地将 AI 集成到实际项目中。

面试准备建议

  • GC 和三色标记是 Java 面试的高频考点,需要理解到源码级别
  • AI 相关问题需要有实际项目经验支撑,不能只谈理论
  • 记忆管理和冲突处理是 Agent 系统的核心难点,需要有具体的方案设计
  • 可靠性保障是区分"会用 AI"和"能工程化 AI"的关键