
1. 先搞清楚要解决什么问题——旅行问答的独特挑战1.1 一个典型问题背后有多复杂先看一个真实用户会问的问题“我计划下周带爸妈去成都四天三晚预算五千以内怎么安排比较合适爸妈腿脚不太好不要太多走路的地方。”这类问题在传统电商客服或者搜索场景里根本处理不了。拆开看需要理解地点、时间、人数、预算、体力约束、兴趣偏好多个限定条件需要组合机票、酒店、门票、餐饮、交通多种信息还涉及实时天气、限流政策、开放时间等动态数据最关键的是回答错了代价很大——用户可能买了错票、走错路、白跑一趟。我做这个智能问答项目时核心任务就是针对“某在线旅行平台”的「问一问」功能做整体架构落地把大模型、向量检索、工具调用、规则兜底串在一起让它能稳定应对这类“一句话问出七八个需求”的场景。这篇博客我尽量把架构思路、关键实现和踩过的坑讲透适合正在做LLM应用、RAG项目或者智能客服的朋友参考也适合想了解大模型在真实业务中怎么落地的产品经理和工程师看。1.2 为什么传统方案撑不住传统检索式FAQ只能处理标准问题跟用户实际表达差得远。知识图谱覆盖面广但建设成本极高维护节奏也跟不上旅行信息的变化。纯生成式模型看着能力强但直接裸奔会一本正经地胡说八道比如告诉你某景区周一正常开放结果人家那天闭园检修。旅行场景信息变化太快航班时刻、景区政策、门票余量、天气预警全是高时效数据。模型训练时的知识根本覆盖不了“今天XX景区是否需要预约”这种问题。所以纯参数记忆路线走不通必须靠实时检索和工具调用补足。方案优点致命问题检索式FAQ实现简单、可控无法处理复合问题、覆盖率极低知识图谱问答逻辑清晰、关系准确构建维护成本高、动态信息缺失纯大模型生成理解能力强、零成本起步幻觉严重、信息时效性差RAG工具编排可控性强、时效性好工程链路复杂、需要评测体系1.3 架构设计的几个硬约束在动手之前我们明确了几条硬约束直接决定了后续所有技术选型。第一结果必须可控旅行场景答错比不答更糟糕拒绝回答也是有效回答。第二性能要在线用户等待超过3秒就会流失流式输出和首字延迟必须优化到位。第三成本要能承受不能每个问题都让最大模型跑一遍要按任务复杂度分层。第四要可监控、可降级、可灰度任何外部依赖挂了都不能让用户看到白屏。这四条硬约束里面最难执行的是第一条。我们内部讨论了很多轮最终把“诚实性”定成第一原则不确定的信息必须标注不确定没有来源的信息不允许用肯定语气。这个原则看着简单但它贯穿了提示词设计、检索阈值调节、展示层设计所有环节。2. 整体架构设计与核心链路拆解2.1 分层架构长什么样整体分为四层。接入层负责多渠道统一接入包括站内客服入口、详情页问答卡片、端内悬浮助手走的都是同一个网关方便做限流和灰度。服务层是整个系统的核心包含会话管理、问题解析、规划编排、工具调度、内容生成、校验拦截六个模块。模型层做多模型路由把“意图分类、摘要生成、正式回答、内容审核”这些任务分给不同规格的模型大模型不是所有任务都干。数据层包含静态知识库和实时数据源知识库有旅行攻略、开放政策、交通接驳、景点POI等结构化与非结构化数据。这个分层核心思想是把模型当组件不把模型当系统。服务层通过编排把各环节串起来任何一个环节都能替换、降级、观测。实测下来这套思路在稳定性上比“一个Agent全包”的方案靠谱得多因为每一层的职责单一出了问题能用指标快速定位。特别说明一下这里的「问一问」不只是单轮问答它承载了从“用户提问”到“获取答案、引导行动”的完整会话体验。所以会话管理模块专门维护了多轮上下文支持“那附近有没有便宜点的”这类带指代的追问同时控制上下文长度避免历史信息过多挤占模型的注意力。2.2 意图解析与问题拆解怎么做用户问题进来自动做四步预处理。第一步拼写纠错和指代消解把“那里”“这家”换成实际的地点或主体。第二步多意图切分旅行问题经常一句话带多个问题比如“故宫怎么预约旁边有什么好吃的”——拆成两个独立子任务否则答案一定会糊。第三步抽取关键槽位地点、出发日期、人数、预算、限制条件全部结构化输出这是后续检索和工具调用的基础。第四步判别能否回答明确超出能力范围的提问直接拦截不进入问答主流程。这里的一个关键经验是不要指望大模型一次把所有事干完让模型只做判断和抽取反而让效果更稳定。我见过很多团队把“解析、检索、生成”全塞在一个Prompt里简单问题还行复杂问题直接翻车。拆开之后每一环节都可以单独评测、单独调优出了问题能快速定位是哪一步偏了。槽位抽取的产出大概长这样{ destination: 成都, departure_date: 2025-06-20, duration: 4天3晚, budget: 5000, companions: [老人, 子女], constraints: [少走路, 不赶行程], intent: 行程规划 }这个结构化结果会被同时用于三个方向文本向量检索、实时工具参数组装、生成阶段的条件约束。没有这一步结构化后面的流程全都会跑偏。2.3 检索增强与信息融合问题解析出的槽位会转成检索条件分别向知识库和实时数据源发起查询。知识库走向量检索加BM25关键词混合召回再用交叉编码器重排这是目前RAG落地最稳定的组合。向量检索擅长语义相近的召回BM25擅长精确匹配两者互补重排器再从候选里挑最精准的结果。实时数据源通过工具调用获取比如天气接口、航班接口、票量查询。工具返回的结果会做标准化带上一段说明信息再交给生成模型。这里对检索控制比很多人想的要严格召回太杂时模型会被无关信息带偏所以我们设置了数量上限最终进入Prompt的外部片段不超过6条超过部分宁可不进。这个“宁缺毋滥”的设计是在评测阶段被逼出来的早期放开到10条准确率反而掉头向下。信息融合阶段还有一个小细节我们会给不同来源的数据打标签。知识库片段标记为“参考信息”工具结果标记为“实时数据”模型在生成时对两类信息的权重不同实时数据优先级更高因为旅行场景里“今天能不能进”比“历史攻略怎么说”重要得多。2.4 生成与自校验生成环节也不是让模型直接输出。我们采用ReAct模式让模型先列出回答依据要求答案必须引用检索到的信息不允许无依据发挥。这个思维链过程只在服务端内部执行用户看到的是最终答案不会暴露给用户。输出之后还有一道自校验关卡这是很多LLM应用容易漏掉的一步。规则校验会检查时间、电话、地址这类实体和知识库是否一致防止模型把数字或名称改错。模型返工机制在检测到可疑输出时把上下文重新交回模型修正一次设置一个返工上限防止死循环。通过不了的内容宁可给用户一个“当前信息不足建议拨打官方客服或查看官方渠道”的答案也不硬答。提示自校验不是让模型重新读一遍自己的回答而是带着“待校验实体清单”去比对。把校验任务也结构化规则负责确定事实类信息模型负责判断语义通顺比全部丢给模型靠谱得多。3. 关键技术环节的实操细节3.1 提示词模板的设计经验很多朋友问提示词怎么写效果最好其实我们的原则是模板固定化、变量最小化。所有回答类任务共用一套结构只注入必要变量绝不让模型自由发挥格式。我们沉淀了一套五段式模板角色、任务、约束、参考资料、输出格式。给一个简化过的生产级模板示例你是某旅行平台的行程规划助手。你的任务是根据用户需求和检索到的资料给出简洁、可执行的回答。 约束条件 1. 回答只能基于【参考资料】和【工具结果】禁止编造信息 2. 行程必须考虑用户明确提到的限制条件如体力、预算、同行老人小孩 3. 对不确定信息明确表达不确定性并引导用户点击官方来源 4. 如果参考资料不足以回答直接说明并建议人工渠道 参考资料 {检索片段} 工具返回 {航班/天气/票量结果} 用户需求 {解析后的槽位与问题} 回答请先给出结论再补充理由最后提供1-2个备选方案。这个模板的细节决定了质量。比如“先结论后理由”是为了适配移动端阅读习惯用户扫一眼就能拿到答案。“备选方案”是为了应对旅行场景中的不确定性用户总是希望有Plan B。我们测试过很多版本的约束措辞“禁止编造”比“不要胡说”效果好得多因为模型对否定式指令的遵从度更高。模板中还有一类隐式技巧角色名称里带上了平台名这是为了让模型在回答时主动站在平台视角提升信任度。另外我们发现模板末尾补一句“如果用户没有指定预算可以给出价格区间而不是具体金额”能显著减少模型在钱数上乱猜的概率。3.2 知识库构建与向量检索调优知识库不是随便抓点数据扔进向量数据库就完了。我们切分策略是有讲究的。攻略文章按三级标题切保证每个片段内部是一个完整主题景点条目按POI维度建独立文档同一景点的开放时间、交通方式、游玩建议放在一起政策类内容按“主体动作条件”结构化保存比如“未成年人入住需要监护人陪同”单独成条。切分做完之后每个片段都做了清洗去掉广告词、去掉与主题无关的段落、统一专有名词写法。这一步真的很重要我们早期直接拿爬来的原文做切分杂音特别多向量检索经常召回到莫名其妙的内容准确率一直上不去。清洗完之后同样参数下评测分数直接涨了快十分。Embedding模型我们最终选了商用的通用模型不是因为效果最好而是维度适中、价格便宜、降级服务多。助手的问题千奇百怪通用模型在长尾问题上更稳。向量检索的相似度阈值设了0.45召回数量Top50重排后取Top6。这个数字是拿评测集一版一版试出来的一开始Top20就够用后来发现复杂问题需要更多候选改成Top50重排后准确率提升了近10个点。3.3 工具调用与实时数据接入旅行场景的时效性信息必须靠工具不能靠模型记忆。我们建了一套轻量级工具协议每个工具三要素参数Schema、调用地址、结果处理器。参数Schema用来告诉大模型这个工具需要什么参数调用地址是实际的服务接口结果处理器负责把接口返回的JSON裁剪成模型关心的最小必要集。{ toolName: query_attraction_ticket, parameters: { attraction_id: string, 必填景点POI编号, visit_date: string, 必填游玩日期 }, returnFields: [ open_time, need_reservation, ticket_price, notice ] }工具的编排逻辑是这样的意图解析之后如果需要天气信息就走天气工具需要票量信息就走票量查询工具需要交通接驳就走交通工具。工具的调用可以并行比如一次行程规划里天气、票务、酒店三路并行请求整体延迟直接降了一个量级。工具解析器会把返回字段裁剪成最少必要集避免冗余信息干扰生成模型。我记得有一次接入一个新景区的数据结果处理器漏了字段映射模型拿到一堆乱码格式还硬着头皮生成用户反馈差得离谱。后来我们规定所有工具返回必须经过一层标准化校验格式不对的直接丢弃并降级到知识库回答。3.4 工程化能力流式输出、限流降级、超时控制上线前最怕的不是模型效果差是流量一进来系统直接打挂。我们把大模型接口和业务接口用同一套治理体系管理。首先是流式输出旅行问答的回答动辄三四百字等全部生成完再返回用户要等十秒。我们做了SSE流式输出配合端侧打字机效果首字延迟控制在几百毫秒体感直接提升一个档次。其次是超时控制。每个外部依赖接口都设置了独立的读超时整体回答链路有个整体预算超过2.5秒就自动截断生成用兜底话术返回。实测下来链路响应P95稳定在4秒以内超时兜底概率控制在极小比例。这里有个经验是宁可让用户看到“正在帮你转接人工”也不能让用户干等无响应。最后是降级策略这个设计比任何重试机制都重要。统计上工具接口持续失败会自动切换成“仅使用静态知识库”的低配模式模型服务也不稳定整体降级为人工客服入口。分级降级的好处是用户永远不会面对一个空白回答页面最差也有一个可用的出口。4. 上线前绕不开的坑——评测与治理4.1 评测集怎么建最花时间的不是写代码是建评测集。我们整理了上千条真实问题覆盖行程规划、门票预约、交通接驳、美食推荐、政策咨询六个大类每个大类又按难度分了三个等级。评测的时候用规则加人工的双盲打分从准确性、完整性、时效性、体验度四个纬度给分。评测维度具体定义打分标准准确性事实是否有依据有明确依据给满分模型臆测扣分完整性用户问题关键点是否覆盖漏掉一个关键约束扣一项分时效性动态信息是否最新使用过期数据或资料不更新扣分体验度表述是否自然、结构是否清晰专业术语卡顿、结构混乱降低分数特别建议把“拒绝率”作为一个核心指标。一个系统如果拒绝回答过多说明召回和生成能力不足如果拒绝太少说明有风险。我们通过调节相似度阈值和自校验严格度来控制这条曲线。发版之前跑一次影子评测把线上真实流量让模型对拍一遍人工抽检后评估合格才让通过灰度门槛。还有一个容易踩的坑评测集千万不能边测边建。我们早期评测集里混进了人工构造的“理想提问”结果模型上线后在真实用户的长语音、错别字、倒装句面前直接崩盘。后来全部改成从线上日志采样的真实问题才让评测有了参考价值。4.2 幻觉治理三层防御模型一本正经胡说八道是LLM应用最大的敌人必须三层防御。第一层在检索侧把不相关的检索结果尽量过滤掉发现问答片段质量差就提前隔离。第二层在生成侧通过提示词强制要求引用来源未标注语源的表述会被判不合格。第三层在展示侧涉及价格、时间、开放状态等确定性信息时要求模型必须调用工具结果并明确标注“信息来源于官方渠道”。三层防御的运行机制是这样的检索侧负责“少给垃圾”生成侧负责“少说错话”展示侧负责“少误导用户”。三个环节各有侧重三层都过不了的问题就进入兜底话术保证了系统永远对用户诚实。举一个实际例子。有用户在问某博物馆是否需要预约知识库里有一篇半年前的文章说“不需要预约”但工具返回的信息是“需提前一天预约”。按照我们设计的优先级规则工具结果比知识库片段优先模型以工具结果为准并标注“信息来自馆方实时接口”。没有这套优先级设计模型很可能把两段矛盾信息混在一起说后果就是用户白跑一趟。注意模型返工修正机制要设次数上限最多修正一次。返工并不是“多试几次就好”有时模型会越修越离谱浪费延迟还增加成本。设上限后至少保证了故障场景下的响应速度。4.3 成本与性能的平衡成本最省的地方在模型路由我们做了一个任务分级。判断用户问题是否需要大模型先让一个小模型做意图分类复杂旅行规划和大规模咨询才让大模型跑简单问题直接走检索加规则模板返回。这里的小模型和大模型不是指同一个模型的不同接口而是两类不同规格的模型小模型参数量小、速度快、便宜大模型负责质量。我们统计下来大约六成的问题由小模型加检索就能解决成本能降低很多。另外做了缓存层同一用户相同意图在短时间内直接复用上一次生成结果热门问题的命中率很高缓存命中的回答延迟直接降到几十毫秒。缓存key的设计要考虑会话维度同一用户同一问题在不同时间段结论可能不同比如门票余量、天气信息变化快缓存时长设置在5到15分钟比较合理。预热机制也值得做。每天早上把前一天的高频问题重新生成一遍缓存用户早上问的时候命中率更高。这个设计看着简单实际对成本影响很大因为上午是旅行咨询的高峰期高峰期的缓存命中直接决定了整个平台的性能曲线。5. 常见问题排查速查表5.1 线上故障排查方法做这个项目期间积攒了一堆问题排查经验整理成一张速查表分享给大家。遇到线上用户反馈问题时先别急着看模型从下往上排查可能效率更高。常见问题排查速查表现象可能原因排查方法用户说“答非所问”意图解析阶段槽位抽取错误查服务日志中的解析结果JSON看槽位是否正确模型回答明显过时知识库更新链路断了检查知识更新任务是否失败核对片段时间戳回答引用不存在的价格工具返回字段映射错误查看工具标准化结果比对原始接口输出用户等待时间过长链路中某工具超时查各环节耗时分布定位到具体接口同一问题两次答案不同缓存未生效或知识库版本不一致查缓存key设计核对知识库版本号回答里出现政治敏感内容拒答分类器漏判检查拒答规则命中情况追补违规样本5.2 四个容易忽略的隐形坑除了上面这些能直接定位的问题还有几个隐性坑值得单独提一下。第一个是指代消解过度用户说“我只想去南门那个”被系统理解成了“上海南门”后来我们在消解规则里加了地理上下文限定问题才消掉。第二个是知识库更新时用了全量重建导致向量索引短暂不可用后来的方案改成增量更新加双版切换线上再无感知。第三个是模型对数字的处理能力确实弱门票价格、开放时间这些数值类信息经常被改错为此我们在自校验环节针对数字做了专门的校验规则。第四个是多轮对话里上下文无限膨胀历史消息全部塞进去导致延迟飙升后来设置了一个“最近两轮槽位快照”的轻量上下文策略效果反而更好。这类隐形坑往往比显性报错更影响体验因为它们不会崩溃就是让回答质量飘忽不定。排查起来也没有现成告警可看只能靠用户反馈归类和周期性抽检来发现。6. 落地经验与未来演进方向6.1 从“能用”到“好用”的团队协作经验这个项目真正推进顺利起来是在产品和算法达成一致之后。我们一开始卡在“回答要不要带免责声明”这件事上产品坚持要加算法觉得会破坏体验。后来明确原则是宁可多给靠谱来源链接也不要让对话变得生硬。最终的产品形态里如果答案是检索来的会自动附上参考卡片如果是工具查的会显示更新时间戳用户能看到来源信任感自然就建立起来了。灰度节奏也很重要先内部小流量再白名单用户再全量开放。每一轮都留出足够的回滚时间线上问题优先恢复而不是现场Debug。我们的经验是灰度期间的坏消息一定是好事说明还有时间修全量上线后再被用户教育代价就大了。6.2 大模型在旅行场景还能怎么演进目前这套架构主要是“问答”下一步自然是“规划”和“预订”。让模型不只回答问题而是根据用户偏好直接生成完整行程并一键下单。这需要在工具调用、用户意图确认、支付链路上下更多功夫尤其要处理好“用户随口一说”和“用户真的要买”的区分不能把浏览当消费意向。多模态也是明确的方向用户拍一张景区实拍图问“这里是哪”旅行问答会多很多玩法。还有个性化结合用户历史订单和浏览记录回答会更贴合习惯。这些都是后续可扩展的路径但每一步都要回到“可控、可观测、可兜底”的原则上来。6.3 我在实操中的几点体会做完这个项目我最大的体会是模型能力只是起点落地能力才是真正的分水岭。旅行这个场景尤其残酷用户在一个App里问了三个问题只要有一个答得离谱信任就没了。架构设计的价值就在于把不确定性控制住把模型当组件留在系统里让每一层都有兜底、有观测、有回退。最后分享一个小技巧别把所有的宝押在一个大模型上尝试给每个环节配置不同规格的模型。我们用“小模型过滤加大模型精答”的组合成本和效果同时得到了优化尤其是意图分类这种简单任务小模型完全够用。这套思路不仅适用于旅行问答任何行业做对话式应用都可以参考。下次遇到模型翻车先想想是不是系统设计的问题不一定非得换更强的模型。