AI 常见概念解析:从大模型到智能体的技术图谱

AI 常见概念技术图谱 - 从大模型到智能体

前言

“LLM、Function Call、MCP、Agent”这些词单独看都认识,但一旦放进同一张架构图里就开始打架——很正常:它们不在同一个抽象层,很多文章还会把不同厂商的术语混在一起讲。

这篇文章只做一件事:把这些概念放回各自的位置,并给你能直接跑起来的最小示例(Python + TypeScript)。读完你至少能回答三个问题:

  • LLM 到底是什么,和“泛称的大模型”差在哪?
  • 工具调用(Tool/Function Calling) 是什么能力,为什么它比“让模型输出 JSON”更像工程?
  • MCP 与 Agent 分别解决什么问题,什么时候该用、什么时候别用?

基础概念:大模型、基础模型、LLM(别只盯参数)

大模型与 LLM 概念示意图

1)”大模型”到底大在哪里?

“大模型(Large Model)”更像一个工程尺度的说法,而不是严格的学术分类。通常它意味着:

  • 参数量大、训练数据大、训练算力大(但参数量不是唯一指标
  • 训练过程复杂:预训练(pretrain)+ 指令微调(SFT)+ 偏好对齐(如 RLHF/RLAIF 等)
  • 部署成本高:推理延迟、显存、并发、成本控制都变成显性问题

很多人把“参数量 = 能力”当成公式,其实只能算“经验相关”,远谈不上“决定因素”。同样 70B,有的模型像瑞士军刀,有的像钝刀——训练数据、训练目标、对齐方式、推理策略都会改变“刀刃形状”。

2)LLM 是什么?它和“大模型”的关系

  • LLM(Large Language Model):专注自然语言(以及代码等序列数据)的模型家族。
  • 大模型:更宽泛的称呼,可以包括视觉、多模态、语音、推荐、科学计算等方向的“基础模型”。

一句话记法:

LLM 是“大模型”里专门负责“语言/序列”的那一支。

3)上下文学习 vs 微调(很多误解来自这里)

  • 上下文学习(In-Context Learning):你在提示词里给示例,模型在当前对话里“临时学会”一种模式。
  • 微调(Fine-tuning):你真的改了模型参数,让它长期稳定地产生某种行为。

工程上更常见的路线是:先做提示词 + 工具/检索,真的到了规模化、稳定性和成本要求很高时,再考虑微调。


交互增强:Tool Calling / Function Calling(让模型”能做事”)

工具调用闭环流程示意图

“Function Call”这个词在不少旧文章里出现得更多;在较新的 API/产品里,你会更常看到 Tool Calling(工具调用)。本质是一件事:

模型不只是“回答”,而是能输出一个结构化的“调用意图”,让你的程序去执行,再把结果喂回模型继续生成。

工具调用解决的不是“格式”,而是“闭环”

只让模型输出 JSON,你依然会遇到:

  • 参数不合法、字段缺失、类型乱飞
  • 多工具协同:先查,再算,再写入
  • 幂等与重试:同一个调用重复执行会不会造成副作用?
  • 超时与失败:工具失败后模型如何恢复?

工具调用把这些问题摆到台面上:你必须写“工具路由 + 参数校验 + 结果回传”,这才像工程。


可运行示例:OpenAI 工具调用(Python,含严格参数约束)

下面给一个“查天气”的最小闭环示例。你可以把它保存为 tool_call_weather.py 直接运行。

依赖与环境

1
2
pip install -U openai
export OPENAI_API_KEY="你的key"

tool_call_weather.py

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
import json
from typing import Literal

from openai import OpenAI

client = OpenAI()


def get_weather(city: str, unit: Literal["c", "f"] = "c") -> dict:
# 这里用假数据模拟真实天气 API
# 真实项目里:在这里请求你自己的天气服务,并做好超时/重试/缓存
fake = {
"北京": {"temp_c": 15, "condition": "晴"},
"上海": {"temp_c": 12, "condition": "小雨"},
}
data = fake.get(city, {"temp_c": 20, "condition": "多云"})

if unit == "f":
temp = data["temp_c"] * 9 / 5 + 32
return {"city": city, "temperature_f": round(temp, 1), "condition": data["condition"]}

return {"city": city, "temperature_c": data["temp_c"], "condition": data["condition"]}


