零基础实战:用ReAct模式打造旅游规划智能体

1. 为什么我建议你从“旅游规划智能体”开始学AI大模型

先说说我自己的体会。很多零基础的朋友一听到“AI大模型”,第一反应就是先啃Transformer、学注意力机制、研究模型权重矩阵,仿佛不把这些底层原理搞清楚就没法动手。我当年也是这样,结果啃了一个多月数学公式,代码一行没写,热情倒是先凉了一半。

后来我换了个思路:先别管模型内部怎么工作,先把它当成一个“会聊天、能推理、但是手和脚需要你自己装”的引擎,直接上手做一个完整的小应用。我做的第一个练手项目,就是标题里这个“旅游规划智能体”,而且专门选了ReAct模式来驱动它。做完之后我才发现,大模型应用开发的核心能力其实不在于懂多少模型原理,而在于你懂不懂“怎么定义一个任务、怎么把一个任务拆成模型能理解的形式、怎么用工具填补模型的短板”。

为什么偏偏选旅游规划这个场景?原因有三个。

第一,旅游规划是典型的“多步骤、需推理、依赖实时信息”的任务。一个合格的旅游规划不能只靠模型背课本知识,它需要查天气、查景点开放信息、算路线时间、估预算。这意味着你必须让模型“学会调用外部工具”——这正是Agent的核心价值。

第二,旅游规划的结果容易验证。模型输出一份三日行程,天气对不对、路线顺不顺、预算有没有超,你一眼就能判断好坏。这种即时反馈对新手太重要了,错了马上知道,知道就能调。

第三,这个项目的技术栈覆盖了Agent开发的全流程:定义工具函数、绑定大模型、配置系统提示词、控制循环、处理异常、优化成本。这套工作流学会了,换个场景做“会议纪要助手”“健身计划规划器”“菜谱定制机器人”都是同一个套路。

我自己也是零基础起步,当时连“什么是API”都要现查。这篇文章我尽量不堆术语,把每一步都拆开讲,关键选择都解释为什么。已经有点编程基础的可以直接照着代码做,完全零基础的朋友也能先读懂思路,再一步步复现。下面我们从最核心的ReAct模式开始说起。

2. ReAct不是魔法:先想一步,再做一步,再看一眼

很多教程一上来就甩出“ReAct = Reasoning + Acting”这个公式,然后就进入代码环节,搞得好像这是个很玄的框架。其实ReAct非常朴素。你可以把它想象成一个人解决问题的正常流程:接到一个问题,先想一想现在缺什么信息,然后动手去查,看到结果之后再想下一步怎么办,查到一个信息后再想想还缺什么,循环往复,直到信息齐了,最后组织出答案。

2.1 大模型本身的信息局限

先说一个大模型很关键、但大家特别容易忽视的点:绝大多数大模型的知识是有截止时间的,它不知道今天哪个景点临时闭园,也不知道明天那座城市下不下雨。它的“知识”是静态的,是从互联网数据里压缩出来的“记忆”。而一个真正能用的智能体,必须能感知真实世界。

解决办法就是给模型装上“工具”。“工具体”听起来高深,本质上就是一段段普通的函数——查天气是一个函数,查景点是一个函数,算预算是一个函数。模型本身不会执行这些函数,但它能决定“我现在需要调用哪把工具、参数填什么”,然后把函数调用的意图以文本(或者结构化指令)的方式发出来,由我们写的代码去真正执行函数,再把执行结果回传给模型。

这个“模型思考→发出调用指令→程序执行代码→把结果喂回给模型→模型继续思考”的闭环,就是Agent和普通聊天机器人的本质区别。

2.2 一个旅游规划场景里的ReAct循环

我拿一个具体的例子带你看一遍完整的循环。假设用户输入:“我在江城市,想去滨海市玩三天,预算3500元,帮我安排一下。”

如果你只是打开一个普通聊天网页,把这句话发给大模型,它能给你一份通顺的行程。但这份行程里大概率没有今天的实时天气,用的是它记忆里“夏天滨海市热”之类的模糊印象,而且预算算得七零八碎。这不算智能体,这只是“内容生成”。

