大模型算法面经:Function Call、MCP、A2A
大模型面试血泪史:Function Call、MCP、A2A,我差点死在面试官下一个追问里!
你信不信?面试官一个轻飘飘的追问,就能让你前半段答得再好也瞬间归零。
去年我面某大厂,前面聊得风生水起,结果面试官突然眯起眼睛:
“Function Call的JSON Schema设计不合理,到底会出什么问题?”
我脑子里“嗡”一下。标准答案谁不会背啊——“会导致模型解析失败……”
他下一秒就追上来:“具体怎么个失败法?你遇到过吗?”
我。当。场。卡。壳。
那一刻我真想钻进地缝。明明简历上写了Agent经验,结果连最基础的东西都没亲手踩过坑。
后来我就发誓:把Function Calling、MCP、A2A从原理到实战全啃透,自己搭项目,亲手踩坑,再还给面试官一个“我不仅知道,我还干过”的答案。
今天,我把这些用血换来的经验全部摊开给你看。不整虚的,全是硬核干货加真实翻车现场。
第一关:Function Call到底怎么训练?面试官最想听的,是你亲手做的数据!
这个问题,十个面试者九个只会答前半句。
标准答案教科书版:通过监督微调(SFT),先教会模型意图识别(要不要调工具),再教会它参数抽取(搞出JSON格式的参数)。
行了,面试官听完只会觉得你背过八股文。
他真正想听的是——你敢不敢说:我亲手做过数据,并且踩了坑。
我做过。最大的坑说出来你都不信:数据格式不一致。
当时用Llama 3.1 8B微调,数据集长这样:
用户:查一下北京明天的天气
可用函数:[{"name": "get_weather", "description": "查询指定城市的天气", "parameters": {"type": "object", "properties": {"city": {"type": "string"}, "date": {"type": "string", "format": "YYYY-MM-DD"}}, "required": ["city"]}}]
期望输出:{"function": "get_weather", "arguments": {"city": "北京", "date": "2024-01-15"}}看起来完美吧?但模型跑出来,函数名一会儿驼峰一会儿蛇形,参数顺序胡乱凑。甚至把name写成function_name。
我查了一周,终于发现:训练数据里JSON key的顺序不统一! 有的样本function在前,有的name在前。模型学成了“怎么摆都行”,结果就是所有样子都输得出。
解决方案:所有样本用同一套模板格式化,key顺序固定。我直接抄OpenAI的tools字段规范——name永远第一,description第二,parameters第三。每一行都遵守,模型终于学会“按规矩来”。
还有一个坑:负样本比例。一开始我只准备“需要调函数”的样本,负样本只占10%。结果模型看啥都想调函数,连“你好”都给你输出一个函数调用——简直是个工具狂魔!后来我把负样本拉到30%-40%,效果立竿见影。
我的建议:面试时,你只要甩出三个关键词——SFT、数据格式统一、负样本比例 —— 面试官眼睛就会亮。因为这是真正干过的人才会说的细节。
真想落地的话,直接上LoRA微调,参数量小,迭代快。我当年用QLoRA在单张A100上跑了3小时,模型就能用了。爽!
第二关:MCP到底是什么?它和Function Call根本不是替代关系!
这个问题今年火出圈。Anthropic推MCP之后,大厂JD上清一色“熟悉MCP优先”。
来,我先说结论,你记好:MCP不是Function Call的替代品,它是Function Call的上一层抽象。
你看啊,Function Call是“一对一”——模型叫一个工具,完事。
MCP是“多对多”——模型发现一堆工具,连接一堆工具,调用一堆工具,这些工具还可能来自不同的服务商。
画个图你就懂了:
- Function Call:模型 → 工具A
- MCP:模型 → MCP客户端 → MCP服务器 → 工具A / 工具B / 工具C
MCP的核心就是标准化。它定义了一套协议,让任何模型都能用同一个接口调用任何工具。就像USB接口——你插鼠标还是键盘,接口长一样。
说到这儿,我得给你讲我第一次用MCP翻车的经历。
我一开始以为MCP就跟Function Call一样,传个JSON搞定。结果它用的是客户端-服务器架构!需要启动一个MCP Server进程,通过SSE或WebSocket通信。
本地测试的时候,MCP Server无声无息地挂了。客户端没报错,模型还在那输出工具调用的JSON,但工具压根没执行。我排查了仨小时,才发现Server进程被系统杀了。
教训:用MCP必须加心跳检测和重连机制。现在我的项目里用的是mcp-python-sdk 0.3.0,我改了里面的Transport层,加了自动重连,这才踏实。
面试官常问的追问,我直接给你标准答案:
- “MCP和Function Calling怎么选?”——如果只有1-2个工具,Function Call省事又轻量。如果超过10个工具,或者工具来自不同团队开发,上MCP。别为了炫耀技术而过度设计。
- “MCP的通信方式有哪些?”——主要两种:SSE(服务端推送)和WebSocket(双向通信)。SSE适合工具状态变化通知,WebSocket适合双向交互的场景。记住这两个就行。
第三关:A2A协议是啥?和MCP到底什么关系?
这个问题是今年面试的“新宠”。Google推A2A(Agent-to-Agent)之后,面试官开始疯狂追问。
先说清楚,别搞混了:MCP是模型和工具之间的协议,A2A是Agent和Agent之间的协议。
你可以这么记:
- MCP:Agent怎么用锤子、扳手、电钻(工具)
- A2A:Agent怎么跟旁边的另一个Agent唠嗑、合作、传消息
A2A的核心叫互操作性。假设你有一个客服Agent,我有一个订单Agent。你的Agent想查我的订单信息,不用管我Agent内部怎么实现的,只要通过A2A协议发个消息过来就行。
我实际测试过:用Google的A2A示例,跑了一个“翻译Agent”和“总结Agent”协作。翻译Agent把英文文档翻成中文,然后调用总结Agent生成摘要。看起来很酷对不对?
但实际跑起来,问题一堆!
1. 延迟翻倍:每个Agent调用一次,中间还得传输上下文,总延迟比单Agent多了40%以上。都快赶上蜗牛爬了。
2. 上下文丢失:A2A协议传的是结构化消息,但Agent的上下文窗口有限,消息一多就丢关键信息。就像聊天聊到一半,对方突然失忆。
3. 调试困难:两个Agent各有各的日志。出了问题,得两边翻,特别痛苦。我有一回找bug找到凌晨两点。
我的判断:A2A现在还太早期,适合做Demo和概念验证。生产环境?先别碰。真要落地,先用Function Call把单个Agent做到极致,等A2A生态成熟了再迁移。
面试官常问的:
- “A2A和MCP冲突吗?”——完全不冲突。它们是不同层级的协议。MCP管工具调用,A2A管Agent间通信。一个Agent内部可以用MCP调工具,对外用A2A跟其他Agent协作。就像你家里用Wi-Fi,出门用5G,互不干扰。
- “A2A的公共卡片是什么?”——相当于Agent的名片,上面写着它能干什么、支持什么协议版本、通信端点在哪。其他Agent通过公共卡片发现并连接它。你就把它想象成LinkedIn上的个人简介。
第四关:Agent面试里“Skills”是啥?很多人答不上来
这个问题有点新,很多人一听就懵。
Skills说白了就是可复用的工具模板。比如你做了一个“搜索技能”,里面封装了搜索引擎调用、结果解析、摘要生成。其他Agent可以直接导入,不用重复造轮子。
Skills和Function Call的区别:Function Call是单次调用,Skills是一组相关的功能集合。比如一个“数据分析技能”可能包含:查询数据库、执行SQL、生成图表、输出报告——这四个Function Call组合在一起才叫一个Skill。
我实际用过:在LangChain里,有个Toolkit的概念,和Skill一模一样。比如SQLDatabaseToolkit,它包含了查询、执行、描述表结构等多个工具。Agent导入这个Toolkit后,就能自动完成数据查询任务。就问你香不香?
面试官追问:“Skills和Prompt有什么区别?”
这个问题问得好。Prompt是给模型看的指令,Skills是给Agent用的功能模块。 Prompt告诉模型“怎么做”,Skills告诉Agent“能做什么”。一个是说明书,一个是工具箱。别搞混了。
第五关:Agent Loop工程里,最容易被忽视的坑是啥?
这个问题面试官不一定会问,但你实际做项目时绝对会遇到。
答案就两个字:上下文!
Agent Loop的原理听着很简单:推理 → 调用工具 → 观察结果 → 再推理。但一跑起来,上下文就越来越长,像滚雪球一样。
我做过一个测试:让Agent完成“查询10个城市天气并生成对比报告”的任务。
第1轮:上下文1K token
第5轮:上下文4K token
第10轮:上下文15K token
到第8轮,模型就开始“失忆”——忘了之前查过哪些城市,重复查询。到第10轮,直接输出乱码。我差点把电脑砸了。
解决方案:用了两个技巧。
1. 滑动窗口:保留最近3轮对话和关键历史摘要,丢弃无关内容。比如城市查询结果保留,工具调用的原始JSON直接扔掉。让模型只关注最重要的信息。
2. 记忆压缩:每5轮对话后,让模型生成一个摘要,替换掉之前的完整对话。我用summarize指令,指定摘要长度不超过500 token。效果出奇好。
另一个坑:死循环! 有一次Agent调用搜索工具,返回“没有结果”。它又调用搜索工具,又返回“没有结果”……循环了20次才被最大迭代次数卡住。你是没看到我当时有多崩溃。
解决方案:加一个“失败容忍度”参数。同一个工具连续失败3次,直接跳出循环,返回错误给用户。别让机器在那傻转。
结尾:说点你可能没想到的(这4个观点,面试官听了都会愣一下)
1. 不要迷信MCP。 MCP确实解决了标准化问题,但也增加了系统复杂度。项目只有3-5个工具的话,Function Call完全够用,简单又稳定。我见过有人为了用MCP而用MCP,上线后运维成本翻倍,老板差点把他骂哭。
2. A2A短期内别碰生产环境。 Google的A2A规范还是0.1版本,连稳定版都没有。我测试时发现不同语言实现的Agent之间通信有兼容性问题,气得我直跺脚。等1.0出来再说,现在先攒经验,别当小白鼠。
3. 面试官最看重的是“你亲手做过”。 背概念只能过第一轮。追问到具体实现时,你得说出“我遇到过什么问题,怎么解决的”。比如我前面提到的数据格式不一致、上下文爆炸、死循环——这些才是面试官想听的。因为有能力的人到处都是,但有经验的人真的很少。
4. 最后推荐一个资源: 有个叫“小林图解面试题”的网站,里面Agent、RAG、LLM的面试题都有图解,很适合快速入门。我面试前刷了一周,确实有用。当然,最靠谱的还是自己去踩坑。
好了,就说这么多。
你要记住:面试官不是在考你背概念,而是在找“有问题能解决”的人。
你自己亲手踩过的坑,才是你面试时最闪亮的勋章。
动起手来,赶紧去搭个Agent项目。踩几个坑,回来再跟面试官侃侃而谈。你会发现——原来掉进去过的坑,都能变成加分项。
PS:评论区见。说说你踩过最惨的坑是什么?我保证不会笑你(除非忍不住)。
读者评论 4