TOOLS = [
{
"type": "function",
"function": {
"name": "get_weather",
"description": "获取指定城市的天气(示例工具:返回模拟数据)",
"parameters": {
"type": "object",
"properties": {
"city": {"type": "string", "description": "城市名称,例如:北京"},
"unit": {
"type": "string",
"enum": ["c", "f"],
"description": "温度单位:c=摄氏度,f=华氏度",
},
},
"required": ["city"],
"additionalProperties": False,
},
# 开启 Structured Outputs:让模型生成的参数严格匹配 JSON Schema
"strict": True,
},
}
]


def call_function(name: str, args: dict) -> str:
if name == "get_weather":
result = get_weather(**args)
return json.dumps(result, ensure_ascii=False)
raise ValueError(f"Unknown function: {name}")


def main() -> None:
model = "gpt-4.1-mini" # 替换成你账号可用的模型

response = client.responses.create(
model=model,
input=[{"role": "user", "content": "北京今天天气怎么样?用摄氏度。"}],
tools=TOOLS,
)

# 持续处理工具调用,直到模型不再要求调用工具
while True:
tool_outputs = []
for item in response.output:
if getattr(item, "type", None) != "function_call":
continue

args = json.loads(item.arguments)
output = call_function(item.name, args)

tool_outputs.append(
{
"type": "function_call_output",
"call_id": item.call_id,
"output": output, # 注意:这里必须是字符串(建议 JSON 字符串)
}
)

if not tool_outputs:
break

response = client.responses.create(
model=model,
previous_response_id=response.id,
input=tool_outputs,
tools=TOOLS,
)

print(response.output_text)


if __name__ == "__main__":
main()

这个示例里隐藏的最佳实践

  • 参数校验别只靠模型:即使开了 strict,你也应该在服务端做校验与兜底。
  • 工具输出用 JSON 字符串:统一格式,后续更容易调试、落日志、重放。
  • 工具要可观测:记录 call_id、入参、耗时、错误码,否则排错会很痛。

协议标准:MCP(Model Context Protocol)

MCP 协议标准化示意图

MCP 解决的是什么问题?

如果说“工具调用”是在模型 ↔ 你的应用代码之间做闭环,那么 MCP 更像是在应用 ↔ 外部工具/数据源之间做标准化:

  • 你可以把“工具、资源、提示模板”打包成一个 MCP Server
  • 不同的 MCP Client(桌面应用、IDE、你的产品)可以用统一方式发现、调用这些能力
  • 你不用为每个客户端各写一套“插件协议”

MCP 的核心对象通常会这样讲:

  • Tools:可执行动作(查询、计算、写入)
  • Resources:可读取的上下文(文件、数据库视图、知识库条目)
  • Prompts:可复用提示模板(把“问法”标准化)

MCP 与传统 API 的区别(更工程化的说法)

维度 传统 API MCP
面向对象 人/程序员 LLM 客户端与工具生态
发现机制 你手动查文档、配路径 客户端可列出 tools/resources/prompts
调用语义 自定义 协议统一(工具、资源、提示)
集成形态 单点集成 “可插拔”的工具服务器

注意:MCP 不是“替代 REST”。它更像一层“给 AI 客户端用的插件总线”。


可运行示例:最小 MCP Server(TypeScript,stdio)

下面示例使用 TypeScript 的 MCP SDK(v1 系列常见写法)。把它保存为 server.ts

初始化与运行

1
2
3
4
5
npm init -y
npm install @modelcontextprotocol/sdk zod
npm install -D tsx typescript @types/node

npx tsx server.ts

server.ts

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
import { z } from "zod";
import { McpServer, ResourceTemplate } from "@modelcontextprotocol/sdk/server/mcp.js";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";

type User = { id: number; name: string; email: string };

const users: User[] = [
{ id: 1, name: "Alice", email: "alice@demo.com" },
{ id: 2, name: "Bob", email: "bob@demo.com" },
{ id: 3, name: "Carol", email: "carol@demo.com" },
];

const server = new McpServer({ name: "user-directory", version: "1.0.0" });

server.tool(
"search_users",
{ query: z.string().min(1).describe("按姓名或邮箱模糊搜索") },
async ({ query }) => {
const q = query.toLowerCase();
const result = users.filter(
(u) => u.name.toLowerCase().includes(q) || u.email.toLowerCase().includes(q)
);
return {
content: [{ type: "text", text: JSON.stringify(result, null, 2) }],
};
}
);