用ReAct模式驱动时,整个流程就变成了这样:

  • 第1轮思考:模型发现“要给用户安排行程,我得先知道滨海市未来三天的天气,还要知道那里有哪些景点”。于是它发出指令:调用get_weather(tool=weather, city=滨海市, date=未来三天)。我们的代码执行这个函数,返回:“第一天小雨,22-26度;第二天晴,24-30度;第三天多云,25-31度。”
  • 第2轮思考:模型看到天气信息后修正计划:“第一天有雨,不适合出海的室外项目,应该安排室内行程;第二天晴天,可以安排滨海步道和沙滩;第三天多云适合爬山或逛古镇。”于是它接着调用get_hot_spots(city=滨海市, category=室内/景点),获取候选景区列表。
  • 第3轮思考:它拿到景点列表后,发现还需要估算路线覆盖和预算。于是调用estimate_budget(景点列表, 交通方式, 天数),返回一个总预算。
  • 第4轮思考:预算超了,模型决定把其中一家海边餐厅换成平价小吃街,重算一次预算。
  • 最终:模型综合所有信息,输出一份按天排布的完整行程,并把住宿、交通、餐饮预算分别算清楚。

看出区别了吗?普通对话一步到底,Agent是多轮“想—做—看—再想”的循环。每一步都在吸收新信息,修正下一步的判断。这就是ReAct的全部秘密,一点不玄。

2.3 传统提示词方案做不到什么

我知道很多零基础的朋友会问:那我直接把“查天气”的结果写进提示词,让模型一次性生成不就行了?还真不一样。

首先,你写提示词的时候,天气数据还是空的。你得先自己去调用天气接口,拿到结果,再把结果拼进提示词里发给模型。如果这个工作需要查三个工具,你就得在主程序里写三遍“调用工具→拼接文本→再调用模型”。整个流程硬编码在代码里,每增加一个工具,都要改主程序逻辑,复杂度随工具数量线性爆炸。

而ReAct是让模型自己决定下一步调用哪个工具。主程序只需要提供一个“工具列表”和一个“循环控制”,模型就能动态规划:先查天气还是先查景点,由它根据当前阶段决定,而不是由你把每一步写死。这就是为什么Agent框架适合做开放式任务,传统提示词方案只适合做流程固定的任务。

为了让你更直观地感受这个区别,我把两种方案的流程对比如下:

维度传统提示词方案ReAct智能体方案
信息获取方式预先手动拼装工具结果到提示词模型运行时自己决定调用工具
增加新工具需要改造外层代码逻辑只需注册一个新工具函数
任务灵活性适合一次性固定流程适合多步骤动态规划
可观测性中间过程不透明每一步思考可记录、可调试

看完这张表你会发现,ReAct并不是在解决“模型聪明不聪明”的问题,而是在解决“模型怎么和真实世界协作”的问题。这个认知很关键,你会少走很多弯路——我最初就把大量精力花在调模型、换更大参数的模型上,后来才意识到,瓶颈根本不在模型脑子,而在“有没有给它一双手”。

3. 环境准备与工具选型:零基础怎么搭才不会劝退自己

理解了原理,接下来就是动手前的准备了。我尽量给你一条最“低摩擦”的路径,让你在半小时内把环境跑起来,不会一上来就陷入“安装失败、版本冲突”的泥潭。

3.1 基础环境:Python和编译环境

开发Agent,目前最通用的语言是Python,建议直接装Python 3.10或以上的版本。我没让你系统学习Python才动手,你只需要能看懂最基础的函数定义、字典、列表就足够了。这篇文章里出现的代码,你完全可以先照着敲,遇到不懂的语法再查,用着用着就会了。

装好Python之后,建议把pip的镜像源配好,否则下载依赖包的速度会很折磨人。这一步网上教程很多,花两分钟配好,后面能省不少事。

3.2 选型问题:为什么我推荐用成熟的Agent开发框架

你可能听说过“手写Agent”这个说法。零基础的人最容易产生一种冲动:既然ReAct循环原理这么简单,那我自己写一个while循环,调大模型接口,不就能控制Agent了吗?没错,理论上完全可行,而且我甚至建议你之后去手写一个看看,对理解Agent的底层非常有帮助。

但第一次做项目时,我不建议从零手写。原因有三:

  • 手写循环时,你要自己处理模型输出的解析。模型输出的是文本,里面可能夹着思考过程和工具调用指令,你要写正则表达式或JSON解析器把它拆出来,这是一个很枯燥而且容易出错的地方。
  • 处理异常太麻烦。模型可能输出一个格式错误的工具调用参数,你要自己写异常处理;工具可能报错,你要把报错反馈给模型;循环次数超了,你要自己写终止逻辑。全做完对新手来说,一个周末基本就没了。
  • 现成框架帮你把调试工具、日志、成本统计都做好了,这些对新手是救命的东西。

