AI 应用开发 — 小白讲解 + 面试题精解
AI 应用开发 — 小白讲解 + 面试题精解
定位:假设你只会调 OpenAI 的 chat 接口,所有概念从零讲起,配代码示例 + 面试题。 覆盖:LangChain4j → RAG 全流程 → Prompt 工程 → 向量数据库 → AI Agent → AI 编程工具 六大模块。 用法:先读讲解理解概念 → 跑代码验证 → 再看面试题自测。 特色:每个知识点都结合简历真实项目案例,面试时能直接用。
目录
- 第一章:LangChain4j 与 RAG 全流程(简历项目二核心)
- 第二章:Prompt 工程(简历直接写了)
- 第三章:向量数据库与 Embedding
- 第四章:AI Agent 编排(简历项目二核心升级)
- 第五章:AI 编程工具与 Skills 规则工程(简历新增亮点)
第一章:LangChain4j 与 RAG 全流程(简历项目二核心)
简历项目二直接写了“基于 LangChain4j 研发 RAG 企业知识库系统”。 面试官会重点考察:你真的懂 RAG 还是只会调 API。
1.1 为什么需要 RAG(而不是直接问 LLM)
小白讲解
直接让 LLM 回答企业知识库问题的三大问题:
1. 知识时效性:LLM 训练数据有截止时间,不知道最新知识
2. 幻觉(Hallucination):LLM 会一本正经地编造不存在的答案
3. 数据隐私:企业文档不能上传给公网 LLM 训练
4. 成本:每次把全部文档塞进 prompt,token 成本爆炸
RAG(Retrieval-Augmented Generation,检索增强生成)的思路:
不让 LLM 凭空回答,而是先"检索"相关文档,再让 LLM"基于文档"生成答案
→ 检索(Retrieval) + 增强(Augmented) + 生成(Generation)
面试题
Q1:什么是 RAG?为什么不用 LLM 直接回答?(高频 ⭐⭐⭐⭐⭐)
答:
- RAG = 检索增强生成:先从知识库检索相关文档片段,再把片段拼进 Prompt 让 LLM 基于文档回答
- 不用 LLM 直接回答的原因:①知识时效性 ②幻觉 ③数据隐私 ④成本
1.2 RAG 全流程(面试必问)
小白讲解
RAG 完整流程(7 步,面试要能背出来):
离线阶段(建库):
① 文档加载(Document Loader):读取 PDF/Word/Excel
② 文档分块(Splitter):把长文档切成 500-800 字的小块
③ 向量化(Embedding):每块文本转成向量
④ 存储(Vector Store):向量存入 pgvector
在线阶段(查询):
⑤ 检索(Retrieve):用户问题向量化 → 相似度检索 Top-K 块
⑥ 增强(Augment):把检索到的块 + 用户问题拼进 Prompt
⑦ 生成(Generate):LLM 基于拼接的 Prompt 生成答案
口诀:加载 → 分块 → 向量化 → 存储 → 检索 → 增强 → 生成
结合简历案例
简历原文:
"开发 PDF/Word/Excel 多格式文档上传接口,基于 Apache Tika 提取文本;
设计文档分块策略(段落语义分割+滑动窗口500-800字);
集成 LangChain4j 调用 Qwen Embedding API 实现向量化;
使用 pgvector 设计余弦相似度检索 SQL,Top-5 召回准确率 85%+;
开发 /chat 对话接口(检索→Prompt拼接→LLM调用→SSE流式返回)"
面试话术(把 RAG 流程和简历对应起来):
"我负责 RAG 系统的后端核心链路:
1. 文档加载:用户上传 PDF/Word/Excel,用 Apache Tika 提取文本
2. 文档分块:按段落语义分割 + 滑动窗口 500-800 字
(太短上下文不完整,太长向量稀释)
3. 向量化:调用 Qwen Embedding API 把分块转成 1536 维向量
4. 存储:向量存入 PostgreSQL + pgvector
5. 检索:用户问题向量化,用余弦相似度检索 Top-5
6. 增强:把 Top-5 分块拼进 Prompt
7. 生成:调用 DeepSeek 生成答案,SSE 流式返回
效果:Top-5 召回准确率 85%+,检索从人工 5 分钟降到 10 秒。"
代码示例
// LangChain4j 实现 RAG 的简化版
@Service
public class RAGService {
@Autowired
private EmbeddingModel embeddingModel; // Qwen Embedding
@Autowired
private ChatLanguageModel chatModel; // DeepSeek
@Autowired
private VectorStore vectorStore; // pgvector
// 建库:文档入库
public void ingest(Document document) {
// 1. 文档分块
List<TextSegment> segments = document.split(
DocumentSplitters.recursive(800, 100) // 800字,100字滑动窗口
);
// 2. 向量化 + 存储
for (TextSegment segment : segments) {
Embedding embedding = embeddingModel.embed(segment.text());
vectorStore.add(embedding, segment);
}
}
// 查询:RAG 问答
public String ask(String question) {
// 1. 检索:问题向量化 → 相似度 Top-5
Embedding questionEmbedding = embeddingModel.embed(question);
List<TextSegment> relevant = vectorStore.findRelevant(questionEmbedding, 5);
// 2. 增强:拼接 Prompt
String context = relevant.stream()
.map(TextSegment::text)
.collect(Collectors.joining("\n\n"));
String prompt = "请基于以下内容回答问题,如果内容中没有答案,回答'不知道'。\n\n"
+ "【知识库内容】\n" + context + "\n\n"
+ "【用户问题】\n" + question;
// 3. 生成:调用 LLM
return chatModel.generate(prompt);
}
}
面试题
Q1:RAG 的完整流程是什么?(超高频 ⭐⭐⭐⭐⭐)
简历直接写了,必须会答!
答:加载 → 分块 → 向量化 → 存储 → 检索 → 增强 → 生成:
- 文档加载(Tika 提取 PDF/Word/Excel)
- 文档分块(500-800 字 + 滑动窗口)
- 向量化(Embedding API 转 1536 维向量)
- 存储(pgvector)
- 检索(余弦相似度 Top-K)
- 增强(检索结果拼进 Prompt)
- 生成(LLM 基于 Prompt 生成答案)
Q2:文档分块为什么是 500-800 字 + 滑动窗口?(高频 ⭐⭐⭐⭐)
简历直接写了,必须会答!
答:
- 太短(如 100 字):上下文不完整,检索到的片段无法理解
- 太长(如 3000 字):向量被稀释,检索精度下降
- 滑动窗口(overlap):保证分块边界的内容不丢失上下文(前后块有重叠)
- 500-800 字是精度和上下文完整性的平衡点
1.3 LangChain4j 核心概念
小白讲解
LangChain4j 是什么?
Java 版的 LangChain,用于构建 LLM 应用
(Python 有 LangChain,Java 有 LangChain4j)
核心组件:
AiServices:声明式接口,把接口方法映射为 LLM 调用
→ 像写 DAO 一样写 AI 调用
EmbeddingModel:文本 → 向量
ChatLanguageModel:文本 → 文本(对话)
VectorStore:向量存储
DocumentLoader:文档加载
DocumentSplitter:文档分块
ChatMemory:对话历史管理
@Tool 注解:给 AI 注册工具,实现 Function Calling
代码示例
// AiServices 声明式接口(简历"对话接口"的底层)
public interface Assistant {
String chat(String userMessage);
}
Assistant assistant = AiServices.builder(Assistant.class)
.chatLanguageModel(chatModel)
.chatMemory(MessageWindowChatMemory.withMaxMessages(10)) // 记忆最近10轮
.build();
String answer = assistant.chat("帮我查一下项目二的进度");
面试题
Q1:LangChain4j 是什么?核心组件有哪些?(中频 ⭐⭐⭐)
答:Java 版 LLM 应用框架。核心组件:AiServices(声明式接口)、EmbeddingModel(向量化)、ChatLanguageModel(对话)、VectorStore(向量存储)、DocumentLoader/Splitter(文档处理)、ChatMemory(对话记忆)、@Tool(Function Calling)。
Q2:AiServices 接口是什么?(中频 ⭐⭐⭐)
答:声明式接口,像 MyBatis 的 Mapper 一样,只定义方法签名,框架自动实现。方法入参是用户输入,返回值是 LLM 输出。简历的 /chat 对话接口就是基于 AiServices 封装的。
1.4 SSE 流式返回(简历直接写了)
小白讲解
SSE(Server-Sent Events,服务端推送事件):
服务端持续向客户端推送数据,类似"打字机效果"
为什么 RAG 回答要用 SSE 流式返回?
LLM 生成一个长答案要几秒到几十秒
如果等全部生成完再返回,用户要干等
SSE 流式:生成一个字推一个字,用户看到"打字机"效果,体验好
SSE vs WebSocket:
SSE:单向(服务端→客户端),基于 HTTP,简单
WebSocket:双向,协议升级,复杂
→ LLM 流式输出只需要服务端推,SSE 够用且简单
面试题
Q1:SSE 流式返回是什么?为什么 RAG 要用?(中频 ⭐⭐⭐)
答:
- SSE 是服务端到客户端的单向推送,基于 HTTP,实现简单
- RAG 生成答案耗时几秒到几十秒,SSE 边生成边推送,用户体验好(打字机效果)
- SSE 单向推送够用,不需要 WebSocket 的双向通信
第二章:Prompt 工程(简历直接写了)
简历项目二直接写了“设计 System Prompt 约束回答范围并实现’不知道’保护机制”。
2.1 System Prompt 约束回答范围
小白讲解
Prompt 的两个部分:
System Prompt(系统提示):
设定 AI 的角色和行为边界
→ "你是企业知识库助手,只回答知识库内的问题"
User Prompt(用户提示):
用户的具体问题
简历的 System Prompt 设计:
"你是 XX 公司的智能知识库助手。
请严格基于提供的【知识库内容】回答问题。
如果知识库中没有相关内容,请直接回答'我不知道',
不要编造答案。"
结合简历案例
简历原文:
"设计 System Prompt 约束回答范围并实现'不知道'保护机制"
面试话术:
"LLM 有个大问题是幻觉——会一本正经地编造答案。
我在 System Prompt 里做了两层约束:
1. 约束回答范围:'只基于提供的知识库内容回答'
2. '不知道'保护:'知识库没有相关内容就回答不知道,不要编造'
另外在代码层面加了一道保险:
检索结果的相似度低于阈值(如 0.75)时,
直接返回'未找到相关信息',不把低质量检索结果给 LLM,
避免 LLM 强行编造。"
面试题
Q1:System Prompt 为什么要约束回答范围?(高频 ⭐⭐⭐⭐)
答:防止 LLM 幻觉。如果不约束,LLM 会用训练数据里的知识回答问题,可能和企业的真实情况不符。约束后 LLM 只基于检索到的知识库内容回答,答案可控。
Q2:“不知道”保护机制怎么实现?(高频 ⭐⭐⭐⭐)
简历直接写了,必须会答!
答:两层:
- Prompt 层:System Prompt 里写“没有相关内容就回答’不知道’,不要编造”
- 代码层:检索结果相似度低于阈值(如 0.75)时,直接返回“未找到相关信息”,不把低质量结果给 LLM
第三章:向量数据库与 Embedding
详见《数据库与缓存-讲解与面试题.md》第四章 pgvector,这里补充 AI 视角的要点。
面试题
Q1:Embedding 是什么?(高频 ⭐⭐⭐⭐)
答:把文本转成高维向量(如 1536 维),语义相近的文本向量距离近。模型通过大量语料训练,让“语义相似”映射为“向量相近”。
Q2:余弦相似度和欧几里得距离的区别?(中频 ⭐⭐⭐)
答:
- 余弦相似度:只看向量方向(夹角),不看长度,适合文本语义相似度
- 欧几里得距离:看绝对距离,适合数值特征
- 文本 Embedding 用余弦相似度(简历 pgvector 检索用的就是
<=>余弦距离)
Q3:为什么选 pgvector 不用 Milvus?(中频 ⭐⭐⭐)
答:数据量万级时 pgvector 性能足够,且 PostgreSQL 已有基础设施,支持向量+结构化数据混合查询,不需要额外维护专门的向量数据库。Milvus 适合百万/亿级向量场景。
第四章:AI Agent 编排(简历项目二核心升级)
简历已将 Function Calling 升级为 AI Agent 工具编排,面试官会问“Agent 和 Function Calling 有什么区别”。
4.1 Function Calling vs AI Agent
小白讲解
Function Calling(单轮工具调用):
用户问"查我的 Jira 任务"
→ AI 判断需要调用 Jira 工具
→ 调用 @Tool jiraQuery(userId)
→ 拿到结果 → 生成回答
→ 结束
AI Agent(多步任务规划):
用户问"查这周的 Jira 任务,顺便看看项目二进度"
→ Agent 规划:
子任务1:查 Jira 任务
子任务2:查项目二进度
→ 执行子任务1 → 观察结果
→ 执行子任务2 → 观察结果(失败则重试/降级)
→ 汇总两个子任务 → 生成综合回答
本质区别:
Function Calling:AI 判断"要不要调工具",调一次
AI Agent:AI 自主"规划任务 + 选工具 + 多轮执行 + 汇总"
结合简历案例
简历原文:
"基于 LangChain4j @Tool 注解与 Function Calling 实现 AI Agent 工具编排
(Jira 分工查询、版本查询、指令进度追踪),
Agent 自主规划任务并决策调用内部 API,支持多轮对话动态工具选择,
系统上线后日均 50+ 次智能问答,信息获取效率提升 30 倍"
面试话术:
"项目二的智能助手不只是问答,还要能查内部系统的数据。
我用 @Tool 注解注册了三个内部工具:
- Jira 分工查询
- 版本查询
- 指令进度追踪
用户问'这周有哪些任务?项目二进展如何?'时,
Agent 会自主规划:
1. 先调 Jira 工具查本周任务
2. 再调进度追踪工具查项目二状态
3. 汇总两个结果生成综合回答
这就是 Agent 和普通 Function Calling 的区别:
Function Calling 是单次工具调用,Agent 是多步任务规划。
上线后日均 50+ 次智能问答,信息获取效率提升 30 倍。"
代码示例
// 用 @Tool 注解注册工具,实现 Agent 工具编排
public class InternalTools {
@Tool("查询某个用户的 Jira 任务分工")
public List<String> queryJiraTasks(String userId) {
return jiraService.queryTasks(userId);
}
@Tool("查询指定项目的版本信息")
public String queryVersion(String projectId) {
return versionService.query(projectId);
}
@Tool("查询指令处理的进度")
public String queryInstructionProgress(String instructionNo) {
return progressService.query(instructionNo);
}
}
// Agent 对话接口(自动编排工具)
Assistant assistant = AiServices.builder(Assistant.class)
.chatLanguageModel(chatModel)
.tools(new InternalTools()) // 注册工具
.chatMemory(MessageWindowChatMemory.withMaxMessages(20)) // 会话状态
.build();
// 用户问"查我的Jira任务,顺便看项目二进度"
// Agent 自主规划 → 依次调用 queryJiraTasks + queryInstructionProgress → 汇总
String answer = assistant.chat("查我的Jira任务,顺便看下项目二进度");
面试题
Q1:AI Agent 和 Function Calling 的区别?(超高频 ⭐⭐⭐⭐⭐)
简历直接写了,必须会答!
答:
- Function Calling:单次工具调用。AI 判断“要不要调工具”,调一次拿结果继续生成
- AI Agent:多步任务规划。AI 自主拆解任务、动态选工具、多轮执行、汇总结果
- Agent 底层可以用 Function Calling 实现,但多了“规划-执行-观察”的循环
- 简历项目二把 Function Calling 升级为 Agent 工具编排,支持多步任务和多轮动态工具选择
Q2:Agent 多轮对话怎么保持状态?(高频 ⭐⭐⭐⭐)
答:Redis 存对话历史(TTL 30 分钟),每轮把上一步工具调用结果作为上下文传给 LLM,Agent 根据历史上下文决定下一步动作。
Q3:工具调用失败怎么办?(中频 ⭐⭐⭐)
答:重试 N 次 → 降级返回默认提示 → 连续失败转人工。简历写了“工具调用失败重试/降级策略”,面试要能说清。
Q4:什么是 ReAct 模式?(中频 ⭐⭐⭐)
答:ReAct = Reason + Act,思考→行动→观察→再思考的循环。Agent 先推理(该做什么),再行动(调工具),观察结果,再推理(下一步),直到完成任务。
第五章:AI 编程工具与 Skills 规则工程(简历新增亮点)
简历新增了 Cursor、Claude Code、DeepSeek 的使用经验,以及“编写 Skills 规则文件约束 AI 输出质量”。 面试官会问“你怎么保证 AI 生成的代码质量”“Skills 规则写了什么”。
5.1 Skills 规则文件是什么
小白讲解
Skills 规则文件 = 给 AI 编程助手设定的"编码规范 + 安全红线"
类似团队的 Code Review check list,但写成 AI 能理解的规则文件,
让 AI 生成代码时自动遵守。
常见规则维度:
1. 代码规范:命名风格、注释要求、包结构
2. 安全红线:资金操作必须加锁、金额必须校验、SQL 必须参数化
3. 异常处理:不允许吞异常、必须记日志、统一错误码
4. 事务边界:哪些方法必须 @Transactional
5. 禁止事项:不允许 Executors 创建线程池、不允许 new Date()
结合简历案例
简历原文:
"编写 AI Skills 规则文件约束代码风格与安全边界
(如资金类操作强制加锁、金额校验不可省略),人工评审后合入"
面试话术:
"用 Cursor + DeepSeek 生成状态机、交收匹配这类核心代码时,
如果无脑让 AI 生成,可能忽略资金操作的安全要求。
我写了 Skills 规则文件,把团队的安全红线固化进去:
1. 资金类操作(扣款/入账/清算)必须加 Redisson 分布式锁
2. 金额字段用 BigDecimal,禁止 double/float
3. SQL 必须参数化(#{}),禁止字符串拼接(${})
4. 状态机变更走统一入口,禁止直接 update 状态字段
AI 生成代码时自动遵守这些规则,
再经过人工评审后才合入,保证代码质量。"
Skills 规则文件示例
# .cursor/rules/custody-system.md
## 安全红线(必须遵守)
- 资金类操作(扣款/入账/清算)必须加分布式锁(Redisson)
- 金额校验不可省略:金额必须 > 0,精度不超过 2 位小数
- SQL 必须使用参数化查询(MyBatis #{}),禁止字符串拼接 ${}
- 状态机变更必须走统一入口,禁止直接 update 状态字段
## 编码规范
- Service 方法名使用动词开头:create/settle/cancel/query
- DTO 命名:XxxCreateDTO / XxxQueryDTO / XxxVO
- 所有金额字段使用 BigDecimal,禁止使用 double/float
## 异常处理
- 不允许 catch Exception 后不处理(吞异常)
- 业务异常抛 BusinessException,系统异常抛 RuntimeException
- 所有异常必须记录日志(包含指令ID、操作人、时间戳)
面试题
Q1:为什么要写 Skills 规则文件?(高频 ⭐⭐⭐⭐)
简历直接写了,必须会答!
答:AI 生成的代码如果不加约束,可能:①不符合编码规范 ②忽略安全红线(资金操作没加锁、SQL 拼接)③异常处理不完整。Skills 规则把团队 Code Review 标准固化成 AI 能理解的规则,让 AI 生成代码时自动遵守,减少人工 review 成本。
Q2:Skills 规则和 System Prompt 的区别?(高频 ⭐⭐⭐⭐)
答:
- System Prompt 约束 LLM 的“回答范围”(如“只基于文档回答”)
- Skills 规则约束 AI 的“编码行为”(如“资金操作必须加锁”)
- 互补:System Prompt 管“说什么”,Skills 规则管“怎么写代码”
Q3:AI 生成的代码直接合入吗?(中频 ⭐⭐⭐)
答:不直接合入。流程是:AI 生成 → 人工评审 → 修改 → 测试 → 合入。Skills 规则减少但不消除人工审查的必要性。简历写了“人工评审后合入”,面试要强调这一点。
Q4:Cursor Rules 和 Claude Code Skills 有什么区别?(中频 ⭐⭐⭐)
答:本质相同,都是约束 AI 编码行为的规则文件,只是语法和存放位置不同:
- Cursor Rules:
.cursor/rules/*.md - Claude Code Skills:
.claude/skills/*.md - 内容维度一致:代码规范、安全红线、异常处理、事务边界
面试速查表(AI 应用开发)
| 考点 | 一句话答案 |
|---|---|
| RAG 流程 | 加载→分块→向量化→存储→检索→增强→生成 |
| 为什么不用 LLM 直接回答 | 时效性+幻觉+隐私+成本 |
| 文档分块 | 500-800字+滑动窗口,平衡精度和上下文 |
| 余弦相似度 | 看方向不看长度,文本语义用余弦 |
| System Prompt | 约束回答范围,防幻觉 |
| “不知道”保护 | Prompt 约束 + 相似度阈值拦截 |
| Function Calling | 单次工具调用 |
| AI Agent | 多步任务规划+动态选工具+多轮执行 |
| ReAct 模式 | 思考→行动→观察→再思考循环 |
| 会话状态管理 | Redis TTL 30分钟,多轮上下文 |
| 工具调用失败 | 重试→降级→转人工 |
| Skills 规则 | 约束 AI 编码行为(规范/安全/异常) |
| Skills vs System Prompt | 一个管写代码,一个管说什么 |
| AI 代码合入 | AI生成→人工评审→测试→合入 |
最后更新:2026-08-19