server.resource(
"user_by_id",
new ResourceTemplate("user://{id}", { list: undefined }),
async (uri, { id }) => {
const user = users.find((u) => u.id === Number(id));
return {
contents: [
{
uri: uri.href,
text: user ? JSON.stringify(user, null, 2) : JSON.stringify({ error: "not_found" }),
},
],
};
}
);

const transport = new StdioServerTransport();
await server.connect(transport);

你会注意到:这个 Server 没有暴露“HTTP 路由”。stdio 模式的目标就是让 MCP Client 以“启动子进程”的方式连接它(典型在桌面端/IDE 集成里)。


智能系统:Agent(智能体)= LLM + 工具 + 规划 + 状态

智能体系统架构示意图

“Agent”在工程语境里不是一个单一技术点,更像一个系统形态

  • LLM:负责理解、推理、生成
  • 工具系统:能查数据、能执行动作(工具调用 / MCP / 内置工具都行)
  • 规划与控制:多步任务拆解、循环、终止条件
  • 状态(Memory/State):短期对话上下文 + 长期记忆/业务状态 + 运行时轨迹

Agent 和“脚本自动化”的关键差异

维度 传统脚本/工作流 Agent
路径 预定义流程 动态选择步骤
失败处理 人写分支兜底 让模型基于反馈调整策略
抽象层 工程师驱动 目标驱动(Goal-driven)
适用范围 稳定、规则清晰 复杂、多变、信息不完备

但也别神化:很多“Agent”项目最后都会回到一个朴素结论——该确定的部分尽量确定,LLM 负责不确定的部分。


可运行示例:一个“最小 Agent 循环”(Python,安全计算器 + 搜索桩)

把它保存为 simple_agent.py

依赖

1
2
pip install -U openai
export OPENAI_API_KEY="你的key"

simple_agent.py

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
import ast
import json
from openai import OpenAI

client = OpenAI()


def safe_eval_arith(expr: str) -> float:
"""
只允许 + - * / () 和数字的安全计算器(示例用,别当完整表达式引擎)。
"""
node = ast.parse(expr, mode="eval")

allowed = (
ast.Expression,
ast.BinOp,
ast.UnaryOp,
ast.Add,
ast.Sub,
ast.Mult,
ast.Div,
ast.USub,
ast.UAdd,
ast.Constant,
ast.Load,
ast.Pow,
ast.Mod,
ast.FloorDiv,
ast.LShift,
ast.RShift,
ast.BitAnd,
ast.BitOr,
ast.BitXor,
ast.Call,
ast.Name,
)

# 禁用一切函数调用/变量名(上面允许列表里包含了 Call/Name,这里直接拦掉)
for n in ast.walk(node):
if not isinstance(n, allowed):
raise ValueError("Unsupported expression")
if isinstance(n, (ast.Call, ast.Name)):
raise ValueError("Calls/names are not allowed")

def eval_node(n):
if isinstance(n, ast.Expression):
return eval_node(n.body)
if isinstance(n, ast.Constant) and isinstance(n.value, (int, float)):
return float(n.value)
if isinstance(n, ast.UnaryOp):
v = eval_node(n.operand)
if isinstance(n.op, ast.UAdd):
return v
if isinstance(n.op, ast.USub):
return -v
if isinstance(n, ast.BinOp):
a = eval_node(n.left)
b = eval_node(n.right)
if isinstance(n.op, ast.Add):
return a + b
if isinstance(n.op, ast.Sub):
return a - b
if isinstance(n.op, ast.Mult):
return a * b
if isinstance(n.op, ast.Div):
return a / b
raise ValueError("Unsupported expression")

return eval_node(node)


def search_stub(query: str) -> dict:
# 示例:用静态数据模拟搜索。真实项目请接入你自己的搜索/知识库/RAG。
return {
"query": query,
"results": [
{"title": "Python 官方教程", "hint": "docs.python.org/zh-cn/"},
{"title": "Real Python 入门", "hint": "realpython.com/"},
],
}


TOOLS = [
{
"type": "function",
"function": {
"name": "search",
"description": "搜索资料(示例工具:返回固定结果)",
"parameters": {
"type": "object",
"properties": {"query": {"type": "string"}},
"required": ["query"],
"additionalProperties": False,
},
"strict": True,
},
},
{
"type": "function",
"function": {
"name": "calculate",
"description": "计算四则运算表达式(示例工具:安全计算器)",
"parameters": {
"type": "object",
"properties": {"expr": {"type": "string", "description": "例如:123 + 456"}},
"required": ["expr"],
"additionalProperties": False,
},
"strict": True,
},
},
]


