大模型演进之路:代码视角

目录

  1. 大模型基础对话
  2. Function Calling
  3. AI Agent
  4. MCP 标准化协议
  5. Skill 技能封装

开场

今天用代码走一遍大模型应用架构的演进。五个阶段:LLM → Function Calling → Agent → MCP → Skill

从”只会说话”,到”能动手”,到”自主决策”,再到”工具标准化”,最后到”技能即插即用”。


第一章:大模型基础对话

核心概念

  • LLM API:最简单的调用
  • Messages:对话历史
  • System/User/Assistant:角色

代码(10行)

1
2
3
4
5
6
7
8
9
10
11
12
from openai import OpenAI
import os

client = OpenAI(api_key=os.getenv("OPENAI_API_KEY"))

def chat(msg):
return client.chat.completions.create(
model="gpt-3.5-turbo",
messages=[{"role": "user", "content": msg}]
).choices[0].message.content

print(chat("你好"))

讲解要点

  • LLM = 函数,输入文本,输出文本
  • 最基础的调用方式,模型只能”说话”

第二章:Function Calling

核心概念

  • Tools:告诉模型有哪些函数可用
  • Tool Calls:模型返回要调用的函数
  • 执行流程:模型判断 → 我们执行 → 返回结果 → 模型回答

代码

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
from openai import OpenAI
import os, json

client = OpenAI(api_key=os.getenv("OPENAI_API_KEY"))

# 定义工具
tools = [{
"type": "function",
"function": {
"name": "get_weather",
"description": "查询天气",
"parameters": {
"type": "object",
"properties": {"city": {"type": "string"}},
"required": ["city"]
}
}
}]

def get_weather(city):
return f"{city} 晴天,20°C"

# 对话
msg = [{"role": "user", "content": "北京天气怎么样?"}]
r = client.chat.completions.create(
model="gpt-3.5-turbo",
messages=msg,
tools=tools
)

# 如果模型要调用工具
if r.choices[0].message.tool_calls:
tc = r.choices[0].message.tool_calls[0]
args = json.loads(tc.function.arguments)

result = get_weather(args["city"])

msg.append(r.choices[0].message)
msg.append({"tool_call_id": tc.id, "role": "tool", "name": "get_weather", "content": result})

final = client.chat.completions.create(model="gpt-3.5-turbo", messages=msg)
print(final.choices[0].message.content)
else:
print(r.choices[0].message.content)

讲解要点

  • 模型不直接执行函数,只返回请求
  • 我们负责执行,然后把结果返回给模型
  • 对比第一章:从”只能说”升级到”能要”

第三章:AI Agent

核心概念

  • ReAct 循环:思考 → 行动 → 观察 → 再思考
  • 自主决策:模型自己决定何时结束
  • Agent = LLM + Tools + Loop

代码

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
from openai import OpenAI
import os, json

client = OpenAI(api_key=os.getenv("OPENAI_API_KEY"))

tools = [{
"type": "function",
"function": {
"name": "get_weather",
"description": "查询天气",
"parameters": {
"type": "object",
"properties": {"city": {"type": "string"}},
"required": ["city"]
}
}
}]

def get_weather(city):
d = {"北京": "晴天 15°C", "上海": "多云 18°C", "武汉": "阴天 12°C"}
return d.get(city, "未知")

def agent(task):
msgs = [
{"role": "system", "content": "你需要完成用户任务,完成后直接回答。"},
{"role": "user", "content": task}
]

while True:
r = client.chat.completions.create(
model=os.getenv("OPENAI_MODEL", "gpt-3.5-turbo"),
messages=msgs,
tools=tools
)
msg = r.choices[0].message

if not msg.tool_calls:
return msg.content

msgs.append(msg)
for tc in msg.tool_calls:
args = json.loads(tc.function.arguments)
result = get_weather(args["city"])
msgs.append({
"tool_call_id": tc.id,
"role": "tool",
"name": "get_weather",
"content": result
})

print(agent("北京和武汉温差多少"))

讲解要点

  • 核心是 while True 循环,不是 for 循环
  • 模型可以多次调用工具,自己决定何时停止
  • 对比第二章:从”手动执行一次”升级到”自动循环执行”

第四章:MCP - 标准化协议

核心概念

问题:每个框架都有自己的工具调用方式,工具无法跨平台复用。

解决:MCP(Model Context Protocol)提供统一的工具调用协议,像 USB 接口一样标准化。

架构

1
2
3
4
5
6
7
8
9
10
11
┌─────────────┐
│ LLM/AI │ 应用层
└──────┬──────┘
│ MCP 协议
┌──────┴──────┐
Client │ 连接层
└──────┬──────┘
│ MCP 协议
┌──────┴──────┐
Server │ 服务层(文件系统、数据库、API...)
└─────────────┘

对比

特性 Function Calling MCP
工具定义 代码中手动定义 Server 注册
调用方式 每个服务单独处理 统一 Client
复用性 低(紧耦合) 高(可组合)
扩展性 麻烦 插拔式

代码示例

MCP Server(定义工具):

1
2
3
4
5
6
7
8
9
10
11
12
from mcp.server import FastMCP

mcp = FastMCP("天气服务")

@mcp.tool()
def get_weather(city: str) -> str:
"""查询城市天气"""
w = {"北京": "晴天 15°C", "上海": "多云 18°C"}
return w.get(city, "未知")

