09-day2-实验-调用真实的网络资源-linux软件清华镜像站
🧪 实验名称:基于 Qwen 大模型的函数调用与外部工具集成
调用真实的网络资源-linux软件清华镜像站
一、实验目标
通过本实验,学生将能够:
- 理解大语言模型(LLM)的“工具调用”(Function Calling)机制
- 配置 DashScope API 并调用 Qwen-Max 模型
- 实现自定义 Python 函数作为 LLM 可调用的外部工具
- 构建交互式多轮对话系统,集成时间、天气、软件下载等实用功能
- 掌握网络请求的健壮性设计(超时、异常处理、fallback 策略)
二、实验原理
1. Function Calling 工作流程
大模型本身不具备实时数据获取能力。通过 Function Calling,模型可:
- 分析用户意图
- 决定是否需要调用外部工具
- 生成结构化工具调用请求(
tool_calls) - 接收工具执行结果后,生成自然语言回答
典型流程:
用户输入 → LLM(第一阶段)→ 是否需工具?
↓ 是
执行本地/网络函数 → 返回结果 → LLM(第二阶段)→ 生成最终回答
↓ 否
直接返回模型生成内容
2. 工具描述规范(OpenAI 兼容格式)
每个工具需定义:
name:函数名(必须与 Python 函数一致)description:功能说明(帮助模型决策)parameters:输入参数(JSON Schema 格式)
3. 两阶段调用必要性
- 第一阶段:模型决定“做什么”
- 第二阶段:模型基于真实数据“怎么说”
三、程序要点
▶ 1:整体结构
- 工具函数定义区(
get_current_time,get_weather,get_nginx_download_link) - 工具注册区(
tools列表) - 主交互循环(含两阶段模型调用)
▶ 2:三个工具函数
| 工具模块 | 类型 | 核心功能 | 关键特性 | 容错/健壮性设计 |
|---|---|---|---|---|
| 时间工具 | 本地函数 | 获取当前系统时间 | • 调用 datetime.now()• 无需外部依赖 |
• 100% 可靠(不依赖网络或外部服务)• 无异常风险 |
| 天气工具 | 网络函数 | 查询指定城市的当前天气 | • 调用 https://wttr.in/城市?format=4&lang=zh• 支持中文输出 |
• 设置 User-Agent 避免被拦截• 请求超时限制(timeout=8 秒)• 捕获网络错误(如连接失败、DNS 错误)• 处理响应编码问题(自动解码 UTF-8) |
| Nginx 下载链接工具 | 混合函数(本地逻辑 + 网络探测) | 返回 Nginx 1.25.4 的下载链接 | • 固定版本:1.25.4(不查最新版)• 优先使用清华镜像源: https://mirrors.tuna.tsinghua.edu.cn/nginx/nginx-1.25.4.tar.gz• 备用官方源: https://nginx.org/download/nginx-1.25.4.tar.gz |
• 使用 requests.head() 快速检测源可用性(不下载全文)• 若主源不可达(超时/404/连接失败),自动切换至备用源• 若双源均失败,返回明确错误信息 |
✅ 设计原则:
- 本地优先(时间)→ 网络智能降级(天气、Nginx)
- 所有网络调用均有 超时 + 异常捕获,避免程序卡死
- 国内用户友好(清华镜像加速)
▶ 3:注册工具、主循环
(1) 构建 tools 列表
- 严格遵循 OpenAI 工具描述格式
- 注意参数是否必填(
required)
(2) 实现两阶段调用逻辑
- 第一次调用:
tool_choice="auto" - 解析
tool_calls,执行对应函数 - 构造包含
role: "tool"的消息列表 - 第二次调用:传入工具结果,获取最终回答
(3) 添加交互与异常处理
- 支持
quit/exit退出 - 捕获
KeyboardInterrupt(Ctrl+C) - 全局异常兜底,避免程序崩溃
✅ 完整交互式代码
tee day2_qwen_tool_calling_true_api.py <<'EOF'
# day2_qwen_tool_calling_true_api.py
import os
import json
import requests
from dotenv import load_dotenv
import dashscope
from dashscope import Generation
from datetime import datetime
# 加载 API Key
load_dotenv()
dashscope.api_key = os.getenv("DASHSCOPE_API_KEY")
# ===== 定义工具函数 =====
def get_current_time():
"""获取本机系统当前时间"""
return datetime.now().strftime("%Y-%m-%d %H:%M:%S")
def get_weather(city: str):
"""使用 wttr.in 获取天气"""
try:
url = f"https://wttr.in/{city}?format=4&lang=zh"
headers = {"User-Agent": "curl"}
response = requests.get(url, headers=headers, timeout=8)
response.encoding = 'utf-8'
if response.status_code == 200:
weather_str = response.text.strip()
if "Unknown location" in weather_str or not weather_str:
return f"未找到城市 '{city}' 的天气信息"
return weather_str
else:
return f"天气服务返回错误状态码: {response.status_code}"
except Exception as e:
return f"获取天气失败: {str(e)}"
def get_nginx_download_link():
"""
返回 nginx 1.25 系列的下载链接(主线版本)
来源:官方 + 清华镜像(双重保障)
"""
official_url = "http://nginx.org/download/nginx-1.25.4.tar.gz"
tuna_url = "https://mirrors.tuna.tsinghua.edu.cn/nginx/nginx-1.25.4.tar.gz"
# 检测清华镜像是否可访问(快速超时)
try:
resp = requests.head(tuna_url, timeout=3)
if resp.status_code == 200:
return f"✅ nginx 1.25.4 下载链接(清华镜像):\n{tuna_url}"
except:
pass
# fallback 到官方
return f"✅ nginx 1.25.4 下载链接(官方):\n{official_url}"
# ===== 工具描述 =====
tools = [
{
"type": "function",
"function": {
"name": "get_current_time",
"description": "获取当前日期和时间",
"parameters": {"type": "object", "properties": {}, "required": []}
}
},
{
"type": "function",
"function": {
"name": "get_weather",
"description": "查询指定城市的实时天气",
"parameters": {
"type": "object",
"properties": {"city": {"type": "string"}},
"required": ["city"]
}
}
},
{
"type": "function",
"function": {
"name": "get_nginx_download_link",
"description": "获取 nginx 1.25 版本的下载链接(固定版本,非最新)",
"parameters": {"type": "object", "properties": {}, "required": []}
}
}
]
# ===== 交互式主循环 =====
print("🤖 欢迎使用 Qwen 实用助手!")
print("你可以问:现在几点?北京天气?nginx 下载链接?")
print("输入 'quit' 或 'exit' 退出。\n")
while True:
try:
user_input = input("💬 你: ").strip()
if not user_input:
continue
if user_input.lower() in ["quit", "exit", "退出"]:
print("👋 再见!")
break
# 第一次调用
response = Generation.call(
model="qwen-max",
messages=[{"role": "user", "content": user_input}],
tools=tools,
tool_choice="auto"
)
message = response.output.choices[0].message
if "tool_calls" in message:
tool_calls = message["tool_calls"]
tool_results = []
for tool_call in tool_calls:
func_name = tool_call["function"]["name"]
if func_name == "get_current_time":
result = get_current_time()
elif func_name == "get_weather":
args = json.loads(tool_call["function"].get("arguments", "{}"))
city = args.get("city", "北京")
result = get_weather(city)
elif func_name == "get_nginx_download_link":
result = get_nginx_download_link()
else:
result = f"未知工具: {func_name}"
tool_results.append({
"tool_call_id": tool_call["id"],
"output": result
})
# 第二次调用(带工具结果)
messages = [
{"role": "user", "content": user_input},
message,
*[{
"role": "tool",
"content": tr["output"],
"tool_call_id": tr["tool_call_id"]
} for tr in tool_results]
]
final_response = Generation.call(
model="qwen-max",
messages=messages,
tools=tools
)
answer = final_response.output.choices[0].message["content"]
else:
answer = message["content"]
print(f"\n🧠 助手: {answer}\n{'─' * 50}")
except KeyboardInterrupt:
print("\n👋 被用户中断,再见!")
break
except Exception as e:
print(f"\n❌ 程序出错: {str(e)}\n{'─' * 50}")
EOF
🧪 测试效果
💬 你: nginx 下载链接?
🧠 助手: ✅ nginx 1.25.4 下载链接(清华镜像):
https://mirrors.tuna.tsinghua.edu.cn/nginx/nginx-1.25.4.tar.gz
──────────────────────────────────────────
💬 你: 现在几点?
🧠 助手: 当前时间是 2026-01-25 15:30:22。
──────────────────────────────────────────
💬 你: mysql
🧠 助手: 您提到 "mysql",请问您需要了解关于 MySQL 的哪方面信息?例如:
- MySQL 的安装和配置
- 基本的 SQL 语句使用
- 数据库设计与优化
- 备份与恢复
- 安全设置
- 性能调优
- 与其他软件的集成
请具体说明您的需求或问题,以便我能为您提供更准确的帮助。
──────────────────────────────────────────────────
💬 你: mysql 下载链接
🧠 助手: 您想要下载 MySQL 的哪个版本?另外,请指明您需要的是社区版(Community Edition)还是企业版(Enterprise Edition)。如果您不确定具体版本,我可以为您提供 MySQL 官方网站上最新的社区版下载链接。请告诉我更多详细信息。如果没有特别要求,我将直接提供最新稳定版的 MySQL 社区版下载链接。
由于我没有直接获取MySQL官方下载链接的函数工具,我将为您提供一个通用的方法来找到MySQL的下载页面:
1. 访问 MySQL 官方网站: https://www.mysql.com/
2. 导航到 Downloads (下载) 页面。
3. 选择您要下载的 MySQL 版本和类型(社区版或企业版)。
对于最新稳定版的 MySQL 社区版,您可以直接访问以下链接:
- MySQL Community Server: https://dev.mysql.com/downloads/mysql/
如果您需要特定版本,请访问上面提供的链接并从版本列表中选择。您也可以告诉我具体的版本号,我可以尝试帮您查找正确的下载链接。
浙公网安备 33010602011771号