第50集:【实战】打造一个能查机票、订酒店、写攻略的旅行规划师

核心知识点讲解

旅行规划师智能体的系统架构

一个完整的旅行规划师智能体需要具备以下核心组件:

  1. 核心决策引擎:负责理解用户需求,制定旅行计划
  2. 工具集成层:整合机票查询、酒店预订等外部服务
  3. 信息处理模块:处理和分析旅行相关信息
  4. 内容生成模块:创建个性化旅行攻略
  5. 用户交互界面:提供友好的用户交互体验

技术栈选择

  • 框架:LangChain + OpenAI API
  • 工具集成:机票API、酒店API、天气API、地图API
  • 数据存储:本地缓存 + 向量数据库(可选)
  • 前端界面:Streamlit或Gradio(可选)

核心功能模块

  1. 需求分析:理解用户的旅行目的地、时间、预算等需求
  2. 航班查询:根据出发地、目的地和日期查询航班信息
  3. 酒店预订:根据目的地、入住时间和预算查询并预订酒店
  4. 行程规划:基于目的地景点和用户兴趣制定行程
  5. 攻略生成:生成详细的旅行攻略,包括景点介绍、交通建议、美食推荐等
  6. 预算计算:估算整个旅行的费用

实用案例分析

案例:周末上海游规划

场景描述:用户想要在本周末去上海游玩,希望智能体能够:

  • 查询从北京到上海的往返机票
  • 预订两晚的酒店
  • 制定两天的行程
  • 生成详细的旅行攻略
  • 估算总预算

实现思路

  1. 收集用户需求:出发地、目的地、日期、预算、偏好
  2. 调用机票查询工具获取航班信息
  3. 调用酒店查询工具获取住宿选项
  4. 基于目的地信息制定行程
  5. 生成完整的旅行攻略
  6. 计算并呈现总预算

代码实现

1. 工具定义与集成

from langchain.tools import BaseTool
from langchain.pydantic_v1 import BaseModel, Field
import requests
import json
import logging

# 配置日志
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)

# 机票查询工具
class FlightSearchInput(BaseModel):
    origin: str = Field(description="出发城市机场代码")
    destination: str = Field(description="目的地城市机场代码")
    departure_date: str = Field(description="出发日期,格式:YYYY-MM-DD")
    return_date: str = Field(description="返回日期,格式:YYYY-MM-DD")
    adults: int = Field(default=1, description="成人数量")

class FlightSearchTool(BaseTool):
    name = "flight_search"
    description = "查询航班信息,需要提供出发地、目的地、出发日期、返回日期和成人数量"
    args_schema = FlightSearchInput
    
    def _run(self, origin: str, destination: str, 
             departure_date: str, return_date: str, 
             adults: int = 1) -> str:
        """查询航班信息"""
        try:
            # 模拟航班API调用
            # 实际项目中应替换为真实的航班API
            logger.info(f"查询航班: {origin} -> {destination}, 出发: {departure_date}, 返回: {return_date}")
            
            # 模拟航班数据
            flights = {
                "departure": [
                    {
                        "airline": "中国国航",
                        "flight_number": "CA1831",
                        "departure_time": "08:00",
                        "arrival_time": "10:20",
                        "price": "¥850"
                    },
                    {
                        "airline": "东方航空",
                        "flight_number": "MU5138",
                        "departure_time": "12:30",
                        "arrival_time": "14:50",
                        "price": "¥780"
                    }
                ],
                "return": [
                    {
                        "airline": "东方航空",
                        "flight_number": "MU5137",
                        "departure_time": "15:30",
                        "arrival_time": "17:50",
                        "price": "¥720"
                    },
                    {
                        "airline": "中国国航",
                        "flight_number": "CA1832",
                        "departure_time": "19:00",
                        "arrival_time": "21:20",
                        "price": "¥800"
                    }
                ]
            }
            
            return json.dumps(flights, ensure_ascii=False, indent=2)
        except Exception as e:
            logger.error(f"航班查询失败: {e}")
            return f"航班查询失败: {str(e)}"

# 酒店查询工具
class HotelSearchInput(BaseModel):
    destination: str = Field(description="目的地城市")
    checkin_date: str = Field(description="入住日期,格式:YYYY-MM-DD")
    checkout_date: str = Field(description="退房日期,格式:YYYY-MM-DD")
    guests: int = Field(default=2, description="入住人数")
    budget: str = Field(default="mid", description="预算级别:low, mid, high")

