基于MCP协议构建智能旅行助手:从工具调用到Agent实现

基于MCP协议构建智能旅行助手:从工具调用到Agent实现

1. 项目概述:从“手搓”一个智能旅行助手说起

最近在折腾AI应用开发,特别是围绕MCP(Model Context Protocol)协议做集成时,有个想法一直在我脑子里转:能不能让AI不只是回答问题,而是能真正“动手”帮我处理一些旅行前的琐事?比如,我想去上海出差,直接告诉AI“帮我查查下周浦东机场附近的酒店,预算800以内,然后打开浏览器让我看看”,它就能自动完成从查询到呈现的全过程。这听起来像是某个成熟商业产品的功能,但我的目标是自己“手搓”一个能实现这个流程的Agent。这不仅仅是为了解决一个具体需求,更是想深入理解如何让大语言模型(LLM)与外部工具和服务进行安全、高效、可控的交互,构建一个真正具有行动力的智能体。

这个项目的核心,就是“调用远程MCP,手搓一个能查酒店、自动打开浏览器的Agent”。这里有几个关键词:“远程MCP”、“手搓”、“Agent”。远程MCP意味着我们的智能体并非完全内置所有能力,而是通过标准协议去调用部署在别处的专业化服务(比如酒店查询服务);“手搓”强调这是一个从零开始、深度定制的开发过程,我们会涉及架构设计、工具封装、逻辑编排;“Agent”则指明了最终产物是一个能够理解用户意图、规划步骤、执行工具调用并返回结果的自主程序。整个过程融合了后端集成、前端交互以及AI决策逻辑,是一个典型的AI应用工程化实践。

2. 核心架构设计与技术选型

2.1 为什么选择MCP(Model Context Protocol)?

在决定让Agent调用外部服务时,我们面临几个选择:直接为LLM编写特定的函数调用(Function Calling)、使用像LangChain这样的框架集成工具链,或者采用一种更标准化的协议。我选择了后者,具体来说是MCP协议。原因在于,MCP为模型(尤其是大语言模型)与外部上下文资源(如数据库、API、文件系统)的交互提供了一套与模型无关的标准化方式。它定义了资源(Resources)和工具(Tools)的发现、描述和调用机制。

对于我们的酒店查询Agent来说,使用MCP有几个明显优势:

  1. 解耦与标准化:酒店查询服务可以作为一个独立的MCP服务器(Server)存在,它只需要向MCP客户端(Client)宣告自己提供了“搜索酒店”这个工具(Tool),并描述其输入参数(城市、日期、价格范围等)。我们的Agent作为客户端,无需关心服务是用Python、Go还是其他语言实现的,也无需绑定特定的SDK,只需遵循MCP协议进行通信。
  2. 动态能力发现:Agent启动时,可以向连接的MCP服务器查询当前可用的所有工具列表。这意味着未来如果我们增加机票查询、天气查询等新的MCP服务器,Agent无需修改核心代码就能获得这些新能力,扩展性极强。
  3. 安全性:MCP服务器可以运行在独立的、受控的环境中(甚至远程),通过SSH或安全的进程间通信(IPC)与客户端连接。这比直接在Agent进程中执行未知代码要安全得多。

2.2 Agent的核心工作流与组件拆解

我们的智能Agent不会是一个单体的庞然大物,而是一个由多个协同组件构成的系统。下图清晰地展示了从用户输入到结果呈现的完整数据流与决策逻辑:

flowchart TD A[用户输入自然语言请求<br>如“查上海下周酒店”] --> B[LLM核心<br>意图理解与规划] B --> C{决策: 需要调用工具吗?} C -- 是 --> D[MCP客户端<br>查询可用工具列表] D --> E[工具匹配与参数提取<br>例: 匹配“search_hotels”工具] E --> F[调用远程MCP服务器<br>发送结构化请求] F --> G[远程MCP服务器<br>执行酒店API查询] G --> H[返回结构化数据<br>酒店列表JSON] H --> I[LLM核心<br>结果分析与下一步规划] C -- 否 --> J[直接生成自然语言回复] I --> K{决策: 需要用户交互吗?} K -- 是,需浏览器展示 --> L[调用本地工具<br>如: webbrowser.open] L --> M[用户浏览器打开<br>展示格式化结果页面] K -- 否,直接回答 --> N[生成最终汇总回复<br>并输出] J --> N M --> O[流程结束] N --> O

