LLM 工具调用
第一层:Function Calling (函数调用) 核心总结
Function Calling 是整个大模型 Agent 架构的最底层基建。它的核心使命是将大语言模型(LLM)的意图转化为可以被代码直接执行的指令。
一、 核心概念与职责分工 (What & Who)
理解 Function Calling 的第一步,是明确各方的"权责边界"。大模型绝对没有自己访问网络或直接执行代码的能力。整个流程是一场标准的任务委托:
- 开发者 (HR) :负责编写结构化的 JSON Schema(职位说明书),清晰定义工具的名称、功能描述和参数规范。
- 大模型 (经理) :只负责决策。它阅读 Schema 后,判断当前任务需要哪个工具,并输出一段结构化的 JSON 指令。
- 宿主代码 (员工) :负责执行。比如你的 Spring Boot 后端拦截到这条 JSON,去调用 MyBatis 查库或者请求第三方 API,然后把真实数据反馈给模型。
二、 训练机制:模型是怎么学会的?(How)
Function Calling 绝不是大模型参数量大自然产生的"涌现能力",而是经过两个阶段专项训练"教"出来的:
-
SFT (监督微调) ------ 解决"会不会调"
- 目标:让模型通过模仿,学会标准动作。
- 方法:给模型喂大量包含完整链路的对话数据(包括 Schema 识别、结构化 JSON 输出、处理外部结果)。
- 关键点:训练数据必须包含失败重试、不需要工具直接回答等场景,否则模型会变成遇到什么问题都去调工具的"傻瓜"。
-
RLHF (人类反馈强化学习) ------ 解决"该不该调"
- 目标 :帮模型建立边界感。
- 方法:通过奖励模型(Reward Model)打分,引导主模型:能用内部知识解决的直接回答,需要实时数据或特定操作时才输出工具调用指令。
三、 核心运行闭环 (The Loop)
在实际的工程运行中,这套机制表现为一个"两轮对话 + 中间执行"的标准闭环:
- 第一轮对话 (模型下指令) :将用户问题和可用工具列表发给模型。模型决定调用工具,暂停回答,输出包含工具名和参数的 JSON,并返回
finish_reason: "tool_calls"信号。 - 中间执行 (代码干活) :宿主程序拦截该信号,解析 JSON,执行本地方法获取结果。
- 第二轮对话 (模型给答案) :将执行结果封装成
role: "tool"的消息,追加到历史对话中再次请求模型。模型结合数据,生成最终的自然语言回复。
四、 进阶特性与工程化考量 (Advanced)
- 并行调用 (Parallel Tool Calling) :当任务需要多个不相关的工具时(如同时查北京和上海的天气),模型可以一次性输出多个 JSON 指令。此时,宿主代码可以利用 Java 的并发工具(如 JUC 的线程池或 CompletableFuture)同时执行这些方法,将耗时极大的多轮串行压缩为"一轮对话 + 并发执行"。前提是工具之间没有依赖关系。
- JSON Schema 的核心命门 :在定义工具时,
description(描述) 字段是模型决定"要不要调"和"怎么填参数"的唯一依据。描述越清晰、边界越明确,模型的准确率越高。
五、 常见面试踩坑预警 (Pitfalls)
- 误区:把"涌现能力"当成工具调用能力。 必须明确指出它是 SFT 和 RLHF 双阶段训练的产物。
- 误区:认为新一代推理模型(如 o1, DeepSeek-R1)的 Function Calling 能力一定更强。 实际上,早期推理模型因为"连续的思维链生成"与"中断等待工具结果"在工作范式上存在根本冲突,往往不支持或需要使用"思考完再调工具"的折中方案。
第二层:MCP (模型上下文协议) 核心总结
一、 为什么有了 Function Calling 还需要 MCP?(痛点与背景)
在只有 Function Calling 的时代,接工具是个纯纯的"体力活":你写了一个查数据库的工具,要在你的系统里写一遍对接代码;如果你换了个项目,或者要把这个工具给 Cursor 用,你得把代码重写一遍。
MCP 的核心使命 :打破这种碎片化,充当 AI 界的 "USB 接口标准" 。只要工具方(比如 GitHub)按照 MCP 标准写好一个 Server 服务,任何支持 MCP 的 AI 客户端插上就能用,真正做到"一次编写,到处复用",零代码接入。
二、 架构分工:三个角色的各司其职
不要把 MCP 简单理解为普通的 C/S 架构,它其实有三个明确的角色:
- Host (宿主应用) :比如你用的 Claude Desktop 或者 Cursor。它是"总指挥",负责决定连接哪些外部 Server,但不亲自负责通信。
- Client (客户端模块) :内嵌在 Host 里的"联络员"。负责转发模型的指令,带回执行结果。
- Server (服务端/工具端) :外部工具的实际实现方(比如本地文件系统 Server)。它不在乎是谁在调用它,只要对方支持 MCP 协议就行。一个 Host 可以同时连接无数个不同的 Server。
三、 核心能力:Server 能提供什么?
面试如果问到 MCP 能暴露什么,千万别只答"能提供工具"。它其实把能力划分成了严格的三类:
- Tools (工具) :有副作用、会改变世界的操作(如建文件、改代码、删库)。因为有破坏性,通常必须经过用户授权确认。
- Resources (资源) :纯只读的资料室(如读本地日志、查天气)。无副作用,安全级别高,可以直接给模型看。
- Prompts (提示模板) :带参数占位符的预定义模板。解决团队协作中重复手写 Prompt 的问题,统一规范。
四、 💣 面试必杀题:MCP 和 Function Calling 到底啥区别?
这是极其容易踩坑的地方!两者处于完全不同的抽象层次,绝不是替代关系。
- 根本区别:Function Calling 解决的是"模型怎么输出调用格式(指令)";MCP 解决的是"工具怎么跨项目复用与自动发现(生态管理)"。
- 依赖关系 :MCP 底层依然是靠 Function Calling 驱动的! 大模型本身根本不知道什么是 MCP。是 MCP Client 连接 Server 后,把工具翻译成了 Function Calling 的 JSON Schema 喂给大模型,大模型依然输出
tool_callsJSON 指令。 - 总结 :原生 Function Calling 是驱动 MCP 最高效、最主要的方式;但不支持原生 FC 的模型并非绝对用不了 MCP------Host 可以把 MCP 工具说明书以自然语言喂给模型(ReAct 式),靠文本解析拿到调用意图后再转成 JSON-RPC,只是可靠性和成本更差。
为了彻底搞懂,我们把整个系统拆解成三个实体角色,并一步步演示它们的交互流程:
- MCP Server(工具端) :比如你本地跑的一个能读写文件的服务。
- AI Client / Host(调度端) :比如你正在用的 Cursor 或 Claude Desktop 软件。
- 大模型 LLM(大脑端) :比如云端的 GPT-4o 或 Claude 3.5。
请记住核心秘密:大模型是瞎子,它根本不知道有 MCP 的存在。全靠中间的 AI Client 在做"翻译"和"跑腿"。
下面是完整的详细执行流程:
🔄 详细协同流程(6步闭环)
第 1 步:自动发现工具(MCP 协议发力)
- 动作:你打开了 Cursor。Cursor (AI Client) 根据配置文件,在后台连接上了本地的文件系统 MCP Server。
- 通信 :Cursor 问:"你会干啥?" MCP Server 返回一份自己支持的工具列表(比如
read_file,write_file)。 - 此时,大模型还没参与进来。
第 2 步:翻译成 Schema(桥梁纽带)
- 动作 :Cursor 拿到工具列表后,在内部默默做了一件事------翻译。
- 转换 :它把 MCP 定义的工具格式,精准翻译成大模型能听懂的 Function Calling JSON Schema (包含
name,description,parameters)。
第 3 步:带上工具问大模型(进入 Function Calling)
- 动作 :你在对话框输入:"帮我读取一下桌面上的
test.txt"。 - 通信 :Cursor 把你的问题,连同刚才翻译好的 JSON Schema 列表,一起打包通过 API 发送给云端的大模型。
- 此时,大模型看到了用户问题和一份说明书。
第 4 步:模型输出 JSON 指令(Function Calling 发力)
- 动作 :大模型读完说明书,发现需要读文件,于是它暂停生成自然语言回答。
- 通信 :大模型输出了一段特定的 JSON 指令(比如
{"name": "read_file", "arguments": {"path": "desktop/test.txt"}}),并返回tool_calls结束信号。 - 记住:模型只输出指令,它自己没有去读文件!
第 5 步:拦截并真正执行(回到 MCP 协议)
- 动作:Cursor 拦截到了模型发来的这条 JSON 指令。它知道要调哪个工具了。
- 通信 :Cursor 通过 MCP 协议 (JSON-RPC),向本地的文件系统 MCP Server 发送执行请求。MCP Server 真正去硬盘里把
test.txt的内容读了出来,返回给 Cursor。
第 6 步:带着结果索要最终答案
- 动作:Cursor 拿到了文件内容(比如里面写着"Hello World")。
- 通信 :Cursor 把这个结果打包成
role: tool的上下文,再次发给大模型。 - 最终:大模型结合内容,生成最终回复:"您桌面上的文件内容是 Hello World。" Cursor 展示给你看。
五、 通信基建:到底怎么传数据?
MCP 的设计非常优雅,做到了消息格式与传输通道解耦:
-
统一语言 :大家都用轻量级的 JSON-RPC 2.0 格式发消息。
-
两种通道任选:
- stdio (标准输入输出) :本地首选。Server 作为子进程直接跑在本地电脑上,通过操作系统的管道通信,零网络延迟,最安全。
- Streamable HTTP :远程首选。通过单一 HTTP 端点处理,方便团队共享云端服务。 (注:老面经里经常提的 SSE 传输方式,在 2025 年的 MCP 规范中已经被正式弃用了!)
第三层:Agent Skill (智能体技能) 核心总结
一、 痛点与背景:有了工具,为什么还需要 Skill?
给新员工配了电脑、开了系统权限(相当于接了 MCP),但他依然可能不知道"财务报表"应该按什么格式写、先查哪个库后查哪个库。
- 过去的做法:人类每次都要手动复制粘贴一大段长长的 Prompt,告诉 AI 步骤,繁琐且团队标准难以统一。如果把所有步骤全塞给 AI,又会撑爆宝贵的上下文窗口(Context Window)。
- Skill 的核心定位 :把重复性的工作流(指令、脚本、模板)打包成一个标准化的、能被 Agent 自动发现并按需加载 的能力模块。它提供的是知识和业务流程(脑) 。
二、 物理形态:Skill 到底长什么样?
Skill 并不是一段简单的文本,它在物理层面上是一个文件夹 。这种纯文本/Markdown 的设计"零门槛",已被各大主流平台广泛支持。 一个标准的 Skill(比如代码审查 code-review)长这样:
SKILL.md:核心灵魂。包含头部描述(告诉 AI 这是啥)和正文步骤(第一步干啥,第二步干啥)。scripts/(可选):放一些辅助脚本,比如安全扫描的 Python 代码。assets/(可选):放输出模板,比如review_report_template.md。
三、 🌟 面试必考亮点:渐进式加载 (Progressive Disclosure)
这是 Skill 最聪明的设计,也是面试拿高分的关键!为了防止成百上千个 Skill 瞬间挤爆 Agent 的脑容量,它采用了"三层按需加载":
- 第一层(看面试) :平时 Agent 只加载 Skill 的名字和一句话介绍(只占几十个 Token),心里有个数。
- 第二层(看详细手册) :只有当你真的让它"做个代码审查"时,它匹配上了,才会去完整读取
SKILL.md里的所有步骤。 - 第三层(用到再取物) :当步骤执行到"请按模板输出"时,它才会在那一刻去读取
assets/里的模板文件。 (这就好比:平时只看目录 -> 报销时才翻看报销流程 -> 填表时才下载报销单模板。)
四、 黄金三角关系:Function Calling vs MCP vs Skill
如果在面试中被问到这三者的区别,直接抛出这个"厨房做菜"的满分推演:
- Function Calling (底层) :是厨师的"手",能拿刀、开火。
- MCP (中间层) :是标准化的"厨房",工具和食材都摆好了,随取随用。
- Skill (顶层) :是"菜谱",告诉你"先用 MCP 拿这块肉,再用 Function Calling 切片,最后按菜谱排盘"。
现代大模型 Agent 全链路架构与运行时解析
核心体系:Function Calling (底层通信) × MCP (工具生态) × Agent Skills (业务编排)
架构哲学:大模型只做无状态的"闭眼决策",宿主应用(Host)掌控全场的状态刷新与数据喂养。
一、 核心组件与物理形态解构
在代码跑起来之前,我们必须明确这四大组件在服务器里的真实物理形态,这是理解数据流转的前提:
| 组件名称 | 物理形态 | 核心职责与状态 |
|---|---|---|
| Host 宿主应用 | Java/Spring Boot 进程 | 全场唯一主宰(Stateful) 。维护长连接、管理状态机、负责工具剪枝(海选)以及向大模型发起网络请求。 |
| MCP Server | 独立子进程 / 微服务 | 外部手脚(执行层) 。将查库、读文件等物理操作标准化为 Tools,通过 stdio/HTTP 供 Host 随时调用。 |
| Agent Skill | 磁盘里的文件夹 | 大脑里的 SOP(战术层) 。包含 SKILL.md(纯文本操作步骤)和输出模板,指导模型"先干嘛,后干嘛"。 |
| LLM 大模型 | 云端计算引擎 | 绝对无状态(Stateless) 。没有记忆,不上网。单次请求只负责阅读 Host 递过来的 JSON 包,并输出下一个 Token。 |
| Function Calling | JSON 文本协议 | 神经电信号。大模型与 Host 之间的结构化意图传递格式。 |
二、 全生命周期:五大执行流转阶段 (核心数据流)
当用户下发任务(如:"帮我审查桌面上的 login.java"),底层会经历极其严密的 5 个阶段流转:
阶段一:系统启动与工具静态收割(初始化)
- MCP 物理建连 :Host 启动时,拉起所有的 MCP Server,通过 RPC 将上百个原子工具的 Schema 全部拉取并常驻在本地内存中。
- 轻量菜单注入 :Host 扫描本地 Skills 目录,只提取每个 Skill 的
name和description,拼入System Prompt。
💡 此时状态 :大模型只知道自己有几个"技能包",对底层的具体操作步骤和细粒度工具一无所知,完全闭眼,极大节省 Token 成本。
阶段二:意图匹配与渐进式加载(技能激活)
- 语义匹配 :大模型阅读用户提问和精简菜单,精准命中
code-review技能,并输出特定激活信号。 - Host 物理读取 :Host 拦截到该信号,立刻去磁盘把
SKILL.md的完整 SOP 步骤文本读取到内存中,准备拼装上下文。
阶段三:前置拦截与运行时工具剪枝(Tool RAG)
SOP 第一步要求:"请读取待审查的代码文件内容。"
-
Host 独自海选 :Host 拿到这一步的文字意图,在本地内存的"百宝箱"中做向量/关键词检索,将 100 个工具强行精简 为当前步骤最需要的 1 个工具(如
read_file)。 -
Payload 组装发货:Host 构造一个全新的 HTTP POST 请求包:
- 将 Skill 的步骤文本 塞进
messages数组(任务语境)。 - 将 海选出的
read_fileSchema 塞进tools数组(唯一的合法工具)。
- 将 Skill 的步骤文本 塞进
-
发送请求:Host 将这个合二为一的数据包,一次性发给云端大模型。
阶段四:大模型决策与脑冻结(输出 FC)
- 双线配对 :大模型收到包,在
messages看到读文件要求,同时在tools看到贴心准备好的read_file说明书。两者结合,触发 SFT 训练形成的肌肉记忆。 - 强制暂停 :大模型立刻中断文本生成。
- 输出指令 :大模型输出结构化的 JSON 指令(包含函数名和路径参数),API 响应
finish_reason: "tool_calls"。大模型随后进入休眠挂起。
阶段五:物理执行与多轮刷新闭环(偷梁换柱)
-
走 MCP 驱动硬件 :Host 拦截 JSON 指令,通过 MCP 协议指挥底层
FileSystem_MCP_Server真正去读取硬盘源码。 -
刷新工具背包,开启下一轮(最核心机制) :
- Host 拿到源码,准备发起全新的一轮 HTTP 请求。
- 动态切换 :Host 发现 SOP 进入第二步(运行扫描脚本)。它会把第一轮用过的
read_file工具从 Payload 中彻底抹掉,换成最新的run_script工具 Schema。 - 数据回喂 :将读出的源码打包成
role: "tool"塞进历史,连同换好的新工具包,再次发给大模型。
-
完美交卷 :大模型经历多次死循环流转,走到 SOP 最后一步(套用模板)。大模型评估无需新工具,直接吐出最终报告文本返回
stop,Host 拦截放行,任务结束。
三、 抓包级揭秘:底层 JSON Payload 对照
为了看清 Host 是如何"偷梁换柱"的,我们对比第一轮和第二轮的真实 HTTP 请求载荷(Payload):
📦 轮次 1:步骤一,Host 只给 read_file 工具
JSON
swift
{
"model": "gpt-4o",
"messages": [
{
"role": "system",
"content": "【code-review】技能 SOP:\n1. 读取代码。\n2. 运行扫描脚本。"
},
{ "role": "user", "content": "审查桌面 login.java" }
],
"tools": [
{
"type": "function",
"function": { "name": "read_file", "description": "读取文件" }
}
]
}
📦 轮次 2:步骤二,Host 拿到源码,动态换成 run_script 工具
JSON
swift
{
"model": "gpt-4o",
"messages": [
{ "role": "system", "content": "【code-review】技能 SOP:\n1. 读取代码。\n2. 运行扫描脚本。" },
{ "role": "user", "content": "审查桌面 login.java" },
{ "role": "assistant", "tool_calls": [{"id": "call_1", "function": {"name": "read_file"}}] },
{ "role": "tool", "tool_call_id": "call_1", "content": "public class Login { ... }" }
],
"tools": [
{
"type": "function",
"function": { "name": "run_script", "description": "运行安全检测脚本" }
}
]
}
🔑 核心密码 :大模型并不在运行中途伸手要工具,而是 Host 趁着每一轮新请求发起前,主动在
tools数组里玩了一场"魔术替换"。
四、 高级架构师面试金句储备
-
"大模型是木偶,Host 才是真正的主宰"
大模型从不主动翻书或找工具,它所有的上下文(SOP)和可见选项(Tools)全靠 Host 应用在 HTTP 请求发起前进行打包组装。大模型每次下达指令后都会断开连接交出控制权,赋予了 Host 拦截和状态重置的绝对权力。
-
"信息减肥(Tool Pruning)是生产级 Agent 的生死线"
绝不能把系统内所有的 MCP 工具在初始化时全塞给模型。必须依靠 Host 结合 Skill 步骤意图进行 Tool RAG(工具海选)动态剪枝。这不仅能死守 Context Window(省钱),更是彻底消灭"模型调错工具"这种高维幻觉的唯一手段。
-
"宏观流程归 Skills,微观原子归 MCP"
Skill 提供的是纯文本 SOP,解耦了业务逻辑;MCP 提供的是通用协议接口,解耦了硬件实现。即使明天读文件底层从本地硬盘换成了阿里云 OSS,Skill 手册连一个字都不用改,大模型依然只需说"我要读文件",底层适配由 Host 和 MCP 搞定。
现代大模型 Agent 第四层:A2A 多智能体协同架构解析
核心体系 :Agent-to-Agent (A2A) / Multi-Agent Orchestration 架构哲学:不要造一个全能的神,而是造一群偏执的专家。大模型之间从不直接通信,一切皆由 Host(宿主代码)通过切换上下文与状态机进行"物理隔离"与"无缝接盘"。
⚠️ ⚠️⚠️ 命名纠偏(面试保命,必读): 本层讲的"Host 内切换 Prompt/Tools 的多 Agent 编排"是进程内(in-process)多智能体架构 。而 Google 2025 年发布的 A2A 是一个真正的开放网络协议 ------支持跨机器、跨组织、异构框架的独立 Agent 通过 HTTP/JSON-RPC 互相发现(Agent Card)与调用,Agent 之间真的会联网通信。面试提到 "A2A" 时默认指后者这个协议;说进程内编排时用 "Multi-Agent Orchestration / Handoff" 更准确,别张冠李戴。
一、 为什么必须引入 A2A?(单体 Agent 的死亡陷阱)
在真实的生产环境中,试图打造一个"既能写代码、又能测 Bug、还能查数据库、最后发邮件"的全能单体 Agent(God-mode Agent) ,在工程上注定会引发三大灾难:
- 人格精神分裂(System Prompt 爆炸) :为了让它什么都会,你必须在
System Prompt里塞入极其庞大的设定和几十个 SOP。大模型的"注意力机制(Attention)"会被彻底分散,导致它什么都做不好,频繁遗忘步骤。 - 工具海选失控(Tool RAG 失效) :当一个 Agent 挂载了跨领域的 500 个微观工具时,语义搜索极易发生灾难性重叠。例如:"删除无用代码"和"删除数据库冗余表"意图相近,大模型一旦幻觉调错,可能直接删库跑路。
- 上下文雪崩(Context Bloat) :一个人干完所有事,其漫长的思考链、报错重试日志全堆积在同一次对话历史中。不出 10 轮,Token 上限被撑爆,系统瘫痪。
A2A 的本质解法 :化繁为简。通过公司级的组织架构编排,建立多个职责单一、隔离运行的专职 Agent(各自拥有极简的 Prompt 和极少的专属 Tool),并通过 Host 宿主应用进行调度。
二、 进程内多 Agent 编排的底层真相:大模型之间如何"聊天"?
打破幻觉:在单进程编排(如 LangGraph/Swarm)里,两个 Agent 角色之间不会通过网络互发消息。
在一个宿主应用中,全场依然只有一个(或少数几个)"大模型 API"(计算引擎),和你的一个"Java 后端"(Host 宿主)。所谓的"多个 Agent",在代码底层其实是"Host 维护的多个配置字典(包含专属 Prompt 和专属 Tools)"。
当 Agent A 需要呼叫 Agent B 时,本质上是: 大模型输出一段 Function Calling ──> Host 拦截该调用 ──> Host 把发给大模型的 System Prompt 从 A 替换成 B ──> Host 再次发包。
三、 进程内多 Agent 编排的三大主流工程落地模式
在 Java/Python 宿主代码的控制下,A2A 呈现出三种极其经典的拓扑结构:
模式 1:交接棒模式 (Handoff / OpenAI Swarm 架构)
最轻量、最优雅的流水线模式。把"转接"本身当成一种工具(Function Calling)。
-
机制 :【前台客服 Agent】的专属背包里,有一个特殊的工具叫
transfer_to_order_agent。 -
执行流:
- 客户问订单状态,【客服 Agent】发现超纲,调用
transfer_to_order_agent工具(输出 JSON)。 - Host 核心魔法(偷梁换柱) :Java 后端拦截到这个函数名,不调物理世界 ,而是将当前的
System Prompt强行切换为"你是订单专家",并将背包里的工具清空,换上query_sql工具。 - Host 带着原来的聊天记录和新的设定,发起新一轮无状态 HTTP 请求。大模型睁眼一看,自己已经"魂穿"成了订单专家。
- 客户问订单状态,【客服 Agent】发现超纲,调用
模式 2:包工头模式 (Supervisor / Router 架构)
适用于高度并行的宏观复杂任务拆解(Map-Reduce 思想)。
-
机制:设立一个不干脏活的【包工头 Agent】(Router),它的工具全都是呼叫小弟的指令。
-
执行流:
- 【包工头 Agent】接到大任务,输出 Function Calling 决定分发给
Coder_Agent和Tester_Agent。 - Host 核心魔法(异步线程) :Java 后端拦截到分发指令,在后台开启两个异步线程(或微服务) ,分别挂载两套不同的 Prompt 和 Tools 请求大模型。
- 两个子线程干完活,Host 将它们的结果汇总成一段 Markdown,作为 Tool Result 塞回给【包工头】,包工头做最终汇报。
- 【包工头 Agent】接到大任务,输出 Function Calling 决定分发给
模式 3:共享白板模式 (StateGraph / LangGraph 思想)
适用于需要频繁打回、反复横跳的环形工作流(如:写代码 -> 跑测试 -> 报错打回重写)。
-
机制 :Host 在 JVM 内存中维护一个全局的 JSON 状态树(State 对象) ,它是一块所有 Agent 共同读写的"大白板"。
-
执行流:
- 【Coder Agent】写完代码,Host 将其存入 State 的
code_snippet字段,Coder 休眠。 - Host 核心魔法(状态机驱动) :Java 后端监听 State 变化,触发图节点流转,唤醒【Tester Agent】。【Tester Agent】只读取白板上的代码,测出 Bug,将报错写入 State 的
error_logs字段。 - Host 再次监测到状态变化,顺着状态图 (注意:带"报错打回重写"回路的图不是 DAG ------DAG 不允许环;LangGraph 的核心卖点恰恰是支持带环的循环图 )重新唤醒【Coder Agent】修复 Bug,直到
error_logs为空。
- 【Coder Agent】写完代码,Host 将其存入 State 的
四、 源码抓包级解密:Handoff 模式的 Payload 变身
我们来看看在"交接棒模式(Handoff)"下,Host 是如何通过修改 HTTP Payload 让大模型瞬间"换脑"的。
🎭 上半场:【接待员 Agent】的 Payload
JSON
json
{
"model": "gpt-4o",
"messages": [
{ "role": "system", "content": "你是前台接待员。如果用户问订单,请调用转接工具交接给订单专员。" },
{ "role": "user", "content": "我昨天的退款到账了吗?" }
],
"tools": [
{
"type": "function",
"function": { "name": "transfer_to_order_agent", "description": "转接给订单专员" }
}
]
}
大模型输出:我要调 transfer_to_order_agent。Host 拦截!
🎭 下半场:Host 偷梁换柱后,发出的【订单专员 Agent】Payload
JSON
json
{
"model": "gpt-4o",
"messages": [
{ "role": "system", "content": "你是严格的订单专员。请使用查库工具解决用户关于退款的问题。" },
{ "role": "user", "content": "我昨天的退款到账了吗?" },
{ "role": "assistant", "content": "为您转接订单专员..." }
],
"tools": [
{
"type": "function",
"function": { "name": "query_database", "description": "查询 MySQL 订单表" }
}
]
}
⚠️ 视觉盲区破除 :你看,根本没有两个大模型在通信!只有 Host 这一双"无形的手",在两次 HTTP 请求之间,强行把大模型的"脑子"(system prompt)和"手脚"(tools)给换掉了。 大模型永远以为自己只是在回答当前上下文的问题。
五、 面试通关核心大局观(背诵金句)
- "A2A 的本质,是 Prompt 和 Tools 的动态沙盒隔离" 多智能体架构并不是 AI 产生意识在互相聊天,而是 Host 宿主应用通过维护复杂的状态机(State Machine),在多轮对话中动态切换 System Prompt 和权限极窄的 MCP 工具集。通过空间隔离,彻底消灭了单体 Agent 的上下文污染和工具乱调问题。
- "调用同僚也是一种 Function Calling" 在现代 A2A 设计(如 Swarm)中,将控制权移交给下一个 Agent,其底层实现就是让大模型触发一个特定的 Function Calling。Host 拦截到这个动作后,不操作物理世界,而是操作内存中的上下文路由表。
- "状态图(带环的图)是 A2A 走向工业级的底座" 面对复杂的长周期业务流(如自动化软件开发),不能依赖大模型自己做路由。必须在 Java/Python 后端引入 LangGraph 思想,通过预先定义好的状态图(支持循环/回路的图,而非严格 DAG------重试打回的场景天然有环) 和共享状态(Shared State)来兜底,确保 AI 的每一步执行都在人类设定的公司组织架构约束之内流转。
现代大模型 Agent 第五层:通信协议与 LLM Gateway 架构解析
核心体系 :网络传输协议栈 × API 网关基建 × SRE 可靠性保障 架构哲学:大模型 API 极其昂贵、缓慢且充满不确定性。绝不能让业务代码直接"裸奔"调用大模型,必须通过统一的 LLM Gateway 充当防弹衣、路由器和印钞机。
一、 通信层:为什么传统的 HTTP 抓不住大模型?
大模型的计算特性是"自回归生成(一个字一个字往外吐)"。传统的 HTTP/1.1 请求-响应模式(必须等整个 JSON 拼完才返回)会导致极高的首字延迟(TTFT)。为了实现流式传输(Streaming),现代后端架构必须在三种长连接协议中做取舍:
1. SSE (Server-Sent Events):纯文本流式的绝对王者
- 底层机制 :建立在标准 HTTP 协议之上。客户端发起请求后,服务端保持连接不断开,持续单向地往客户端推送
text/event-stream格式的数据块。 - 工程优势 :对反向代理(Nginx)、防火墙极其友好;在 Java 体系中实现极其轻量(Spring Boot 原生支持
SseEmitter或 WebFlux 的Flux<ServerSentEvent>)。 - 架构痛点 :它是单向水管。大模型在吐字时,如果用户想打断它,不能在同一根管子里逆流喊停,必须重新发起一个 HTTP POST 请求去通知服务端中断。
2. WebSocket:全双工的对讲机与高并发噩梦
- 底层机制:通过 HTTP 握手升级协议,建立持久的 TCP 全双工通道,客户端和服务端随时可以互发消息。
- 架构痛点(后端必考题) :WebSocket 是强状态绑定(Stateful)的。当系统面临百万并发洪峰时,长连接死死绑在某一台特定的 JVM 实例上,导致极难进行水平扩容(Scale-out)。如果该节点宕机,所有连接瞬间断开。为了解决这个问题,往往需要引入 Redis Pub/Sub 或 RocketMQ 来做跨节点的会话状态路由,极大增加了系统架构的复杂度。
3. WebRTC:实时语音 Agent 的唯一解(抗击网络抖动)
- 底层机制 :彻底抛弃 TCP,走向 UDP 协议。
- 核心破局点 :为什么语音通话不能用 WebSocket?因为 TCP 追求"绝对可靠"。一旦网络抖动丢失了一个数据包,TCP 会触发队头阻塞(Head-of-Line Blocking),死等重传,导致语音瞬间卡顿。而 WebRTC 基于 UDP, "宁可丢包,绝不等候" ,配合底层的 PLC(丢包隐藏算法),换取了低至 100ms 以内的极致丝滑打断体验。
二、 网关层(LLM Gateway):企业级 AI 架构的中枢防线
在微服务架构中,如果几十个业务模块各自在代码里写死 OpenAI 的 SDK、直连公网,系统将面临密钥泄露、节点宕机雪崩、账单失控三大灾难。
引入独立部署的 LLM Gateway(大模型网关) ,是解决这些问题的标准动作:
核心功能 1:统一路由与 SRE 故障转移(Failover)
- 无缝模型切换 :网关对外暴露一套标准化的 OpenAI API 协议。业务层代码完全不用动,只需在网关后台将路由配置从
gpt-4o指向私有化部署的Qwen,流量瞬间无缝切换。 - 熔断与降级保护:引入高并发熔断机制。当海外大模型 API 出现严重网络超时或 500 报错时,网关立即触发断路器,将请求秒级平滑地 Failover(故障转移)到国内的备用模型节点,保障系统的极致高可用。
核心功能 2:安全防御与鉴权(Cybersecurity 防火墙)
作为抵御恶意攻击的第一道防线,网关承担着至关重要的安全责任:
- 密钥隔离:将真实的厂商 API Key 封印在网关内存或 Vault 加密机中,对外只给各个业务团队颁发虚拟 Key(JWT Token)。
- 防注入与漏洞拦截:在流量清洗阶段,集成安全探针。不仅能拦截常见的 Prompt Injection(提示词注入),更能对流入的 Payload 进行深度的模型漏洞分析,精准过滤包含恶意触发器(Trigger)的污染样本,防范潜在的后门攻击(Backdoor Attacks),保护云端模型的纯洁性。
核心功能 3:限流控制(Rate Limiting)与配额管理
大模型接口是极其稀缺的计算资源,极易被恶意请求打挂或刷爆信用卡。
- 高并发控流:结合 Redis 和 Lua 脚本,实现分布式的令牌桶(Token Bucket)或滑动窗口限流算法。
- 租户隔离:对不同业务线(如 C端免费用户、B端付费大客)进行细粒度的并发度(TPS)与总 Token 消耗额度控制,防止"吵闹的邻居"效应。
核心功能 4:语义缓存(Semantic Cache)------ 降本增效的核武器
这是大模型网关独有的高级特性,彻底颠覆了传统的 HTTP 文本精准匹配缓存。
- 原理:用户提问到达网关后,网关首先将其转为向量(Embedding),去后端的 Redis 或专门的向量数据库中进行相似度检索。
- 效果 :如果发现历史请求中存在极度相似的意图(例如"怎么用 Docker 部署 MySQL"和"MySQL 的 Dockerfile 怎么写",向量相似度 > 0.95),网关将直接拦截请求,把缓存的答案秒级返回给前端。
- 收益:彻底绕过大模型的漫长推理,API 成本降为 0,响应延迟从 10 秒骤降至 50 毫秒以内。
三、 从底至上的终极技术栈串联
为了将整个五层架构落地为可运行的企业级系统,你可以这样组织你的技术栈:
- 容器化基建 :将网关、Host 应用与所有的 MCP Server 打包进 Docker 镜像,通过
docker-compose或 K8s 进行隔离编排。 - 并发与异步调度:在 Host 宿主层(Java 端),利用多线程并发工具包(JUC)、线程池隔离或虚拟线程(Virtual Threads)来处理密集的多 Agent A2A 异步回调与状态流转。
- 数据持久与缓存:使用 Redis 来支撑网关层的分布式限流、会话状态(StateGraph)保存以及语义缓存的极速响应。
🎯 终极面试大局观(第五层核心金句)
- "大模型的算力瓶颈,必须靠后端的网关基建来填补。" > 不要试图在业务代码里处理大模型的超时与并发。通过引入独立的高可用 LLM Gateway,将熔断、限流、故障转移等 SRE 职责下沉,才能让上层的 Agent 专心做业务编排。
- "安全和成本,是企业级 AI 架构的生命线。" 通过网关层的集中化虚拟 Key 签发、动态流量审计以及向量化的语义缓存拦截,将大模型的调用从"不可控的黑盒"变成"可观测、可防御、可计费"的标准化企业资产。
企业级 AI Agent 全链路架构与底层工程实践
架构哲学:大模型只是无状态的"闭眼决策引擎"。真正的智能体架构,是通过宿主应用(Host)掌控全场的状态刷新、数据喂养与上下文沙盒隔离。
🏗️ 第一篇:基础武器库(单兵作战基建)
要构建企业级 Agent,必须先将底层能力解耦为三个层次:指令语言、工具生态、业务大脑。
1. 第一层:Function Calling (底层神经元)
Function Calling 的核心使命是将大模型(LLM)的自然语言意图,转化为可被代码直接执行的结构化指令。
-
训练机制:它绝不是模型的"涌现能力",而是通过 SFT(监督微调)教会格式,再通过 RLHF(人类反馈强化学习)建立边界感(知道什么时候该调,什么时候该直接回答)。
-
并行调用 (Parallel Tool Calling) :当任务无依赖时(如同时查北京和上海天气),模型可一次性输出多个指令。
底层细节:此时大模型返回的
tool_calls是一个 JSON 数组[{"name": "get_weather", "args": {"city": "Beijing"}}, {"name": "get_weather", "args": {"city": "Shanghai"}}]。宿主代码需遍历数组,丢进 JUC 线程池并发执行,将耗时的串行网络请求压缩为一轮并发。
2. 第二层:MCP 模型上下文协议 (工具生态)
打破 Function Calling 必须硬编码对接的痛点,充当 AI 界的 "USB 接口标准" 。
- 物理隔离:MCP Server 是独立运行的外部服务(提供 Tools、Resources、Prompts),它完全不在乎调用者是谁。
- 绝对盲区 :大模型根本不知道什么是 MCP! 全靠中间的 AI Client(宿主)去连接 MCP Server,将工具列表"翻译"成 Function Calling 的 JSON Schema,大模型依然只输出原生的 FC 指令。
3. 第三层:Agent Skill (战术大脑)
解决重复手写 Prompt 以及 Context Window 被撑爆的问题。以标准化文件夹的形式持久化业务 SOP。
-
渐进式加载 (Progressive Disclosure) :这是控制 Token 成本的核心。
- 第一层:平时只加载所有 Skill 的名字和简介(用于意图路由)。
- 第二层 :只有匹配命中时,才全量读取
SKILL.md正文(业务步骤)。 - 第三层 :走到最后一步时,才动态读取
assets/下的输出模板文件。
⚙️ 第二篇:单体 Agent 的运行时黑盒(执行流与抓包)
在代码跑起来后,系统分为两大阵营:有状态的 Host (Java/Spring Boot 后端)与 无状态的 LLM(云端计算引擎)。
🔄 全生命周期:五大执行流转阶段
- 系统启动(静态收割) :Host 启动,拉起 MCP Server,将上百个工具 Schema 缓存在本地内存,大模型此时完全闭眼。
- 技能激活(渐进加载) :用户发问,大模型命中 Skill。Host 拦截信号,去磁盘读取完整
SKILL.md准备拼装。 - 工具剪枝(Tool RAG) :Host 拿到当前步骤文本,在内存中做向量检索,将 100 个工具强行精简(剪枝)为当前唯一需要的 1 个工具,组装成 Payload 发给模型。
- 脑冻结(输出 FC) :大模型看到步骤和说明书,触发肌肉记忆,立刻中断文本生成,吐出 JSON 指令并休眠。
- 多轮刷新(偷梁换柱) :Host 走 MCP 驱动硬件拿到结果。在发起下一轮请求前,Host 主动将旧工具 Schema 丢弃,换上下一步需要的新工具 Schema,连同结果发给模型,直到任务结束。
📦 源码抓包级解密:Host 的 Payload 魔术
-
第一轮请求 (Host 看到了步骤一,只配给
read_file工具)JSON
json{ "messages": [ {"role": "system", "content": "SOP: 1. 读取代码 2. 运行脚本"}, {"role": "user", "content": "审查 login.java"} ], "tools": [{"function": {"name": "read_file"}}] } -
第二轮请求 (Host 拿到源码,动态换成了
run_script工具)JSON
json{ "messages": [ {"role": "system", "content": "SOP: 1. 读取代码 2. 运行脚本"}, {"role": "assistant", "tool_calls": [{"function": {"name": "read_file"}}]}, {"role": "tool", "content": "public class Login { ... }"} ], "tools": [{"function": {"name": "run_script"}}] }(注:第二轮的 tools 数组里,read_file 被彻底抹去,换成了 run_script。大模型是被 Host 牵着鼻子走的。)
🌐 第三篇:从单兵到军团的宏观基建
单体 Agent 容易陷入"人格分裂"和"上下文雪崩"。走向工业级,必须引入多智能体协同与底层网关护城河。
4. 第四层:A2A 多智能体协同 (组织架构)
A2A 的本质是Prompt 和 Tools 的动态沙盒隔离 (注意版本语境:这说的是进程内编排 ;真正的 A2A 网络协议下 Agent 之间通过 HTTP/JSON-RPC 跨网络互调)。单进程内,Agent 之间不联网通信,全靠 Host 进行内存路由。
-
Handoff (交接棒模式) :转接也是一种 Function Calling。Host 拦截到转接指令后,不调物理世界,而是直接替换大模型的 System Prompt 和专属工具,发起新请求让其"瞬间换脑"。
-
Supervisor (包工头模式) :包工头负责拆解任务,Host 拦截后开启异步子线程,并发挂载不同 Prompt 拉起子 Agent 执行。
-
StateGraph (共享白板模式) :适用于复杂的环形工作流。
底层细节:Host 在内存中维护一个全局 State 状态树。这是典型的黑板模式 (Blackboard Architecture) 或 响应式事件驱动 (Event-Driven) 设计。Agent A 更新白板数据后休眠,Host 监听到状态变更,自动唤醒 Agent B 接盘,直到全流程走完。
5. 第五层:LLM Gateway (基础设施与 SRE)
绝不能让业务代码直连大模型裸奔。引入独立的 LLM Gateway 充当防弹衣、路由器和印钞机。
- 网络协议选型 :普通文本流式首选 SSE (对 Nginx 友好,单向流);高并发打断不选有状态的 WebSocket,而选走 UDP 的 WebRTC (宁可丢包绝不重传,抗网络抖动防队头阻塞)。
- SRE 故障转移 (Failover) :海外 API 宕机超时,网关触发熔断,秒级平滑切流至国内备用模型节点,业务方零感知。
- 降本核武器 (Semantic Cache 语义缓存) :网关将用户提问向量化,通过计算 Cosine Similarity,拦截相似度 > 0.95 的意图(如"怎么用 Docker"与"Dockerfile 咋写"),直接返回历史答案,API 成本降为 0,延迟降至 50ms 级别。
💡 架构师箴言 : 不要试图让 AI 产生意识去自己找工具。优秀的 Agent 平台,是一个极其精密、充满心机的高并发后端状态机。用 Host 的算力去剪枝,用 Gateway 的缓存去挡枪,把大模型的上下文环境剥离到极简,才是企业级 AI 落地的唯一真相。
⚡ 补充层一:并行工具调用(Parallel Tool Calls,面试高频)
1. 是什么
- 一次响应里模型同时输出多个
tool_calls(数组多元素,共享同一个tool_call_id批次),如"查天气 + 查日历"一次说完。 - 触发判断在模型侧: 是否并行由模型自己决定(多个调用互不依赖时倾向并行);API 侧可关 (
parallel_tool_calls: false,要强串行时用------比如写操作的顺序敏感场景)。
2. Host 侧实现要点(工程答案,讲这个拿分)
- 并发执行: 收到 N 个 tool_calls,用
Promise.all(JS)或线程池(Java)并发分发------串行执行是浪费延迟,面试官等着你说这句。 - 结果回喂的顺序铁律: 下一轮
messages里必须按 tool_call_id 一一对应地回填所有结果,顺序错/漏一个,API 直接 400------因为模型按 id 关联"哪次调用哪个结果"。 - 失败处理: 单个工具失败不要中断整批 ------失败的那条回填 error 消息(
is_error标记),模型看到后会自行决定重试/换路------与 自研 Agent 平台 的"错误回喂自愈"一脉相承。 - 写操作慎并行: 并行前提是调用间无依赖且幂等;有依赖的调用模型自己会拆到多轮(但也出现过竞态翻车,所以关键写路径显式关掉 parallel)。
3. 一句话总结
"并行工具调用 = 模型一次给一篮子互相独立的调用,Host 并发执行后按 tool_call_id 对齐回填再进下一轮------收益是延迟取 max 而不是求和;代价是必须自己管好失败隔离和顺序对齐。"
🤖 补充层二:DeepAgents(面试高频,三个考点)
-
是什么: LangChain 团队推出的深度研究 Agent 框架(2025),= 规划(todo 清单)+ 子 Agent(隔离上下文的文件系统)+ 长时任务管理 三合一的参考实现。
-
核心机制:
- Planning Tool: 维护结构化 todo 列表,每完成一项勾一项------对抗长任务"迷路"。
- FileSystem: 把中间产物(笔记/草稿/报告)当文件读写,跨子 Agent 共享------上下文以文件形式外化,突破单轮 context 限制。
- SubAgents: 研究型子任务独立上下文执行,结果写回文件系统(与 Supervisor 模式同源,但共享的是文件不是内存 State)。
-
面试话术: "DeepAgents 的价值不在框架本身,而在它示范了长时 Agent 的三件套------计划外置(todo)、记忆外置(文件)、上下文隔离(子 Agent) 。我项目实践做的 自研 Agent 平台 三层记忆与多 Agent 委派,和它解决的是同一类问题,思路可以互相印证。"
🛡 补充层三:SSRF 与 API 限流退避(自研 Agent 平台 三层防线点名)
1. SSRF(服务器端请求伪造)------ 动态 API 工具的生死题
-
是什么: 攻击者诱导服务端 替自己去访问内网资源(
http://169.254.169.254/云元数据、http://localhost:6379Redis、内网管理后台)------Agent 拿 URL 去调接口的场景天然高危。 -
三层防线(对齐 自研 Agent 平台 生产实现):
- 权限过滤: 工具清单来自 RBAC + swagger 白名单------不在清单里的接口 URL 根本不可达(源头治理)。
- 鉴权注入: 以当前登录用户的身份调用(而非服务账号超级权限)------即使被诱导,权限也只有用户本人那么多(最小权限)。
- 目标校验: 解析 DNS 后校验 IP 非内网段/环回/链路本地(防 DNS rebinding:域名解析时换 IP 绕过校验,需在连接时二次校验)、禁非常规协议与端口、跟随重定向时逐跳复检。
-
一句话: "Agent 能动态调 URL = 把 SSRF 风险当一等公民设计------白名单源头、用户级权限、目标 IP 校验三道闸。"
2. 429 与退避(LLM API 语境)
- 429 Too Many Requests: 上游限流信号,响应头
Retry-After: n(等 n 秒)优先按它来。 - 指数退避 + 抖动: 重试间隔 1s→2s→4s...,加随机抖动(jitter)防止集体同步重试造成二次洪峰(雷霆群羊效应);一般 3~5 次后放弃并走降级(切备用模型/返回兜底)。
- 注意幂等: 429 后重发的请求必须是可安全重放的(补全类请求天然幂等------同 prompt 结果语义等价;带副作用的自定义工具调用要带幂等键)。
- 与后端限流的呼应: 微服务速记的"重试三原则"(只重试幂等、次数有限、退避)完全通用------区别只在 LLM 场景多了
Retry-After头和"切模型降级"这个选项。