所以我选择用一套成熟的开源Agent开发框架,为了叙述方便,下面统一称它为“AgentKit”。它在封装了ReAct循环的基础上,把工具注册、对话历史调用、循环次数限制、运行日志都变成了配置项。零基础的人用它,一周之内做出一个能用的Agent是完全现实的。

3.3 大模型服务的接入思路

Agent的“大脑”需要一个支持函数调用(业界叫function calling或tool calling)的大模型服务。这个能力很关键,因为它允许模型在对话过程中输出结构化的“工具调用指令”,而不是一段人类阅读的自然语言文本。如果用的模型不支持这个能力,Agent就只能用“提示词约束模型,让它把工具名称和参数写成固定格式文本”的兼容方案,难度会大不少。

我当前接入的是一个通用大模型API服务,下面管它叫“LLM-Service”。你只需要在这个平台注册一个账号、创建一个API Key,并确保账户有少量可用额度就行。具体申请流程每个平台大同小异,注意两点就好:

  • 选模型的时候看清楚它是否支持function calling。大多数新一代模型都支持,旧版本的模型不一定。
  • 把API Key保存到环境变量里,不要硬编码在代码中。这能避免不小心把密钥传到公开仓库里,也方便换服务时统一修改。

3.4 三个核心工具函数的设计

设计工具函数是Agent开发里最容易忽略、但其实极其重要的一环。工具函数好不好用,直接决定模型上手的成功率。我给旅游规划Agent设计了三个工具函数,每个工具都统一成这样的格式:一个函数名、一段“功能描述”、若干个参数、一个JSON格式的返回值。

  • get_weather(city, date_range):查询指定城市未来几天天气。返回每天的温度、天气状况和出行建议。
  • get_hot_spots(city, category=None):查询城市的景点列表。可按“室内”“自然风光”“历史人文”等类别筛选。返回景点名称、简介、建议游玩时长和门票价格。
  • estimate_budget(days, transport_mode, accommodation_level, include_meals=True):估算一个行程的基础预算。返回交通、住宿、餐饮、门票的分项费用和总预算。

这三个工具恰好覆盖了旅游规划最核心的三个信息维度:天气影响行程内容、景点决定路线、预算约束整体方案。把这三个函数写好,Agent就有了“感知真实世界”的基础。

我建议你在定义工具函数时有一个原则:永远不要只返回“数据”,要返回“带语义的结论”。什么意思?get_weather如果只返回“降水概率60%”,模型就得自己判断这个数字对旅游行程意味着什么;但如果你在返回值里加上“建议:降雨天优先安排室内场馆”,模型拿到之后就能直接利用这个信息,行程合理性一下子提高不少。这个经验之后你写任何工具都适用。

4. 一步步搭起旅游规划Agent:核心代码与运行过程

这一章我们进入实战。我会带你把工具函数、Agent初始化和一次完整对话跑通,全部代码都是可以直接复制的结构。我会在每段代码后解释关键点的设计意图。

4.1 先写三个工具函数

我先把前面设计的三个工具函数用Python写出来。为了让零基础的朋友更好理解,返回值我故意设计成方便模型读取的结构化字典格式:

def get_weather(city: str, date_range: list[str], api_key: str = None) -> dict: # 真实项目中这里会调用天气服务的API # 示例返回模拟数据,实际开发时替换成实时接口 weather_data = { "city": city, "daily": [ {"date": date_range[0], "condition": "小雨", "temp": "22-26°C", "tip": "有降雨,适合安排室内场馆或博物馆"}, {"date": date_range[1], "condition": "晴", "temp": "24-30°C", "tip": "户外活动首选日,海边步道和沙滩体验佳"}, {"date": date_range[2], "condition": "多云", "temp": "25-31°C", "tip": "适合爬山、逛古镇等轻度户外活动"} ] } return weather_data def get_hot_spots(city: str, category: str = None) -> dict: # 项目演示用模拟数据,替换为真实接口即可 all_spots = [ {"name": "蓝湾海滨栈道", "category": "自然风光", "duration": "2-3小时", "ticket": 0, "tip": "晴天傍晚景色最佳"}, {"name": "云岭古镇", "category": "历史人文", "duration": "3-4小时", "ticket": 60, "tip": "适合多云天气,主街保存完整"}, {"name": "城市海洋馆", "category": "室内", "duration": "2小时", "ticket": 120, "tip": "雨天首选,互动性强"}, {"name": "望海登山道", "category": "自然风光", "duration": "3小时", "ticket": 0, "tip": "天气晴朗时视野极佳"} ] if category: all_spots = [s for s in all_spots if s["category"] == category] return {"city": city, "spots": all_spots} def estimate_budget(days: int, transport_mode: str, accommodation_level: str, include_meals: bool = True) -> dict: # 这里做的是快速估算,真实项目里可以接入具体价格数据 transport_cost = {"高铁": 800, "飞机": 1500, "自驾": 600}.get(transport_mode, 800) hotel_cost = {"经济": 200, "舒适": 400, "豪华": 800}.get(accommodation_level, 400) meal_cost_per_day = 150 if include_meals else 0 budget = { "transport": transport_cost, "hotel": hotel_cost * days, "meals": meal_cost_per_day * days, "tickets": 500, "total": transport_cost + hotel_cost * days + meal_cost_per_day * days + 500 } return budget