整个系统可以分解为以下几个核心部分:

  1. LLM核心(大脑):这是Agent的决策中心。我选择了GPT-4o的API,因为它在大语言模型中具有优秀的指令遵循、思维链(Chain-of-Thought)和工具调用(Function Calling)能力。它的任务是理解用户的自然语言请求,将其分解为可执行的步骤(规划),判断何时需要调用MCP工具,并解析工具返回的结果。

  2. MCP客户端(手和脚):这是Agent与外部世界交互的接口。我们需要实现一个MCP客户端,负责:

    • 与一个或多个远程MCP服务器建立连接(例如通过SSH或Stdio)。
    • 从服务器获取可用的工具列表及其模式(Schema)。
    • 将LLM生成的工具调用请求,按照MCP协议格式打包并发送给服务器。
    • 接收服务器返回的结果,并传递给LLM核心。
  3. 远程MCP服务器(专业化工具):这是提供具体能力的“专家”。对于酒店查询,我们需要部署一个MCP服务器,它内部会封装调用真实酒店预订API(例如携程、Booking.com的Affiliate API,或模拟数据)的逻辑。这个服务器会向客户端宣告一个名为search_hotels的工具。

  4. 本地工具执行器(另一双手):除了远程服务,有些操作需要在用户本地环境执行,比如“自动打开浏览器”。这通常通过调用系统命令或本地库(如Python的webbrowser模块)来实现。这部分逻辑可以直接集成在Agent主程序中,也可以包装成一个本地MCP服务器供Agent调用,后者架构更统一但稍显复杂。本项目为简化,采用直接集成的方式。

  5. 上下文管理与记忆:一个简单的Agent可能只处理单轮对话。但为了更好的体验,我们需要让Agent记住对话历史(例如用户之前说过的预算偏好),这可以通过维护一个对话消息列表来实现。

2.3 技术栈敲定

基于以上设计,我的技术选型如下:

  • 编程语言:Python。生态丰富,在AI和自动化领域有大量库支持,开发效率高。
  • LLM接口:OpenAI API (GPT-4o)。使用官方的openaiPython库。
  • MCP协议实现:使用 Anthropic 官方开源的mcpPython SDK。它提供了客户端和服务器的底层协议处理,大大降低了开发难度。
  • 本地浏览器控制:Python标准库webbrowser,用于打开默认浏览器。为了展示更美观的结果,可能会搭配一个简单的本地HTTP服务器(如http.server)来生成一个临时HTML页面。
  • 酒店数据源:出于演示目的,初期可以使用模拟数据或免费的公共API(如一些旅游开放平台)。生产环境则需要接入商业API。

3. 分步实现:从零搭建智能体

3.1 第一步:构建远程酒店查询MCP服务器

我们的旅程从打造第一个专业化工具开始。MCP服务器的核心是声明工具并处理调用请求。

# hotel_search_server.py import asyncio from typing import Any from mcp import Server, StdioServerParameters from mcp.types import Tool, TextContent, ImageContent import json import random # 模拟数据用 # 模拟酒店数据函数 async def mock_search_hotels(city: str, check_in: str, check_out: str, max_price: float) -> list: """模拟酒店搜索,实际应调用真实API""" await asyncio.sleep(0.5) # 模拟网络延迟 hotels = [] names = ["和平饭店", "浦东香格里拉", "外滩华尔道夫", "智选假日", "全季酒店"] for i in range(random.randint(3, 6)): hotel = { "name": f"{names[i % len(names)]}({city}分店)", "price": round(random.uniform(300, max_price), 2), "rating": round(random.uniform(3.5, 5.0), 1), "address": f"{city}市模拟路{random.randint(1, 999)}号", "url": f"https://example.com/hotel/{i}" # 模拟详情页链接 } hotels.append(hotel) # 按价格排序 hotels.sort(key=lambda x: x['price']) return hotels async def main(): # 创建MCP服务器,使用标准输入输出作为传输层 async with Server(StdioServerParameters()) as server: # 1. 声明此服务器提供的工具列表 tools = [ Tool( name="search_hotels", description="根据城市、入住/退房日期和最高价格搜索酒店。", inputSchema={ "type": "object", "properties": { "city": {"type": "string", "description": "城市名,例如:上海、北京"}, "check_in": {"type": "string", "description": "入住日期,格式:YYYY-MM-DD"}, "check_out": {"type": "string", "description": "退房日期,格式:YYYY-MM-DD"}, "max_price": {"type": "number", "description": "每晚最高价格(人民币)"} }, "required": ["city", "check_in", "check_out", "max_price"] } ) ] await server.list_tools.set(tools) # 2. 处理工具调用请求 @server.tool_call() async def handle_tool_call(name: str, arguments: dict[str, Any]) -> list[TextContent | ImageContent]: if name == "search_hotels": city = arguments["city"] check_in = arguments["check_in"] check_out = arguments["check_out"] max_price = arguments["max_price"] print(f"[MCP Server] 正在搜索酒店:{city}, {check_in} 至 {check_out}, 价格<{max_price}元") hotels = await mock_search_hotels(city, check_in, check_out, max_price) # 将结果格式化为易读的文本 result_text = f"在{city}找到{len(hotels)}家符合条件的酒店:\n" for i, h in enumerate(hotels, 1): result_text += f"{i}. {h['name']} - ¥{h['price']}/晚,评分{h['rating']},地址:{h['address']}\n" # 同时返回结构化数据供Agent进一步处理 structured_data = json.dumps({"hotels": hotels}, ensure_ascii=False) return [ TextContent(type="text", text=result_text), TextContent(type="text", text=f"结构化数据:{structured_data}") ] else: raise ValueError(f"未知工具:{name}") # 3. 等待并处理请求 print("酒店查询MCP服务器已启动,等待连接...", flush=True) await server.run() if __name__ == "__main__": asyncio.run(main())