if __name__ == "__main__":
mcp.run()

MCP Client(Agent 调用):

1
2
3
4
5
# 动态获取工具列表(不需要手动定义)
mcp_tools = await mcp.list_tools()

# 调用工具(标准化接口)
result = await mcp.call_tool("get_weather", {"city": "北京"})

讲解要点

  • MCP 解决的是工具调用的标准化
  • 工具可以远程,也可以本地
  • Agent 不需要预先知道有哪些工具,连接后自动发现
  • 对比第三章:从”工具写死在代码里”升级到”工具通过标准协议调用”

第五章:Skill - 技能封装

核心概念

问题:工具虽然标准化了,但还是散的。如何让工具像插件一样即插即用?

解决:Skill 把工具 + 提示词 + 触发条件打包成一个文件夹,一个文件夹就是一个完整的技能。

文件结构

1
2
3
4
5
weather-skill/                ← 技能文件夹
├── SKILL.md ← 技能描述(触发条件 + 说明)
├── scripts/
│ └── weather.py ← 工具实现
└── references/ ← 参考资料(可选)

SKILL.md 示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
---
name: weather-skill
description: "天气查询技能。查询城市天气、温差对比。Keywords: 天气, weather, 温度"
---

## 概述
查询城市天气信息,支持温差对比。

## 触发条件
用户提到:天气、温度、气候、出门穿什么

## 使用步骤
1. 读取 scripts/weather.py 获取天气数据
2. 根据用户问题组织回答

工具实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# scripts/weather.py

def get_weather(city: str) -> dict:
"""查询城市天气"""
data = {
"北京": {"weather": "晴天", "temp": 15},
"上海": {"weather": "多云", "temp": 18},
}
return data.get(city, {"weather": "未知", "temp": 0})

def suggest_clothes(temp: str) -> str:
"""根据温度建议穿衣"""
t = int(temp)
if t < 10: return "羽绒服、围巾、手套"
elif t < 18: return "外套、长裤"
elif t < 25: return "薄外套、T恤"
else: return "短袖、短裤"

Agent 加载 Skill

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
def load_skills(skill_dir):
"""扫描文件夹,自动加载所有技能"""
skills = {}
for name in os.listdir(skill_dir):
skill_path = os.path.join(skill_dir, name)
if os.path.isdir(skill_path) and os.path.exists(os.path.join(skill_path, "SKILL.md")):
with open(os.path.join(skill_path, "SKILL.md"), "r") as f:
skills[name] = {"path": skill_path, "content": f.read()}
return skills

def agent(task):
# 1. 加载所有技能
skills = load_skills("./skills/")

# 2. 根据关键词匹配技能
skill_name = match_skill(task, skills)

# 3. 加载技能的工具
tools, tool_map = register_tools(skill_name, skills[skill_name])

# 4. 在技能内循环(和第三章 Agent 一样)
msgs = [{"role": "system", "content": skills[skill_name]["content"]},
{"role": "user", "content": task}]

while True:
r = client.chat.completions.create(model="gpt-3.5-turbo", messages=msgs, tools=tools)
msg = r.choices[0].message
if not msg.tool_calls: return msg.content

msgs.append(msg)
for tc in msg.tool_calls:
args = json.loads(tc.function.arguments)
result = tool_map[tc.function.name](**args)
msgs.append({"tool_call_id": tc.id, "role": "tool", "name": tc.function.name, "content": str(result)})

讲解要点

  • 文件夹即技能:放进去就能用,删了就没了
  • SKILL.md 是说明书:告诉系统什么时候用、怎么用
  • scripts/ 是实现:放实际的工具代码
  • 自动加载:Agent 启动时扫描文件夹,自动发现所有技能
  • 对比第四章:从”工具标准化调用”升级到”技能即插即用”

总结:完整演进路径

1
2
3
4
5
6
7
8
9
10
11
12
13
14
第一章: LLM API
└─ 只能说话

第二章: + Function Calling
└─ 能请求调用函数

第三章: + Loop(Agent)
└─ 自主循环思考和行动

第四章: + MCP(标准化协议)
└─ 工具调用标准化,可远程可本地

第五章: + Skill(技能封装)
└─ 技能即插即用,文件夹就是一个完整的能力包

核心演进

维度 第一章 第二章 第三章 第四章 第五章
模型能力 对话 请求工具 自主循环 自主循环 自主循环
工具位置 代码里 代码里 远程/本地 文件夹
工具调用 手动 自动循环 标准协议 自动加载
扩展方式 改代码 改代码 加 Server 加文件夹

最终总结

从”对话”到”工具”,从”工具”到”自主循环”,从”紧耦合”到”标准化协议”,从”手写代码”到”即插即用”。

Agent 的本质没有变——还是 LLM + 工具 + 循环。变的是我们组织和扩展能力的方式。

这就是大模型应用架构演进的方向:让 AI 的能力边界不断扩展,让工具的接入成本不断降低。


代码仓库

  • 完整代码:llm-evolution-code
  • 01-llm-basics:基础对话
  • 02-function-calling:函数调用
  • 03-ai-agent:Agent 循环
  • 04-mcp:MCP 协议
  • 05-skill:Skill 技能

系列:大模型应用架构演进 | LLM | Agent | MCP | Skill