摘要:大模型(LLM)基于预训练数据,天生存在“知识截止”的硬伤。本文将基于 ModelScope 环境,使用 Python 和 DeepSeek API,通过 Function Calling 机制实现一个最小可行性 Agent(MVP),让模型拥有获取实时天气的能力。
0. 前言:从 Chatbot 到 Agent
大模型很强,但它不仅是一个只知道过去的“书呆子”,还常常一本正经地胡说八道。
如果你问 DeepSeek:“现在抚州气温多少度?”
它只能依靠预训练数据中的概率预测,无法给出事实。因为文本模式匹配实时感知。
要打破这个限制,我们需要引入 Function Calling(工具调用) 。简单来说,就是教 LLM 在遇到无法回答的问题时,不要瞎编,而是生成一个“调用指令”,由 Python 去执行这个指令,并将结果返还给 LLM。
Python 是粘合剂,LLM 是大脑。本文将带你手写一个具备联网感知能力的 AI Agent。
0.5 环境准备:工欲善其事
在开始编写代码之前,我们需要安装两个核心库。如果你熟悉前端开发,Python 的 pip 就相当于 Node.js 的 npm。
在 Jupyter Notebook 或 ModelScope 的交互式环境中,我们需要使用 ! 前缀来运行 Shell 命令:
Python
# ! 代表在 Notebook 单元格中运行系统 Shell 命令
!pip install requests openai
依赖解析:
- requests:Python 界的 HTTP 标配库。我们的 get_weather 工具需要用它向气象接口发起网络请求(相当于 JS 中的 axios 或 fetch)。
- openai:官方 SDK。为什么调 DeepSeek 要装 OpenAI? 因为 DeepSeek 采用了与 OpenAI 完全一致的 API 规范。这意味着你无需学习新的 SDK,只需更改 base_url,就能用这套最成熟的工具链顺滑接入。
1. The Hand:定义“工具” (Python Side)
Agent 的第一步,是给它一双手。
我们定义一个 get_weather 函数,通过调用第三方 API(这里使用心知天气)获取数据。
核心代码实现:
Python
import requests
# Type Hinting 在这里至关重要,它不仅仅是给开发者看的
# 更是后续生成 JSON Schema 给 LLM 理解的关键依据
def get_weather(location: str) -> str:
# 实际开发中,Key 应存放在环境变量中
url = 'https://api.seniverse.com/v3/weather/now.json'
params = {
'key': 'Sq7ZF2yrZ_zczwqg-', # 示例 Key
'location': location,
'language': 'zh-Hans'
}
try:
# 同步阻塞请求,适合简单工具链
resp = requests.get(url, params=params, timeout=10)
data = resp.json()
if 'results' in data:
r = data['results'][0]
city = r['location']['name']
now = r['now']
# 将结构化 JSON 转化为自然语言描述,降低 LLM 理解成本
return f"{city}当前天气:{now['text']},气温:{now['temperature']}度"
else:
return "查询失败:未找到该城市"
except Exception as e:
return f"接口异常: {e}"
# 本地测试
# print(get_weather("抚州"))
# Output: 抚州当前天气:阴,气温:8度
技术点:
- 鲁棒性:网络请求必须包含 try-except,Agent 的工具报错不应导致整个对话崩溃,返回错误信息本身也是一种有效的反馈。
- Pythonic:利用 Python 强大的字符串处理能力,清洗 API 返回的冗余 JSON,只喂给 LLM 最核心的信息。
2. The Brain:配置模型 (DeepSeek)
DeepSeek 完美兼容 OpenAI SDK 标准,这意味着我们不需要学习新的库,直接替换 base_url 和 api_key 即可。
codePython
from openai import OpenAI
client = OpenAI(
api_key='sk-xxxx', # 你的 DeepSeek API Key
base_url='https://api.deepseek.com/v1'
)
3. The Protocol:确立通信协议 (JSON Schema)
这是最关键的一步。LLM 运行在云端,它跑不了本地 Python 代码。我们需要用 JSON Schema 告诉它:“我有这个工具,参数格式如下”。
Python
tools = [
{
'type': 'function',
'function': {
'name': 'get_weather',
'description': '获取指定城市的当前天气信息', # Prompt Engineering 的一部分,越清晰模型决策越准
'parameters': {
'type': 'object',
'properties': {
'location': {
'type': 'string',
'description': '城市名称,例如 "北京", "Shanghai"'
}
},
'required': ['location']
}
}
}
]
4. The Loop:构建闭环 (Agent Logic)
真正的 Agent 是一个闭环系统。我们需要手动处理模型和工具之间的“握手”。
流程解析:
- Ask: 用户提问。
- Reason: 模型思考,发现自己不知道,但工具列表里有能用的,于是返回 tool_calls。
- Act: Python 捕获 tool_calls,解析参数,执行 get_weather。
- Observe: 将执行结果封装为 role: tool 的消息,追加回历史记录。
- Response: 模型结合“用户问题”+“工具结果”,生成最终答案。
完整代码逻辑:
Python
import json
# 1. 初始对话上下文
messages = [{"role": "user", "content": "北京天气怎么样"}]
# 2. 第一轮交互:模型决策
response = client.chat.completions.create(
model='deepseek-reasoner',
messages=messages,
tools=tools,
tool_choice="auto", # 让模型自己决定是否用工具
temperature=0.3
)
response_message = response.choices[0].message
# 必须将模型的“思考结果”加入历史,否则上下文不连续
messages.append(response_message)
# 3. 检查模型是否发起了工具调用请求
if response_message.tool_calls:
print(f"Triggered Tool Calls: {len(response_message.tool_calls)}")
for tool_call in response_message.tool_calls:
function_name = tool_call.function.name
# 解析 LLM 生成的 JSON 参数字符串
function_args = json.loads(tool_call.function.arguments)
# 路由分发
if function_name == "get_weather":
print(f"Executing: {function_name} with {function_args}")
tool_result = get_weather(location=function_args.get("location"))
else:
tool_result = "未知工具"
# 4. 关键:构造 tool 类型的消息回传给模型
# tool_call_id 是连接请求与结果的唯一标识
messages.append({
"tool_call_id": tool_call.id,
"role": "tool",
"name": function_name,
"content": tool_result
})
# 5. 第二轮交互:模型根据工具结果生成最终回答
final_response = client.chat.completions.create(
model="deepseek-reasoner",
messages=messages
)
print("-" * 20)
print("Final Answer:", final_response.choices[0].message.content)
else:
print("Model did not call any tools.")
5. 总结
通过以上 50 行左右的代码,我们实现了一个 Agent 的雏形。
- DeepSeek 负责理解意图(Intent Recognition)和参数提取(Slot Filling)。
- Python 负责与物理世界(API)交互。
- Context (Messages) 是两者同步状态的内存。
这就将 LLM 从一个“聊天机器”升级为了一个能干活的“智能体”。下一步,你可以尝试加入 Google Search 工具,或者让 Agent 操作本地文件,玩转更广阔的自动化场景。