这些函数本身逻辑并不复杂,真正关键的是函数名和参数名要起得清晰,方便模型理解。我见过很多新手把函数名写成缩写,比如get_w、get_hs,结果模型经常用错——不是模型笨,而是你的“武器库”标签太模糊了。永远把工具函数当作给一个看不见的协作者用的说明文档来写。

4.2 初始化Agent并注册工具

接下来是Agent初始化的部分。在AgentKit里,整个流程可以归纳为三个步骤:加载模型、注册工具、创建循环。

from agentkit import AgentKit, LLMSession from tools import get_weather, get_hot_spots, estimate_budget # 1. 初始化大模型会话 llm = LLMSession( api_key=os.environ["LLM_API_KEY"], model="llm-service-tool-v1", # 该模型支持function calling temperature=0.3 ) # 2. 创建Agent实例并注册工具 agent = AgentKit( llm=llm, tools=[ get_weather, # 直接传入函数对象,框架自动提取函数名和文档字符串 get_hot_spots, estimate_budget ], system_prompt=( "你是一位资深的旅游规划师,擅长根据天气、景点和预算信息" "为游客安排合理的行程。你的原则是:" "先收集必要信息,再给出方案;天气不适合户外时优先室内安排;" "预算优先保证住宿和交通,再安排门票和餐饮。" ), max_iterations=8 )

有几个设计细节我想单独说明。temperature设置成0.3,是为了让模型在生成时偏向稳定和理性,而不是自由发挥——做规划类任务,太高的“创造力”只会带来不靠谱。system_prompt里那段话不是装饰品,它其实在塑造Agent的“决策偏好”。比如我特意写了“雨天优先室内”,这是查天气之后模型做景点筛选时最重要的决策依据。

max_iterations=8是给整个ReAct循环设了一个天花板,防止在某些特殊情况下模型陷入“反复思考、不断调用工具”的死循环。这个值在调试时特别有用,后面讲踩坑我会再用到。

4.3 跑一次完整的ReAct会话

初始化完成后,向Agent发起用户请求,循环就会自动启动:

user_query = "我从江城市出发去滨海市玩三天,预算3500元,高铁往返,住舒适型酒店,帮我把行程安排好。" response = agent.run(user_query) print(response)

AgentKit会在后台执行一串这样的过程:

第1步,模型收到用户查询后,把任务拆解为多个信息需求:“需要天气信息”和“需要景点信息”,于是它发出第一个工具调用请求get_weather。框架解析请求,执行函数,拿到天气数据回传给模型。

第2步,模型看到未来三天有雨有晴有多云,结合系统提示词里的决策偏好,发起了第二个调用get_hot_spots,而且它聪明地先按“室内”类别筛选了第一天的备选地,再按“自然风光”类别筛选后两天的景点。

第3步,模型调用estimate_budget,估算总费用。第一次测算结果是高铁800元,酒店400元乘以3晚,餐饮450元,门票估算500元,总计3550元,超出预算50元。模型发现超支后,给出结论:“可以将海洋馆换成免票的海滨栈道,门票预算砍掉120元,总预算降至3430元,满足用户要求。”

第4步,模型不再需要新信息,进入“总结答案”阶段,把所有信息组织成一份按天排列的行程表输出。

这个过程你会在AgentKit的日志面板里完整看到。我强烈建议你跑通之后认真读一遍日志——它比任何教程都能让你直观感受到“模型是怎么一步步决策的”。很多时候你觉得Agent“不够聪明”,看日志就会发现,其实是工具返回的数据语义不够明确,导致模型没能在正确时机利用信息。