关键点解析

  • StdioServerParameters():这意味着服务器通过标准输入/输出与客户端通信。这是最简单的调试和集成方式,客户端可以作为一个子进程启动此服务器。
  • server.list_tools.set(tools):这是MCP协议的核心之一,服务器启动时向客户端宣告自己的能力。
  • @server.tool_call():装饰器用于注册工具调用处理器。当客户端调用search_hotels时,这个函数会被触发。
  • 返回多个Content:我返回了两个TextContent,一个是给人看的自然语言摘要,另一个是结构化的JSON数据。LLM可以解析后者来获取精确信息,这比从自然语言文本中再提取要可靠得多。这是设计MCP工具返回结果的一个最佳实践。

3.2 第二步:打造智能体核心——MCP客户端与LLM的集成

这是最核心的一步,我们将创建一个既能与MCP服务器对话,又能驱动LLM的智能体程序。

# travel_agent.py import asyncio import json from typing import List from openai import OpenAI from mcp import ClientSession, StdioServerParameters import mcp.client.stdio import webbrowser import tempfile import os class TravelAgent: def __init__(self, openai_api_key: str): self.openai_client = OpenAI(api_key=openai_api_key) self.mcp_session: ClientSession | None = None self.conversation_history: List[dict] = [] # 维护对话上下文 async def connect_to_mcp_server(self, server_command: List[str]): """连接到远程MCP服务器(这里以本地子进程为例)""" print(f"正在启动MCP服务器: {' '.join(server_command)}") server_params = StdioServerParameters(command=server_command[0], args=server_command[1:]) stdio_transport = await mcp.client.stdio.stdio_client(server_params) self.mcp_session = ClientSession(stdio_transport[0], stdio_transport[1]) await self.mcp_session.initialize() print("MCP服务器连接成功。") async def get_available_tools(self) -> List[dict]: """从MCP服务器获取可用工具列表""" if not self.mcp_session: return [] response = await self.mcp_session.list_tools() return response.tools async def call_tool(self, tool_name: str, arguments: dict) -> str: """调用指定的MCP工具""" if not self.mcp_session: return "错误:未连接到MCP服务器。" print(f"[Agent] 调用工具: {tool_name},参数: {arguments}") result = await self.mcp_session.call_tool(tool_name, arguments) # 合并所有文本结果 full_result = "" for content in result.content: if content.type == "text": full_result += content.text + "\n" return full_result def open_hotels_in_browser(self, hotels_data: dict): """将酒店数据生成一个简单的HTML页面并在浏览器中打开""" hotels = hotels_data.get('hotels', []) html_content = """ <!DOCTYPE html> <html> <head><title>酒店查询结果</title><meta charset="utf-8"> <style>body{font-family: sans-serif; margin: 40px;} .hotel{border:1px solid #ddd; padding:15px; margin-bottom:10px; border-radius:5px;} .price{color:#e74c3c; font-weight:bold;}</style> </head> <body><h2>为您找到的酒店:</h2> """ for hotel in hotels: html_content += f""" <div class="hotel"> <h3>{hotel['name']}</h3> <p>价格:<span class="price">¥{hotel['price']}</span> / 晚</p> <p>评分:{hotel['rating']} / 5.0</p> <p>地址:{hotel['address']}</p> <p><a href="{hotel.get('url', '#')}" target="_blank">查看详情</a></p> </div> """ html_content += "</body></html>" # 创建临时HTML文件 with tempfile.NamedTemporaryFile('w', suffix='.html', delete=False) as f: f.write(html_content) temp_file_path = f.name # 用浏览器打开 webbrowser.open(f'file://{temp_file_path}') print(f"[Agent] 已在浏览器中打开结果页面: {temp_file_path}") # 注意:实际应用中可能需要稍后清理临时文件 async def process_user_query(self, query: str) -> str: """处理用户查询的核心逻辑""" # 1. 将用户查询加入历史 self.conversation_history.append({"role": "user", "content": query}) # 2. 获取当前可用的工具列表 available_tools = await self.get_available_tools() # 将MCP工具格式转换为OpenAI函数调用格式 openai_tools = [] for tool in available_tools: openai_tools.append({ "type": "function", "function": { "name": tool.name, "description": tool.description, "parameters": tool.inputSchema } }) # 添加一个本地工具:打开浏览器 openai_tools.append({ "type": "function", "function": { "name": "open_browser_with_results", "description": "将结构化的酒店列表在用户的默认网页浏览器中打开,以便于可视化浏览。调用此工具前,必须已经获得了结构化的酒店数据。", "parameters": { "type": "object", "properties": { "hotels_json_str": { "type": "string", "description": "包含酒店列表的JSON字符串,必须包含一个'hotels'数组。" } }, "required": ["hotels_json_str"] } } }) # 3. 调用LLM,让其决定是否需要以及如何调用工具 response = self.openai_client.chat.completions.create( model="gpt-4o", # 或 "gpt-3.5-turbo" messages=self.conversation_history, tools=openai_tools, tool_choice="auto", # 让模型自动决定是否调用工具 ) message = response.choices[0].message self.conversation_history.append(message) # 将助手的回复也加入历史 final_answer = "" tool_calls = message.tool_calls # 4. 处理LLM可能发起的工具调用 if tool_calls: for tool_call in tool_calls: func_name = tool_call.function.name func_args = json.loads(tool_call.function.arguments) if func_name == "search_hotels": # 调用远程MCP工具 tool_result = await self.call_tool(func_name, func_args) # 将工具执行结果加入对话历史,让LLM知晓 self.conversation_history.append({ "role": "tool", "tool_call_id": tool_call.id, "content": tool_result }) # 尝试从结果中提取结构化数据,用于后续可能的浏览器打开操作 # 这里简单查找包含“结构化数据”的行 for line in tool_result.split('\n'): if line.startswith('结构化数据:'): self.last_hotel_data = line.replace('结构化数据:', '') elif func_name == "open_browser_with_results": # 执行本地操作:打开浏览器 hotels_json_str = func_args["hotels_json_str"] try: hotels_data = json.loads(hotels_json_str) self.open_hotels_in_browser(hotels_data) tool_result = "已成功在浏览器中打开酒店列表页面。" except json.JSONDecodeError: tool_result = "错误:提供的酒店数据不是有效的JSON格式。" self.conversation_history.append({ "role": "tool", "tool_call_id": tool_call.id, "content": tool_result }) # 工具调用后,需要让LLM根据结果生成面向用户的最终回复 follow_up_response = self.openai_client.chat.completions.create( model="gpt-4o", messages=self.conversation_history, ) final_message = follow_up_response.choices[0].message self.conversation_history.append(final_message) final_answer = final_message.content else: # LLM没有调用工具,直接回复 final_answer = message.content return final_answer if final_answer else "(未生成回复)" async def chat_loop(self): """简单的交互循环""" print("旅行助手已启动。输入您的要求(例如:'帮我查一下下周五上海浦东的酒店,预算500元'),或输入'退出'结束。") while True: try: user_input = input("\n您: ").strip() if user_input.lower() in ['退出', 'exit', 'quit']: break if not user_input: continue answer = await self.process_user_query(user_input) print(f"助手: {answer}") except KeyboardInterrupt: break except Exception as e: print(f"出错: {e}") async def main(): # 配置 OPENAI_API_KEY = "your-openai-api-key-here" # 务必替换成你的Key MCP_SERVER_CMD = ["python", "hotel_search_server.py"] # 启动MCP服务器的命令 agent = TravelAgent(OPENAI_API_KEY) await agent.connect_to_mcp_server(MCP_SERVER_CMD) await agent.chat_loop() if __name__ == "__main__": asyncio.run(main())