class HotelSearchTool(BaseTool):
    name = "hotel_search"
    description = "查询酒店信息,需要提供目的地、入住日期、退房日期、人数和预算级别"
    args_schema = HotelSearchInput
    
    def _run(self, destination: str, checkin_date: str, 
             checkout_date: str, guests: int = 2, 
             budget: str = "mid") -> str:
        """查询酒店信息"""
        try:
            # 模拟酒店API调用
            logger.info(f"查询酒店: {destination}, 入住: {checkin_date}, 退房: {checkout_date}, 人数: {guests}, 预算: {budget}")
            
            # 模拟酒店数据
            hotels = [
                {
                    "name": "上海外滩华尔道夫酒店",
                    "address": "上海市黄浦区中山东一路2号",
                    "price": "¥2500/晚",
                    "rating": "5星",
                    "description": "豪华五星级酒店,位于外滩核心区域,俯瞰黄浦江"
                },
                {
                    "name": "上海浦东香格里拉大酒店",
                    "address": "上海市浦东新区富城路33号",
                    "price": "¥1800/晚",
                    "rating": "5星",
                    "description": "豪华酒店,位于陆家嘴金融区,视野开阔"
                },
                {
                    "name": "上海静安瑞吉酒店",
                    "address": "上海市静安区北京西路1008号",
                    "price": "¥1500/晚",
                    "rating": "5星",
                    "description": "高端酒店,位于市中心,交通便利"
                }
            ]
            
            # 根据预算过滤酒店
            if budget == "low":
                hotels = [h for h in hotels if int(h["price"].replace("¥", "").split("/")[0]) < 1000]
            elif budget == "high":
                hotels = [h for h in hotels if int(h["price"].replace("¥", "").split("/")[0]) > 2000]
            
            return json.dumps(hotels, ensure_ascii=False, indent=2)
        except Exception as e:
            logger.error(f"酒店查询失败: {e}")
            return f"酒店查询失败: {str(e)}"

# 天气查询工具
class WeatherSearchInput(BaseModel):
    city: str = Field(description="城市名称")
    date: str = Field(description="查询日期,格式:YYYY-MM-DD")

class WeatherSearchTool(BaseTool):
    name = "weather_search"
    description = "查询城市天气信息,需要提供城市名称和日期"
    args_schema = WeatherSearchInput
    
    def _run(self, city: str, date: str) -> str:
        """查询天气信息"""
        try:
            # 模拟天气API调用
            logger.info(f"查询天气: {city}, 日期: {date}")
            
            # 模拟天气数据
            weather = {
                "city": city,
                "date": date,
                "temperature": "18-25°C",
                "condition": "晴转多云",
                "humidity": "60%",
                "wind": "东北风3级",
                "suggestion": "天气适宜出行,建议携带轻便衣物"
            }
            
            return json.dumps(weather, ensure_ascii=False, indent=2)
        except Exception as e:
            logger.error(f"天气查询失败: {e}")
            return f"天气查询失败: {str(e)}"

2. 智能体构建

from langchain.agents import initialize_agent, AgentType
from langchain.chat_models import ChatOpenAI
from langchain.memory import ConversationBufferMemory
import os

# 设置API密钥
os.environ["OPENAI_API_KEY"] = "your-openai-api-key"

# 初始化工具
flight_tool = FlightSearchTool()
travel_tools = [flight_tool, HotelSearchTool(), WeatherSearchTool()]

# 初始化LLM
llm = ChatOpenAI(temperature=0.7, model="gpt-3.5-turbo-16k")

# 初始化记忆
memory = ConversationBufferMemory(memory_key="chat_history", return_messages=True)

# 初始化智能体
travel_agent = initialize_agent(
    tools=travel_tools,
    llm=llm,
    agent=AgentType.CHAT_CONVERSATIONAL_REACT_DESCRIPTION,
    memory=memory,
    verbose=True,
    agent_kwargs={
        "system_message": "你是一个专业的旅行规划师,能够帮助用户查询机票、预订酒店、了解天气情况,并生成详细的旅行攻略。请根据用户的需求,提供专业、贴心的旅行建议。"
    }
)

# 测试智能体
response = travel_agent.run("我想在本周末(5月13-14日)从北京去上海玩,预算3000元,帮我规划一下行程。")
print(response)

3. 攻略生成模块

from langchain.prompts import PromptTemplate
from langchain.chains import LLMChain

