2026-09-10 秋招XX AI应用开发一面复盘
这场面试从项目聊起,接着问了 Agent 框架、Redis 和 MySQL,最后是一道链表重排。按问题把思路和参考回答记一下。
项目里最大的困难是什么
自我介绍之后,面试官让我介绍项目,并追问项目里遇到的最大困难。
我讲的是工单状态变化之后触发审核这一环。最初想用状态判断和固定流程把逻辑写出来,后来发现,有些步骤需要结合工单上下文判断,分支也比较多,于是考虑把其中一部分决策交给 Agent,根据当前状态、上下文和已有工具决定下一步做什么。
这个例子要说清楚哪一部分需要模型。固定规则可以继续写成普通代码,比如审核权限、必填项、允许流转的状态;Agent 在允许的范围内判断下一步、选择工具,需要人工确认时再停下来。不能因为用了 Agent,就把明确的业务约束也都交给模型临场决定。
Hook 是什么
Hook 可以理解为框架在特定执行位置留下的扩展点。流程运行到这里,就调用预先注册的逻辑。例如,模型请求前补充上下文,请求后记录结果,工具调用前检查参数。
放到 Agent 里,主流程仍然是调用模型、执行工具、把结果交回模型。Hook 用来在这些步骤前后插入处理。以当前 LangChain 为例,middleware 就通过这类钩子实现日志、提示词调整、重试等功能。具体能改哪些状态、能否中断执行,要看框架给出的接口。官方说明
LangChain、LangGraph、Deep Agents 怎么分工
按目前的文档,可以从三层来理解:
- LangChain 提供模型、工具等常用接口,以及现成的 Agent 构建方式,减少接不同模型和工具时的重复代码。
- LangGraph 更关注执行流程。用状态、节点和边组织任务,适合把固定步骤和模型决策放在同一个流程里;需要时再配置持久化、暂停和恢复等能力。它也可以独立使用,不要求整个项目都通过 LangChain 搭建。LangGraph 官方说明
- Deep Agents 在这些基础上提供更完整的 Agent 执行配套,包括任务规划、文件工具、子 Agent 和上下文管理。当前 SDK 建立在 LangChain 组件之上,使用 LangGraph 运行时。Deep Agents 官方说明
再追问 Deep Agents,可以从一个具体问题讲:任务长了以后,所有材料和工具结果都塞进同一段对话,会越来越难管理。文件工具可以承接较大的中间内容,子 Agent 可以处理相对独立的子任务,只把必要结果带回主流程。规划则用来记录任务拆成了哪些步骤、现在做到哪里。
这些能力是否需要,要回到项目本身。如果只是一次模型调用或很短的工具循环,就不必为了框架名字把三层都堆上去;确实需要拆任务、管理较长上下文时,再解释 Deep Agents 帮忙省掉了哪部分工作。
Redis、MySQL 怎样回答到具体场景
可以先说两者在业务里的位置。MySQL 适合保存工单、用户、审核记录等需要可靠落库的数据,通过事务保证一组修改的一致性。Redis 常用来做缓存、计数、限流或短期状态存储,但缓存里的内容可能过期,也可能与数据库短暂不一致。
拿工单状态举例:主记录保存在 MySQL,读取频繁时才考虑加 Redis 缓存。更新数据库后,可以删除相应缓存,让后续读取重新加载;并发下仍要考虑旧值回填和失效失败。审核能否执行不能只看一个可能过期的缓存值,关键状态检查应当落到可靠的数据和更新条件上。
链表重排
以常见的首尾交错形式为例:
L0 → L1 → L2 → … → Ln
变为
L0 → Ln → L1 → Ln-1 → …
1 → 2 → 3 → 4 → 5
变为
1 → 5 → 2 → 4 → 3思路分三步:找中点,把链表断成两段;反转后半段;再把两段交替接起来。这样每次都能从两段的头部取节点,不需要反复找原链表的尾节点。
快慢指针找中点,后半段长度不超过前半段。合并时先保存两个节点原来的后继,再修改指针,避免把剩下的链表弄丢。时间复杂度 ,额外空间 。
def reorder_list(head):
if head is None or head.next is None:
return
slow = fast = head
while fast.next and fast.next.next:
slow = slow.next
fast = fast.next.next
cur = slow.next
slow.next = None
prev = None
while cur:
nxt = cur.next
cur.next = prev
prev, cur = cur, nxt
first, second = head, prev
while second:
next_first, next_second = first.next, second.next
first.next = second
second.next = next_first
first, second = next_first, next_second