超全AI应用开发面试知识点(持续更新)
目录
2. list、tuple、dict、set 分别适合什么场景?
5. vector、list、map、unordered_map 怎么选?
4. GET、POST、PUT、DELETE 如何设计 RESTful API?
5. Cookie、Session、Token、JWT 区别?
2. APIRouter、Pydantic、Depends 分别解决什么问题?
6. redo log、undo log、binlog 区别?
3. Function Calling / Tool Calling 怎么理解?
8. Prompt Engineering 为什么体现工程能力?
7. LangGraph 为什么适合做 Agent 工作流?
3. Controller、Service、DAO 分别负责什么?
10. DataClawHub 领域迁移中 RAG 能起什么作用?
2. uvicorn、gunicorn、nginx 分别负责什么?
9. 为什么选择Drogon而不是其他C++ Web框架?Drogon的哪些特性对秒杀场景特别有帮助?
11. Redis预减后,MySQL还扣库存吗?如何保证一致性?
第一部分:技术知识点高频考点
一、Python 开发
1. Python 的可变对象和不可变对象怎么理解?
答:Python 里变量本质上保存的是对象引用,不是直接保存对象本身。不可变对象包括 int、float、bool、str、tuple 等,创建后值不能在原地址上修改;可变对象包括 list、dict、set 等,可以在原对象上增删改。面试时我会结合函数传参解释:把 list 传入函数后 append,会影响外部对象,因为函数里拿到的是同一个可变对象引用;但把 int 或 str 传进去重新赋值,只是让局部变量指向新对象,不会影响外部变量。项目里处理大模型返回的分镜 JSON 时,dict 和 list 都是可变对象,所以修改 scene、material、subtitle 这类嵌套结构时要特别注意副作用。
2. list、tuple、dict、set 分别适合什么场景?
答:list 是有序可变序列,适合存储会动态变化的列表,例如视频分镜列表、任务列表、商品列表;tuple 是有序不可变序列,适合存固定配置,例如坐标、状态枚举、不可变参数组合,也可以作为 dict 的 key;dict 是键值对结构,底层基于哈希表,适合通过 key 快速定位 value,例如 job_id 到任务状态、scene_id 到素材信息;set 是无序不重复集合,适合去重、判断存在、求交集并集差集,比如素材 URL 去重、用户权限集合判断。回答这类问题不能只背定义,要把数据结构和业务场景对应起来。
3. dict 为什么查询快?哈希冲突怎么办?
答:Python dict 平均查询快,是因为底层使用哈希表。查询时会对 key 计算哈希值,再根据哈希值定位到数组中的位置,平均时间复杂度接近 O(1)。但不同 key 可能算出相同或相近位置,这就是哈希冲突,Python 会通过开放寻址等机制继续寻找可用位置。面试中我会补充:dict 快不代表任何情况下都一定 O(1),如果哈希冲突严重或频繁扩容,性能会下降。项目中 job_id -> status、scene_id -> material 这种映射关系就适合用 dict;如果要跨进程共享,就会放到 Redis Hash 或 String 里。
4. 深拷贝和浅拷贝怎么回答?
答:浅拷贝只复制最外层容器,里面的嵌套对象仍然共享引用;深拷贝会递归复制内部嵌套对象。比如 a = [{'scene': 1}],浅拷贝后修改内部 dict,原对象也会受影响;深拷贝则不会。项目里大模型生成的分镜数据通常是 list + dict 的嵌套结构,如果我要基于原始分镜生成一个可修改版本,例如给每个 scene 补充 material_url、duration、subtitle,就要注意不能误改原始数据。简单结构可以浅拷贝,复杂嵌套结构需要 deepcopy,但 deepcopy 成本更高,所以也不能无脑使用。
5. == 和 is 有什么区别?
答:== 比较的是两个对象的值是否相等,is 比较的是两个变量是否指向同一个对象,也就是内存身份是否相同。比如两个内容相同的 list,a == b 可能是 True,但 a is b 通常是 False。面试中我会补充:判断 None 时应该写 is None,因为 None 是单例对象;判断业务值时用 ==。这个问题本质考 Python 对象模型和引用语义,不要把值相等和对象相同混为一谈。
6. Python 函数参数传递是值传递还是引用传递?
答:更准确地说,Python 是对象引用传递,或者叫共享传参。函数接收到的是对象引用的一份副本。如果传入的是可变对象,在函数内部修改对象内容,外部能看到变化;如果在函数内部给参数重新赋值,只是让局部引用指向新对象,不会改变外部变量。面试中我会用 list append 和 int 重新赋值两个例子说明。项目里封装工具函数时,如果函数会修改传入的 dict 或 list,我会在函数名、注释或实现上明确这一点,避免调用方误以为原始数据不会变。
7. 装饰器是什么?项目里怎么用?
答:装饰器本质是一个接收函数并返回新函数的高阶函数,可以在不修改原函数代码的情况下增强功能。常见用途是日志记录、权限校验、接口耗时统计、异常捕获、重试机制。FastAPI 里的 @app.get、@router.post 也是装饰器写法,它把函数注册成接口路由。项目里我可以用装饰器封装 LLM 调用重试、记录视频生成每一步耗时,也可以统计接口执行时间。回答时要强调装饰器不是语法糖背诵题,而是工程中做横切逻辑复用的工具。
8. 迭代器和生成器有什么区别?
答:迭代器是实现了 __iter__ 和 __next__ 的对象,可以被 for 循环逐个取值;生成器是创建迭代器的一种更简单方式,使用 yield 逐步产出数据。生成器不会一次性把所有数据放到内存里,而是需要时再生成,适合大文件读取、大量任务遍历、流式输出等场景。AI 应用中,大模型流式输出、分批处理素材、按 scene 逐步合成视频,都可以用生成器思想降低内存压力。
9. 闭包和 lambda 怎么理解?
答:闭包是内部函数引用了外部函数的局部变量,并且外部函数返回后这个变量仍然被内部函数持有。它常用于装饰器、函数工厂、延迟执行等场景。lambda 是匿名函数,适合写简单的一行函数,比如排序 key、map/filter 的简单转换。面试时我会说:lambda 不适合写复杂逻辑,复杂逻辑应该用普通函数提高可读性。
10. Python 垃圾回收机制是什么?
答:Python 主要使用引用计数管理对象生命周期,当对象引用计数变为 0 时会被释放;为了解决循环引用问题,还引入了标记-清除和分代回收。循环引用比如两个对象互相引用,即使外部没有引用,引用计数也不为 0,这时需要循环垃圾回收器处理。项目中一般不需要手动管理内存,但处理大文件、图片、视频、音频时要注意及时关闭文件句柄、释放临时对象,避免长任务内存持续上涨。
11. GIL 是什么?它对多线程有什么影响?
答:GIL 是 CPython 解释器里的全局解释器锁,它使得同一时刻一个进程内通常只有一个线程执行 Python 字节码。所以 Python 多线程不适合提升 CPU 密集型任务的计算性能,但适合 IO 密集型任务,比如网络请求、数据库查询、文件读写、调用外部 API。CPU 密集型任务可以考虑多进程、C 扩展、NumPy 或直接交给 FFmpeg 这类外部工具。视频生成项目里,LLM、TTS、素材下载是 IO 等待,适合并发或异步;视频编码更偏 CPU/外部进程处理,不能只靠 Python 多线程解决。
12. async/await 和多线程的区别?
答:async/await 是协程异步模型,通常在单线程事件循环中通过主动让出控制权处理大量 IO 等待;多线程是操作系统线程,由系统调度,线程之间可能并发执行但有锁竞争和上下文切换成本。async 更适合高并发 IO,比如同时请求多个素材接口、TTS 服务、LLM API;多线程适合调用阻塞库或少量并发任务。FastAPI 支持 async,但如果内部调用的是阻塞函数,比如普通 requests 或同步数据库驱动,就会阻塞事件循环,所以要么使用异步库,要么把阻塞任务放到线程池或后台任务。
13. Python 异常处理怎么设计才算工程化?
答:工程化异常处理不是简单 try except 然后 pass,而是要做到捕获预期异常、记录上下文日志、返回明确错误状态、必要时重试、最后有兜底方案。比如 AI 视频生成链路中,LLM 可能超时、JSON 解析可能失败、素材下载可能 404、TTS 可能失败、FFmpeg 可能返回非 0 状态。我的设计会给每一步记录 current_step、error_message、trace_id 或 job_id,失败后更新任务状态,能重试的重试,不能重试的返回明确失败原因。
14. Python 项目工程化体现在哪些方面?
答:我理解的 Python 工程化包括目录结构清晰、模块职责单一、依赖可管理、配置不写死、日志可排查、异常可追踪、测试可执行、部署可复现。具体做法包括 requirements.txt 或 pyproject 管理依赖,.env 管理 API Key 和数据库地址,config.py 统一读取配置,logging 记录任务链路,pytest 测试核心函数,类型注解提高可维护性,脚本化处理批量任务。面试时我会强调:会写 Python 语法只是基础,能把脚本变成可维护服务才是工程能力。
15. *args 和 **kwargs 是什么?
*args 用来接收多个位置参数,结果是 tuple。**kwargs 用来接收多个关键字参数,结果是 dict。
def func(*args, **kwargs):
print(args)
print(kwargs)
在封装通用工具函数时很有用,比如封装日志、请求模型 API、统一接口响应等。
16. 进程、线程、协程区别?
答:进程:资源独立,开销最大,稳定性强
线程:共享进程资源,开销比进程小
协程:用户态调度,开销最小,适合高并发 IO
在 AI 应用中:CPU密集型:适合多进程
IO密集型:适合多线程或协程
高并发网络请求:适合协程
比如调用大模型 API、下载素材、调用 TTS,本质都是 IO 等待,所以适合异步协程。
17. 什么是 GIL?
答:GIL 是 Python 的全局解释器锁。它导致同一时刻一个 Python 进程里只有一个线程真正执行 Python 字节码。所以:CPU密集型:适合多进程;IO密集型:适合多线程或协程;高并发网络请求:适合协程。例如视频编码、图像处理这种更偏 CPU 密集型,不能只靠 Python 多线程解决。
18. async 和 await 是什么?
答:async 用来定义协程函数。await 用来等待异步任务完成。
async def call_model():
result = await request_llm()
return result
它适合处理 IO 密集型场景,比如:调用大模型 API,调用 TTS 接口,下载图片素材,查询数据库
读写文件
19. asyncio.gather 有什么用?
答:asyncio.gather 可以并发执行多个异步任务。比如我的 AI 视频系统里,每个 scene 都需要搜索素材,如果串行处理会很慢,可以用 gather 并发请求,提高整体速度。
二、C/C++ 与数据结构基础
1. C 和 C++ 的区别?
答:C 是面向过程语言,重点是函数、结构体和手动内存管理;C++ 在 C 的基础上支持面向对象、泛型编程、异常处理、RAII 和 STL。面试回答时我会从编程范式、标准库、内存管理、工程组织四个角度说。C 更贴近底层,适合系统和嵌入式;C++ 既能写底层又能组织大型工程。对我来说,C/C++ 不是当前 AI 应用项目主线,但它帮助我理解内存、指针、对象生命周期和性能问题。
2. 指针和引用的区别?
答:指针是一个变量,保存地址,可以为空,也可以改变指向;引用是已有变量的别名,定义时必须初始化,之后不能再绑定到其他对象。指针使用时需要解引用,引用使用上更像普通变量。函数参数中,如果需要表达可选对象或可能为空,可以用指针;如果明确必须传入一个对象并希望避免拷贝,可以用引用。这个问题常考 C++ 基础和内存模型。
3. 堆和栈有什么区别?
答:栈由系统自动管理,函数调用时创建局部变量,函数返回后自动释放,速度快但空间有限;堆由程序员手动申请或通过智能指针管理,生命周期更灵活但分配释放成本更高,也更容易出现内存泄漏。Python 虽然不直接让我们手动管理堆栈,但理解堆栈有助于理解函数调用、对象生命周期和内存占用。
4. 虚函数和多态怎么理解?
答:虚函数是 C++ 实现运行时多态的机制。基类中声明 virtual,子类重写后,通过基类指针或引用调用时,会根据实际对象类型调用对应实现。底层通常通过虚函数表和虚表指针实现。面试时我会补充:有多态使用场景的基类析构函数应该设为虚函数,否则通过基类指针删除子类对象可能只调用基类析构,导致资源释放不完整。
5. vector、list、map、unordered_map 怎么选?
答:vector 底层连续数组,随机访问快,缓存友好,尾插效率高,适合大多数顺序存储场景;list 是链表,随机访问慢,但中间插入删除方便;map 底层通常是红黑树,key 有序,查询 O(log n);unordered_map 底层是哈希表,key 无序,平均查询 O(1)。面试回答时不要只背复杂度,要结合场景:需要频繁随机访问用 vector,需要有序遍历用 map,需要平均快速查询用 unordered_map。
6. 红黑树、B+ 树、哈希表分别解决什么问题?
答:哈希表适合等值查询,平均 O(1),但不适合范围查询和有序遍历;红黑树是自平衡二叉搜索树,适合内存中的有序映射;B+ 树更适合数据库和磁盘存储,因为树高低、节点能存多个 key、叶子节点有序链表方便范围查询。MySQL InnoDB 使用 B+ 树索引,就是因为数据库查询既需要等值查询,也常需要范围查询、排序和减少磁盘 IO。
7.C++三大特性
(1)封装
“封装就是把数据和操作数据的方法放到一起,同时隐藏内部实现。比如类里面会把成员变量设成 private,对外提供接口访问,这样安全性更高,也降低了模块之间的耦合。”
(2)继承
“继承主要是代码复用。比如我有一个 Animal 父类,Dog 和 Cat 可以直接继承 Animal 的一些公共属性和方法,这样不用重复写。”
(3)多态
“多态就是同一个接口,不同对象会有不同表现。我理解最核心的是虚函数。
比如父类指针指向子类对象,调用同一个函数时,运行时会根据实际对象类型执行对应函数。底层其实是通过虚函数表和虚函数指针实现的。”
8. C++ 11新特性
(1)智能指针
智能指针主要是解决内存泄漏问题。像 unique_ptr 是独占所有权,一个资源只能有一个指针管理。shared_ptr 是引用计数,多个指针共享同一个资源。weak_ptr 主要是解决 shared_ptr 循环引用问题,它不会增加引用计数。”
(2)右值引用和移动语义
“右值引用我理解主要是为了支持移动语义。以前对象传递可能会发生深拷贝,性能开销比较大。C++11 引入移动语义之后,可以直接把资源所有权转移过去,而不是重新拷贝一份。比如 vector 很大的时候,用 move 可以减少大量内存复制,提高性能。”
三、Linux 与操作系统
1. 进程、线程、协程区别?
答:进程是资源分配的基本单位,拥有独立地址空间;线程是 CPU 调度的基本单位,同一进程内线程共享内存和文件描述符;协程是用户态轻量级执行单元,由程序主动让出控制权,适合高并发 IO。进程隔离性强但开销大,线程共享数据方便但要注意锁和线程安全,协程开销更小但不能直接利用多核跑 CPU 密集型任务。我的视频生成项目里,接口层可以用异步协程处理 IO,视频合成这类耗时任务适合后台任务或独立进程。
2. 进程间通信有哪些方式?
答:常见 IPC 包括管道、消息队列、共享内存、信号量、Socket、文件等。管道适合有亲缘关系进程之间简单通信;消息队列适合异步传递结构化消息;共享内存速度快但需要同步机制;Socket 可以跨机器通信。后端项目中更常见的是通过 Redis、数据库、消息队列或 HTTP 接口实现服务间通信。
3. 什么是上下文切换?为什么开销大?
答:上下文切换是 CPU 从一个进程或线程切到另一个进程或线程时保存当前执行状态、加载新任务状态的过程。它会涉及寄存器、程序计数器、内存映射、缓存命中率变化等成本。线程或进程过多会导致大量时间花在切换上,而不是业务执行。高并发 IO 场景下使用协程可以减少线程数量和切换成本。
4. 死锁是什么?怎么避免?
答:死锁是多个线程或进程互相等待对方持有的资源,导致都无法继续执行。它通常满足互斥、占有且等待、不可抢占、循环等待四个条件。避免死锁可以通过统一加锁顺序、减少锁范围、设置锁超时、避免持锁执行耗时 IO、使用数据库事务时保持访问资源顺序一致。校园交易平台如果同时操作商品和订单,也要注意事务和锁顺序,避免数据库死锁。
5. select、poll、epoll 区别?
答:select、poll、epoll 都是 IO 多路复用机制,用一个线程监听多个文件描述符。select 有文件描述符数量限制,每次需要拷贝和遍历;poll 去掉了固定数量限制,但仍然需要线性遍历;epoll 使用事件驱动,内核维护就绪列表,适合大量连接中少量活跃的场景,性能更好。面试里这个问题常和高并发网络、Nginx、Redis 为什么快一起问。
6. Linux 服务访问不了怎么排查?
答:我会按从外到内、从基础到应用的顺序排查:先确认域名或 IP 是否正确,再用 ping/curl 测网络连通性;用 lsof -i 或 netstat/ss 看端口是否监听;用 ps/top 看进程是否存在和资源是否异常;看 Nginx、Uvicorn、应用日志;检查配置文件、环境变量、数据库/Redis 连接;最后看防火墙、安全组和权限问题。回答时要体现排查路径,而不是只报几个命令名。
7. FastAPI 在 Linux 上如何部署?
答:部署流程是准备 Python 环境,安装依赖,配置 .env,使用 uvicorn 或 gunicorn+uvicorn worker 启动服务,再用 Nginx 做反向代理,最后用 systemd 管理后台常驻。生产环境要关注日志、端口、防火墙、进程守护、环境变量安全和静态文件访问。简单启动可以用 uvicorn app.main:app --host 0.0.0.0 --port 8000,但正式部署不能只靠手动命令挂着。
四、计算机网络与 API 设计
1. TCP 和 UDP 区别?
答:TCP 是面向连接的可靠传输协议,提供确认、重传、排序、流量控制和拥塞控制,适合 HTTP、文件传输、数据库连接等可靠性要求高的场景;UDP 是无连接协议,不保证可靠和有序,但开销小、延迟低,适合直播、实时音视频、游戏等更关注实时性的场景。回答时我会强调:不是 TCP 一定好、UDP 一定差,而是可靠性和实时性取舍不同。
2. 三次握手和四次挥手怎么讲?
答:三次握手是客户端发 SYN,服务端回 SYN+ACK,客户端再回 ACK,用来确认双方收发能力正常并建立连接。不能只两次,是因为服务端也需要确认客户端能收到自己的响应,避免历史连接请求造成错误连接。四次挥手是因为 TCP 是全双工连接,一方关闭发送能力后,另一方可能还有数据要发,所以关闭双方方向通常需要 FIN 和 ACK 分开完成。
3. HTTP 和 HTTPS 区别?
答:HTTP 是明文传输,数据可能被窃听或篡改;HTTPS 在 HTTP 基础上加入 TLS/SSL,通过证书验证服务器身份,并通过密钥协商建立加密通道,保证机密性、完整性和身份认证。面试中可以补充:HTTPS 不是绝对安全,但能解决明文传输的大部分风险;登录、支付、个人信息接口必须使用 HTTPS。
4. GET、POST、PUT、DELETE 如何设计 RESTful API?
答:RESTful API 用 URL 表示资源,用 HTTP 方法表示操作。GET 用于查询资源,POST 用于创建资源,PUT/PATCH 用于整体或局部更新资源,DELETE 用于删除资源。比如视频任务可以设计为 POST /video-tasks 创建任务,GET /video-tasks/{id} 查询任务,GET /video-tasks/{id}/result 获取结果。校园交易平台中 GET /items 查询商品,POST /items 发布商品,POST /orders 创建订单。
5. Cookie、Session、Token、JWT 区别?
答:Cookie 是浏览器端存储机制,Session 是服务端保存用户状态的机制,Cookie 通常保存 session_id;Token 是客户端携带的访问令牌,服务端验证后识别用户;JWT 是一种自包含 Token,里面可以放用户 id、过期时间、签名等信息。Session 更依赖服务端存储,JWT 更适合无状态认证,但 JWT 一旦签发,在过期前撤销比较麻烦,所以可以结合 Redis 做黑名单或登录态控制。
五、FastAPI
1. FastAPI 为什么适合 AI 应用后端?
答:FastAPI 基于标准 Python 类型提示,结合 Pydantic 做参数校验和序列化,自动生成 OpenAPI/Swagger 文档,并支持 async/await 异步接口。AI 应用通常需要调用 LLM、TTS、素材服务、数据库和缓存,很多都是 IO 密集型,FastAPI 的异步能力和自动文档能提高开发和联调效率。我会用它作为视频生成任务入口、校园交易平台业务接口和后台管理接口。
2. APIRouter、Pydantic、Depends 分别解决什么问题?
答:APIRouter 用来拆分接口模块,让用户、商品、订单、视频任务等接口分文件管理;Pydantic 用来定义请求体和响应体,自动做类型校验、默认值和错误提示;Depends 是依赖注入机制,适合复用数据库会话、当前用户、权限校验、分页参数等公共逻辑。这三个点能体现 FastAPI 项目不是把所有接口堆在 main.py,而是有工程结构。
3. FastAPI 的 async 接口一定更快吗?
答:不一定。async 的优势在 IO 等待,如果接口内部使用异步数据库驱动、异步 HTTP 客户端、异步文件操作,才能释放事件循环去处理其他请求。如果 async 函数里调用阻塞的 requests、同步数据库查询或 CPU 密集计算,仍然会阻塞事件循环,甚至更糟。AI 视频项目里,LLM/TTS/素材下载适合异步,FFmpeg 合成应该放后台任务或独立进程。
4. 后台任务、任务队列、定时任务怎么选?
答:FastAPI BackgroundTasks 适合轻量、短时间、失败影响不大的后台操作,比如发送通知、写日志、简单后处理;如果任务耗时长、需要重试、需要持久化和分布式执行,比如视频生成,就更适合 Celery/RQ/自建任务队列 + Redis。定时任务适合周期性同步数据或清理临时文件。面试时我会说:视频生成不能只靠普通接口同步阻塞,至少要设计 job_id + 状态查询。
5. 如何设计视频生成接口?
答:我会设计成异步任务模式:POST /video-tasks 提交主题、风格、时长等参数,后端创建 job_id 并返回;GET /video-tasks/{job_id} 查询任务状态、进度、当前步骤和错误信息;GET /video-tasks/{job_id}/result 获取最终视频地址。任务状态可以存在 Redis,最终结果和任务记录可以落 MySQL。这样可以避免接口超时,也方便前端展示进度和失败原因。
六、Redis
1. Redis 为什么快?
答:Redis 快的原因不是单一的。第一,它主要基于内存读写,避免大量磁盘 IO;第二,核心命令执行模型简单,单线程避免了多线程锁竞争;第三,使用 IO 多路复用处理大量网络连接;第四,内部数据结构针对不同场景做了优化。面试时我会补充:Redis 单线程指的是命令执行主流程,不代表整个 Redis 没有后台线程;Redis 快也不意味着可以存无限数据,内存、淘汰策略、持久化都会影响性能。
2. Redis 五种基础数据结构怎么用?
答:String 适合验证码、Token、计数器、任务状态字符串;Hash 适合存对象字段,比如 user:{id} 或 video:task:{job_id};List 适合简单队列和按顺序存消息;Set 适合去重、共同关注、权限集合;ZSet 适合排行榜、热门商品、按分数或时间排序的数据。项目里校园平台可以用 String 存验证码,Hash 存用户会话,ZSet 做热门商品榜;视频智能体可以用 Hash 存任务进度和当前步骤。
3. 缓存穿透、击穿、雪崩怎么回答?
答:缓存穿透是请求的数据缓存和数据库都不存在,导致每次都打到数据库,可以用缓存空值、布隆过滤器、参数校验解决;缓存击穿是热点 key 过期瞬间大量请求打到数据库,可以用互斥锁、逻辑过期、热点 key 不过期解决;缓存雪崩是大量 key 同时过期或 Redis 故障导致数据库压力暴增,可以用过期时间加随机值、多级缓存、限流降级、Redis 高可用解决。三者区别是:不存在、热点失效、大面积失效。
4. Redis 持久化 RDB 和 AOF 区别?
答:RDB 是在某个时间点生成内存快照,恢复速度快、文件紧凑,但两次快照之间的数据可能丢失;AOF 是记录写命令日志,数据安全性更高,可以配置 always/everysec/no 等刷盘策略,但文件可能更大,恢复速度相对慢。生产中常常结合使用,RDB 用于快速恢复,AOF 提高数据安全。项目中如果 Redis 只做缓存,丢失可以重建;如果存任务状态,需要考虑持久化和任务恢复。
5. Redis 分布式锁怎么实现?
答:基本实现是 SET lock_key value NX EX seconds,NX 保证不存在时才加锁,EX 防止死锁,value 用唯一随机值标识持有者,释放锁时必须先判断 value 是否一致再删除,避免删掉别人的锁。更严谨的释放要用 Lua 脚本保证判断和删除原子性。校园交易平台如果要防止同一商品并发下单,可以用 Redis 锁做第一层保护,但最终还要靠 MySQL 事务和条件更新保证一致性。
6. Redis 和 MySQL 如何保证一致性?
答:缓存和数据库很难做到强一致,常见目标是最终一致。一般做法是先更新数据库,再删除缓存,让下一次查询重新加载新数据。直接更新缓存容易因为并发写导致旧值覆盖新值。高并发下可以加延迟双删、消息队列重试、binlog 监听等方案。校园平台更新商品状态后应该删除商品详情缓存;视频任务状态如果以 Redis 为主,可以最终落库到 MySQL 保存历史记录。
7. Redis 内存淘汰策略有哪些?
答:Redis 内存达到 maxmemory 后会按策略淘汰 key,常见有 noeviction、allkeys-lru、volatile-lru、allkeys-lfu、volatile-lfu、allkeys-random、volatile-random、volatile-ttl 等。面试时不一定要把所有名字背死,但要知道 LRU 是最近最少使用,LFU 是最不经常使用,volatile 表示只淘汰设置了过期时间的 key,allkeys 表示所有 key 都可能淘汰。缓存场景常用 allkeys-lru 或 allkeys-lfu。
七、MySQL
1. MySQL 索引为什么用 B+ 树?
答:InnoDB 使用 B+ 树是因为数据库索引通常存储在磁盘或页中,B+ 树每个节点能存多个 key,树高低,可以减少磁盘 IO;所有数据都在叶子节点,非叶子节点只存索引信息,范围查询时叶子节点之间有链表,遍历效率高。相比哈希索引,B+ 树不仅支持等值查询,还支持范围查询、排序、最左前缀等场景,所以更适合通用数据库索引。
2. 聚簇索引、非聚簇索引、回表、覆盖索引怎么讲?
答:InnoDB 主键索引是聚簇索引,叶子节点直接存整行数据;普通二级索引是非聚簇索引,叶子节点存主键值。如果通过普通索引查到主键后还要回到主键索引查整行数据,这叫回表。如果查询字段都能从二级索引里拿到,就叫覆盖索引,可以避免回表。比如商品表建立 (status, category, created_at, id, title, price) 这样的组合索引,在列表页只查这些字段时就可能覆盖查询。
3. 最左前缀原则和索引失效怎么回答?
答:联合索引遵循最左前缀原则,查询条件要从联合索引最左列开始连续匹配,才能充分利用索引。比如索引 (category, status, created_at),只查 status 可能用不上这个索引;查 category 和 status 可以用;范围查询后面的列可能无法继续用于有序定位。常见索引失效包括对索引列使用函数、隐式类型转换、like 以通配符开头、or 条件不当、范围查询后列利用受限等。
4. 事务 ACID 和隔离级别怎么讲?
答:事务是数据库中一组要么全部成功、要么全部失败的操作,ACID 分别是原子性、一致性、隔离性、持久性。隔离级别包括读未提交、读已提交、可重复读、串行化。隔离级别越高,并发能力通常越低。MySQL InnoDB 默认可重复读,通过 MVCC 和锁机制解决很多并发读写问题。校园交易平台下单时,创建订单和更新商品状态必须在一个事务里,否则可能出现订单创建成功但商品状态没更新的异常。
5. MVCC 是什么?
答:MVCC 是多版本并发控制,通过保存数据的多个版本,让读写可以并发进行,减少锁冲突。InnoDB 中每行记录有隐藏字段,比如事务 id 和回滚指针,结合 undo log 形成版本链,再通过 Read View 判断当前事务能看到哪个版本。读已提交每次查询生成新的 Read View,可重复读通常事务内第一次一致性读生成 Read View,所以同一事务内多次读取结果一致。回答 MVCC 时要说它解决的是读写并发和一致性读问题。
6. redo log、undo log、binlog 区别?
答:redo log 是 InnoDB 的重做日志,用来保证崩溃恢复后的持久性;undo log 是回滚日志,用于事务回滚和 MVCC 版本链;binlog 是 MySQL Server 层的二进制日志,用于主从复制和数据恢复。简单说,redo 保证已提交事务不丢,undo 保证可以回滚和做一致性读,binlog 用于复制和恢复。面试中这个问题经常和两阶段提交、事务一致性一起问。
7. explain 怎么看?
答:explain 用来查看 SQL 执行计划。重点看 type、possible_keys、key、rows、Extra。type 从好到差大致有 const、eq_ref、ref、range、index、ALL,ALL 通常表示全表扫描要警惕;key 表示实际使用的索引;rows 表示预计扫描行数;Extra 里 Using index 表示覆盖索引,Using filesort 或 Using temporary 可能需要优化。回答 SQL 优化时,我会先用 explain 定位问题,再调整索引或 SQL。
8. 慢 SQL 怎么优化?
答:慢 SQL 优化先定位慢查询日志,再用 explain 看执行计划,确认是否走索引、扫描行数是否过大、是否出现 filesort/temporary。优化手段包括只查必要字段,避免 select *,给 where/order by/group by 高频字段建合适索引,避免对索引列做函数和隐式转换,合理设计联合索引,分页深时改用基于 id 或时间游标的分页。校园平台商品列表页就是典型优化场景。
9. 如何防止同一商品重复下单?
答:我会把下单设计成事务内的条件更新:先根据商品 id 和 status='available' 更新商品状态为 locked 或 sold,如果影响行数为 1,说明抢到商品,再创建订单;如果影响行数为 0,说明已被别人买走。整个过程放在 MySQL 事务中,必要时使用行锁或乐观锁版本号。Redis 分布式锁可以作为并发流量的前置保护,但最终一致性必须由数据库条件更新和事务保证。
八、AI Agent 与大模型应用
1. AI Agent 到底是什么?
答:AI Agent 是以大模型为核心,具备任务理解、规划、工具调用、记忆和执行能力的系统。普通 LLM 调用通常是输入一个 Prompt 得到一个回答,而 Agent 会把复杂目标拆成步骤,根据上下文选择工具,执行后观察结果,再决定下一步。我的概念解读视频智能体里,Agent 思想体现在把“生成视频”拆成脚本、分镜、素材、TTS、字幕、合成多个步骤,并对每一步做校验和重试。
2. 大模型输出不稳定怎么解决?
答:我会从提示词、模型参数、结构化约束和工程兜底四层解决。提示词上明确输出 JSON 和字段含义;参数上降低 temperature;结构上使用 JSON Schema 或 Pydantic 校验;工程上 json.loads 失败就尝试修复、重试或走兜底模板,并记录错误日志。关键原则是不能完全相信模型输出,必须把模型当成不稳定外部服务来治理。
3. Function Calling / Tool Calling 怎么理解?
答:Function Calling 是让模型按照约定选择要调用的工具和参数,真正的工具执行由系统完成。它让模型从“只生成文本”变成“能调工具完成任务”。在视频智能体里,模型可以决定生成素材关键词、调用素材搜索工具、调用 TTS 工具、调用视频合成工具。面试时我会强调:工具调用要有参数校验、权限控制、超时控制和结果校验,不能让模型随便执行危险操作。
4.什么是 LLM?
答:LLM 全称是 Large Language Model,也就是大语言模型。我的理解是:它本质上是通过海量文本数据训练出来的概率模型,根据上下文预测下一个最可能出现的 Token。像:GPT,Claude,Qwen,Gemini,DeepSeek都属于 LLM。对于开发者来说,LLM最重要的能力其实是:理解自然语言,推理,总结,生成内容,结构化输出。比如我做的概念解读视频智能体里,LLM主要负责:内容理解,知识拆解,脚本生成,视觉规划,所以我更多把它看成一个智能推理引擎,而不是聊天机器人。
5.什么是 Prompt?
答:Prompt 就是给大模型的输入指令。因为大模型本身不会主动知道我要什么,所以需要通过 Prompt 告诉它:你是谁,你要干什么,有哪些要求,最终输出什么例如:请介绍Redis,也是 Prompt。但是这种 Prompt 比较弱。更好的 Prompt 应该是:你是一名计算机老师,请面向大学生用通俗易懂的方式,讲解Redis缓存,输出500字以内。这样结果会更稳定。
6.什么是 Prompt Engineering?
答:Prompt Engineering 就是提示词工程。简单理解:通过设计高质量 Prompt,让模型稳定输出符合预期的结果。我在项目里经常使用结构化 Prompt。一般包含:角色,任务,背景,约束,输出格式,示例。例如视频脚本生成:角色:知识科普导演,任务:生成60秒视频脚本,约束:通俗易懂,输出:JSON格式。这样模型输出稳定性会明显提升。
7. 一个好的 Prompt 应该包含哪些要素?
我觉得一个好的 Prompt 至少要有角色、任务目标、输入信息、输出格式、约束条件和示例。比如视频智能体里,我不会只写“帮我生成一个脚本”,而是会说明这是面向小白的概念解读视频,要有开场、解释、例子、总结,并要求输出 JSON。这样模型更容易生成可被程序解析和后续处理的内容。
8. Prompt Engineering 为什么体现工程能力?
因为 Prompt 不是写一句话让模型回答,而是要让模型输出稳定、可控、可接入系统。工程里要考虑格式约束、异常兜底、Token 成本、版本管理和测试样例。比如视频项目里,如果脚本格式不稳定,后面的 TTS、字幕和合成都会受影响,所以 Prompt 设计本质上是在设计 AI 模块的接口。
9. 如何降低大模型幻觉?
我会从三方面做:第一,给模型明确上下文,不让它凭空发挥;第二,要求它不知道就说明不确定,不要编造;第三,结合 RAG 或业务数据,让它基于检索材料回答。在项目里,如果是概念讲解,可以让模型生成通俗解释,但如果涉及具体规则参数,就应该来自数据库或知识库。
10. 如何提高大模型输出稳定性?
可以降低 temperature,明确输出格式,提供 few-shot 示例,并对输出做 JSON Schema 校验。如果失败,可以让模型重新修复格式,或者走兜底模板。我的项目里会尽量让大模型输出结构化结果,而不是一整段自然语言,因为结构化结果更方便后续 TTS、字幕和视频合成。
11. Prompt 太长怎么办?
Prompt 太长会增加成本,也可能稀释重点。我会把固定规则抽成模板,只动态填充必要输入;长文档可以先摘要或用 RAG 检索相关片段;重复说明尽量压缩。对于多步骤任务,也可以拆成多个小 Prompt,比如先生成大纲,再生成分镜,而不是一次让模型完成所有事情。
12.什么是 Token?
答:Token 可以理解成大模型处理文本的最小单位。它不是字,也不是单词。例如:Hello World
可能会被拆成多个 Token。中文也是一样,也会被拆分。模型实际上看到的并不是文字,而是一串 Token。Token 的重要性主要体现在:上下文长度,调用成本,推理速度。因为模型是按 Token 计费的。
13. Token 成本怎么优化?
首先减少无效上下文,只传当前任务需要的内容。其次把长 Prompt 模板精简,避免每次重复传大量说明。对于知识库场景,用 RAG 只召回相关 Chunk,而不是把整份文档塞进去。还可以根据任务难度选择合适模型,不是所有步骤都需要最强模型,比如格式修复可以用成本更低的模型。
14. Zero-shot、Few-shot 分别是什么?
Zero-shot 就是不提供示例,直接让模型完成任务;Few-shot 是给几个示例,让模型模仿格式和风格。比如我让模型生成概念讲解脚本,如果只给规则就是 zero-shot;如果给一两个“输入概念、输出脚本 JSON”的例子,就是 few-shot。实际工程里,few-shot 对稳定格式很有帮助。
15. 项目中 Prompt 是怎么设计和迭代的?
我会先根据任务拆 Prompt,比如脚本生成、标题生成、分镜生成分别设计。第一版先跑通流程,然后看模型输出哪里不稳定,比如 JSON 字段缺失、内容太长、口语化不足,再逐步加约束和示例。迭代时不会只看一次结果,而是用多个概念测试,保证 Prompt 对不同输入都比较稳定。
16. 为什么 AI 应用经常要求结构化输出?
因为 AI 应用不是聊天,后面还有程序要消费模型输出。比如视频智能体里,脚本、字幕、分镜、素材关键词都要给后续模块使用。如果只返回一段自然语言,程序很难稳定解析。结构化输出比如 JSON,可以让系统更容易校验、重试、落库和进入下一步流程。
17.什么是上下文窗口?
答:上下文窗口可以理解成:模型一次能够看到的最大 Token 数量。模型一次能够看到最大 Token 数量。上下文越大。模型记住的信息越多。例如:长文档分析,代码仓库分析,多轮对话,都会受上下文窗口影响。我在视频智能体里生成长脚本的时候,也需要考虑上下文长度,否则模型可能忘记前面内容。
18.什么是 Temperature?
答:Temperature 是控制模型随机性的参数。一般范围:0~2Temperature 越低:结果越稳定
Temperature 越高:结果越发散。例如:数学题,代码生成,通常会设置低一点。而:创意文案,故事创作,可以设置高一点。例如:我的项目生成 JSON 时一般会设置较低 Temperature,因为我要的是稳定而不是创意。
19.什么是 Embedding?
答:Embedding 可以理解成:把文本转换成向量。例如:Redis是什么,什么是Redis缓存。虽然字面不同。但是语义接近。Embedding以后。它们的向量距离会很近。Embedding主要用于:语义搜索,知识库检索,RAG,推荐系统。本质上是把自然语言转换成机器更容易计算的向量空间。
20.什么是向量数据库?
答:向量数据库是专门存储 Embedding 向量的数据库。例如:Milvus,FAISS,Chroma,Pinecone。普通数据库:根据ID查。向量数据库:根据语义查。例如:用户问:Redis为什么快?系统可以找到:Redis缓存机制,Redis底层原理,这些相关内容。即使文字不完全一样。
21.什么是 RAG?
答:RAG 全称:Retrieval Augmented Generation检索增强生成。核心思想:先查资料,再让大模型回答。流程:用户提问↓Embedding↓向量检索↓找到相关知识↓拼接Prompt↓LLM生成答案,这样回答会更准确。因为模型不仅依赖训练时知识。还可以使用外部知识库。
22.为什么需要 RAG?
答:因为大模型有两个问题:第一:知识过时。第二:幻觉
例如:公司内部文档,最新产品信息。模型训练时并不知道。这时候就需要 RAG。让模型先查知识库再回答。
23.什么是 Agent?
答:我理解 Agent 本质上是在大模型基础上增加了执行能力。通常包括:规划能力,工具调用能力,记忆能力,执行能力。普通 LLM:你问他答。Agent:理解任务,拆解任务,调用工具,执行任务,返回结果。所以 Agent 更像一个能够真正完成工作的数字员工。
24.Agent和LLM区别?
答:我觉得:LLM只是大脑。Agent是完整的人。LLM 负责思考和推理。Agent 除了思考之外,还具备:规划,执行,工具调用,状态管理。例如:LLM 可以告诉你怎么订机票。Agent 可以:查询航班,比较价格,完成预订,返回结果。所以LLM负责思考,Agent负责执行。
25.Agent有哪些核心能力?
答:我认为 Agent 通常包含五个核心能力:规划能力,工具调用能力,记忆能力,反思能力,执行能力
26.什么是 Tool Calling?
答:Tool Calling 就是工具调用。当大模型发现自己无法直接完成任务时,会调用外部工具获取信息或执行操作。例如:搜索工具,数据库工具,天气工具,邮件工具,视频生成工具。举个例子:用户问:北京今天天气怎么?模型本身并不知道实时天气。所以会:调用天气API,获取天气结果,组织自然语言回答。
27.什么是 Workflow?
答:Workflow 就是工作流。主要负责:控制执行顺序,管理依赖关系,管理任务状态。例如我的项目:脚本Agent,视觉Agent,素材Agent,TTS Agent,渲染Agent。前一个完成,后一个才能执行。这就是 Workflow。
28.什么是 AIGC?
答:AIGC 全称:AI Generated ContentAI生成内容。也就是利用 AI 自动生成各种内容。包括:文本生成,图片生成,语音生成,视频生成。现在的大模型应用大部分都属于 AIGC。
29.AI API调用流程是什么?
答:整体流程是:客户端,HTTP请求,LLM API,返回JSON,业务系统处理。调用模型之后,会得到模型返回结果。然后解析 JSON,进入后续脚本生成、视觉规划或者素材处理流程。
30.为什么很多AI应用都要结构化输出?
答:因为程序无法稳定处理自然语言。例如:请生成视频脚本如果返回一大段文字。后面模块很难解析。所以我会要求:
{
"title": "",
"scenes": []
}
这样:脚本模块,素材模块,字幕模块,渲染模块。都可以直接读取固定字段。在我的项目里,结构化输出也是解决大模型工程化落地最重要的方法之一。
Agent 深挖
1. 什么场景适合用 Agent?
适合任务目标明确,但中间步骤需要动态决策的场景。比如用户只输入一个概念,系统要判断怎么写脚本、找什么素材、生成什么字幕、怎么合成视频,这种多步骤任务就适合用 Agent 思想。但我理解的 Agent 不一定是完全自由决策,也可以是在工程流程约束下,让模型负责部分规划和生成。
2. 什么场景不适合用 Agent?
如果任务规则非常固定,用普通 Workflow 就够了,不一定要 Agent。比如简单 CRUD、固定字段转换、固定报表生成,用 Agent 反而增加不确定性和成本。AI 应用不是越 Agent 越高级,关键要看是否真的需要模型做推理、规划或工具选择。
3. Agent 和 Workflow 的区别是什么?
Workflow 更像固定流程,第一步做什么、第二步做什么提前写死;Agent 更强调根据目标和上下文做决策,可能会选择不同工具或路径。我的视频项目更接近“Workflow + Agent 能力”,主流程是固定的,但脚本生成、素材关键词、分镜内容由大模型生成,这样稳定性和智能性比较平衡。
4. 多 Agent 之间如何通信?
多 Agent 之间最好通过明确的数据结构通信,比如 JSON、任务状态、数据库记录或消息队列,而不是互相传一大段自然语言。比如脚本 Agent 输出脚本和分镜,素材 Agent 根据关键词找素材,合成 Agent 根据字幕和音频生成视频。每一步都要有清晰输入输出,否则后面很难调试。
5. Agent 执行失败怎么办?
首先要记录失败发生在哪个节点,是模型调用失败、格式解析失败,还是工具执行失败。然后根据错误类型决定重试、跳过、降级还是终止。比如脚本 JSON 解析失败可以让模型修复一次;TTS 失败可以重试;视频合成失败就要保留中间文件和 FFmpeg 日志,方便排查。
6. 状态机在 Agent 项目里有什么作用?
状态机可以让长任务的执行过程可控,比如 pending、running、script_done、audio_done、compose_failed、success。视频生成这种链路比较长,如果不用状态管理,失败后很难知道执行到哪一步。状态机还能支持断点恢复和前端查询进度,对工程化落地很重要。
7. LangGraph 为什么适合做 Agent 工作流?
LangGraph 适合把 Agent 任务建模成图,每个节点负责一个步骤,边表示流转关系,还可以保存状态。它比简单链式调用更适合复杂流程,比如有重试、有条件分支、有人工确认的场景。我的理解是,如果项目后续要做更复杂的多 Agent 编排,LangGraph 会比手写 if-else 更清晰。
8. 为什么不是所有 AI 应用都要做成 Agent?
因为 Agent 会带来成本、延迟和不确定性。很多业务其实只需要一次模型调用加规则后处理,比如摘要、分类、格式转换。如果强行做 Agent,系统更难测试和维护。我的判断是:能用确定性代码解决的就用代码,只有需要语言理解、规划、生成的部分才交给大模型。
9. Agent 项目怎么做日志和调试?
要按任务 id 记录每个节点的输入、输出摘要、耗时、错误信息和状态变化。Prompt 版本、模型名称、temperature 这些也要记录,否则同一个问题复现不了。比如用户说视频结果不对,我需要能追溯是脚本生成偏了、素材匹配错了,还是合成阶段出了问题。
九、多模态与视频生成
1. 什么是多模态?
答:多模态是系统同时处理或生成文本、图像、音频、视频等不同信息形态。视频生成项目中,文本脚本是文本模态,素材是视觉模态,TTS 是音频模态,字幕是文本和时间轴结合,最终视频是多模态融合结果。难点不在于单独生成某个模态,而在于脚本、画面、语音、字幕在语义、时间和风格上保持一致。
2. 视频生成完整链路怎么讲?
答:完整链路是用户输入主题和参数,LLM 生成讲解脚本,LLM 或规则模块把脚本拆成分镜 JSON,每个 scene 包含旁白、画面描述、素材关键词和预计时长;素材模块检索或生成图片/视频;TTS 生成旁白音频;字幕模块根据文本和音频时长生成字幕时间轴;最后用 FFmpeg/MoviePy 合成画面、配音、字幕、转场和背景音乐。这个流程我必须能从输入讲到输出。
3. 字幕和语音怎么对齐?
答:如果 TTS 服务返回字级或句级时间戳,就直接用时间戳生成字幕;如果没有时间戳,可以先按句子切分文案,再根据音频总时长、每句字数和语速估算时间轴;更准确的方案是用 ASR 或强制对齐工具重新识别音频,生成 SRT/ASS 字幕。面试时我会承认简单估算会有误差,然后说明如何逐步提高准确度。
4. FFmpeg 和 MoviePy 怎么分工?
答:FFmpeg 是底层音视频处理工具,性能强,适合转码、拼接、混音、烧录字幕、调整分辨率和码率;MoviePy 是 Python 层封装,写起来更直观,适合快速编排视频片段。项目中可以用 Python 负责流程和参数生成,用 FFmpeg 做最终可靠合成。遇到性能和兼容性问题时,我会优先检查 FFmpeg 命令、编码格式、路径转义、字幕字体和音视频时长。
十、软件工程与系统设计
1. 什么是高内聚低耦合?
高内聚就是一个模块内部做的事情比较集中,比如视频智能体里,脚本生成 Agent 就专门负责脚本,TTS 模块就专门负责语音,不要一个函数里既调大模型又合成视频又写数据库。低耦合就是模块之间依赖尽量少,通过清晰的输入输出交互。这样好处是后面某个模块出问题,比如字幕生成失败,我可以单独定位,不会影响整条链路的理解和维护。
2. 为什么项目要采用分层架构?
分层主要是为了让职责清楚,方便维护和扩展。比如 FastAPI 项目里,接口层负责接收请求,Service 层负责编排业务流程,底层再封装 LLM、TTS、素材检索、FFmpeg 等能力。这样如果以后把大模型接口从一个厂商换成另一个厂商,只需要改服务封装层,不需要把 Controller 全部改一遍。
3. Controller、Service、DAO 分别负责什么?
Controller 主要负责接收请求、参数校验和返回响应;Service 负责真正的业务逻辑,比如视频生成流程怎么编排、失败怎么处理;DAO 负责和数据库交互,比如商品、用户、订单这些数据的增删改查。在校园交易平台里,这种分层可以让接口逻辑、业务规则和数据库操作分开,秒杀逻辑也更容易维护。
4. MVC 是什么?
MVC 是 Model、View、Controller。Model 负责数据和业务模型,View 负责展示,Controller 负责接收用户请求并调用业务逻辑。在后端项目里,虽然不一定有传统页面 View,但这个思想仍然有用,比如接口层不要直接写数据库 SQL,而是通过模型和服务层组织逻辑,本质上也是为了职责分离。
5. 单体架构和微服务有什么区别?
单体架构是把功能放在一个应用里,部署简单,适合早期项目或者实习项目。微服务是把用户、订单、支付、素材、生成任务等拆成多个服务,扩展性更好,但会引入服务治理、链路追踪、分布式事务等复杂度。我的项目目前更适合单体加模块化设计,因为功能还在验证阶段,先保证能稳定落地更重要。
6. 如何做需求分析?
我一般会先明确用户是谁、解决什么问题、输入输出是什么。比如概念解读视频智能体,需求不是简单“生成视频”,而是用户输入一个概念后,系统能自动生成讲解脚本、语音、字幕和画面,减少人工剪辑和整理成本。然后再拆成必须有的功能、可以后续优化的功能,以及异常情况,比如大模型输出失败、素材不足等。
7. 如何做技术方案设计?
我会先根据需求拆模块,再确定技术选型和数据流。比如视频智能体可以拆成脚本生成、素材匹配、TTS、字幕、视频合成几个阶段。技术上用 Python 和 FastAPI 做接口,用大模型做脚本生成,用 FFmpeg 或 Remotion 做合成。方案设计时还要考虑失败重试、日志、配置管理和后续扩展,而不是只把 Demo 跑通。
8. 项目从需求到上线一般经历哪些流程?
一般是需求分析、方案设计、接口和数据结构设计、编码实现、联调测试、异常处理、部署上线和后续监控。以 AI 应用来说,还要额外做 Prompt 测试、输出格式校验、模型接口异常兜底,以及日志记录。因为大模型输出不完全稳定,所以测试不能只测正常流程,还要测 JSON 解析失败、超时、内容不符合预期这些情况。
9. 如何判断一个方案是否适合落地?
我会看几个点:第一,能不能解决真实问题;第二,开发和维护成本是否可控;第三,稳定性和异常处理是否足够;第四,后续能不能扩展。比如一个 Agent 方案如果链路太复杂,每一步都依赖大模型自由发挥,那虽然看起来智能,但落地风险很高。实际项目里我会更倾向于 Agent 思想加工程化约束,让模型负责生成和判断,流程由程序控制。
十一、RAG 与知识库
1. 什么是 RAG?
RAG 可以理解为“检索增强生成”。大模型回答问题前,先从知识库里检索相关资料,再把资料和问题一起交给模型生成答案。它不是让模型凭记忆回答,而是让模型基于外部知识回答。在企业知识库、领域问答、DataClawHub 这类领域迁移场景里,RAG 很适合用来补充模型不了解的业务资料。
2. 为什么需要 RAG?
因为大模型本身的知识可能过时,也可能不了解企业内部资料,还可能出现幻觉。RAG 的价值就是把回答限制在可检索的知识范围内。比如在差旅费用分摊或者领域知识问答里,如果直接让模型回答,可能会编规则;但如果先检索公司制度、报销规则、业务文档,再让模型总结,结果会更可靠。
3. RAG 的完整流程是什么?
一般流程是:先把文档清洗和切分成 Chunk,然后用 Embedding 模型转成向量,存到向量数据库里。用户提问时,也把问题转成向量,去数据库里检索相似内容,再把召回内容拼到 Prompt 中,让大模型生成答案。最后还可以加引用来源、格式校验和答案后处理,保证输出可追溯。
4. RAG 和微调有什么区别?
RAG 更适合接入经常变化的知识,比如业务文档、制度、产品说明;微调更适合让模型学习某种固定风格、任务模式或领域表达。RAG 更新知识比较方便,改文档、重建索引就可以;微调成本更高,也不适合频繁更新。我的理解是,实习项目里如果是知识问答或领域迁移,优先考虑 RAG,而不是一上来就微调。
5. Embedding 在 RAG 中起什么作用?
Embedding 的作用是把文本转成向量,让机器可以计算语义相似度。比如用户问“报销怎么分摊”,原文里可能写的是“差旅费用按人员和项目比例分摊”,关键词不完全一样,但语义接近。Embedding 可以帮助系统找到相关内容,而不是只靠关键词匹配。
6. 向量数据库是什么?
向量数据库就是专门存储和检索向量的数据库。它可以根据相似度快速找到和问题最相关的文档片段。普通数据库更擅长精确查询,比如按 id 查用户;向量数据库更适合语义检索,比如查“和这个问题意思相近的文档”。RAG 里常用它来做知识召回。
7. Chunk 怎么切?
Chunk 不能太大,也不能太小。太大会塞进很多无关内容,占 Token;太小又容易丢上下文。我会按标题、段落、语义边界去切,比如一条制度、一段说明、一个功能说明尽量保持完整。必要时可以加 overlap,让相邻 Chunk 保留一点上下文,避免模型拿到的信息断裂。
8. 召回不准怎么办?
我会先看问题是切分问题、Embedding 问题,还是检索策略问题。可以优化 Chunk 粒度,加关键词检索和向量检索混合召回,也可以做 rerank,把初步召回的内容重新排序。如果是业务词汇比较特殊,还可以补充同义词、领域词表,或者在 Prompt 里要求模型只基于召回内容回答。
9. 知识库内容更新后怎么处理?
如果是少量文档更新,可以只更新对应文档的 Chunk 和向量;如果结构变化很大,就需要重新切分并重建索引。同时要保留文档版本,避免用户问到旧规则时系统混用新旧内容。工程上还要考虑更新时间、来源、文档 id,这样后面排查答案错误时能追溯到具体知识片段。
10. DataClawHub 领域迁移中 RAG 能起什么作用?
DataClawHub 做领域迁移时,RAG 可以把目标领域的文档、术语、业务规则接入系统,让模型回答时更贴近本地业务。比如不改变大模型本身,只通过知识库补充领域材料,就能降低迁移成本。这样比直接微调更灵活,也更适合实习项目里快速验证一个 AI 应用能不能落地。
十二、部署与工程化
1. FastAPI 项目如何部署到 Linux?
一般流程是先在 Linux 上准备 Python 环境,安装 requirements,然后配置 .env,用 uvicorn 或 gunicorn 启动 FastAPI 服务,前面再用 nginx 做反向代理。如果是正式部署,还会用 systemd 或 Docker 保证服务能后台运行和异常重启。AI 项目还要额外确认模型 API Key、FFmpeg、字体、素材路径这些环境依赖。
2. uvicorn、gunicorn、nginx 分别负责什么?
uvicorn 是 ASGI 服务器,负责真正运行 FastAPI 应用;gunicorn 更像进程管理器,可以拉起多个 worker,提高稳定性;nginx 一般放在最前面,负责反向代理、静态资源、HTTPS、限流等。简单说,uvicorn 跑应用,gunicorn 管进程,nginx 扛入口流量。
3. Docker 是什么?为什么要用 Docker?
Docker 可以把应用和依赖环境一起打包,保证在不同机器上运行环境一致。比如视频智能体里可能依赖 Python 包、FFmpeg、字体文件、环境变量,如果手动部署容易漏东西。用 Docker 后,可以减少“我本地能跑,服务器不能跑”的问题,也方便后续迁移和部署。
4. 项目中的配置管理怎么做?
配置不要硬编码在代码里,比如 API Key、数据库地址、Redis 地址、模型名称、输出目录都应该放到配置文件或环境变量里。代码里通过统一的 config 模块读取。这样开发环境、测试环境、生产环境可以使用不同配置,也避免敏感信息直接写进代码仓库。
5. .env 和 config.py 分别解决什么问题?
.env 主要放环境相关和敏感配置,比如 API Key、数据库密码、服务地址;config.py 负责在代码里统一读取、校验和组织这些配置。我的理解是,.env 是配置来源,config.py 是配置入口。这样项目里其他模块不用到处读环境变量,只依赖统一配置对象。
6. 日志系统应该怎么设计?
日志至少要记录请求入口、关键步骤、耗时、错误原因和任务 id。比如视频生成链路很长,我会给每次任务一个 job_id,然后脚本生成、TTS、字幕、合成每一步都带着这个 id 打日志。这样用户说生成失败时,我能快速定位是模型输出问题、素材问题,还是 FFmpeg 合成问题。
7. AI 项目中如何做异常处理?
AI 项目的异常要分层处理。模型接口可能超时,输出可能不是合法 JSON,TTS 可能失败,视频合成也可能失败。所以不能只 try-except 打印错误,而是要分类处理:可重试的重试,不可重试的给出明确错误,关键中间结果要保存,方便恢复和排查。对用户返回的信息要友好,对开发者日志要详细。
8. 大模型 API 超时怎么办?
首先要设置合理 timeout,不能无限等待。超时后可以做有限次数重试,并且使用退避策略,避免短时间疯狂请求。如果任务比较耗时,可以改成异步任务,接口先返回任务 id,后台继续执行,用户轮询状态。对于视频生成这种长任务,这种方式比让 HTTP 请求一直挂着更合理。
9. 如何设计重试机制?
重试要有边界,不能无限重试。我会设置最大重试次数,比如 2 到 3 次,并且只对网络抖动、接口超时这类临时错误重试。对于参数错误、JSON 格式一直不对、素材不存在这种问题,应该快速失败并记录原因。重试最好配合日志和任务状态,避免用户不知道系统卡在哪里。
10. 如何保证项目在不同环境下能运行?
核心是依赖和配置标准化。依赖用 requirements 或 Docker 固定版本,配置用 .env 区分环境,路径不要写死,外部服务地址可配置。像视频项目还要检查 FFmpeg 是否安装、字体是否存在、输出目录是否有权限。上线前最好有一份启动检查脚本或部署文档,把环境问题提前暴露出来。
第二部分:实习经历与简历技能点追问
1. 你这段实习/经历主要体现什么能力?
答:我这段经历主要体现 AI 应用开发和后端工程落地能力。具体来说,我能用 Python 和 FastAPI 搭建接口服务,用 Redis 做缓存和任务状态管理,用 MySQL 做业务数据建模和事务处理,用 Linux 完成部署和排查,同时能把大模型、Prompt、Agent、TTS、字幕和视频合成这些 AI 能力串成一个完整业务流程。面试时我不会只说“我会某个技术”,而是强调我能把技术组合成可运行、可排查、可优化的系统。
2. 你熟悉 Python,项目中具体怎么体现?
答:我的 Python 能力体现在三层:第一是语言基础,比如 list/dict/set、装饰器、生成器、异常处理、面向对象和异步;第二是工程化,比如模块拆分、配置管理、日志、测试、依赖管理;第三是业务落地,比如用 Python 编排 LLM 调用、素材处理、TTS 请求、字幕生成和 FFmpeg 合成。概念解读视频智能体就是一个典型 Python 工程,而不是单个脚本。
3. 你熟悉 FastAPI,具体做了什么?
答:我会用 FastAPI 设计 RESTful 接口,包括 APIRouter 拆分模块,Pydantic 定义请求和响应模型,Depends 处理认证和数据库连接,后台任务处理耗时流程,Swagger 文档辅助调试。比如视频生成系统里,我会设计提交任务、查询任务状态、获取结果三个接口;校园交易平台里,我会设计用户登录、商品发布、商品查询、收藏和下单接口。
4. 你熟悉 Redis,项目中怎么用?
答:Redis 在我的项目里不是只会 set/get,而是根据场景选择数据结构。校园平台可以用 String 存验证码和 Token,用 Hash 存用户会话,用 ZSet 做热门商品排序,用缓存降低商品详情查询压力;视频智能体可以用 Hash 存 job_id 的 status、progress、current_step、result_url 和 error_message。涉及缓存一致性时,我会采用先更新数据库再删除缓存的策略。
5. 你熟悉 MySQL,项目中怎么体现?
答:MySQL 主要体现在表结构设计、索引设计、事务一致性和 SQL 优化。校园交易平台要设计用户表、商品表、订单表、收藏表;商品列表要按分类、状态、发布时间查询,所以要设计联合索引;下单要保证创建订单和更新商品状态在一个事务里,避免重复购买。面试时我会主动讲“表关系 + 索引 + 事务”,而不是只说会写 SQL。
6. 你熟悉 Linux,能解决什么问题?
答:我能在 Linux 上部署 FastAPI 项目,配置 Python 环境、依赖、环境变量、Nginx 反向代理和 systemd 服务,也能用 ps/top/lsof/ss/tail/grep/df/free/curl 等命令排查服务启动失败、端口不通、接口超时、日志报错、磁盘满、内存高等问题。后端开发不能只会写代码,还要能把服务跑起来并排查线上问题。
第三部分:项目一 - 概念解读视频智能体深挖
1.项目简要描述
我独立开发了一个概念解读视频智能体,主要解决的是从一个主题自动生成科普短视频的问题。用户输入一个主题,比如“什么是黑洞”或者“什么是提示词优化”,系统会先调用大模型完成内容理解和知识拆解,然后生成结构化脚本和分镜,再进行视觉规划、语音生成、字幕生成以及视频渲染,最终输出一个完整的短视频。整个项目采用多Agent工作流架构,我负责从架构设计到功能开发的全部过程,包括FastAPI接口设计、Agent编排、多模态生成链路、TTS、字幕同步以及FFmpeg视频渲染等核心模块。
2. 项目背景和价值是什么?
答:这个项目解决的是知识讲解视频制作成本高的问题。传统流程需要人工写脚本、找素材、配音、加字幕、剪辑,耗时长且流程重复。我的项目目标是用户输入一个概念,系统自动生成讲解脚本、分镜、素材、配音、字幕和最终视频。它的价值在于把大模型能力和多模态工具链结合起来,形成一个可自动化执行的内容生产流程。
3. Prompt怎么设计?
我一般按照六要素设计Prompt。角色->任务->背景->约束->输出格式->示例.比如知识拆解阶段。我会明确要求:你是科普内容专家,请将主题拆解成5个知识点,输出JSON格式,不要输出额外解释,这样模型输出会稳定很多。
4. 整体架构怎么讲?
答:我会把架构分成 API 接入层、任务管理层、Agent 编排层、模型服务层、素材服务层、TTS 服务、字幕服务、视频合成服务和存储层。FastAPI 接收请求并返回 job_id;Redis 存任务状态和进度;Agent 编排脚本、分镜、素材、配音、字幕、合成;LLM 负责生成结构化脚本和分镜;FFmpeg/MoviePy 负责合成最终视频。这样讲能体现系统分层,而不是一个脚本从头跑到尾。
5. 为什么要用 Agent 思想?
答:因为生成视频不是一次模型问答,而是一个多步骤、多工具、多模态的流程。Agent 思想可以把复杂目标拆解为脚本生成、分镜生成、素材检索、TTS、字幕生成、视频合成等子任务,并根据每一步结果决定继续、重试还是兜底。它的价值是提高流程可控性、可扩展性和可排查性。如果只用一个 Prompt,输出不可控,任何一步失败都很难定位。
6. 为什么要拆多个Agent?
一开始我也尝试过用一个Prompt直接生成最终结果。但是很快发现效果不稳定。因为一个模型同时做内容理解、知识拆解、脚本生成和视觉规划,任务太复杂了。输出质量波动特别大。后来我参考Agent设计思想,把任务拆成多个阶段:主题分析Agent,知识拆解Agent,脚本生成Agent,视觉规划Agent,素材处理Agent,视频生成Agent。这样每个Agent只负责一个任务。Prompt更简单。结果也更稳定。而且后期维护成本更低。
7. Agent和Workflow有什么区别?
我的理解是:Workflow更像固定流程。例如:A->B->C->D。每一步都是提前确定好的。而Agent更强调自主决策能力。Agent会根据当前状态决定下一步做什么。我项目里其实两者都用了。整体上是Workflow。但是每个节点内部会调用大模型完成推理和决策。所以我把它理解成:Workflow负责流程编排,Agent负责智能决策
8. 任务状态怎么设计?
答:项目里我设计了统一的VideoState。所有Agent共享同一个状态对象。例如:topic,script
storyboard,materials,audio,subtitle,video每个Agent读取自己需要的数据。处理完成后再写回状态。这样避免了Agent之间直接耦合。后面新增功能也比较方便。
9. 大模型输出 JSON 不稳定怎么办?
答:我会先在 Prompt 中明确要求只输出 JSON,并给出字段定义和示例;然后后端用 json.loads 和 Pydantic/Schema 校验字段是否完整、类型是否正确、duration 是否合理。如果解析失败,先尝试格式修复,再重试模型请求,仍失败则使用兜底分镜模板并记录日志。工程上不能依赖“模型应该听话”,必须把模型输出当成不稳定外部输入来处理。
10. 素材匹配怎么做?
答:最开始用的是本地素材库。但是问题很明显。比如:黑洞,TCP,Transformer。很难找到准确素材。后来改成:大模型先分析场景视觉意图。然后生成搜索词。再去百度图片搜索。例如:什么是黑洞->黑洞宇宙模拟图,事件视界,时空扭曲。然后下载素材并进行尺寸校验。提高匹配准确率。
11. TTS、字幕、画面怎么对齐?
答:我会优先先生成 TTS 音频,再根据音频时长调整 scene duration 和字幕时间轴。如果 TTS 服务提供时间戳,就直接用;如果没有,就按句子长度和音频总时长估算;更准确可以用 ASR 对音频重新识别生成字幕。画面时长要和对应旁白时长一致,字幕不能太长,长句要切分。这个问题体现多模态系统最核心的时间对齐能力。
12. 字幕怎么同步?
最开始尝试过Whisper识别。但是会出现识别错误。后来改成脚本驱动方案。因为剧本本身就是已知的。所以直接根据TTS返回的时间戳生成字幕。这样字幕内容和旁白完全一致。同步效果更好。
13. 视频合成失败怎么排查?
答:我会先看 FFmpeg 返回码和 stderr 日志,再检查输入素材路径是否存在、文件格式是否支持、音频时长是否异常、字幕文件编码和字体路径是否正确、输出目录是否有权限。如果是 Windows 路径或中文路径,还要注意转义和编码。项目中每一步都要记录日志,否则只看到最终失败很难定位是哪一个 scene 或哪一个素材出问题。
14. FFmpeg和MoviePy怎么分工?
MoviePy主要负责:
视频拼接
时间轴处理
转场
FFmpeg主要负责:
音视频合成
字幕烧录
转码输出
简单理解:MoviePy负责编辑。FFmpeg负责最终生产。
15. Remotion为什么要用?
因为我后期发现单纯拼接图片和视频。画面表现力不够。比较像PPT。所以引入了Remotion。Remotion本质上是:React+视频渲染,我可以像写前端页面一样写动画。实现:数字增长,粒子动画,流程图动画,镜头运动,最终视频观感明显提升。
16. 为什么用FastAPI?
主要有三个原因。第一:开发效率高。第二:天然支持异步。第三:和Pydantic结合很好。特别适合AI应用。因为AI项目经常涉及:大模型调用,文件上传,视频生成,异步任务。FastAPI处理这些场景比较方便。
17. 项目最大的技术难点是什么?
答:最大难点是长链路稳定性和多模态一致性。长链路意味着 LLM、素材、TTS、字幕、FFmpeg 任一步都可能失败;多模态一致性意味着脚本、画面、语音、字幕要表达同一个意思且时间同步。我的解决思路是模块化拆分,每一步做输入输出校验,失败可重试,关键状态落 Redis,日志带 job_id,最终有兜底策略。
18. 如果优化这个项目,你会怎么做?
答:我会从稳定性、性能、效果和工程化四个方向优化。稳定性上加 JSON Schema、重试、兜底和任务恢复;性能上并发下载素材、缓存复用素材、引入任务队列;效果上优化 Prompt、素材筛选和字幕对齐;工程化上增加日志追踪、配置化、测试和监控。这样回答能体现我不是只完成 demo,而是知道如何向生产级系统演进。
第四部分:项目二 - 校园闲置交易平台深挖
项目描述:
我做的是一个基于 C++ Drogon 框架开发的校园闲置交易平台后端系统。项目主要是模拟校园二手交易场景,提供:用户注册登录,商品发布,商品查询,订单创建,秒杀下单这些核心功能。整体技术栈主要用了:C++,Drogon,MySQL,Redis,Linux 项目整体采用的是:Controller / Service / DAO三层架构。这样做的目的是:把接口处理,业务逻辑,数据访问解耦。后期维护和扩展会更方便。比如:Controller层主要负责接收HTTP请求,参数校验,返回JSON 。Service层负责:秒杀逻辑,订单逻辑 缓存逻辑。DAO层负责:和MySQL交互。项目里我觉得最核心的部分是:秒杀高并发场景下的库存一致性问题。因为如果多个用户同时下单。很容易出现:库存已经没了但订单还创建成功也就是超卖。所以这里我采用了:Redis + Lua脚本 + MySQL事务的方案。具体流程大概是:用户请求秒杀后:先在Redis里通过Lua脚本进行库存原子预减。Lua脚本会:判断库存是否大于0 ,扣减库存。因为Redis执行Lua脚本是原子的,所以不会出现并发竞争问题。只有Redis扣减成功后:才会继续执行数据库事务。数据库事务里:同时完成:扣减MySQL库存,创建订单。这样保证:库存和订单数据一致。最后如果成功:再删除商品缓存,避免缓存脏数据。另外项目里还用了:Cache Aside 模式。因为商品详情属于高频查询场景。如果每次都访问MySQL:数据库压力会比较大。所以:优先查Redis。Redis没有再查MySQL并回写缓存。商品更新或下架后:主动删除缓存,保证数据一致性。最后我还通过:Shell脚本模拟并发秒杀。验证:库存是5时。最终只有5个订单成功创建。保证:不会超卖。
每个模块:
1. 用户注册登录怎么做的?
用户模块这块,我主要是通过 Drogon 提供的 HTTP 接口实现的。比如注册的时候:前端会传:用户名 密码 这些信息。Controller 接收到请求后,会先做参数校验。然后进入 Service 层。Service 里会先查数据库,判断用户名是否已经存在。如果不存在:再把用户信息写入 MySQL。登录逻辑的话:会先根据用户名查数据库。然后校验密码是否正确。验证成功之后返回对应结果。因为项目主要还是偏后端逻辑,所以认证这块我做的是比较基础的账号密码登录
2. 商品发布/查询/更新/下架怎么做?
商品发布本质上就是:新增商品数据。前端传商品信息后。Controller接收请求。然后Service层处理业务。最后DAO层写入MySQL。商品表里我设计了:商品名称 价格 库存 status状态 这些字段。
商品查询这里我加了 Redis 缓存。因为商品详情属于高频读场景。如果每次都查 MySQL。数据库压力会比较大。所以查询的时候:会先查 Redis。如果 Redis 里有。直接返回。如果没有:再查 MySQL。然后把结果回写 Redis。这个其实就是Cache Aside 模式。
商品更新的时候:我会先更新 MySQL。更新成功后:删除 Redis 缓存。因为如果直接更新缓存。可能会出现:缓存更新失败。或者并发覆盖问题。所以我这里采用的是:删除缓存。让后续查询自动重建缓存。
商品下架我做的是逻辑下架。不是直接删除数据库数据。因为真实业务里:通常不会真的删数据。所以我在商品表设计了:status字段。下架时:只是把状态改成“已下架”。查询商品时:只查询status正常的数据。
3. 秒杀功能怎么做?
秒杀功能主要是解决:高并发下的超卖问题。因为如果多个用户同时下单。可能都会读到:库存还有。最后导致超卖。所以我这里设计的是:先 Redis。后 MySQL。具体流程是:用户请求过来之后。先在 Redis 查询库存。然后通过 Lua 脚本完成:判断库存 扣减库存 这两个操作。因为 Lua 在 Redis 里执行是原子的。所以不会出现并发问题。如果 Redis 扣减失败。说明库存没了。直接返回秒杀失败。如果 Redis 扣减成功。才继续执行 MySQL事务。事务里:同时完成:数据库扣库存 创建订单 这样保证订单和库存一致。最后事务成功后:会删除商品缓存。避免缓存脏数据。
4. Shell并发测试怎么做
写了 Shell 脚本模拟并发请求。比如:库存设置为5。然后同时发很多请求。最后我会去数据库验证:是不是最终只有5个订单成功创建。这个主要是为了验证:高并发下不会超卖。
相关问题
1. 为什么采用三层架构?
因为如果业务逻辑直接写在Controller里。后期项目一大:代码会非常混乱。所以我拆分成:Controller,Service,DAO。这样:职责更清晰。后期:比如数据库替换。或者业务逻辑修改。影响会更小。
2. 为什么秒杀要先Redis再MySQL?
因为Redis性能远高于MySQL。高并发下:如果所有请求直接打数据库。数据库压力会很大。所以:Redis先抗住高并发请求。MySQL负责最终数据落库。
3.Lua脚本为什么原子?
Redis执行Lua脚本时:会把整个脚本作为一个整体执行。中间不会插入其他命令。所以:库存判断和扣减可以一次完成。避免并发问题。
4. 如果Redis扣成功了,但MySQL事务失败怎么办?
目前这个项目里:如果MySQL事务失败。我会:回滚数据库事务。
同时:补偿Redis库存。把库存加回去。避免Redis和MySQL数据不一致。
5. 为什么删除缓存而不是更新缓存?
因为删除缓存实现更简单。一致性更好。如果直接更新缓存:可能更新失败,并发覆盖 所以实际项目里:很多都会采用:更新数据库后删除缓存。让后续查询自动重建缓存。
6.为什么用Lua。
我项目里 Lua 脚本主要是为了保证:库存判断和库存扣减的原子性。因为如果不用 Lua。而是:先GET库存再decr扣库存中间可能会被其他请求插入。比如:两个线程同时读到库存还有1。最后都扣成功。这样就超卖了。所以我把:判断库存 扣减库存 写到一个 Lua 脚本里。 Redis 一次执行完成。因为 Redis 执行 Lua 脚本时:整个脚本不会被其他命令打断。所以天然保证原子性。
7.Redis缓存三剑客
1. 缓存穿透查不存在的数据。每次都打数据库。解决:布隆过滤器,缓存空值
2. 缓存击穿热点Key突然过期。大量请求同时打数据库。解决互斥锁,热点永不过期
3. 缓存雪崩大量Key同时过期。解决:随机过期时间,Redis集群
8.校园交易这个项目http怎么接收的
我这个项目里 HTTP 请求主要是通过 Drogon 提供的 Controller 路由机制接收的。比如:用户请求:GET /product/1这种接口,请求到达服务端之后,Drogon会根据配置好的路由,自动分发到对应Controller的处理函数。比如:商品查询接口。我会在 Controller 里定义:对应的 GET 接口。然后 Drogon 收到 HTTP 请求后。会自动调用对应函数。函数里再获取:URL参数,JSON数据,请求头这些信息。处理完业务逻辑后。再通过 JSON 格式返回结果。
9. 为什么选择Drogon而不是其他C++ Web框架?Drogon的哪些特性对秒杀场景特别有帮助?
-
Drogon是高性能异步非阻塞框架,基于
proactor模型(epoll + 线程池),类似Golang的netpoller,适合IO密集型(如大量数据库/Redis请求)。 -
对秒杀场景特别有用的特性:
-
协程支持:可以用同步风格写异步代码,避免回调地狱,方便在秒杀接口中串行调用“Redis预减 -> MySQL事务 -> 返回结果”。
-
内置ORM:自动连接池、事务管理,减少手写SQL的出错风险。
-
高性能HTTP解析:基于
http_parser,每秒可处理数万请求。 -
插件化过滤器:可以轻松实现限流、鉴权等中间件。
-
10.如果Redis崩溃了,库存状态会丢失吗?
-
如果Redis未开启RDB/AOF持久化,重启后库存全丢。
-
解决方案:使用Redis Cluster + 持久化,或秒杀活动前将初始库存从MySQL加载到Redis,并定期备份。更严格的做法:Redis只做预扣,最终以MySQL为准。
11. Redis预减后,MySQL还扣库存吗?如何保证一致性?
-
会扣。Redis预减是为了快速过滤超卖请求,真正扣减仍在MySQL事务中完成(
UPDATE products SET stock=stock-1 WHERE id=? AND stock>0)。 -
一致性保证:
-
先Redis预减成功,再进入MySQL事务扣减。
-
如果MySQL事务失败(比如网络异常、行锁超时),需要回滚Redis(重新
INCR库存)。可以用Lua脚本回滚,或发送延迟消息补偿。 -
最终以MySQL为准,通过定时任务对账(MySQL剩余库存 = Redis剩余库存?不匹配时修复)。
-
第五12. 如果超卖,排查步骤?
-
检查MySQL
products.stock最终值是否为负数。 -
检查Redis Lua脚本是否没有原子执行(比如用了多条Redis命令而非eval)。
-
检查MySQL隔离级别(默认Repeatable Read可能引起幻读),是否用了
SELECT ... FOR UPDATE? -
检查代码中是否有并发路径下两次扣库存(比如业务逻辑重复调用)。
-
查看Drogon日志,是否有事务回滚但忘记回滚Redis。
第五部分:自我介绍
面试官您好,我叫王俞涵,目前就读于西安工业大学软件工程专业,是一名大三学生。在校期间系统学习了数据结构、计算机网络、操作系统、数据库原理以及软件工程等课程,前期主要以 C++ 后端开发和 Linux 开发方向为主,做过校园闲置交易平台后端项目,对数据库设计、缓存、网络编程以及系统开发有一定实践经验。进入实习之后,我开始将重心逐渐转向 Python 和 AI 应用开发方向。在实习期间,我独立负责并完成了多个 AI 应用项目,包括概念解读视频智能体、差旅费用分摊智能体、DataClawHub 搭建以及智能眼镜场景相关项目开发。在这些项目中,我主要负责需求分析、方案设计、功能开发以及问题排查和优化工作,接触并实践了大模型应用开发、多Agent工作流、Prompt设计、多模态内容生成以及AI产品落地相关内容。在AI应用开发方面,我对 Prompt Engineering、Agent工作流以及多模态内容生成比较感兴趣,也积累了一些实际项目经验。相比单纯调用模型接口,我更关注如何结合具体业务场景进行需求分析和方案设计,把大模型能力真正落地到实际产品中,并通过工程化手段提升系统的稳定性和可用性。
第六部分:其他项目(未写到简历上)
1.差旅费用分摊智能体
差旅费用分摊智能体是我在实习期间独立完成的一个财务业务智能体项目。项目背景是公司财务数据分散在 U8、OA、商旅系统以及各类 Excel 台账中,尤其是差旅报销场景,需要财务人员手动导出数据、拆分发票、核对金额、进行费用归集和部门分摊,整个过程重复度高且容易出现人为错误。
我负责的这部分主要是围绕差旅费用自动核算与分摊展开。系统需要处理来自空港嘉华、在路上等商旅系统导出的差旅明细,同时结合 OA 报销单、人力部门提供的分摊表以及财务核算规则,对机票、火车票、住宿费、代理服务费、退票费等不同类型费用进行自动分类和汇总。
在实现过程中,我首先对业务规则进行了梳理和结构化建模,把原本依赖人工经验判断的规则转化成可执行逻辑。例如不同费用类型对应不同部门归属、不同发票对应不同核算口径、含税与不含税金额处理方式不同、退票费用需要单独统计等。
在系统设计上,我通过 Python 构建数据处理流程,对多个来源的数据进行统一清洗、标准化和映射处理,然后结合规则引擎自动完成费用归集、部门分摊以及差异核对。对于无法直接匹配的数据,系统会生成异常清单和差异说明,方便财务人员进一步确认。
这个项目最大的难点其实不在代码实现,而在业务规则抽象。因为同样一笔费用,在不同系统里的字段名称、统计口径和归属逻辑可能完全不同。我花了比较多时间和财务同事沟通业务流程,把这些规则沉淀成统一的数据模型和处理逻辑,最终实现了从原始数据导入、费用分类、自动分摊到结果输出的完整自动化流程。
通过这个项目,我对企业财务场景的数据治理、规则引擎设计以及AI结合业务流程自动化有了比较深入的理解,也积累了从需求分析、方案设计到最终落地交付的完整项目经验。
2.DataClawHub搭建
DataClawHub 是公司内部用于大模型应用落地的平台项目,我参与并独立负责了本地化部署以及领域迁移适配工作。项目最初主要面向物流行业场景,平台本身集成了大模型、知识库检索以及Agent能力,能够为业务提供智能问答、知识查询和任务处理等功能。随着业务需求变化,公司希望将其从物流领域扩展到网络安全领域,因此需要完成环境部署、模型接入、知识库重构以及业务场景适配等工作。
在项目中,我首先完成了平台的本地化部署,包括运行环境搭建、依赖配置、服务启动以及模型接入等工作,保证平台能够稳定运行。随后针对网络安全场景进行了领域迁移,重新梳理网络安全相关知识内容,构建对应知识库,并对Prompt和业务流程进行调整,使系统能够围绕漏洞分析、安全知识查询、安全场景问答等任务进行回答。
项目过程中最大的难点是领域迁移。因为物流和网络安全属于完全不同的业务领域,原有知识库和提示词体系无法直接复用。我需要分析目标业务场景,重新设计知识组织方式和检索逻辑,保证知识召回的准确性和回答内容的相关性。同时在测试过程中持续优化Prompt和知识内容,解决模型回答偏离业务场景的问题。
通过这个项目,我对RAG知识库、Prompt Engineering、Agent应用以及企业级AI平台部署和落地有了更深入的理解,也积累了从环境部署、知识库建设到业务场景适配的完整实践经验。
第七部分:场景题
1. Redis 挂了怎么办?
我会先看 Redis 是完全不可用还是连接数、内存、网络问题。如果业务强依赖 Redis,比如秒杀库存预扣,要先降级或暂停秒杀,避免直接打到 MySQL 造成更大问题。如果只是缓存场景,可以临时走数据库,但要加限流。恢复后再检查 Redis 和 MySQL 数据是否一致,必要时做库存校准。
2. MySQL 突然变慢怎么排查?
我会先看是不是慢 SQL 增多,用 slow log 和 explain 看索引有没有命中。然后看连接数、锁等待、CPU、磁盘 IO 是否异常。如果是某个查询没走索引,就优化 SQL 或加索引;如果是并发突然变高,就考虑缓存、限流或者读写分离。排查时不能只看代码,要结合数据库状态一起看。
3. 大模型接口超时怎么处理?
先设置 timeout,避免请求一直卡住。然后做有限重试和退避,如果仍然失败,就返回明确状态,不能让整个任务无响应。对于视频生成这种长任务,我会设计成后台任务,接口先返回任务 id,用户查询进度。这样即使模型接口慢,也不会阻塞前端请求。
4. 视频生成时间太长怎么优化?
我会先拆分耗时,看是脚本生成、TTS、素材下载还是视频合成慢。能并行的部分尽量并行,比如多个字幕片段或素材处理。素材可以缓存,避免重复下载。视频合成阶段可以减少不必要的转码,统一格式和分辨率。工程上还可以用任务队列,把长任务放后台执行。
5. JSON 解析失败怎么办?
首先不要直接让程序崩掉,要捕获异常并记录原始输出。然后可以做格式修复,比如让模型根据错误重新输出合法 JSON,或者用正则提取 JSON 块后再解析。更根本的是 Prompt 里明确字段、类型和示例,并在代码里做 Schema 校验。失败多次就走兜底或提示生成失败。
6. Agent 执行到一半失败怎么办?
要看失败节点和任务状态。如果前面已经生成了脚本和音频,就不要全部丢掉,可以保留中间结果,支持从失败节点重试。比如合成失败就重点看 FFmpeg 日志,而不是重新调大模型生成脚本。状态机和日志在这里很关键,可以避免用户和开发者都不知道任务卡在哪里。
7. 线上 CPU 100% 怎么排查?
先用 top 或 htop 看是哪个进程占 CPU,再看是业务请求暴增、死循环、视频转码,还是某个任务并发太高。AI 视频项目里,FFmpeg 合成很可能吃 CPU,所以要限制并发任务数。排查时还要看日志和最近上线变更,如果是新代码导致的,就考虑回滚或限流。
8. 内存持续上涨怎么排查?
我会先确认是哪个进程内存上涨,再看是否有大对象没有释放,比如视频中间文件、音频数据、图片素材、任务结果缓存等。Python 项目里还可以用内存分析工具看对象增长。对于长任务系统,要注意及时关闭文件句柄、清理临时文件、限制队列长度,避免任务堆积把内存撑满。
9. 用户说生成结果不对,怎么定位问题?
我会先拿到用户输入和任务 id,查看完整日志。然后按链路排查:Prompt 输入是否正确,模型输出是否偏题,结构化解析是否出错,素材匹配是否不相关,字幕和音频是否错位。AI 应用的问题不一定是代码 bug,也可能是 Prompt、模型输出或数据质量问题,所以要能追溯每一步中间结果。
10. 如果并发用户变多,系统怎么扩展?
首先接口层可以加多 worker 或多实例,前面用 nginx 做负载均衡。耗时任务比如视频生成要放到任务队列,不要同步阻塞请求。Redis 可以做缓存和任务状态存储,数据库要优化索引和连接池。对大模型 API 还要做限流和排队,因为真正瓶颈可能不是后端代码,而是外部模型接口和视频合成资源。
AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。
更多推荐



所有评论(0)