def call_tool(name: str, args: dict) -> str:
if name == "search":
return json.dumps(search_stub(**args), ensure_ascii=False)
if name == "calculate":
value = safe_eval_arith(args["expr"])
return json.dumps({"expr": args["expr"], "value": value}, ensure_ascii=False)
raise ValueError(f"Unknown tool: {name}")


def run_agent(task: str) -> str:
model = "gpt-4.1-mini" # 替换成你账号可用的模型

response = client.responses.create(
model=model,
input=[
{
"role": "system",
"content": (
"你是一个务实的任务型助手。能用工具就用工具,"
"需要计算就调用 calculate,需要查资料就调用 search。"
"拿到工具结果后,用简短步骤说明你的结论。"
),
},
{"role": "user", "content": task},
],
tools=TOOLS,
)

max_rounds = 8
for _ in range(max_rounds):
tool_outputs = []
for item in response.output:
if getattr(item, "type", None) != "function_call":
continue
args = json.loads(item.arguments)
out = call_tool(item.name, args)
tool_outputs.append(
{"type": "function_call_output", "call_id": item.call_id, "output": out}
)

if not tool_outputs:
return response.output_text.strip()

response = client.responses.create(
model=model,
previous_response_id=response.id,
input=tool_outputs,
tools=TOOLS,
)

return "任务未在轮次内完成(超时保护触发)。"


if __name__ == "__main__":
print(run_agent("帮我找两份 Python 入门资料,并计算 123 + 456。"))

概念对比与关系:一张“分层图”更不容易混

把这些东西按层级放回去,会清晰很多:

1
2
3
4
5
6
7
8
9
10
11
12
13
┌─────────────────────────────────────────────┐
│ Agent(智能体系统) │
│ - 目标/规划/循环/状态/评估/安全策略 │
├─────────────────────────────────────────────┤
│ 工具与上下文层 │
│ - Tool/Function Calling(模型发起调用) │
│ - MCP(把工具/资源做成可插拔服务器) │
├─────────────────────────────────────────────┤
│ 模型层 │
│ - LLM(语言为主的基础模型能力) │
├─────────────────────────────────────────────┤
│ 训练与规模(“大模型”常指这里的工程尺度) │
└─────────────────────────────────────────────┘

关系一句话总结

  • LLM:负责“想”(理解与生成)
  • 工具调用:让 LLM 能“伸手做事”(但手要你来接)
  • MCP:让“工具与上下文”变成可复用、可共享的标准接口
  • Agent:把“想 + 做 + 记 + 控制”组织成一个能长期运行的系统

怎么选:从最小可用到可扩展(别一上来就 Agent)

一个更现实的演进路线通常是:

  1. LLM + 提示词:先把任务跑通(别急着上工具)
  2. 加工具调用:解决实时数据/动作执行/结构化提取
  3. 工具变多后上 MCP:统一接入方式,减少重复集成
  4. 任务变复杂再做 Agent:引入规划、状态、评估与安全

你会发现:很多场景其实在第 2 步就够用了。


总结

  • “大模型/LLM”讲的是模型能力与训练尺度
  • “Tool/Function Calling”讲的是模型如何把意图变成可执行的调用
  • “MCP”讲的是工具与上下文如何标准化、可插拔、可复用
  • “Agent”讲的是把多步任务做成系统:规划、状态、循环、终止与治理

如果你准备把文章里的示例改成你自己的业务版本,我可以基于你的具体场景(比如:客服、数据分析、研发提效、运维自动化)帮你把“工具设计、参数 schema、错误与幂等、日志与评估”补齐成一套更像生产系统的骨架。


参考资源

  • OpenAI Function Calling / Tools 指南:https://platform.openai.com/docs/guides/function-calling
  • OpenAI API Reference(Responses / Chat Completions):https://developers.openai.com/api/reference
  • MCP 官网与规范入口:https://modelcontextprotocol.io/
  • MCP TypeScript SDK:https://github.com/modelcontextprotocol/typescript-sdk
  • LangChain Agents 概念(对比用):https://python.langchain.com/docs/concepts/agents/