4.4 一份完整的输出示例

上面这个案例最终会输出一份大概长这样的行程:

第一日的安排是:下午抵达滨海市后先入住酒店,随后前往城市海洋馆。因为当天预报有小雨,海洋馆作为室内项目完全不受影响,门票120元,游玩时间约两小时,晚餐选择酒店附近的小吃街,人均消费约60元。

第二日天气放晴,安排早上走蓝湾海滨栈道,免费,傍晚看日落效果最佳。午后可以顺路去附近的沿海公园,之后在滨海路吃海鲜晚餐,这一晚餐饮预算放宽到200元。

第三日多云,安排云岭古镇半日游,门票60元,古镇主街保留完整,适合拍照和买手信。下午返回江城,建议预留出高铁站候车时间,午餐古镇附近简餐即可。

输出虽然看起来只是一段话,但它背后是多次工具调用和信息修正之后的结果。零基础的朋友到了这一步,已经完成了一个真正意义上的Agent应用——包含了思考、工具感知、动态规划和最终生成,并且有清晰的扩展空间。

5. 跑通之后,最容易踩的四个坑

作为一个做了不少类似项目的人,我可以负责任地说:第一次写Agent,跑通是很快的,真正耗时间的是处理各种“看起来没什么问题但效果很差”的情况。我把自己的踩坑经历整理成四个典型的坑,每个都给出完整的排查链路。你看完之后可以省下大量无头绪排查的时间。

5.1 模型不按预期调用工具,或者参数乱传

我第一次让Agent跑旅游规划时,遇到的第一个问题就是模型偶尔会自己编造天气,完全不调用get_weather。日志里显示的思考过程是“根据我的知识,滨海市夏季通常是晴天”,然后就直接进入生成行程阶段。

排查链路是这样的:我先怀疑是不是工具没注册成功,检查代码后发现注册没问题。接着我看模型发出的调用请求,发现它有时候确实会正确调用get_weather,但偶尔不调用。我又检查system_prompt,发现里面只说了“你是一位旅游规划师”,没有明确要求“必须使用工具获取实时信息”。问题就出在这里。

解决办法是,在系统提示词里明确加上一条硬性规则:“在任何情况下,你必须先调用get_weather和get_hot_spots获取实时信息,禁止凭借自身记忆编造天气和景点数据。只有在工具调用失败时,才能声明信息不足。”加完之后,模型基本每次都乖乖先查工具。后来我形成了一条经验:系统提示词里写“你具备什么能力”远远不如写“你必须做什么、禁止做什么”有效。

另一个相关问题是参数乱传。比如模型在调用get_weather时把城市参数写成“海边城市”,或者date_range传了一个不存在的日期格式。这时候不用急,先看一眼工具函数描述是不是写得太简略。在工具函数的文档字符串里把参数格式完整写出来,比如“date_range参数格式为YYYY-MM-DD的字符串数组”,模型的调用准确率会提高一大截。

5.2 Agent陷入无限循环,来回调用工具

第二个坑来得比第一个更隐蔽。坦白说,大多数模型在复杂任务里会“想太多”。有一次我的Agent在规划过程中反复在“查景点”和“查天气”之间来回横跳:查完景点发现天气不匹配,调整日期之后重新查天气,查到天气后又重新筛选景点,再来一轮……好像永远都找不到一个满意解。

这个问题的根因是模型的目标函数里没有“终止条件”。它不知道“达到什么水平可以收手”,于是默认追求“再优化一下”。日志看起来就是一连串“Action: get_hot_spots → Observation → Action: get_weather → Observation → Action: get_hot_spots……”循环往复。

排查的方式很简单:我给Agent加了一个硬性上限max_iterations=5,跑一轮发现它5步内根本完不成任务。这说明不是死循环配置问题,而是它的执行路径效率太低。我又调整系统提示词,增加“你应该在收集到天气、景点、预算三方面关键信息后立即输出行程,不要过度重复查询。”同时在工具描述里增加了“该城市未来三天天气”这种明确的语义,让查一次就能覆盖三天,而不是一天一天地查。

这两处调整之后,原本动辄8-10步的流程被压缩到了4-5步以内。经验总结:如果你的Agent总是超过5步才完成简单任务,不要急着加max_iterations,先检查是不是工具粒度太碎或者决策偏好缺失。用“限制迭代次数”来硬止损,只是把问题掩盖了。

5.3 上下文越滚越大:响应变慢、费用悄悄上涨

