面试官让你把 LLM、RAG、Agent、MCP 串起来讲清楚,90% 的 Java 工程师当场露馅
1. 为什么这道题能"劝退"大半 Java 工程师
面试进行到一半,面试官突然来一句:
“你简历上写了做过 AI 应用,那你把 LLM、RAG、Agent、MCP 这几个概念串起来讲清楚,它们之间是什么关系?”
很多人当场就卡住了。不是完全没听过,而是脑子里是四个孤立的词:LLM 是大模型,RAG 是检索增强,Agent 是智能体,MCP 是……好像是 Anthropic 搞的一个协议?
然后就开始背概念,越背越乱,最后面试官一句"那你实际项目里是怎么用的",直接露馅。
问题不在于你不懂,而在于你没有把它们放进同一条技术演进链路里。这四个词不是并列关系,而是层层递进、互相依赖的关系。一旦你能用一条主线把它们串起来,这道题就从"送命题"变成"加分题"。
本文就用 Java 工程师熟悉的视角,把这条链路讲透,并给出可以直接在面试里复述的表达框架。
2. 一句话主线:从"会说话"到"会干活"
先给结论,这四个概念的关系可以浓缩成一句话:
LLM 提供智能,RAG 补充知识,Agent 赋予行动能力,MCP 统一工具接入标准。
再展开一点:
| 概念 | 解决的问题 | 类比(Java 视角) |
|---|---|---|
| LLM | 语言理解与生成 | 一个能力很强但没有记忆、没有手脚的"计算核心" |
| RAG | 知识时效性与私有知识 | 给核心外挂一个"数据库查询层" |
| Agent | 多步骤任务与工具调用 | 给核心加一个"调度器 + 执行引擎" |
| MCP | 工具接入的标准化 | 类似 JDBC,统一"驱动"接口,屏蔽各家差异 |
这条主线背后的逻辑是:模型本身的能力边界是固定的,工程的价值在于围绕模型补齐它缺的东西。缺知识就上 RAG,缺行动就上 Agent,工具太多太乱就上 MCP。
3. LLM:一切的起点,也是天花板
3.1 LLM 到底给了我们什么
大语言模型本质上是一个概率性的文本生成器:给定上下文,预测下一个 token。但工程上我们更关心它带来的三个能力:
- 语义理解:能把自然语言映射成结构化意图;
- 知识压缩:训练语料里的通用知识被压缩进参数;
- 指令遵循:能按格式要求输出 JSON、SQL、代码等。
对 Java 工程师来说,最直观的接入方式就是 HTTP 调用:
public class LlmClient {
private final HttpClient httpClient = HttpClient.newHttpClient();
private final String apiKey;
private final String endpoint;
public LlmClient(String apiKey, String endpoint) {
this.apiKey = apiKey;
this.endpoint = endpoint;
}
public String chat(String prompt) throws Exception {
String body = """
{
"model": "your-model-name",
"messages": [{"role": "user", "content": %s}]
}
""".formatted(toJsonString(prompt));
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create(endpoint))
.header("Content-Type", "application/json")
.header("Authorization", "Bearer " + apiKey)
.POST(HttpRequest.BodyPublishers.ofString(body))
.build();
HttpResponse<String> response =
httpClient.send(request, HttpResponse.BodyHandlers.ofString());
return response.body();
}
private String toJsonString(String raw) {
return "\"" + raw.replace("\\", "\\\\").replace("\"", "\\\"") + "\"";
}
}
3.2 LLM 的三个硬伤
面试时如果能主动说出 LLM 的局限,比只会夸它强得多:
- 知识有截止日期:训练数据之后的事情它不知道;
- 不知道你的私有数据:公司内部文档、业务库表它一概不知;
- 只会输出文本,不会执行动作:它没法帮你查订单、发消息、改数据库。
这三个硬伤,正好对应后面三个概念要解决的问题。这就是"串起来"的关键钩子——每讲一个概念,都先说它补的是 LLM 的哪个洞。
4. RAG:给 LLM 外挂一个"知识库"
4.1 RAG 的本质
RAG(Retrieval-Augmented Generation,检索增强生成)的核心思想非常朴素:
不要指望模型记住一切,而是在提问时把相关资料"喂"给它。
流程分两段:
- 离线索引:文档切分 → 向量化(Embedding)→ 存入向量库;
- 在线检索:用户问题向量化 → 相似度检索 Top-K → 拼进 Prompt → 交给 LLM 生成。
4.2 Java 侧的实现骨架
public class RagService {
private final EmbeddingClient embeddingClient;
private final VectorStore vectorStore;
private final LlmClient llmClient;
public RagService(EmbeddingClient embeddingClient,
VectorStore vectorStore,
LlmClient llmClient) {
this.embeddingClient = embeddingClient;
this.vectorStore = vectorStore;
this.llmClient = llmClient;
}
/** 离线:文档入库 */
public void index(List<String> chunks) {
for (String chunk : chunks) {
float[] vector = embeddingClient.embed(chunk);
vectorStore.upsert(chunk, vector);
}
}
/** 在线:检索 + 生成 */
public String answer(String question) throws Exception {
float[] queryVector = embeddingClient.embed(question);
List<String> contexts = vectorStore.search(queryVector, 5);
String prompt = """
请仅根据以下资料回答问题,资料中没有的信息请明确说明"不知道"。
【资料】
%s
【问题】
%s
""".formatted(String.join("\n---\n", contexts), question);
return llmClient.chat(prompt);
}
}
4.3 面试常被追问的点
- 切分策略:按固定长度切还是按语义切?重叠多少?这直接影响召回质量。
- 为什么用向量检索而不是关键词:向量能捕捉语义相似,关键词只能字面匹配,实践中常常混合检索。
- 幻觉怎么控制:Prompt 里强约束"只依据资料回答",并给出引用来源。
- 效果怎么评估:召回率、答案忠实度,需要构建评测集,不能靠感觉。
能答出这些,说明你不是"调了个 API",而是真的踩过坑。
5. Agent:让 LLM 从"说"到"做"
5.1 Agent 的核心循环
RAG 解决了"知识"问题,但 LLM 依然只会输出文本。Agent 的本质是把 LLM 变成一个决策器,让它自己决定"下一步做什么"。
经典循环是 ReAct(Reasoning + Acting):
关键点在于:LLM 的输出不再是给人看的文本,而是给程序解析的"动作指令",比如"调用 queryOrder,参数是 orderId=123"。程序执行完把结果再喂回去,循环直到任务完成。
5.2 一个极简的 Agent 实现
public class SimpleAgent {
private final LlmClient llmClient;
private final Map<String, Tool> tools;
public SimpleAgent(LlmClient llmClient, Map<String, Tool> tools) {
this.llmClient = llmClient;
this.tools = tools;
}
public String run(String goal, int maxSteps) throws Exception {
String scratchpad = "";
for (int step = 0; step < maxSteps; step++) {
String prompt = buildPrompt(goal, scratchpad);
String decision = llmClient.chat(prompt);
if (decision.startsWith("FINAL:")) {
return decision.substring("FINAL:".length()).trim();
}
// 期望格式:ACTION: toolName | args
String action = decision.substring("ACTION:".length()).trim();
String[] parts = action.split("\\|", 2);
String toolName = parts[0].trim();
String args = parts.length > 1 ? parts[1].trim() : "";
Tool tool = tools.get(toolName);
String observation = tool == null
? "工具不存在: " + toolName
: tool.execute(args);
scratchpad += "\n思考: " + decision + "\n观察: " + observation;
}
return "达到最大步数,任务未完成";
}
private String buildPrompt(String goal, String scratchpad) {
StringBuilder sb = new StringBuilder();
sb.append("你可以使用以下工具:\n");
tools.forEach((name, tool) ->
sb.append("- ").append(name).append(": ").append(tool.description()).append("\n"));
sb.append("\n目标:").append(goal);
sb.append("\n历史:").append(scratchpad);
sb.append("\n请输出 ACTION: 工具名 | 参数,或 FINAL: 最终答案");
return sb.toString();
}
}
5.3 Agent 的工程难点
面试官很爱问"Agent 落地有什么坑",可以这样答:
- 不可控性:LLM 可能选错工具、传错参数,需要参数校验和兜底;
- 循环失控:必须设最大步数、超时、成本上限;
- 状态管理:多轮对话的上下文、中间结果怎么存,本质是个状态机问题;
- 可观测性:每一步的思考、工具调用、返回都要能追踪,否则线上出问题无从排查。
6. MCP:工具接入的"JDBC 时刻"
6.1 为什么需要 MCP
Agent 要调用工具,问题来了:每个工具都要单独写适配代码。查数据库一套、调内部 API 一套、读文件一套,换个模型或换个 Agent 框架,全部重写。
MCP(Model Context Protocol)就是来解决这个问题的:它定义了一套标准协议,让"工具提供方"和"模型使用方"解耦。
用 Java 工程师最熟悉的类比:
MCP 之于 AI 工具,就像 JDBC 之于数据库。
JDBC 之前,每种数据库一套 API;JDBC 之后,面向 Connection、Statement 编程,换数据库只换驱动。MCP 干的是同一件事:工具按协议暴露能力,Agent 按协议调用,双方都不关心对方是谁。
6.2 MCP 的核心抽象
MCP 里主要三类能力:
- Tools(工具):可被模型调用的函数,有明确的输入 schema;
- Resources(资源):可被读取的数据,类似文件或文档;
- Prompts(提示模板):预置的提示词模板,供复用。
传输层通常有两种:本地进程用 stdio,远程用 HTTP/SSE。对 Java 侧来说,就是实现一个 MCP Server,把内部能力按协议暴露出去。
/** 一个简化的 MCP 工具定义示意 */
public record McpTool(
String name,
String description,
Map<String, String> inputSchema,
Function<Map<String, Object>, String> handler
) {
public String invoke(Map<String, Object> arguments) {
return handler.apply(arguments);
}
}
public class McpToolRegistry {
private final Map<String, McpTool> tools = new ConcurrentHashMap<>();
public void register(McpTool tool) {
tools.put(tool.name(), tool);
}
public String call(String name, Map<String, Object> args) {
McpTool tool = tools.get(name);
if (tool == null) {
throw new IllegalArgumentException("未注册的工具: " + name);
}
return tool.invoke(args);
}
public List<McpTool> list() {
return List.copyOf(tools.values());
}
}
6.3 MCP 带来的变化
- 一次实现,多处复用:同一个 MCP Server 可以被不同 Agent、不同模型使用;
- 权限边界清晰:工具在服务端统一管控,谁能调什么一目了然;
- 生态可组合:社区工具即插即用,不用为每个工具写胶水代码。
7. 把四个概念串成一条完整链路
现在回到面试现场。你可以这样组织回答:
第一层,LLM 是底座。它提供语义理解和生成能力,但知识有截止日期、不懂私有数据、只会输出文本。
第二层,RAG 补知识。把私有文档向量化存起来,提问时检索相关片段拼进 Prompt,解决"不知道"的问题。
第三层,Agent 补行动。让 LLM 输出结构化的动作指令,程序执行工具再把结果喂回去,循环直到任务完成,解决"不会做"的问题。
第四层,MCP 补标准。Agent 要接的工具越来越多,每个都单独适配成本太高,MCP 用统一协议把工具接入标准化,就像 JDBC 统一了数据库访问。
所以它们不是四个并列的技术,而是一条演进链:模型能力固定 → 补知识 → 补行动 → 补工具生态。我做的项目里,就是 LLM 打底、RAG 保证答案准确、Agent 编排多步任务、MCP 统一接入内部系统。
配一张图更直观:
8. 面试加分项:主动暴露工程细节
光讲清概念只能算及格。真正拉开差距的是你有没有工程视角。以下几个点,主动抛出来效果很好:
关于 RAG
- 切分粒度怎么定?我一般按语义段落切,重叠 10%~20%,再用小规模评测集验证召回。
- 纯向量检索不够,关键词和向量混合召回效果更稳。
- 一定要做引用溯源,让用户能点开原文核对。
关于 Agent
- 工具描述写得好不好,直接决定模型选得对不对,description 要写清"什么时候用"。
- 必须有最大步数和超时,否则一次死循环能把成本打穿。
- 每一步的 trace 都要落库,线上排查全靠它。
关于 MCP
- 工具暴露要遵循最小权限原则,别把整个数据库的写权限都开出去。
- 输入 schema 要严格,参数校验放在服务端,不能信任模型输出。
关于整体架构
- 成本控制:简单问题走小模型,复杂任务才上大模型。
- 降级策略:检索失败、模型超时都要有兜底回复。
- 可观测性:链路追踪、Token 消耗、延迟指标一个都不能少。
9. 常见追问与参考回答
Q:RAG 和微调怎么选?
A:知识频繁变化、需要溯源,选 RAG;风格、格式、领域术语需要固化,选微调。两者不冲突,实践中常常 RAG 打底、微调优化表达。
Q:Agent 会不会取代 RAG?
A:不会。Agent 里经常把 RAG 当成一个工具来调用。它们是包含关系,不是替代关系。
Q:MCP 是不是必须用?
A:不是。工具少的时候直接写适配代码更简单。工具多、跨团队、跨模型复用时,MCP 的价值才体现出来。
Q:这些在 Java 生态里怎么落地?
A:LLM 走 HTTP 客户端调用,向量库可以用 Milvus、Qdrant 的 Java 客户端,Agent 编排可以自己写状态机也可以接框架,MCP Server 用 Java 实现后通过 stdio 或 HTTP 暴露即可。核心还是那套东西:接口抽象、依赖注入、异常兜底。
10. 总结
把这道题答好,关键不在于背熟四个定义,而在于建立一条问题驱动的技术演进主线:
- LLM 有能力,但缺知识、缺行动、缺工具生态;
- RAG 补知识,Agent 补行动,MCP 补标准;
- 四者层层递进,共同构成一个可落地的 AI 应用架构。
下次面试官再问,别急着背概念,先说一句:“这四个不是并列的,是一条演进链,我从 LLM 的局限讲起。”——这一句,就已经赢了一半。
更多推荐


所有评论(0)