关键逻辑与避坑指南

  1. 工具格式转换:MCP协议定义的工具(Tool)与OpenAI函数调用(tools)的格式略有不同。我们需要在process_user_query方法中进行适配转换,这是集成中的关键一步。
  2. 对话历史管理:为了让LLM拥有上下文记忆,我们维护了conversation_history列表。每次用户输入、AI回复、工具调用及结果都需要按正确角色(user,assistant,tool)添加进去。tool角色的消息必须包含对应的tool_call_id,否则LLM无法关联。
  3. 多轮工具调用:注意代码中,当LLM调用工具后,我们用工具执行结果更新了历史,然后再次调用LLMfollow_up_response),让它来消化工具结果并生成面向用户的回复。这是实现多步规划(先搜索,再打开浏览器)的关键。更复杂的Agent可能会让LLM在单轮中规划多个工具调用,然后并行或依次执行。
  4. 结构化数据传递:在search_hotels工具的结果中,我特意返回了结构化JSON数据,并尝试将其保存到self.last_hotel_data。当LLM决定调用open_browser_with_results时,它需要将这个JSON字符串作为参数。这里存在一个挑战:LLM如何知道这个数据的存在?一种方法是在工具的自然语言结果中明确提示“结构化数据已就绪,可供open_browser_with_results工具使用”。另一种更鲁棒的方法是使用MCP的“资源”(Resources)特性,将结构化数据发布为一个资源,供其他工具引用。本例为简化采用了提示法。

