文章目录
多种工具组合
python
import os
from typing import Dict, List, Any, TypedDict
from langchain.agents import create_agent, AgentState
from langchain.tools import tool
from langchain.messages import HumanMessage
from langchain_community.chat_models import ChatTongyi
from datetime import datetime
from dotenv import load_dotenv
load_dotenv()
# ============ 自定义状态定义 ============
class TravelAgentState(AgentState):
"""旅游助手 Agent 的自定义状态"""
user_preferences: Dict[str, Any]
conversation_history: List[Dict[str, str]]
current_city: str
# ============ 使用 @tool 装饰器定义工具 ============
@tool
def weather_query(city: str) -> str:
"""查询城市天气信息。输入应该是城市名称,如'北京'或'上海'。
返回该城市当前天气情况、温度、湿度等信息。"""
try:
# 模拟天气数据
weather_data = {
"北京": {"city": "北京", "weather": "晴", "temperature": "25°C",
"humidity": "45%", "wind": "东南风3级"},
"上海": {"city": "上海", "weather": "多云", "temperature": "28°C",
"humidity": "65%", "wind": "东风2级"},
"广州": {"city": "广州", "weather": "阵雨", "temperature": "30°C",
"humidity": "80%", "wind": "南风2级"},
"杭州": {"city": "杭州", "weather": "晴转多云", "temperature": "26°C",
"humidity": "60%", "wind": "微风"},
}
if city in weather_data:
data = weather_data[city]
return f"""
{city}天气情况:
- 天气:{data['weather']}
- 温度:{data['temperature']}
- 湿度:{data['humidity']}
- 风速:{data['wind']}
- 更新时间:{datetime.now().strftime('%Y-%m-%d %H:%M')}
"""
else:
return f"未找到{city}的天气信息,请确认城市名称是否正确。"
except Exception as e:
return f"查询天气时出错:{str(e)}"
@tool
def attraction_recommendation(query: str) -> str:
"""推荐旅游景点。输入应该是城市名称和可选的主题或偏好,
如'北京 历史'或'上海 美食'。
返回该城市的推荐景点、评分和简介。"""
try:
# 解析查询参数
parts = query.split()
city = parts[0] if parts else ""
preference = parts[1] if len(parts) > 1 else ""
# 模拟景点数据
attractions_db = {
"北京": {
"历史": [
{"name": "故宫", "rating": 4.8, "description": "明清两代的皇家宫殿", "type": "历史文化"},
{"name": "长城", "rating": 4.9, "description": "世界文化遗产,古代军事防御工程", "type": "历史遗迹"},
{"name": "天坛", "rating": 4.7, "description": "明清皇帝祭天祈谷的场所", "type": "历史建筑"}
],
"公园": [
{"name": "颐和园", "rating": 4.8, "description": "皇家园林,风景秀丽", "type": "园林景观"},
{"name": "北海公园", "rating": 4.6, "description": "古典皇家园林", "type": "城市公园"}
]
},
"上海": {
"现代": [
{"name": "外滩", "rating": 4.7, "description": "上海标志性景观,万国建筑博览", "type": "城市景观"},
{"name": "东方明珠", "rating": 4.6, "description": "上海地标性建筑", "type": "现代建筑"}
],
"美食": [
{"name": "城隍庙", "rating": 4.5, "description": "上海小吃聚集地", "type": "美食文化"},
{"name": "田子坊", "rating": 4.4, "description": "文艺小资聚集地,特色小吃", "type": "文艺美食"}
]
},
"杭州": {
"自然": [
{"name": "西湖", "rating": 4.9, "description": "人间天堂,风景如画", "type": "湖泊风光"},
{"name": "西溪湿地", "rating": 4.7, "description": "城市湿地公园", "type": "自然生态"}
]
}
}
if city in attractions_db:
recommendations = []
if preference and preference in attractions_db[city]:
recommendations = attractions_db[city][preference]
else:
# 如果没有指定偏好,返回所有景点
for pref, attrs in attractions_db[city].items():
recommendations.extend(attrs)
if recommendations:
result = f"{city}推荐景点:\n"
for i, attr in enumerate(recommendations[:5], 1):
result += f"{i}. {attr['name']}(评分:{attr['rating']})\n"
result += f" 类型:{attr['type']}\n"
result += f" 简介:{attr['description']}\n\n"
return result
else:
return f"未找到{city}的{preference}相关景点推荐。"
else:
return f"暂无{city}的景点数据。"
except Exception as e:
return f"查询景点时出错:{str(e)}"
@tool
def trip_planner(query: str) -> str:
"""规划旅游行程。输入应该包含城市、天数、偏好等信息,
如'北京 3天 历史'或'上海 2天 美食购物'。
返回详细的行程安排。"""
try:
parts = query.split()
if len(parts) < 2:
return "请输入城市和天数,如'北京 3天'"
city = parts[0]
days = parts[1].replace("天", "")
preference = parts[2] if len(parts) > 2 else "general"
# 模拟行程数据
sample_itineraries = {
"北京": {
"1": "第一天:上午参观故宫,下午游览天安门广场和王府井",
"2": "第一天:上午参观故宫,下午游览天坛\n第二天:全天游览八达岭长城,晚上品尝北京烤鸭",
"3": "第一天:上午参观故宫,下午游览天安门广场\n第二天:全天游览八达岭长城\n第三天:上午参观颐和园,下午逛什刹海胡同,晚上体验老北京文化"
},
"上海": {
"1": "第一天:上午游览外滩,下午参观东方明珠,晚上逛南京路步行街",
"2": "第一天:上午游览外滩和豫园,下午参观城隍庙\n第二天:上午参观上海博物馆,下午逛田子坊,晚上品尝本帮菜",
"3": "第一天:外滩、南京路步行街\n第二天:豫园、城隍庙、上海博物馆\n第三天:迪士尼乐园或朱家角古镇"
}
}
if city in sample_itineraries and days in sample_itineraries[city]:
itinerary = sample_itineraries[city][days]
return f"{city}{days}天{preference}主题行程建议:\n{itinerary}\n\n温馨提示:请根据实际情况调整,注意景区开放时间。"
else:
return f"暂无{city}{days}天的标准行程,建议结合天气和景点推荐自行规划。"
except Exception as e:
return f"规划行程时出错:{str(e)}"
# ============ 使用第三方包的工具示例 ============
@tool
def currency_converter(amount: float, from_currency: str, to_currency: str) -> str:
"""货币转换工具。输入:金额, 原货币, 目标货币,如'100, USD, CNY'"""
try:
# 模拟汇率数据
rates = {
"USD": {"CNY": 7.2, "EUR": 0.92, "JPY": 150},
"CNY": {"USD": 0.14, "EUR": 0.13, "JPY": 21},
"EUR": {"USD": 1.09, "CNY": 7.8, "JPY": 163}
}
if from_currency in rates and to_currency in rates[from_currency]:
rate = rates[from_currency][to_currency]
converted = amount * rate
return f"{amount} {from_currency} = {converted:.2f} {to_currency} (汇率: 1 {from_currency} = {rate} {to_currency})"
else:
return f"不支持{from_currency}到{to_currency}的货币转换"
except Exception as e:
return f"货币转换失败:{str(e)}"
@tool
def get_local_food(city: str) -> str:
"""获取当地美食推荐。输入:城市名称"""
try:
food_db = {
"北京": ["北京烤鸭", "炸酱面", "豆汁焦圈", "卤煮火烧", "炒肝", "爆肚"],
"上海": ["小笼包", "生煎包", "本帮红烧肉", "蟹粉汤包", "油爆虾", "腌笃鲜"],
"广州": ["早茶点心", "煲仔饭", "烧鹅", "肠粉", "云吞面", "白切鸡"],
"成都": ["火锅", "串串香", "麻婆豆腐", "担担面", "夫妻肺片", "龙抄手"],
"杭州": ["西湖醋鱼", "东坡肉", "龙井虾仁", "叫化鸡", "片儿川", "定胜糕"],
}
if city in food_db:
return f"{city}特色美食推荐:\n" + "\n".join([f"- {food}" for food in food_db[city]])
else:
return f"暂无{city}的美食数据"
except Exception as e:
return f"查询美食时出错:{str(e)}"
# ============ 创建 Agent ============
def create_travel_agent():
"""创建旅游助手 Agent"""
# 初始化通义千问模型
llm = ChatTongyi(
model="qwen-plus",
temperature=0.1,
max_tokens=2000
)
# 工具列表
tools = [
weather_query,
attraction_recommendation,
trip_planner,
currency_converter,
get_local_food
]
# 系统提示词
system_prompt = """你是一个专业的旅游助手,可以帮助用户:
1. 查询城市天气信息
2. 推荐旅游景点(可按主题筛选)
3. 规划旅游行程
4. 货币汇率转换
5. 推荐当地特色美食
请根据用户的需求,选择合适的工具来提供帮助。
如果用户的问题需要多个信息,请按顺序使用相关工具。
最后给出完整、有用的回答。"""
# 使用 create_agent 创建 Agent(新版API)
# 使用新版的create_agent(正确的参数)
agent = create_agent(
model=llm, # 必需:模型实例或字符串标识
tools=tools, # 必需:工具列表
system_prompt=system_prompt, # 系统提示词
)
return agent
# ============ 测试函数 ============
def test_agent():
"""测试 Agent 的不同功能"""
travel_agent = create_travel_agent()
test_cases = [
"北京今天的天气怎么样?",
"我想去上海旅游,有什么推荐的景点吗?",
"推荐一些杭州的自然风光景点",
"帮我规划一个北京3天的行程",
"我想去广州玩,先查一下天气,再推荐一些景点",
"100美元能换多少人民币?",
"成都有什么好吃的?"
]
print("=" * 60)
print("开始测试旅游助手Agent")
print("=" * 60)
for i, query in enumerate(test_cases, 1):
print(f"\n测试 {i}: {query}")
print("-" * 40)
try:
# 初始化状态
initial_state = {
"messages": [HumanMessage(content=query)],
"user_preferences": {"language": "zh", "detail_level": "normal"},
"conversation_history": [],
"current_city": ""
}
# 调用 Agent
result = travel_agent.invoke(initial_state)
# 提取最终回答
final_message = result["messages"][-1]
print(f"助手回答:\n{final_message.content}")
except Exception as e:
print(f"执行出错:{e}")
# ============ 交互式对话 ============
def interactive_chat():
"""交互式对话模式"""
travel_agent = create_travel_agent()
print("=" * 60)
print("旅游助手交互模式")
print("输入 '退出' 结束对话")
print("=" * 60)
# 初始化状态
state = {
"messages": [],
"user_preferences": {"language": "zh", "detail_level": "normal"},
"conversation_history": [],
"current_city": ""
}
while True:
user_input = input("\n你:").strip()
if user_input.lower() in ['退出', 'quit', 'exit', 'q']:
print("感谢使用,再见!")
break
if not user_input:
continue
# 添加用户消息到状态
state["messages"].append(HumanMessage(content=user_input))
try:
print("思考中...")
# 调用 Agent
result = travel_agent.invoke(state)
# 更新状态
state = result
# 提取并显示助手的最新回复
for msg in reversed(state["messages"]):
if hasattr(msg, 'content') and msg.content and msg.content != user_input:
print(f"\n助手:{msg.content}")
break
except Exception as e:
print(f"出错:{e}")
# ============ 主程序 ============
if __name__ == "__main__":
print("旅游助手 Agent 系统")
print("=" * 40)
print("1. 测试模式(运行预设测试)")
print("2. 对话模式(交互式对话)")
choice = input("\n请选择模式 (1/2): ").strip()
if choice == "1":
test_agent()
else:
interactive_chat()