第三个坑可能一开始感觉不到,等感觉到了已经花了冤枉钱。ReAct模式有一个天然问题:每调用一次工具,模型和工具之间的一轮“思考—观察”对话都会追加到上下文历史里。随着工具调用次数增多,历史越来越长,每次新请求要处理的Token数量也随之膨胀。

直观的表现是:前几轮对话很快,到了后面几轮,模型响应越来越慢,费用曲线迅速变陡。我跑一个复杂任务时,上下文Token量一度达到初始的十倍不止。

排查之后,我的解决方案分三层。第一层是精简工具返回值:get_weather返回的数据不要把所有实时信息都堆进去,只返回Agent规划所必需的关键指标,比如天气、温度、建议;查景点时如果默认返回20个景点,模型根本处理不过来,我会加上limit参数,只返回前5个,并允许模型按条件继续查询。

第二层是使用缓存。在同一天内,同一个城市的天气结果基本不变,我在工具函数内部加了简单缓存,相同参数重复调用时直接返回上次结果,不再请求外部接口。这省下了大量无关的重复信息。

第三层是对于超长历史,做一次上下文裁剪。ReAct模式的“最近几轮信息”通常比最开始的内容更关键。框架有历史管理的钩子,我会在轮次超过一定数量时,把最久远的“思考—观察”对压缩成一行摘要放进上下文,而不是全部丢弃。这个做法能在不影响效果的前提下大幅缩短Token长度。

5.4 工具返回了无数据,模型却硬编结果

最后一个坑很滑稽但也最常见。某次我故意把天气接口返回为空值,想测试Agent的容错能力,结果发现模型在拿到空数据之后,仍然“面不改色”地输出了一份完整行程,还写了“滨海市明日晴转多云”。这说明模型在生成时,会默认结合自身记忆来补全缺失数据,这是它的固有倾向。

排查后的修复方法是:在工具返回信息里明确加入一个“data_status”字段,当数据缺失时标记为“unavailable”,同时在系统提示词里写清楚:“如果天气工具返回unavailable,你必须明确告知用户暂时无法获取天气信息,并基于历史同期气候提供备选建议,禁止编造实时天气数据。”

这里涉及一个很重要的理念:模型的“补全倾向”是双刃剑。在信息充足时,它能帮你填充合理的细节;在信息缺失时,它则会编造事实。你要做的不是咒骂模型为何生造,而是设计一套机制,让它“面对缺失时有明确的替代路径”。工具函数的返回值、系统提示词、异常处理逻辑,三者要配合得足够精确,才能把幻觉压到最低。

6. 从“能跑”到“好用”:我沉淀下来的优化手段

跑通了、也避坑了,这时候Agent已经能完成基本的旅游规划任务。但如果想让这个项目真正变得实用,从“演示Demo”升级到“能真的帮到人”,还有几个优化手段值得做。我按性价比从高到低排序讲。

第一招,给行程输出加上结构化字段。模型直接输出一大段文本,展示起来不方便,也难做后续处理。我调整了生成阶段的任务:让模型先输出一个JSON格式的行程结构,比如包含daily_plan数组,每一天下面有morning、afternoon、evening三个字段,再针对每一天写一段自然语言描述。这样前端拿到JSON可以直接渲染,后续做“重新安排某一天”的功能也方便很多。

第二招,加入用户偏好参数。原版Agent只能处理用户临时提出的需求,缺少记忆能力。我给系统提示词增加了“在行程中主动询问并记录用户偏好,包括饮食忌口、步行强度偏好、亲子需求等”的引导,并将这些偏好以持久化方式存储。下一次用户再来时,Agent会先读取历史偏好再进行规划。这个改动让整体的体验感提升十分明显,现实中使用的人也更愿意继续用下去。

第三招,增加“行程校验器”。我们总说模型不是人,它容易犯一些低级错误——比如安排两个相距很远的景点在相邻时段,或者安排一个周一闭馆的博物馆。我的做法是写了一个名为verify_route的工具函数,它接收模型生成的行程草稿,然后检查每个景点之间的通勤时间、开放时间合理性,如果发现问题,就返回修改建议,让模型根据建议重新调整。这其实是对模型“自检能力”的一个外部兜底,效果相当好。你也可以针对具体场景写类似的校验器,比如预算校验器、交通衔接校验器。