3.3 第三步:运行与测试

  1. 准备环境:确保安装了必要的Python包。

    pip install openai mcp
  2. 配置密钥:在travel_agent.py中替换OPENAI_API_KEY为你的有效密钥。

  3. 启动测试:在同一目录下,打开两个终端窗口。

    • 终端1:直接运行MCP服务器(它会等待连接)。
      python hotel_search_server.py
    • 终端2:运行智能体。
      python travel_agent.py

    智能体会自动启动服务器子进程并连接。现在,你可以尝试输入:

    “帮我查一下下周五上海浦东的酒店,住两晚,预算800以内。”

    观察控制台输出,你会看到Agent识别了意图,调用了search_hotels工具,MCP服务器返回结果,然后LLM生成摘要回复。接着,你可以说:

    “把结果在浏览器里打开给我看看。”

    Agent应该会调用open_browser_with_results工具,你的默认浏览器将弹出一个显示酒店列表的临时页面。

4. 进阶优化与问题排查

4.1 提升Agent的可靠性与用户体验

基础的跑通只是第一步,要让这个“手搓”的Agent真正可用,还需要不少优化:

  1. 参数提取与错误处理:用户的自然语言请求可能不完整或模糊。例如,“下周去北京”缺少具体日期和价格。我们的LLM在调用工具前,应该主动询问澄清:“请问您具体哪一天入住,住几晚,预算大概是多少呢?”这需要设计更复杂的对话状态管理逻辑。

  2. 工具调用验证:在调用MCP工具前,应对参数进行基本验证(如日期格式、价格是否为数字)。MCP服务器端也应做验证,并返回清晰的错误信息。

  3. 更优雅的浏览器展示:临时文件的方式不够优雅。可以改为启动一个微型的本地HTTP服务器(如使用aiohttp),动态生成页面,并通过webbrowser.open打开http://localhost:端口的地址。关闭Agent时再关闭服务器。

  4. 连接多个MCP服务器:一个真正的智能体应该能连接多个专家服务器。mcpSDK支持创建多个ClientSession实例。我们需要修改TravelAgent类,管理一个服务器连接池,并在获取工具列表时进行聚合。

  5. 使用更强大的提示词(Prompt Engineering):在系统消息(conversation_history的开头)中给LLM更明确的指令,例如:“你是一个旅行助手,可以调用工具查询酒店信息,并能在用户要求时将结果在浏览器中展示。当用户查询酒店时,你必须调用search_hotels工具。如果用户要求打开浏览器查看,且你已经有了酒店数据,就调用open_browser_with_results工具。”