# 攻略生成提示词
itinerary_template = """
你是一位专业的旅行攻略作家,请根据以下信息为用户生成一份详细的旅行攻略:

目的地:{destination}
旅行日期:{start_date} 至 {end_date}
预算:{budget}
用户偏好:{preferences}

攻略应包含以下内容:
1. 行程概览
2. 详细的每日行程安排(包括景点、交通、餐饮建议)
3. 交通指南(如何在城市内出行)
4. 美食推荐(当地特色美食和推荐餐厅)
5. 住宿建议
6. 购物指南
7. 注意事项和旅行提示
8. 预算明细

请确保攻略内容详细、实用,并且符合用户的预算和偏好。
"""

# 创建提示词模板
itinerary_prompt = PromptTemplate(
    input_variables=["destination", "start_date", "end_date", "budget", "preferences"],
    template=itinerary_template
)

# 创建攻略生成链
itinerary_chain = LLMChain(llm=llm, prompt=itinerary_prompt)

# 生成攻略
def generate_itinerary(destination, start_date, end_date, budget, preferences):
    """生成旅行攻略"""
    try:
        logger.info(f"生成{destination}的旅行攻略")
        result = itinerary_chain.run(
            destination=destination,
            start_date=start_date,
            end_date=end_date,
            budget=budget,
            preferences=preferences
        )
        return result
    except Exception as e:
        logger.error(f"攻略生成失败: {e}")
        return f"攻略生成失败: {str(e)}"

# 测试攻略生成
itinerary = generate_itinerary(
    destination="上海",
    start_date="2024-05-13",
    end_date="2024-05-14",
    budget="3000元",
    preferences="喜欢历史文化景点和美食"
)
print(itinerary)

4. 完整的旅行规划师集成

class TravelPlanner:
    """旅行规划师类"""
    
    def __init__(self):
        # 初始化工具和智能体
        self.flight_tool = FlightSearchTool()
        self.hotel_tool = HotelSearchTool()
        self.weather_tool = WeatherSearchTool()
        
        self.tools = [self.flight_tool, self.hotel_tool, self.weather_tool]
        
        # 初始化LLM
        self.llm = ChatOpenAI(temperature=0.7, model="gpt-3.5-turbo-16k")
        
        # 初始化记忆
        self.memory = ConversationBufferMemory(memory_key="chat_history", return_messages=True)
        
        # 初始化智能体
        self.agent = initialize_agent(
            tools=self.tools,
            llm=self.llm,
            agent=AgentType.CHAT_CONVERSATIONAL_REACT_DESCRIPTION,
            memory=self.memory,
            verbose=True,
            agent_kwargs={
                "system_message": "你是一个专业的旅行规划师,能够帮助用户查询机票、预订酒店、了解天气情况,并生成详细的旅行攻略。请根据用户的需求,提供专业、贴心的旅行建议。"
            }
        )
        
        # 初始化攻略生成链
        self.itinerary_prompt = PromptTemplate(
            input_variables=["destination", "start_date", "end_date", "budget", "preferences"],
            template=itinerary_template
        )
        self.itinerary_chain = LLMChain(llm=self.llm, prompt=self.itinerary_prompt)
    
    def plan_trip(self, user_query):
        """规划旅行"""
        try:
            # 1. 理解用户需求
            logger.info(f"处理用户请求: {user_query}")
            
            # 2. 使用智能体处理请求
            agent_response = self.agent.run(user_query)
            
            # 3. 提取关键信息(这里简化处理,实际项目中需要更复杂的信息提取)
            # 示例:从用户查询中提取目的地、日期、预算等信息
            # 实际项目中可以使用NLP技术或结构化输出解析
            
            # 4. 生成详细攻略
            # 这里假设我们已经提取了关键信息
            itinerary = self.itinerary_chain.run(
                destination="上海",
                start_date="2024-05-13",
                end_date="2024-05-14",
                budget="3000元",
                preferences="喜欢历史文化景点和美食"
            )
            
            # 5. 整合结果
            final_response = f"{agent_response}\n\n=== 详细旅行攻略 ===\n{itinerary}"
            
            return final_response
        except Exception as e:
            logger.error(f"旅行规划失败: {e}")
            return f"旅行规划失败: {str(e)}"

# 测试完整的旅行规划师
planner = TravelPlanner()
result = planner.plan_trip("我想在本周末(5月13-14日)从北京去上海玩,预算3000元,帮我规划一下行程。")
print(result)

代码分析

关键技术点

  1. 工具集成

    • 封装外部API调用为LangChain工具
    • 处理API响应和错误
    • 提供标准化的输入输出格式
  2. 智能体设计

    • 使用CHAT_CONVERSATIONAL_REACT_DESCRIPTION代理类型
    • 结合记忆功能实现上下文理解
    • 设计专业的系统提示词
  3. 攻略生成

    • 使用专门的提示词模板
    • 结构化输出详细的旅行攻略
    • 考虑用户偏好和预算约束
  4. 信息提取

    • 从用户查询中提取关键信息
    • 处理不完整或模糊的用户需求
    • 填充默认值和合理假设