第四招,控制生成风格的稳定性。旅游规划写作风格是否统一,直接影响用户对产品专业度的感知。我建议在系统提示词里给出一个“段落模板范例”,让模型严格按示例风格输出。别小看这一件事,实际体验差异很大——没有模板的模型写出来的行程,一会儿像攻略公众号,一会儿像朋友闲聊,观感非常不稳。

做完这些优化之后,这个旅游规划Agent已经不再像一个初学者练手项目,而是有可用性的应用了。我常常跟人说,学AI大模型应用开发,不能只看课程、只读文档,必须亲手把一个项目从零推到可用的状态,中间的每一个决策、每一次试错、每一轮日志阅读,才是真正长在身上的东西。

如果你也想动手练这个项目,我的建议是从最小版本出发:三四个工具函数、一个Agent循环、一份系统提示词,先跑通,再逐步加偏好、校验器、缓存这些复杂功能。中间遇到问题时,优先看日志——日志里记录着模型每一次工具调用的依据,顺着它,绝大多数问题都能定位到根因。

相关新闻

零售柜商品检测实战:YOLOv5到YOLOv8多版本训练与PySide6界面集成

零售柜商品检测实战:YOLOv5到YOLOv8多版本训练与PySide6界面集成

做零售柜商品检测这个项目,表面上看是“调一个YOLO模型跑起来”那么简单,真正动手之后才发现,从数据采集、标注策略、模型选型到桌面端界面集成,每一环都是坑。这篇就把我实际搭建这套基于YOLOv8/YOLOv7/YOLOv6/YOLOv5的零售柜商品…

2026/10/21 5:05:01 阅读更多 →
iOS屏幕尺寸适配全解析:从逻辑分辨率到安全区与Auto Layout实战

iOS屏幕尺寸适配全解析:从逻辑分辨率到安全区与Auto Layout实战

iPhone屏幕尺寸这个话题,很多刚开始做iOS开发的同学觉得没什么好讲的:不就屏幕变大变小吗?但实际真刀真枪上手做适配时,才发现这里面的水比想象中深得多。同一个UIView,在旧机型上稳稳地贴在底部,到了带灵动…

2026/10/21 5:05:01 阅读更多 →
书匠策AI辅助课程论文写作全流程实战指南

书匠策AI辅助课程论文写作全流程实战指南

写课程论文这事儿,说难不难,说简单也真不简单。尤其是到了大三、大四,专业课一门接一门,每门课期末都要交一篇几千字的课程论文,选题要新、结构要稳、文献要全、格式还得规范。光是想想就头大。我之前写过几篇&#xf…

2026/10/21 5:05:01 阅读更多 →

最新新闻

AI信息挖掘实战:从提问到交叉验证,把碎片信息串成认知

AI信息挖掘实战:从提问到交叉验证,把碎片信息串成认知

元旦的钟声刚敲过,我猜不少人正把“新的一年多学点东西、把手头的事做精”写进计划表。这几天我发现一个很有意思的现象:大家不是不想查资料,而是被资料淹没了。打开浏览器想看某个行业的最新动态,结果十条链接里八条是去年的&…

2026/10/21 5:48:18 阅读更多 →
从SLAM到AMCL:自制差速机器人地图导航模块实战解析

从SLAM到AMCL:自制差速机器人地图导航模块实战解析

lingbot-map 这个名字听起来像某个开源仓库的代号,其实是我给自制的差速移动机器人开发的一套完整地图与导航模块。项目核心就一句话:让一台只会上电转圈的底盘,变成能在办公室和家里自主巡航的机器人。它由三个子功能组成——离线建图、在线…

2026/10/21 5:48:18 阅读更多 →
Python语法基础精讲:变量、缩进与运算符优先级实战避坑指南

Python语法基础精讲:变量、缩进与运算符优先级实战避坑指南

简介:这份PPT课件面向Python零基础学习者与编程入门教学场景,系统梳理第2章Python语法基础的核心知识框架。内容围绕变量与数据类型展开,涵盖整型、浮点型、复数、布尔、字符串、列表、元组、字典、集合等类型,并延伸至标识符命名…

2026/10/21 5:48:18 阅读更多 →
互联网医院管理制度文档编写指南:从制度条款到系统代码的落地实践

互联网医院管理制度文档编写指南:从制度条款到系统代码的落地实践

简介:这份文档面向医院管理者、信息科人员及互联网医疗从业者,系统梳理了互联网医院从组织架构到具体业务规范的完整制度框架,可用于制度建设参考、合规自查或岗位培训。压缩包内为1个doc文件,约176KB,内容以制度条文与…