4.2 常见问题与排查实录

在开发过程中,我遇到了不少坑,这里记录下最典型的几个:

问题1:MCP连接失败,报错[Errno 2] No such file or directory

  • 现象:运行travel_agent.py时,无法启动MCP服务器子进程。
  • 排查:检查MCP_SERVER_CMD变量。["python", "hotel_search_server.py"]假设python命令在系统路径中,且hotel_search_server.py在当前工作目录。
  • 解决:确保命令正确。在Windows上,可能需要["python.exe", "..."]。或者使用绝对路径。一个更健壮的方法是先检查文件是否存在。

问题2:LLM不调用工具,总是直接回复文本

  • 现象:输入查询后,Agent只是用文字描述“我可以帮你查酒店”,但没有实际调用search_hotels工具。
  • 排查
    1. 检查openai_tools列表是否成功从MCP服务器获取并转换。可以在process_user_query中打印一下这个列表。
    2. 检查发送给OpenAI API的messages历史。确保系统消息或之前的对话没有抑制工具调用。
    3. 检查工具的描述(description)是否清晰。模糊的描述会导致LLM不理解何时该调用它。search_hotels的描述必须明确说明其用途和参数。
  • 解决:优化工具描述,确保LLM理解其功能。在系统提示词中明确要求LLM在特定场景下调用工具。也可以尝试调整tool_choice参数为"required"来强制调用某个工具(如果确定需要)。

问题3:工具调用结果后,LLM的后续回复不理想

  • 现象:工具成功调用并返回了数据,但LLM生成的最终回复只是简单重复数据,或者说“已调用工具”,没有进行有效的总结或下一步建议。
  • 排查:检查conversation_history在工具调用后的状态。是否正确添加了role: tool的消息?消息内容是否清晰?如果工具返回的是纯JSON,LLM可能不易理解。
  • 解决:像我在MCP服务器中做的那样,返回“人读”和“机读”两种格式的结果。让role: tool的消息内容包含清晰的文本摘要,这样LLM更容易生成友好的回复。同时,可以在系统提示词中要求LLM:“当你收到工具返回的数据后,请用清晰、有条理的方式总结给用户。”

问题4:open_browser_with_results工具调用失败,参数错误

  • 现象:LLM尝试调用浏览器工具,但参数hotels_json_str不是一个有效的JSON字符串,或者格式不对。
  • 排查:LLM是如何知道这个JSON字符串的?它需要从上下文中提取。如果之前search_hotels返回的结果是自然语言文本,LLM很难精确提取出JSON。
  • 解决:这是架构设计问题。更好的模式是使用MCP的“资源”(Resource)。让search_hotels工具除了返回文本,还声明一个资源,比如resource://hotels/search-results,其内容就是结构化JSON。然后,open_browser_with_results工具的描述改为“使用resource://hotels/search-results资源中的数据打开浏览器”。这样,LLM只需要引用资源URI,而不需要处理具体的字符串,更可靠。这是MCP协议更高级的用法。

5. 总结与展望

通过这个项目,我们完成了一个从协议理解、服务端开发、客户端集成到AI决策编排的完整链条。这个“手搓”的Agent虽然简单,但清晰地演示了如何利用MCP协议将专业化服务与大型语言模型的能力结合起来,创造出具有实际行动力的AI应用。

我个人在实际操作中的体会是,MCP协议带来的最大好处是关注点分离。酒店查询服务的开发者可以专注于API集成和数据清洗,而Agent的开发者可以专注于对话逻辑和用户体验,两者通过一个清晰的协议接口协作。这比写一个庞大的、包含所有功能的单体应用要灵活和可持续得多。

这个项目可以沿着多个方向扩展:

  • 集成更多服务:加入航班查询、天气查询、景点推荐等MCP服务器,让Agent成为真正的全能旅行管家。
  • 实现持久化记忆:将对话历史和用户偏好(如常去城市、预算区间)存储到数据库,实现个性化服务。
  • 增加语音接口:结合语音识别和合成,打造一个语音交互的旅行助手。
  • 部署为Web服务:使用FastAPI或Gradio为Agent构建一个Web界面,方便更多人使用。

“手搓”的过程虽然繁琐,但每一步都加深了对AI Agent架构、工具调用协议以及实际工程问题的理解。希望这个详细的拆解能为你构建自己的智能体提供一份实用的路线图。