前言
Hello,大家好,我是
GISer Liu
😁,一名热爱AI技术的GIS开发者,本系列是作者参加DataWhale2025年2月份组队学习的wow-agent技术笔记文档。今天我将手把手教大家如何用DeepSeek大模型从零构建一个天气查询Agent!
在人工智能技术的发展过程中,语言模型(LLM)已经成为自然语言处理(NLP)的核心。然而,随着需求的变化,单一的语言模型不再足够满足复杂的交互需求。智能体(Agent)的概念应运而生,它能理解、决策并执行任务,而不仅仅是生成语言输出。本文将详细介绍智能体的设计思想、核心组件、优势,并展示如何构建一个自定义的智能体——天气查询 Agent。
OK,我们先介绍一下什么是Agent!🤔
一、什么是 Agent?
1. 定义
Agent(智能体) 是一种能够自主感知环境、决策并采取行动的系统。与传统的语言模型不同,Agent 不仅仅是一个生成文本的工具,而是一个具备决策能力和执行能力的智能系统。通过与外部环境(如数据库、API、用户交互等)的交互,Agent 可以完成复杂的任务。
核心思想:
- 自主性:无需人为干预,独立感知环境并作出反应。
- 灵活性:通过模块化设计,处理多种任务。
- 可扩展性:通过集成更多服务和功能,持续增强能力。
- 交互性:与用户和其他系统无缝互动,完成任务。
2. Agent 的核心组件
一个完整的 Agent 通常由以下核心组件构成:
组件 | 功能描述 | 关键技术 |
---|---|---|
感知模块 | 感知外部环境的信息,接收用户输入或外部数据。 | 传感器、输入接口、自然语言理解(NLU) |
决策模块 | 根据感知到的信息进行推理和决策,规划下一步行动。 | 机器学习、推理引擎、优化算法 |
执行模块 | 根据决策模块的输出执行具体操作,如调用 API、操作数据库或生成回复。 | API 调用、数据库操作、自然语言生成(NLG) |
反馈机制 | 评估执行效果并调整决策,持续优化智能体的表现。 | 强化学习、评估指标(如准确率、响应时间) |
3. Agent 的优势
优势 | 描述 |
---|---|
提高效率 | 自动化执行重复性任务,减少人工干预。 |
支持复杂任务 | 能够处理多步推理和决策,适用于复杂的任务场景。 |
适应性强 | 通过持续学习和环境适应,在动态变化的环境中发挥作用。 |
可扩展性高 | 通过集成更多工具和服务,不断扩展智能体的能力范围。 |
开源社区上有这么多Agent框架,为什么我们要手搓呢?🤔
二、为什么要"手搓"Agent?
1. 主流框架的局限性
- 依赖过多:如 Langchain 需要安装大量依赖库,部署复杂。
- 灵活性不足:框架通常有固定的设计模式,难以完全满足定制化需求。
- 性能开销:框架的通用性设计可能导致性能损耗,不适合轻量化场景。
2. 手搓 Agent 的优势
优势 | 描述 |
---|---|
轻量化 | 仅需核心依赖库(如 openai 和 python-dotenv ),部署简单快速。 |
高度定制化 | 完全根据需求设计架构,灵活应对不同场景。 |
性能优化 | 去除框架的冗余功能,专注于核心逻辑,提升执行效率。 |
学习价值 | 通过手动构建,深入理解 Agent 的工作原理,提升技术能力。 |
3. 手搓 vs 框架
对比项 | 手搓 Agent | 使用框架 |
---|---|---|
依赖库数量 | 2 个(openai + python-dotenv ) | 通常 50+ 个依赖库 |
部署时间 | 15 秒内完成 | 15 分钟以上 |
定制化程度 | 完全自定义 | 受框架限制 |
学习曲线 | 需要理解底层原理 | 框架提供抽象接口,上手较快 |
适用场景 | 轻量化、定制化需求 | 复杂任务、快速开发 |
4.核心价值
- 快速部署:仅需 2 个依赖库,轻松实现轻量化部署。
- 灵活扩展:根据需求自由添加功能模块,如数据库连接、API 调用等。
- 成本控制:减少不必要的依赖,降低资源消耗和运行成本。
- 技术提升:通过手动构建,深入理解 Agent 的底层逻辑和实现细节。
三、 获取 API 及接口测试
接下来,我们将使用 DeepSeek API 来构建一个简单的智能体。DeepSeek 提供了类似于 OpenAI 的接口,因此非常适合我们测试。以下是获取 API Key 和进行接口测试的步骤。
1. 获取 DeepSeek API Key
- 注册登录:首先,前往 DeepSeek 的平台 https://platform.deepseek.com/usage,进行注册并登录。
- 创建 API Key:在 DeepSeek 的控制面板中,创建一个新的 API Key,并复制保存。
🧨现在复制保存下来这个API Key即可;请确保妥善保管您的 API Key,避免泄露,否则可能导致经济损失。
2. 测试接口
接下来,我们使用 Python 的 OpenAI SDK 来测试 DeepSeek 接口。
pip3 install openai
from openai import OpenAI
client = OpenAI(api_key="<DeepSeek API Key>", base_url="https://api.deepseek.com")
response = client.chat.completions.create(
model="deepseek-chat",
messages=[
{"role": "system", "content": "You are a helpful assistant"},
{"role": "user", "content": "Hello"},
],
stream=False
)
print(response.choices[0].message.content)
👌实测可用!
3. 环境变量配置
为了防止 API Key 泄露,建议使用环境变量来配置 API Key。
- 在项目根目录创建
.env
文件,并设置环境变量:
API_KEY=<Your DeepSeek API Key>
BASE_URL=https://api.deepseek.com
- 安装
python-dotenv
,用于加载环境变量:
pip install python-dotenv
- 在代码中加载环境变量:
from dotenv import load_dotenv
import os
from openai import OpenAI
load_dotenv()
api_key = os.getenv("API_KEY")
base_url = os.getenv("BASE_URL")
client = OpenAI(api_key=api_key, base_url=base_url)
response = client.chat.completions.create(
model="deepseek-chat",
messages=[
{"role": "system", "content": "You are a helpful assistant"},
{"role": "user", "content": "介绍一下你自己!"},
],
stream=False
)
print(response.choices[0].message.content)
测试通过!
四、构建客服 Agent
1. LangGPT 的概念
LangGPT 是一种结合结构化 Prompt 设计和角色扮演的智能体。我们可以通过定义不同的角色、行为规则和工作流来构建智能体。
结构化 Prompt 的核心思想是将输入分成不同的层级和模块,使模型更容易理解任务的结构。
2. 构建一个智能客服
我们构建一个简单的智能客服,能够处理用户的注册、查询和删除操作。客服根据用户输入判断任务,并调用相应的服务。
定义角色和任务
system_prompt = """你是一个聪明的客服。您将能够根据用户的问题将不同的任务分配给不同的人。您有以下业务线:
1.用户注册。如果用户想要执行这样的操作,您应该发送一个带有"registered workers"的特殊令牌。并告诉用户您正在调用它。
2.用户数据查询。如果用户想要执行这样的操作,您应该发送一个带有"query workers"的特殊令牌。并告诉用户您正在调用它。
3.删除用户数据。如果用户想执行这种类型的操作,您应该发送一个带有"delete workers"的特殊令牌。并告诉用户您正在调用它。
"""
角色和任务模块
registered_prompt = """
您的任务是根据用户信息存储数据。您需要从用户那里获得以下信息:
1.用户名、性别、年龄
2.用户设置的密码
3.用户的电子邮件地址
如果用户没有提供此信息,您需要提示用户提供。如果用户提供了此信息,则需要将此信息存储在数据库中,并告诉用户注册成功。
"""
query_prompt = """
您的任务是查询用户信息。您需要从用户那里获得以下信息:
1.用户ID
2.用户设置的密码
如果用户没有提供此信息,则需要提示用户提供。如果用户提供了此信息,那么需要查询数据库。如果用户ID和密码匹配,则需要返回用户的信息。
"""
delete_prompt = """
您的任务是删除用户信息。您需要从用户那里获得以下信息:
1.用户ID
2.用户设置的密码
3.用户的电子邮件地址
如果用户没有提供此信息,则需要提示用户提供该信息。
"""
实现智能客服类
class SmartAssistant:
def __init__(self):
self.client = client
self.system_prompt = system_prompt
self.registered_prompt = registered_prompt
self.query_prompt = query_prompt
self.delete_prompt = delete_prompt
# Using a dictionary to store different sets of messages
self.messages = {
"system": [{"role": "system", "content": self.system_prompt}],
"registered": [{"role": "system", "content": self.registered_prompt}],
"query": [{"role": "system", "content": self.query_prompt}],
"delete": [{"role": "system", "content": self.delete_prompt}]
}
# Current assignment for handling messages
self.current_assignment = "system"
def get_response(self, user_input):
self.messages[self.current_assignment].append({"role": "user", "content": user_input})
while True:
response = self.client.chat.completions.create(
model="deepseek-chat",
messages=self.messages[self.current_assignment],
temperature=0.9,
stream=False,
max_tokens=2000,
)
ai_response = response.choices[0].message.content
if "registered workers" in ai_response:
self.current_assignment = "registered"
self.messages[self.current_assignment].append({"role": "user", "content": user_input})
elif "query workers" in ai_response:
self.current_assignment = "query"
self.messages[self.current_assignment].append({"role": "user", "content": user_input})
elif "delete workers" in ai_response:
self.current_assignment = "delete"
self.messages[self.current_assignment].append({"role": "user", "content": user_input})
return ai_response
完整代码如下:
from dotenv import load_dotenv
import os
from openai import OpenAI
# Load environment variables from .env file
load_dotenv()
# Retrieve API key and base URL from environment variables
api_key = os.getenv("API_KEY")
base_url = os.getenv("BASE_URL")
# Initialize the OpenAI client
client = OpenAI(api_key=api_key, base_url=base_url)
# Define system prompts for different tasks
sys_prompt = """你是一个聪明的客服。您将能够根据用户的问题将不同的任务分配给不同的人。您有以下业务线:
1.用户注册。如果用户想要执行这样的操作,您应该发送一个带有"registered workers"的特殊令牌。并告诉用户您正在调用它。
2.用户数据查询。如果用户想要执行这样的操作,您应该发送一个带有"query workers"的特殊令牌。并告诉用户您正在调用它。
3.删除用户数据。如果用户想执行这种类型的操作,您应该发送一个带有"delete workers"的特殊令牌。并告诉用户您正在调用它。
"""
registered_prompt = """
您的任务是根据用户信息存储数据。您需要从用户那里获得以下信息:
1.用户名、性别、年龄
2.用户设置的密码
3.用户的电子邮件地址
如果用户没有提供此信息,您需要提示用户提供。如果用户提供了此信息,则需要将此信息存储在数据库中,并告诉用户注册成功。
"""
query_prompt = """
您的任务是查询用户信息。您需要从用户那里获得以下信息:
1.用户ID
2.用户设置的密码
如果用户没有提供此信息,则需要提示用户提供。如果用户提供了此信息,那么需要查询数据库。如果用户ID和密码匹配,则需要返回用户的信息。
"""
delete_prompt = """
您的任务是删除用户信息。您需要从用户那里获得以下信息:
1.用户ID
2.用户设置的密码
3.用户的电子邮件地址
如果用户没有提供此信息,则需要提示用户提供该信息。
"""
class SmartAssistant:
def __init__(self):
self.client = client
# Define system prompts for different tasks
self.system_prompt = sys_prompt
self.registered_prompt = registered_prompt
self.query_prompt = query_prompt
self.delete_prompt = delete_prompt
# Using a dictionary to store different sets of messages
self.messages = {
"system": [{"role": "system", "content": self.system_prompt}],
"registered": [{"role": "system", "content": self.registered_prompt}],
"query": [{"role": "system", "content": self.query_prompt}],
"delete": [{"role": "system", "content": self.delete_prompt}]
}
# Current assignment for handling messages
self.current_assignment = "system"
def get_response(self, user_input):
# Append user input to the current assignment's messages
self.messages[self.current_assignment].append({"role": "user", "content": user_input})
# Get response from the AI model
response = self.client.chat.completions.create(
model="deepseek-chat",
messages=self.messages[self.current_assignment],
temperature=0.9,
stream=False,
max_tokens=2000,
)
# Extract AI response
ai_response = response.choices[0].message.content
# Check for special tokens and switch assignment if necessary
if "registered workers" in ai_response:
self.current_assignment = "registered"
self.messages[self.current_assignment].append({"role": "user", "content": user_input})
elif "query workers" in ai_response:
self.current_assignment = "query"
self.messages[self.current_assignment].append({"role": "user", "content": user_input})
elif "delete workers" in ai_response:
self.current_assignment = "delete"
self.messages[self.current_assignment].append({"role": "user", "content": user_input})
return ai_response
# Example usage
if __name__ == "__main__":
assistant = SmartAssistant()
while True:
user_input = input("You: ")
if user_input.lower() in ["exit", "quit"]:
break
response = assistant.get_response(user_input)
print(f"Assistant: {response}")
运行测试:
运行成功,一切正常!🙂
五、构建一个天气查询Agent
1. 构建思路
这个天气查询 Agent 会通过与 DeepSeek 的 API 交互,接收用户输入的城市或地点,查询该地点的天气情况,并返回给用户。我们需要将天气查询的功能嵌入到一个 Agent 中。
为了实现这个功能,我们需要几个步骤:
- 获取天气信息(通过外部 API,例如 高德天气API)。
- 处理用户输入,判断是否包含查询天气的指令。
- 如果用户输入的是查询天气的请求,就通过调用天气 API 获取信息。
- 输出天气信息。
高德天气API申请教程看这里:https://blog.csdn.net/qq_51055690/article/details/126885110
2. 代码实现
import openai
import os
from dotenv import load_dotenv
import requests
# 加载环境变量
load_dotenv()
# 配置 OpenAI API 和 DeepSeek API
api_key = os.getenv("API_KEY")
base_url = os.getenv("BASE_URL")
# 设置 DeepSeek 客户端
client = openai.OpenAI(api_key=api_key, base_url=base_url)
# 高德地图天气 API
weather_api_key = os.getenv("WEATHER_API_KEY")
weather_base_url = "https://restapi.amap.com/v3/weather/weatherInfo"
class WeatherAgent:
def __init__(self):
self.client = client
self.system_prompt = "你是一个智能助手,能够提供天气查询服务。请用户提供城市名,查询并返回当地的天气情况。"
self.messages = [{"role": "system", "content": self.system_prompt}]
def get_weather_info(self, city_name):
"""查询天气信息(带错误处理)"""
params = {
'key': weather_api_key,
'city': city_name,
'extensions': 'base',
'output': 'JSON'
}
try:
response = requests.get(weather_base_url, params=params)
response.raise_for_status() # 自动触发HTTP错误
weather_data = response.json()
if weather_data.get('status') != '1':
return f"请求失败:{weather_data.get('infocode', '未知错误')}"
lives = weather_data.get('lives', [])
if not lives:
return "该城市无天气数据"
live_data = lives[0]
return (
f"当前天气:{live_data['weather']}\n"
f"温度:{live_data['temperature']}°C\n"
f"湿度:{live_data['humidity']}%\n"
f"更新时间:{live_data['reporttime']}"
)
except requests.exceptions.RequestException as e:
return f"网络请求失败:{str(e)}"
except KeyError as e:
return f"数据解析错误:缺少字段 {str(e)}"
def get_response(self, user_input):
"""改进后的响应逻辑"""
self.messages.append({"role": "user", "content": user_input})
# 通过AI识别城市名(更精准)
prompt = f"""
用户问:{user_input}
请严格按以下格式回答,只需返回城市名,提取的城市要符合查询标准,尽量是标准城市命名:
{{
"city": "提取到的城市名"
}}
如果无法识别则返回:{{"city": null}}
"""
# 调用模型提取城市
extraction_response = self.client.chat.completions.create(
model="deepseek-chat",
messages=[{"role": "user", "content": prompt}],
temperature=0.3,
max_tokens=50
)
# 解析城市名
try:
city_info = eval(extraction_response.choices[0].message.content)
city_name = city_info.get('city')
except:
city_name = None
if city_name:
weather_info = self.get_weather_info(city_name)
return weather_info
else:
# 普通对话
response = self.client.chat.completions.create(
model="deepseek-chat",
messages=self.messages,
temperature=0.7,
stream=False,
max_tokens=1000
)
return response.choices[0].message.content
# 测试
if __name__ == "__main__":
agent = WeatherAgent()
test_cases = [
"北京天气怎么样?",
"上海市浦东新区今天会下雨吗",
"帮我查一个不存在的城市的天气", # 测试错误处理
"讲个笑话"
]
for query in test_cases:
print(f"用户:{query}")
print(f"助手:{agent.get_response(query)}\n")
3. 代码解释
环境变量加载
load_dotenv() # 加载环境变量
api_key = os.getenv("API_KEY")
base_url = os.getenv("BASE_URL")
weather_api_key = os.getenv("WEATHER_API_KEY")
通过 .env
文件加载 API 密钥,避免硬编码敏感信息。
天气查询接口
weather_base_url = "https://restapi.amap.com/v3/weather/weatherInfo"
我们使用 高德地图
提供的天气查询 API。你可以注册 高德天气地图 获取 API Key。
WeatherAgent 类
get_weather_info
:调用 OpenWeatherMap API 获取天气信息。返回天气、温度、湿度等数据。get_response
:根据用户输入的指令生成智能回应。如果用户请求查询天气,则调用get_weather_info
获取并返回天气数据。
测试输入
test_cases = [
"北京天气怎么样?",
"上海市浦东新区今天会下雨吗",
"帮我查一个不存在的城市的天气", # 测试错误处理
"讲个笑话"
]
4. 如何运行
- 安装所需的库:
pip install openai python-dotenv requests
- 在项目根目录创建
.env
文件,添加以下内容:
API_KEY=你的DeepSeek API密钥
BASE_URL=https://api.deepseek.com
WEATHER_API_KEY=你的OpenWeatherMap API密钥
- 运行 Python 脚本,输入天气查询请求,Agent 会返回天气信息。
运行结果如下:
运行测试通过!没有问题,今天我们就学到这里!😉👌🎉
文章参考
项目地址
如果觉得我的文章对您有帮助,三连+关注便是对我创作的最大鼓励!或者一个star🌟也可以😂.