高德 AI应用开发 一面
1. 做一下自我介绍,重点讲你在 AI 编码和跨端工程结合上的经历
2. Flutter 的核心原理是什么,如果不从 Widget 开始讲,你会怎么讲
Flutter 真正的核心不是 Widget,而是它自带了一整套渲染体系。它绕过了各平台原生控件树,直接基于 Skia 或 Impeller 进行绘制,上层通过 Widget、Element、RenderObject 三棵树来描述配置、生命周期和布局绘制职责。Widget 是声明式配置,Element 负责把配置和实例关系稳定下来,RenderObject 才是真正参与 layout、paint、hitTest 的对象。这样做的好处是跨平台一致性很强,坏处是需要自己承担一整套输入、排版、合成和性能治理问题。
class CounterText extends StatelessWidget {
final int count;
const CounterText({super.key, required this.count});
@override
Widget build(BuildContext context) {
return Text('count=$count');
}
}
3. Flutter 和 React Native、原生开发最大的区别,不要只说性能
真正大的区别在“控制权”上。原生开发直接操作平台能力,UI、事件分发、手势、生命周期都由系统托管;React Native 大量依赖 JS 与原生桥接,UI 最终仍然落到原生控件体系;Flutter 则是把渲染权拿到自己手里,所以在一致性和可定制性上更强。代价也很明显,应用体积、平台深度适配、混合栈调试、可观测性接入和原生能力暴露的复杂度会更高。面试里如果只答“Flutter 性能更好”,其实很浅,因为很多业务并不单纯由 FPS 决定。
4. Flutter 的 UI 为什么能回到原生页面上,这个过程本质上发生了什么
Flutter 页面并不是“回到原生”,而是宿主容器切换了显示和路由控制权。通常是原生 Activity 或 ViewController 里承载一个 FlutterEngine 和 FlutterView,页面跳转时由宿主决定展示哪个容器。所谓从 Flutter 回原生,本质上是导航栈从 Flutter route 切到宿主路由,或者通过平台通道通知宿主做原生跳转。真正复杂的点在混合栈场景,导航状态、生命周期、手势返回和页面恢复都要处理干净,不然很容易出现黑屏、状态丢失或栈错乱。
static const platform = MethodChannel('app/nav');
Future<void> openNativePage() async {
await platform.invokeMethod('openNativePage', {'page': 'detail'});
}
5. 如果文字内容变化导致宽度发生变化,Flutter 的重排到底是怎么发生的
这件事不是简单的“重新 build 一下”。当状态变化触发 setState 后,先是 Widget 层产生新配置,Element 做 diff,如果对应 RenderObject 的布局相关属性发生变化,就会被标记为 dirty layout。接着在 pipeline flush 阶段重新执行 layout,父节点把 BoxConstraints 往下传,子节点基于约束回传 size,如果新的 size 影响父布局,脏标记会沿树传播。真正 expensive 的不是文本变了,而是变更是否击穿了上层布局边界,如果一路传到更高层,代价就会明显上升。
6. Flutter 里 build、layout、paint、composite 这几段如果线上卡顿,你怎么判断卡在哪一段
要先把渲染链路拆开看。build 卡顿常见于频繁 setState、列表项大面积重建、InheritedWidget 传播过广;layout 卡顿通常和多次测量、intrinsic 尺寸计算、复杂嵌套布局有关;paint 卡顿往往是大量阴影、裁剪、透明混合、路径绘制;composite 和 raster 卡顿则更接近 GPU 压力,比如过多 layer、saveLayer、图片纹理切换。真实排查时不会靠猜,通常会结合 Flutter DevTools 的 frame chart、rebuild stats、raster timeline 和 shader jank 一起看。
7. Java 里的强引用、软引用、弱引用、虚引用在工程里怎么理解,别只背定义
强引用最常见,生命周期由业务代码直接控制,只要链路可达就不会被回收。软引用更适合做“有内存就留着”的缓存,但线上不能指望它做稳定缓存,因为回收时机受 GC 压力影响很大。弱引用更像一种观察机制,常用于 ThreadLocalMap、WeakHashMap 这类避免对象被强持有;虚引用本身拿不到对象内容,更多是配合 ReferenceQueue 感知对象被回收,用于堆外资源释放或更细粒度的生命周期管理。真正会用这些引用的人,重点不是知道名字,而是知道什么时候该让 GC 介入、什么时候绝不能把资源管理交给 GC 猜。
ReferenceQueue<byte[]> queue = new ReferenceQueue<>(); PhantomReference<byte[]> ref = new PhantomReference<>(new byte[1024], queue); System.gc(); // 通过 queue 观察对象回收事件
8. 讲一下你做过的 Agent Skill,不要从业务价值讲,直接讲技术拆分
可以把它讲成一个 代码巡检与修复 Skill。输入是仓库路径、规则集和目标模块,Skill 先做仓库索引与依赖扫描,再做静态规则匹配、语义检索、变更建议生成,最后输出 patch、风险说明和回归检查建议。真正的难点不在“会不会调模型”,而在于如何把大任务拆成可验证的子任务。比如先生成候选修改点,再做约束校验,再做 patch 生成,最后跑静态检查和单测。这样模型每一步都有边界,不会一口气改崩整个模块。
def run_skill(repo_path, rule_text):
symbols = index_repo(repo_path)
candidates = search_related_code(symbols, rule_text)
plan = build_fix_plan(candidates, rule_text)
patch = generate_patch(plan)
return validate_patch(repo_path, patch)
9. 团队里常用哪些开发工具比较多,如果从 AI 协作方式去分类,你会怎么讲
现在团队工具可以不按 IDE 名称分,而按协作层次分。第一层是编码层,比如 IDE 插件、终端补全、局部 patch 工具;第二层是检索层,比如仓库语义搜索、符号索引、调用链分析;第三层是编排层,比如让模型串联 lint、test、build、deploy 沙箱;第四层是知识层,比如把 ADR、历史 issue、review 结论沉淀进可检索系统。真正高效的团队不是“大家都在用一个 AI 工具”,而是把这些层次连起来,形成可复用的工作流。
10. 你是什么时候开始用 Claude Code 这一类工具的,真正改变你的是什么
11. 用过哪些模型,模型选择不是看排行榜的话,你一般怎么选
12. 对商业项目来说,开发者过去习惯手动掌控每个细节,到了 AI 提供生产力的时代,你怎么看这个变化
13. 你用 AI 写代码时一般怎么拆解任务,才能让结果比较稳定
我不会直接把一个模糊需求甩给模型,而是先拆成上下文收集、约束定义、候选方案、局部实现、验证回归几段。先让模型读代码结构和相关依赖,
剩余60%内容,订阅专栏后可继续查看/也可单篇购买
本专栏聚焦 AI-Agent 面试高频考点,内容来自真实面试与项目实践。系统覆盖大模型基础、Prompt工程、RAG、Agent架构、工具调用、多Agent协作、记忆机制、评测、安全与部署优化等核心模块。以“原理+场景+实战”为主线,提供高频题解析、标准答题思路与工程落地方法,帮助你高效查漏补缺.