2026/10/21 5:48:18 阅读更多 →
kubeadm 安装 Kubernetes 集群完整指南:初始化、加入节点与排障

kubeadm 安装 Kubernetes 集群完整指南:初始化、加入节点与排障

经常有人问我:“想自己搭一套 Kubernetes 集群,到底从哪下手?”我一般都会回复一句话:先把 kubeadm 用熟,再谈别的。kubeadm 是 Kubernetes 官方维护的集群引导工具,它的目标就是让你别在节点初始化、证书签…

2026/10/21 5:48:18 阅读更多 →
MediaSoup SDP协商详解:ICE、DTLS与RTP参数三层拆解

MediaSoup SDP协商详解:ICE、DTLS与RTP参数三层拆解

做WebRTC服务端的时间长了,你会发现SDP协商是所有“看起来简单、跑起来折磨”的问题里最典型的一个。文本就那么几行,但每一行都对应着一段连接的生命周期。MediaSoup的SDP协商尤其有意思——它并没有像传统服务器那样去解析和重写SDP文本,而…

2026/10/21 5:47:17 阅读更多 →

日新闻

统一内存+量化:锐龙AI Max PRO 400如何本地跑320B大模型

统一内存+量化:锐龙AI Max PRO 400如何本地跑320B大模型

这段时间硬件圈和AI圈都在传一个事:AMD锐龙AI Max PRO 400系列把最高192GB统一内存搬进了PC形态的产品里,按宣传口径,本地跑320B参数的大家伙不再是纸面概念。我第一反应倒不是“内存真大”,而是这话背后的含金量——它把过去只能…

2026/10/21 0:00:11 阅读更多 →
AI助手深度使用体验:对话质量、长文本处理与指令遵循如何留住用户

AI助手深度使用体验:对话质量、长文本处理与指令遵循如何留住用户

1. 从“封号重开”这个行为说起:用户到底在追求什么“封号重开”这四个字,放在任何产品语境里都带着一股决绝的味道。一个账号从零开始积累使用记录、调教偏好、沉淀工作流,背后是大量的时间和精力成本。正常情况下,没有人愿意主动…

2026/10/21 0:00:11 阅读更多 →
ROS中YOLOv3工程落地:通信同步、坐标变换与性能调优

ROS中YOLOv3工程落地:通信同步、坐标变换与性能调优

1. 为什么在ROS里硬刚YOLOv3不是“炫技”,而是工程落地的必经之路我第一次在某高校机器人实验室看到那台搭载Jetson TX2的移动底盘原地打转、反复识别错垃圾桶时,就意识到:单纯跑通darknet_ros demo和真正让YOLOv3在ROS里“干活”&#xff0c…

2026/10/21 0:00:11 阅读更多 →

周新闻

基于GMM的语音识别系统原理与MATLAB实现详解

基于GMM的语音识别系统原理与MATLAB实现详解

说到基于高斯混合模型(GMM)的语音识别系统,很多人第一反应就是一堆数学公式,觉得门槛很高。但如果你真的在MATLAB里把它落地跑通,会发现核心其实就是三件事:把声音变成特征向量,用GMM给每个类别…

2026/10/20 10:02:13 阅读更多 →
数字图像处理入门:反白、灰度化、调色板修改与导出txt实践

数字图像处理入门:反白、灰度化、调色板修改与导出txt实践

数字图像处理这四个字听起来挺唬人,但落到具体操作上,无非就是让计算机按你的想法“摆弄”像素。我在一个模拟项目X里用了一套特别经典的基础处理流程:对图像做反白、改调色板、彩色转灰度,最后把像素数据导出成txt文件。单看每一…

2026/10/20 20:43:59 阅读更多 →
机器人大脑技术盘点:具身智能的感知、决策与数据闭环

机器人大脑技术盘点:具身智能的感知、决策与数据闭环

如果你的信息流最近也天天刷到“机器人大脑”这个词,你会发现一个很有意思的现象:每个人说的“大脑”根本不是同一个东西。有人指的是大语言模型,有人指的是运动控制系统,还有人指的是能理解物理世界的端到端模型。在2026年这个时…

2026/10/21 4:27:17 阅读更多 →

月新闻

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/20 10:02:08 阅读更多 →
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/20 9:50:17 阅读更多 →
黑夜航拍船只数据集训练YOLOV5模型全流程解析

黑夜航拍船只数据集训练YOLOV5模型全流程解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/20 9:50:45 阅读更多 →