高级技巧

1. 多工具协同策略

  • 工具选择逻辑:根据用户需求自动选择合适的工具
  • 工具调用顺序:先查询航班和酒店,再根据结果生成攻略
  • 结果整合:将多个工具的结果整合为统一的旅行方案

2. 个性化推荐

  • 用户画像:基于历史交互构建用户偏好模型
  • 兴趣匹配:根据用户兴趣推荐相关景点和活动
  • 季节性建议:根据旅行时间提供季节性建议

3. 实时数据集成

  • API集成:整合真实的航班、酒店、天气API
  • 数据缓存:缓存频繁查询的结果,提高响应速度
  • 价格监控:监控航班和酒店价格变动,提供最优选择

4. 多语言支持

  • 语言检测:自动检测用户语言
  • 多语言响应:支持多语言旅行攻略生成
  • 本地化建议:提供符合当地文化的旅行建议

最佳实践

工具设计最佳实践

  1. 参数标准化:为所有工具定义清晰的参数结构
  2. 错误处理:为每个工具实现完善的错误处理机制
  3. 结果格式化:统一工具返回格式,便于智能体处理
  4. 超时设置:为API调用设置合理的超时时间

代码实现最佳实践

  1. 模块化设计:将不同功能模块分离为独立组件
  2. 配置外部化:将API密钥和配置信息外部化
  3. 日志记录:实现详细的日志记录,便于调试和监控
  4. 性能优化:使用异步调用处理多个API请求

工具使用最佳实践

  1. 上下文感知:根据对话历史理解用户需求
  2. 主动追问:当信息不足时,主动向用户追问
  3. 多方案对比:提供多个旅行方案供用户选择
  4. 用户反馈:收集用户对旅行规划的反馈,持续改进

部署与安全最佳实践

  1. API密钥保护:使用环境变量或密钥管理服务存储API密钥
  2. 速率限制:遵守API提供商的速率限制,避免被封禁
  3. 数据隐私:保护用户的个人信息和旅行计划
  4. 系统监控:监控系统运行状态,及时发现和解决问题

常见问题与解决方案

问题 原因 解决方案
API调用失败 网络问题或API密钥无效 实现重试机制,提供友好的错误提示
信息提取不准确 用户输入模糊或不完整 主动追问用户,使用默认值填充缺失信息
攻略生成质量低 提示词不够详细 优化提示词模板,提供更具体的生成指导
系统响应缓慢 多个API调用串行执行 使用异步编程,并行处理多个API请求
预算估算不准确 缺少实时价格数据 集成实时价格API,定期更新价格信息

未来发展趋势

  1. 多模态旅行规划:结合图片、视频等多模态信息提供更丰富的旅行建议
  2. 智能行程调整:根据实时天气、交通状况自动调整行程
  3. 社交化旅行规划:支持多人协作规划旅行,整合不同人的偏好
  4. AR导航集成:结合AR技术提供实时导航和景点介绍
  5. 个性化推荐系统:基于用户行为和偏好的智能推荐

总结

本集通过实战案例,详细介绍了如何构建一个集成机票查询、酒店预订和旅行攻略生成功能的AI旅行规划师智能体。我们从工具定义、智能体构建到攻略生成,实现了一个完整的旅行规划系统。

在实现过程中,我们学习了多工具集成、错误处理、上下文理解等关键技术,以及模块化设计、配置管理等最佳实践。这些技术和实践不仅适用于旅行规划场景,也可以推广到其他需要多工具协作的智能体应用中。

随着API集成技术的不断发展和LLM能力的提升,旅行规划师智能体将变得越来越智能和个性化,为用户提供更加贴心、专业的旅行规划服务。未来,我们可以进一步扩展其功能,如整合更多服务、提供实时行程调整、支持多语言等,打造一个真正智能的旅行助手。


思考与练习

  1. 尝试集成真实的航班和酒店API,替换模拟数据
  2. 为旅行规划师添加景点推荐功能
  3. 实现一个简单的前端界面,提供可视化的旅行规划体验
  4. 扩展系统支持多目的地旅行规划

扩展阅读

  • LangChain工具集成文档
  • 航班和酒店API使用指南
  • 旅行规划应用的用户体验设计
  • 多工具协作智能体的设计模式
« 上一篇 工具调用的错误处理与重试机制 下一篇 » 为什么要用多智能体?——复杂任务的分解与协作