1. 项目概述:一次高强度实习面试的深度复盘
前几天面了一家公司的AI应用开发实习岗,流程走完,面试官问“你还有什么问题吗?”,我没忍住,半开玩笑地反问了一句:“就面个实习,至于上这么大强度吗?” 面试官笑了笑,回了我一句:“你对RAG、Agent、MCP、Skill这些概念理解得很到位,所以我们要求自然就高一点。” 这句话让我琢磨了很久,也让我意识到,现在的AI应用开发岗位,尤其是前沿的实习岗,考察的深度和广度早已超出了“会用API”的范畴。他们不是在招一个调包侠,而是在找一个能理解技术脉络、能设计系统、能解决实际问题的准工程师。
这次面试几乎涵盖了当前AI工程化落地的几个核心范式:RAG(检索增强生成)、Agent(智能体)、MCP(模型上下文协议)以及Skill(技能)。面试官没有停留在概念提问上,而是层层递进,从原理到架构,从选型到踩坑,问得非常细。回来之后,我花了点时间,把面试中涉及的关键技术点、讨论到的实战场景,以及我自己的一些理解和后续的思考,系统地整理出来。这篇文章,既是对这次高强度面试的复盘,也是给想进入这个领域的朋友们一份“避坑指南”和“能力地图”。你会发现,搞懂这四个词,你就能摸到当前AI应用开发的命脉。
2. 核心概念拆解:为什么是这四个关键词?
面试官把RAG、Agent、MCP、Skill并列提出,绝非偶然。这四者恰好构成了一个从数据到智能,从单点能力到系统协同的完整技术栈。理解它们各自的位置和关联,是构建复杂AI应用的基础。
2.1 RAG:给大模型装上“外部记忆”
RAG,检索增强生成,现在几乎是解决大模型“幻觉”和知识滞后问题的标准答案。但面试官问的可不是“RAG是什么”,而是直接跳到了深水区。
2.1.1 超越简单的向量检索最初的RAG流程很简单:用户问题 -> 向量化 -> 向量数据库检索相似片段 -> 连同片段和问题一起扔给LLM生成答案。但面试官指出,在生产环境中,这种“朴素RAG”问题很多。比如,检索到的片段可能相关但不精确,或者多个片段之间存在矛盾。这就引出了RAG的重排序(Re-ranking)和查询转换(Query Transformation)等进阶技术。
重排序是指在向量检索出Top K个候选片段后,再用一个更精细的(通常是交叉编码器)模型对这些片段进行相关性打分,重新排序,把最相关的放在前面。这能显著提升最终答案的质量。而查询转换则包括查询扩展(用LLM生成与原问题相关的其他问题,一并检索)和查询改写(将复杂的用户问题分解成多个子问题)。面试官让我现场设计一个针对“比较Python中FastAPI和Flask在异步支持上的差异”这个问题的查询转换策略,这很考验对问题本质的理解。
2.1.2 数据管道的质量决定上限另一个讨论重点是数据预处理管道。很多团队只关注检索和生成,却忽略了喂给模型的数据本身是否干净、结构化是否良好。对于技术文档,可能需要剥离无关的导航栏、广告、版本号;对于长文本,需要设计合理的分块(Chunking)策略,既要保证语义完整性,又要避免上下文窗口的浪费。面试官分享了一个坑:他们曾直接用按固定字符数分块,结果把一个函数定义从中间切断,导致检索到的片段完全无法理解,生成的代码自然错误百出。后来改用基于语义(如句子边界、段落)或递归式的分块,效果才好起来。
注意:分块大小没有银弹。技术文档可能适合较小的块(256-512字符),而连贯的论述文章可能需要更大的块(1024字符以上)。关键是要通过评估(比如检索精度、答案质量)来确定最适合你数据集的策略。
2.2 Agent:从“工具调用者”到“自主决策者”
如果说RAG解决了“知识从哪来”的问题,那么Agent要解决的就是“如何用知识去行动”。面试官强调,现在业界对Agent的期待,早已超越了简单的“Function Calling”(函数调用)。
2.2.1 Agent的核心循环与规划能力一个典型的Agent框架(如LangChain的Agent、AutoGPT的架构)包含几个核心部分:规划(Planning)、工具调用(Tool Use)、记忆(Memory)。规划是大脑,决定下一步做什么;工具是手脚,执行具体操作;记忆是经验,记录历史交互。
面试官问了一个经典场景:“请设计一个Agent,帮助用户分析其GitHub仓库的代码质量,并给出改进建议。” 这要求Agent能自主规划一系列步骤:1. 获取仓库列表;2. 克隆目标仓库;3. 静态代码分析(调用SonarQube或类似工具);4. 检查依赖安全性(调用Trivy或Snyk);5. 汇总分析报告。这里的关键是,Agent需要能根据上一步的结果动态决定下一步,比如如果静态分析发现复杂度极高,可能需要额外建议进行重构。
2.2.2 工具生态与安全性Agent的强大依赖于其可用的工具集。除了常见的搜索、计算、API调用,现在还有连接数据库、操作浏览器(通过Playwright)、甚至控制IDE(通过MCP,下文会讲)的工具。面试官特别提到了Agent安全性:一个拥有强大工具集的Agent,如果指令被恶意注入(Prompt Injection),可能会执行危险操作,比如删除文件、发送恶意邮件。因此,在设计Agent时,必须对工具进行权限分级,并对用户指令和Agent的决策过程进行严格的审查和沙箱隔离。
2.3 MCP:连接大模型与万物工具的“统一插座”
MCP,全称Model Context Protocol,是Anthropic提出的一种协议。它是我在面试前研究得相对较少,但面试中讨论让我豁然开朗的部分。你可以把它理解为LLM世界的“USB-C接口”或“驱动协议”。
2.3.1 MCP解决了什么痛点?在没有MCP之前,每个AI应用、每个框架(如LangChain、LlamaIndex)都要为每一种工具(如数据库、代码库、JIRA)编写各自的适配器或插件。这导致了生态碎片化和重复劳动。MCP定义了一套标准协议,让任何工具只要实现一个MCP服务器(Server),就能被任何支持MCP协议的客户端(Client,通常是AI应用或Agent框架)所使用。
面试官举了个例子:公司内部有一个老旧的项目管理系统,API很怪异。以前,要让它能被AI助手调用,需要专门为LangChain写一个Tool,为Cursor编辑器写一个插件,为内部平台再写一个适配器。有了MCP,只需要开发一个MCP Server,将这个系统的功能(如“创建任务”、“查询项目进度”)通过标准接口暴露出来。之后,任何支持MCP的AI客户端(如Claude Desktop、Cursor、甚至是你们自己开发的Agent)都能直接发现并使用这个系统的功能,无需额外开发。
2.3.2 MCP Server实战:连接SQLite数据库面试官让我简述如何为一个SQLite数据库创建一个MCP Server。核心步骤是:
- 定义工具(Tools):明确要暴露哪些操作,比如
execute_sql_query(执行查询)、list_tables(列出表)。 - 实现Server:使用MCP SDK(如TypeScript/ Python的
@modelcontextprotocol/sdk)创建一个服务器。为每个工具定义处理函数,在函数内使用SQLite驱动执行实际操作。 - 处理资源(Resources):MCP还支持“资源”,可以理解为只读的数据源。比如,你可以将某个复杂的查询视图定义为一个资源,客户端可以直接读取其内容,而无需理解SQL。
- 配置与连接:将编写好的Server配置到客户端。例如在Cursor编辑器中,在设置里添加该Server的启动命令(如
python sqlite_mcp_server.py --db-path /path/to/db)。
这个过程将工具能力“服务化”,实现了AI能力与后端基础设施的解耦,是构建企业级AI应用架构的关键一步。
2.4 Skill:可组合、可分发的“原子能力”
Skill这个概念,在不同语境下含义不同。在AI Agent领域,它通常指一个封装好的、可独立完成特定任务的AI能力单元。它比“工具(Tool)”更上层,通常包含预设的Prompt、对工具的调用逻辑、甚至简单的规划能力。
2.4.1 Skill与Tool的细微差别面试官让我辨析Skill和Tool。我的理解是:Tool是基础API,Skill是使用这些API完成一个具体任务的“脚本”或“工作流”。例如,“调用Google Search API”是一个Tool,而“进行竞品分析”就是一个Skill,它内部可能会依次调用搜索Tool、总结Tool、图表生成Tool。
一些AI平台(如微软的Copilot Studio、阿里的通义灵码)提供了Skill市场或Skill开发功能。开发者可以将一个复杂的任务流程打包成一个Skill,供其他用户一键调用。这极大地降低了AI应用的使用和开发门槛。
2.4.2 Skill的编码与发现面试中提到“skill编码196”,这可能指的是某些平台内部对Skill的唯一标识符。在架构设计上,一个完善的Skill系统需要解决Skill的描述、发现、加载和执行问题。通常,一个Skill会有一个描述文件(如skill.yaml),定义其名称、功能、输入输出参数、所需工具等。AI Agent或平台在启动时,会扫描Skill目录或远程仓库,加载这些描述,从而让用户或Agent在需要时能够调用合适的Skill。
3. 技术架构融合:构建一个AI辅助编程助手
纸上谈兵终觉浅。面试官最后抛出了一个综合设计题:“如何设计一个服务于开发者的AI编程助手,它需要具备代码理解、智能检索、自动执行命令的能力?” 这需要将RAG、Agent、MCP、Skill融合起来。
3.1 系统架构设计
我提出的架构分为四层:
- 数据与知识层(RAG核心):
- 知识库:包含公司内部代码规范、技术栈文档、常用库的API文档、过往优秀代码片段。这部分使用RAG技术构建。
- 检索系统:采用“混合检索”策略。首先用向量检索(基于代码或文档的嵌入)找到相关片段,再用轻量级模型进行重排序,确保返回最相关的知识。
- 能力接入层(MCP核心):
- 开发多个MCP Server,作为助手与外界交互的“手”和“眼”。
- 代码库MCP Server:提供读取文件、搜索代码、获取git历史等功能。
- 命令行MCP Server:在安全沙箱内执行
git,npm,docker等命令。 - 项目管理MCP Server:连接JIRA、Confluence,获取任务上下文。
- 网络搜索MCP Server:集成Tavily或Brave Search,获取最新技术资讯。
- 智能中枢层(Agent核心):
- 一个主Agent,负责理解用户意图(如“为这个函数添加错误处理”)、制定计划(检索知识、调用工具)。
- 主Agent可以调度多个子Agent或Skill处理特定子任务。例如,一个“代码审查Skill”专门分析代码风格和潜在Bug。
- 交互与Skill层:
- Skill市场:预置和用户自定义的Skill,如“自动生成单元测试”、“依赖漏洞扫描”、“代码性能分析”。
- 交互接口:可以是IDE插件(如VS Code、Cursor)、聊天界面或CLI。
3.2 工作流程示例:实现一个“代码重构建议”功能
当用户提出“帮我重构这个Python函数,提高其可读性”时,系统内部流程如下:
- 意图解析与规划:主Agent分析请求,规划步骤:a) 理解当前函数;b) 检索重构最佳实践;c) 分析代码问题;d) 生成重构建议和代码。
- 知识检索(RAG):Agent通过“代码库MCP Server”获取目标函数及其上下文。同时,向RAG知识库发起查询,检索“Python重构技巧”、“PEP 8规范”等相关文档。
- 调用分析Skill:Agent调用“代码分析Skill”。该Skill内部可能使用
ast模块解析代码结构,计算圈复杂度,并与检索到的规范进行比对,生成问题列表(如“函数过长”、“变量名不清晰”)。 - 生成与执行:Agent综合代码上下文、检索到的知识、分析结果,生成重构后的代码片段和修改说明。如果用户同意,可以通过“命令行MCP Server”执行创建新分支、替换文件等git操作。
- 记忆与学习:此次交互的完整上下文(问题、代码、解决方案)被存入Agent的长期记忆,可用于优化未来的回答或作为RAG知识库的补充材料。
这个设计体现了四种技术的协同:RAG提供知识支撑,MCP提供安全可控的工具接入,Agent负责规划和决策,Skill将复杂流程模块化。
4. 实战避坑与经验心得
面试中和面试后,我总结了一些在学习和实践这些技术时容易踩的坑,这也是面试官觉得“理解到位”可能需要具备的实战意识。
4.1 RAG实践中的“魔鬼细节”
- 嵌入模型的选择不是小事:不要无脑用
text-embedding-ada-002。对于代码检索,专门针对代码训练的嵌入模型(如bge-code)效果远好于通用模型。同样,对于中文场景,中文优化的嵌入模型是必须的。选择前,用你的业务数据做一个小规模的检索精度评估。 - 重排序模型的成本与收益:重排序模型(如
bge-reranker)虽然能提升效果,但会增加延迟和计算成本。在实时性要求高的场景(如聊天),需要权衡。有时,通过优化查询(更好的查询扩展)和分块策略,可以在不使用重排序的情况下达到可接受的效果。 - 处理“未找到答案”:RAG系统必须能优雅地处理知识库中没有答案的情况。简单的做法是让LLM根据检索到的片段判断“知识库中暂无此信息”,并可以结合网络搜索MCP去获取最新信息。更复杂的可以设计一个置信度分数,低置信度时触发人工审核或进一步查询。
4.2 Agent设计的稳定性挑战
- 规划幻觉与循环陷阱:Agent在规划步骤时,可能会陷入循环(比如反复检查同一个条件)或生成不切实际的步骤。需要在Agent循环中设置最大步数限制,并实现状态检查,避免重复操作。给Agent提供清晰的边界约束(“你只能使用以下工具...”)也很重要。
- 工具输出的解析:工具(尤其是命令行工具)的输出可能是非结构化的文本。让LLM从大段文本中准确提取关键信息有时会失败。一个最佳实践是,尽可能让工具输出结构化数据(如JSON)。如果不行,在Prompt中要详细指导LLM如何解析,例如“从输出中提取版本号,它通常出现在‘Version: ’之后”。
- 长上下文管理:Agent的决策依赖于完整的对话历史和工具调用结果。随着交互进行,上下文会越来越长。需要设计摘要策略,定期将冗长的历史压缩成简洁的要点,以节省Token并保持关键信息不丢失。
4.3 MCP部署与集成的考量
- Server的安全性:MCP Server通常需要执行敏感操作(读数据库、执行命令)。必须确保Server本身有严格的认证和授权机制。在客户端配置Server时,最好使用本地或网络隔离环境,避免暴露到公网。
- 资源发现与描述:一个好的MCP Server应该通过资源(Resources)清晰地暴露其数据模式。例如,数据库Server应该能列出所有表名和模式作为资源,这样AI客户端在规划时就能知道“有哪些数据可用”,而不是盲目地尝试查询。
- 协议版本兼容性:MCP协议本身在演进。在开发时要注意与主流客户端(如Claude Desktop、Cursor)的协议版本兼容性,避免使用了新特性导致旧客户端无法连接。
4.4 Skill设计的可复用性思维
- Skill的输入输出要标准化:一个良好的Skill应该像函数一样,有明确的输入参数和输出格式。这有利于Skill之间的组合。例如,“代码审查Skill”输出一个标准化的
Issue列表,这个列表可以直接被“生成修复代码Skill”使用。 - Skill应保持轻量和专注:一个Skill只做好一件事。不要设计一个“万能开发Skill”,而应该拆分成“代码生成Skill”、“测试生成Skill”、“部署Skill”等。这样更容易维护、测试和复用。
- 文档和示例至关重要:再好的Skill,如果别人不知道它能做什么、怎么用,也是无效的。为每个Skill编写清晰的
README,并提供至少一个典型的使用示例Prompt。
这次面试让我深刻感受到,AI工程化的战场已经从“模型调优”转向了“系统架构”。RAG、Agent、MCP、Skill正是构建下一代AI应用的四块基石。理解它们,不仅是知道概念,更要清楚它们如何连接、如何在具体场景中取舍、如何规避其中的陷阱。面试官那句“要求高一点”,其实是对我们能否具备这种系统化、工程化思维的要求。这条路很长,但每一个坑踩过去,都是实打实的成长。