Function Calling与智能Agent开发

更新时间: 2026-03-30 08:51:12

# 课前问题解答

Qwen3-Coder-480B-A35B-Instruct模型介绍

  • 参数特点:总参数480B,激活参数35B,采用MOE架构,激活参数不到总参数的十分之一
  • 专业领域:主要擅长代码生成任务,在代理编码、代理测试等任务上表现优异,支持256K长上下文
  • 对比优势:在开放模型中性能可与Claude Sonnet媲美,支持特别设计的函数调用格式
  • 局限性:处理常识问答、作文等非代码任务能力相对较弱

Qwen3-235B-A22B-Instruct模型介绍

  • 参数特点:总参数235B,激活参数22B,是相对通用的全能模型
  • 能力提升:增强了256K长上下文理解能力,在指令执行、逻辑推理等方面有显著改进
  • 版本差异:相比Qwen3-Coder,参数更少但更通用,适合非专业代码场景

激活参数的含义与MOE架构

  • 激活参数解释:类比医院问诊,480B总参数相当于全院医生,35B激活参数相当于实际参与会诊的专家
  • 动态路由:不同问题会激活不同参数子集,通过路由机制动态选择
  • MOE特点:采用稀疏激活模式,相比稠密模型(Dense)更高效
  • 部署要求:虽然推理时只需部分参数,但部署需要完整480B参数存储

向量数据库与数据表向量化

向量化策略:
少量表(1-2张):直接放入prompt
大量表(如10万张):需要向量化存储和检索
典型应用:
存储QA对(问题和答案向量)
数据表结构(DDL)通常作为prompt输入
性能考量:表结构向量化可能带来计算开销,需根据实际需求权衡

知识库管理与大模型运行

知识库组织:
按产品系列划分知识库
独立产品使用独立知识库
PDF处理:推荐使用MindView转换为Markdown格式
企业应用:产品手册问答系统可采用多知识库路由机制

# Function Calling

Function Calling在大模型中的作用是什么?

  • 扩展模型能力 大模型本身无法直接操作外部系统(如数据库、计算工具),但通过调用预设函数,可以完成:
    实时数据获取(天气、股价、新闻)
    复杂计算(数学运算、代码执行)
    操作外部系统(发送邮件、控制智能设备)

  • 结构化输出 模型可将用户自然语言请求转化为结构化参数,传递给函数。例如:
    用户说“明天北京天气如何?”→模型调用get_weather(location="北京", date="2025-05-06")

  • 动态决策流程 模型可根据上下文决定是否/何时调用函数,甚至链式调用多个函数(如先查天气,再推荐穿搭)。

# Function Calling与MCP的区别?

维度 Function Calling MCP
定位 模型厂商私有接口(如OpenAI, Qwen) 开放协议(类似HTTP/USB-C)
扩展性 需为每个模型单独适配 一次开发,多模型兼容
复杂性 适合简单、单次调用任务 支持多轮对话、复杂上下文管理
生态依赖 依赖特定模型(如GPT-4) 跨模型、跨平台(如Claude、Cursor)
安全性 依赖云端API密钥 支持本地化数据控制

# 已经有了MCP还需要Function Calling么?

简单、原子化任务使用Function Calling会更方便

  • 查询天气get_weather(city="北京")
  • 计算数学公式calculate(expression="3+5")
  • 发送单条通知send_email(to="user@example.com")

优势:

  • 开发快捷:无需配置MCP Server,直接通过模型API调用预定义函数。
  • 低延迟:单次请求-响应,无需协议层开销。

MCP可能成为主流,但Function Calling作为底层能力仍将存在

# CASE:天气调用(Function Calling)

import requests
from http import HTTPStatus
import dashscope

# 设置dashscope API key
dashscope.api_key = "sk-cd87191136be484d92f1ac53551440f1"

# 高德天气API的天气工具定义
# 这段代码定义了一个"工具说明书"
# 告诉 AI:"如果你需要查天气,可以用这个工具"
# 工具的名字叫 get_current_weather
# 需要一个参数 location(必填),还有一个可选参数 adcode
weather_tool = {
    "type":"function",
    "function":{
        "name": "get_current_weather",
        "description": "Get the current weather in a given location",
        "parameters":{
            "type": "Object",
            "properties": {
                "location": {
                    "type": "string",
                    "description": "The city name,e.g. 北京",
                },
                "adcode": {
                    "type": "string",
                    "description": "The city code, e.g. 110000 (北京)",
                }
            },
            "required": ["location"]
        }
    }
}

def get_weather_from_gaode(location:str, adcode:str = None):
    # 调用高德地图API查询天气
    gaode_api_key = "681b65a915ffbcb806f8ec482b2fa638"
    base_urk = "https://restapi.amap.com/v3/weather/weatherInfo"

    params = {
        "key": gaode_api_key,
        "city": adcode if adcode else location,
        "extensions": "base"  # base:返回实况天气, all:返回预报天气
    }

    response = requests.get(base_urk, params=params)
    print(response.json())
    if response.status_code == 200:
        return response.json()
    else:
        return {"error": f"Failed to get weather: {response.status_code}"}

def run_weather_query():
    # 使用Qwen3 + 查询天气
    messages = [
        {"role": "system", "content": "你是一个智能助手,可以查询天气信息"},
        {"role": "user", "content": "长沙现在天气怎么样?"}
    ]

    response = dashscope.Generation.call(
        model="qwen-turbo",
        messages=messages,
        tools=[weather_tool],
        tool_choice="auto"
    )
    print(response)
    if response.status_code == HTTPStatus.OK:
        # 检查是否需要调用工具
        if "tool_calls" in response.output.choices[0].message:
            tool_call = response.output.choices[0].message.tool_calls[0]
            if tool_call["function"]["name"] == "get_current_weather":
                # 解析参数并调用高德API
                import json
                args = json.loads(tool_call["function"]["arguments"])
                location = args.get("location", "北京")
                adcode = args.get("adcode", None)

                weather_data = get_weather_from_gaode(location, adcode)
                print(f"查询结果:{weather_data}")
        else:
            print(response.output.choices[0].message.content)
    else:
        print(f"请求失败:{response.code}-{response.message}")

if __name__ == "__main__":
    run_weather_query()
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

运行结果:

完整流程图:

用户:"长沙今天天气怎么样?"
         ↓
    你的代码
         ↓
调用 Qwen 模型,传入工具定义
         ↓
Qwen 分析:"我需要调用 get_current_weather 工具"
         ↓
Qwen 返回:{"function": {"name": "get_current_weather", "arguments": "{\"location\": \"长沙\"}"}}
         ↓
你的代码解析参数,调用 get_weather_from_gaode("长沙")
         ↓
高德 API 返回天气数据:{"temperature": "16", "weather": "雾"}
         ↓
你的代码把这个结果再传回 Qwen(代码中还没实现这一步)
         ↓
Qwen 组织语言:"长沙今天雾,16度"
         ↓
把答案返回给用户
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19

完整的第二轮调用应该为:

# 把AI回复的调用工具调用message加到对话历史
 messages.append(response.output.choices[0].message)  

# 把天气结果追加到对话历史
messages.append({
    "role": "tool",
    "name": "get_current_weather",
    "content": str(weather_data)  # 把天气数据转为字符串
})

# 再次调用 Qwen,让它生成最终答案
final_response = dashscope.Generation.call(
    model="qwen-turbo",
    messages=messages
)

print(final_response.output.choices[0].message.content)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17