文旅Agent(三)导览Agent

文旅Agent系列第三篇,详解导览Agent的设计与实现

💬 导览Agent简介

导览Agent不是一个泛化的问答机器人,而是一个面向文化展品与场馆参观场景设计的智能导览 Agent。用户拍摄展品或提出导览问题后,系统会围绕当前展品、展厅和参观意图,联动本地知识库、多轮对话记忆与工具调用能力,完成信息理解、知识检索、讲解生成与推荐补充的完整链路。

它要解决的核心问题,不是“把某一个问题答出来”,而是承接游客在真实参观过程中的连续需求:既能解释展品背景,也能衔接同主题内容、场馆服务信息和后续参观建议。换句话说,它更像一个能够理解上下文、持续推进导览任务的文旅智能助手,而不是只做单轮问答的聊天入口。

从系统能力上看,导览Agent本质上是 LLM + RAG + Memory + Tools + Planning 的工程化组合:LLM 负责理解与生成,知识库负责提供可靠内容底座,记忆模块负责维持多轮上下文,工具模块负责补充场馆与外部信息,规划模块负责把模糊需求拆成可执行步骤。这样系统不仅知道“有什么”,还知道“现在应该查什么、调用什么、先讲什么、再补什么”。

🎯 核心定位

导览Agent的核心定位,不只是文旅知识的一站式问答入口,更是面向参观过程的智能导览中枢。它位于用户需求与底层知识、记忆和工具能力之间,负责把“游客的自然语言问题”转换成“可执行的检索、推理、调用与生成流程”,最终输出连续、可信且贴合场景的导览结果。

具体来说,它承担三层角色:

  • 展品讲解入口:围绕单件展品完成背景解释、细节补充与同主题延展,把静态图文说明升级为可追问、可延展的连续讲解。
  • 场馆咨询入口:承接开放时间、展厅分布、参观规则、活动安排等高频咨询,降低游客查找分散信息的成本。
  • 导览决策入口:结合用户兴趣、时间预算、当前展厅和对话状态,进一步提供路线、活动与内容推荐,让 Agent 从“回答问题”升级为“辅助参观决策”。

🔗 与知识库的关系

如果说导览Agent是面向游客的智能导览中枢,那么知识库就是它完成讲解、问答与推荐任务的内容执行底座。两者并不是简单的“上层调用下层”,而是深度耦合、共同完成一次导览任务的关系:Agent负责理解用户意图、组织执行流程和生成最终回答,知识库负责提供可检索、可引用、可扩展的文旅内容依据。

在这套架构里,知识库不是一个被动存放资料的静态仓库,而是导览Agent运行时持续参与决策的核心模块。用户每一次提问,不论是展品背景讲解、展厅内容追问,还是活动与路线推荐,背后都需要知识库参与内容召回、上下文补充与答案约束,帮助系统把生成结果尽可能建立在真实文旅资料之上,而不是仅依赖模型自由发挥。

从职责划分上看:

  • 知识库:负责完成文旅资料的解析、分片、向量化、索引构建与检索召回,为系统提供结构化、可搜索的知识底座
  • 导览Agent:负责接收用户问题,结合会话状态、记忆信息与工具能力,决定检索什么、何时检索、如何组织结果,并最终生成连续、贴合场景的导览回答

知识库既是“基础知识源”,又是“执行时按需查询的内容底座”。因此知识库有两个使用入口:

  • 作为主链路默认能力接入:知识库检索直接嵌入导览Agent的核心问答链路,作为回答生成前的基础步骤。这样系统在处理展品、展厅、活动等问题时,默认先从知识库中获取可靠依据,再进入后续推理与生成流程,保证回答尽量建立在文旅资料之上。
  • 作为执行阶段的工具化能力调用:当任务进入某个具体步骤时,Agent 可以按展品名、展厅名、活动主题或服务规则发起更精准的定向查询,用来补充讲解细节、校验信息边界或支撑推荐决策。这样知识库不仅服务“先查后答”,也服务“边执行边补充”。

🏗️ Agent的系统架构

导览Agent并不是一个单独的对话模块,而是一条围绕“用户输入—任务规划—知识检索—工具执行—答案生成—记忆更新”展开的完整链路。对于这个项目来说,更合适的拆法不是简单分成调度层、工具层和记忆层,而是拆成接入层、Agent 编排层、检索层、工具层、记忆层、异步事件层与底层存储层。

  • 接入层:接入层负责承接游客的拍照识别触发与文本问答请求,对外提供统一的交互入口。结合项目中的 Hertz 与 SSE,这一层更适合承担 HTTP 请求接入、参数校验、会话建立和流式结果返回等职责:用户拍摄展品或输入问题后,请求先在这里完成标准化,再进入后续 Agent 主链路。对于导览场景来说,这一层解决的是“怎么把用户请求稳定接进来,并把连续讲解自然返回出去”的问题。
  • Agent 编排层:编排层是整个系统的总控中枢,负责把游客的自然语言需求转换成可执行任务。这一层的核心职责不是直接生成答案,而是先判断当前问题属于单轮问答、连续讲解还是多步骤导览任务,再决定是否要查知识库、调用工具、读取记忆或进入重规划。也就是说,这一层真正负责的是“先做什么、后做什么、结果不够时怎么调整”。通过 Plan-Execute-Replan 模式和 ReAct 架构,利用 LLM 生成计划,协调检索、记忆和工具调用,最终组织出更贴合上下文的回答
  • 检索层:。检索层负责把文旅资料转化为模型可调用的知识能力,是回答质量的主要来源。根据简历中的项目描述,知识库已经支持 Markdown、PDF、DOCX 等多格式文档解析,并完成结构化切分、向量化与索引构建;在查询阶段采用“粗召回 + 精排”的两阶段架构:先用 BM25 + 向量检索 做初步召回,再用 RRF 融合排序,最后通过 Cross-Encoder 做 ReRank。这意味着检索层在系统里不是附属模块,而是直接参与回答生成的主链路。
  • 工具层:工具层负责补齐“知识库之外但任务执行必须要有”的能力边界。除了知识库召回本身,导览Agent还需要围绕场馆信息查询、导览推荐和外部补充查询提供工具化能力
  • 记忆层:记忆层负责把“这一次对话”与“这个用户过去的状态”接起来,是导览Agent能够进行多轮讲解和个性化推荐的关键。按照简历里的设计,这一层不是单一存储,而是 Redis + MySQL + Milvus 的异构组合:Redis 负责承接当前会话中的短期上下文和状态,MySQL 保存强事实、确定性标签等高准确数据,Milvus 负责长期偏好、历史主题和模糊语义经验的召回。
  • 异步事件层:异步事件层负责把高时延、非必须同步完成的操作从主链路中剥离出去,保证对话响应速度。使用 Kafka 驱动记忆异步更新,这意味着主链路在生成回答后,可以先把用户输入、模型输出和状态变更事件投递到消息队列,再由后台消费者完成长期记忆抽取、分类、落盘与清理。这样系统的回答速度和记忆更新速度被解耦,能够更稳地兼顾 RT 与功能完整性。
  • 底层存储层:底层存储层是整个 Agent 架构的运行基础,由 MySQL、Redis、Milvus 和 Kafka 共同构成。它们并不是孤立的中间件集合,而是围绕“强事实存储、短期状态缓存、语义召回、异步事件驱动”四类职责分工协作:MySQL 保证结构化数据的确定性,Redis 保证主链路的低时延访问,Milvus 保证语义检索与长期经验召回,Kafka 保证写路径与更新路径的解耦。导览Agent之所以能在复杂多轮场景下保持可用,本质上依赖的就是这套后端底座协同。

🧠 记忆层

💾 工作记忆

导览Agent支持工作记忆,能够记住用户最近的交互,包括问题、回答、工具调用等。这使得Agent能够根据用户 previous 的问题,生成更准确、更相关的回答。

Agent 的工作记忆,最直接的载体就是 LLM 的 Context Window(上下文窗口)。每次调用 LLM 时,我们把之前的对话历史、系统提示词、工具调用记录等信息拼接成一个 prompt 发给模型,模型就是基于这些“短期记忆”来理解当前状态并做出决策的。

所以记忆层要解决的,本质上是三个问题:

  • 当前会话怎么记:保证多轮问答中,用户刚刚说过的实体、约束和目标不会丢
  • 跨会话偏好怎么记:把真正值得长期保留的兴趣、习惯和事实沉淀下来
  • 读写链路怎么解耦:不能为了更新记忆阻塞主链路,也不能因为异步更新导致状态读旧

🗄️ 总体思路:异构记忆存储

记忆层不是单一数据库,而是一套 Redis + MySQL + Milvus 的异构存储体系。不同类型的记忆由不同组件承载,按数据确定性和访问方式划分职责,而不是全部混进一个向量库里。

  • Redis:负责会话级短期记忆,保存最近几轮完整对话、当前 Session 状态和临时兜底数据,强调低延迟与高频读取
  • MySQL:负责强事实和确定性状态,比如明确的用户画像标签、已确认约束、不可容错的结构化信息,强调准确性和一致性
  • Milvus:负责长期偏好、历史主题和模糊语义经验等非结构化内容,提供语义召回能力,用来补充跨轮次的长期记忆

⏳ 短期记忆

短期记忆的职责,是保证当前这场对话在主链路里始终连贯。这里并不追求“记住所有内容”,而是优先保住对当前任务真正重要的信息。 具体的工程实践如下:在 Redis 里维护两层结构化存储,从根源上解决核心信息丢失的问题:

  • 高频对话流缓存:固定保留最近 5-10 轮的完整原始对话,带 Session 级别的 TTL 过期时间,直接塞进 messages 数组,保证对话的上下文连贯性,这一层只负责“连贯”,不负责“核心记忆”

  • Session 级动态状态机 State:后台用轻量小模型,实时增量抽取当前会话里的关键实体、核心约束、用户身份、待办事项和偏好信息,结构化后钉死在 System Prompt 里。只要 Session 不断,这个 State 就会全程跟着对话走,永远不会被滑动窗口截断,优先级远高于普通对话内容

相比单纯依赖上下文窗口,这种方式的关键优势在于:即便轮次很多、历史消息被裁剪,系统仍然能保住“当前最重要的状态”,不会因为滑动窗口截断而丢掉核心条件。相比单纯依赖上下文窗口,这种方式的关键优势在于:即便轮次很多、历史消息被裁剪,系统仍然能保住“当前最重要的状态”,不会因为滑动窗口截断而丢掉核心条件。

📚 长期记忆

如果说短期记忆解决的是“当前对话怎么记”的问题,那长期记忆解决的就是“跨对话怎么记、怎么用”的问题。长期记忆方案,不能纯靠向量库,而是一套异构混合存储架构。不同类型的记忆,用不同的存储承载,严格划分优先级,从根源上规避幻觉风险:

  • 强事实结构化数据:用户基础信息、确定性标签等零容错数据,用关系型数据库存储。召回优先级最高,必须 100% 准确,结果不可被推翻

  • 半结构化长文本:历史对话总结、过往导览偏好、长文本需求、关键字强相关内容,用 BM25 做精确召回,召回优先级高

  • 非结构化模糊语义数据:比如讲解风格偏好、兴趣主题、隐性内容倾向等无法结构化的内容,仅做语义补充,用向量数据库存储。召回优先级最低,允许有一定误差

🔍 记忆检索

  • 查短期缓存(Redis):根据 SessionID,优先去 Redis 捞取最近 5 轮的完整对话记录,以及当前 Session 的动态状态机 State。这一步保证核心信息不丢失,对话上下文连贯

  • 查强事实标签(MySQL):根据 UserID,并发去 MySQL 查询用户的确定性画像标签,比如 interest_theme=青铜器visit_mode=亲子time_budget=2小时。这部分数据零容错,必须 100% 准确,优先级最高

  • 查经验与补充知识(Milvus 混合检索):对用户输入做意图识别,如果涉及长期偏好、历史主题或补充经验查询,就在 Milvus 中同时发起 BM25 与向量检索,两路结果返回后做 Rerank 重排和截断,只保留高相关度内容

  • Prompt 组装与大模型调用:把 MySQL 的强事实标签、Milvus 的混合检索结果按优先级塞进 System Prompt 里,把 Redis 里的短期对话塞进 messages 数组,统一格式化后,再传给 LLM 做推理生成

在主链路上,大模型只是一个“没有感情的计算 CPU”,真正的记忆提取、过滤、排序工作,全是由 RedisMySQLMilvus 这些成熟组件并发完成的,这也是控制 RT、降低幻觉的核心。

📥 记忆落盘

⚡ 异步记忆更新

记忆更新并不放在主线程同步完成,而是通过 Kafka 驱动异步落盘,把对话响应和记忆沉淀彻底解耦。主链路在拿到用户输入和模型输出后,不会等待记忆更新完成,而是先返回结果,再把需要处理的事件丢到消息队列中,由后台消费者做后续分类、抽取和写入。

  • 关键事件投递(MQ):主链路拿到用户的输入和 LLM 的输出后,直接打包丢进 Kafka,主线程立刻给用户返回结果,不做任何额外的耗时操作

  • 路由与意图分类:后台消费者线程拉取 MQ 消息,通过一个低成本的轻量小模型做判断:这句话里有没有包含需要长期记住的新事实、有没有状态变更?如果没有,直接丢弃;如果有,就解析成标准的结构化 JSON 指令

  • 异构路由更新落盘:根据解析后的指令,给不同类型的记忆路由到对应的存储做更新:

    • MySQL 更新:针对强事实状态变更,直接执行 UPDATE 操作
    • Milvus 更新:如果是长文本的历史偏好总结、讲解偏好或语义经验,重新做 Embedding 后存入 Milvus
  • 短期记忆清理:长期记忆落盘成功后,通过 ACK 机制,清理 Redis 中不必要的临时数据,释放缓存空间

🛡️ 一致性兜底

如果在异步更新的过程中,MQ 消息积压了,导致用户下一次提问时,大模型取到了旧的长期记忆,给出了错误的回复,本质上就是分布式系统里经典的“数据一致性”问题:

  • 核心兜底:会话内状态永久优先:同一个 Session 内,用户新提交的状态变更,会直接写入 Session 级 State,优先级永久高于长期记忆的旧数据。哪怕长期记忆还没更新,主链路也会优先读取 Session 内的最新状态

  • 双写缓存临时兜底:触发状态变更时,除了丢 MQ 异步更新 MySQL,同时会把新状态写入 Redis 临时缓存,设置 5 分钟短 TTL。主链路读取时优先读 Redis 临时状态,待 MQ 消费 ACK 后再清理临时缓存

  • 关键数据同步更新,非关键数据异步更新:预约场次、票务状态、已确认的时间约束这类零容错数据,直接同步更新 MySQL,不经过 MQ 异步,保证更新成功后再返回;非核心偏好走异步更新,兼顾一致性与性能

  • 版本号乐观锁 + 重试补偿机制:给用户记忆数据加上版本号,每次更新必须匹配版本号才能成功;消费失败的消息进入重试队列,同时给数据加上“待更新”标记,主链路读到标记时触发补偿查询

📋 Agent编排层

编排层是整个系统的总控中枢,负责把游客的自然语言需求转换成可执行任务。它的职责不是直接生成答案,而是先判断当前问题属于单轮问答、连续讲解还是多步骤导览任务,再决定是否要查知识库、调用工具、读取记忆或进入重规划。这也是导览Agent区别于普通对话系统的关键:系统不是每次都直接“问一句、答一句”,而是会先组织执行流程,再决定回答如何产生。

其中 Plan-Execute-Replan 放在总控层,负责“做什么”;ReAct 放在执行层,负责“怎么做”。

🧭 总控层

项目中采用 Plan-Execute-Replan 模式来组织复杂任务,它解决的是“做什么”的问题。

  • Planner(规划器):任务拆解,把用户目标拆成可执行的步骤清单,确保每个步骤清晰、有序。理解复杂目标的内在逻辑,生成结构化计划

  • Executor(执行器):步骤行动,严格执行计划中的当前第一步,调用工具完成具体任务,返回执行结果。它不负责整体规划,只专注做好眼前事

  • Replanner(重规划器):进度监理,评估 Executor 的执行结果,判断是否需要调整计划。若步骤完成且结果有效,就推进到下一步;若结果缺失或错误,就修改计划;若所有步骤完成,就终止任务并返回最终结果

这套机制非常适合文旅导览场景,因为导览问题天然具有开放性、多跳性和上下文依赖性。系统需要先理解目标,再动态决定下一步,而不是无脑把所有知识一次性拼进回答里。

  • 结构化规划解决开放式咨询Planner 把用户模糊目标拆成明确步骤,减少“回答看起来流畅但没有真正解决问题”的情况

  • 动态调整应对信息不足Replanner 能根据检索结果和工具反馈及时修正计划,避免在错误路径上持续推理

  • 多工具协同整合信息源Executor 统一调度知识库、场馆信息和联网检索等工具,把分散信息组织成一条可执行链路

在文旅场景下:

  • 计划生成(Planner):基于用户问题、当前会话状态和召回的文旅资料,生成可执行的多步骤讲解或咨询计划,替代一次性拍脑袋式回答

    • 输入:用户问题 + 会话状态 + 召回的展品/场馆资料
    • 输出:结构化计划(JSON 格式),包含步骤描述、工具调用参数、预期结果
  • 执行计划(Executor):通过集成知识库检索、场馆信息查询和联网检索工具,执行计划中的步骤,完成内容查询、信息补充和答案组织

    • 输入:结构化计划(JSON 格式)
    • 输出:执行结果(JSON 格式),包含工具调用结果、预期结果对比
  • 动态重规划(Replanner):根据 Executor 的执行结果,判断是否需要调整计划

    • 成功条件:当前步骤结果符合预期,比如已召回展品背景资料,并补齐相关展厅或活动信息,执行下一步
    • 调整条件:结果不符合预期,比如检索结果过少、用户问题发生偏移,触发计划修正,如扩大关键词范围、切换到场馆资料或活动信息查询
    • 终止条件:达到目标,比如已完成展品讲解和补充推荐,或无法继续,如需要外部系统提供更多实时信息

此模式通过规划、执行、调整的闭环,让对话Agent不只是“会回答”,而是能像讲解员一样在复杂文旅咨询中持续组织信息、解释信息和补充信息。

⚙️ 执行层

在执行层,ReAct 架构负责“怎么做”,协调检索层和LLM层,生成最终回答。

ReAct 的核心思想非常朴素:想一步、做一步、看一步,根据每一步的反馈来调整下一步的计划。ReAct 就是把这个“交替进行推理和行动”的过程形式化了。

在文旅场景下,ReAct 的核心优势是让Agent能边推理、边检索、边调整。例如用户先问“这件展品是什么朝代的”,接着追问“那同一展厅还有哪些值得一起看”,ReAct 可以先调用知识库检索展品资料,再根据结果决定是否补充查询展厅信息和推荐内容,而不是一次性把所有信息硬拼进回答里。

🔧 工具层

设计 tool 的关键,是思考对话Agent在文旅场景下到底需要哪些能力。当前工具集合主要围绕文旅问答与导览链路组织,部分工具也可以通过 MCP 方式接入:

  • 知识库召回工具:从 Milvus 中召回与展品、场馆、活动最相关的文档片段,作为对话回答的核心依据

  • 场馆信息查询工具:查询开放时间、展厅分布、服务说明、活动安排等结构化信息,为问答和推荐补充实时上下文

  • 导览规划工具:结合用户兴趣、时间约束和当前对话状态,生成更贴合场景的展厅、活动或内容推荐

  • 联网查询工具:在知识库之外仍需补充公开信息时,接入外部搜索能力,避免回答停留在封闭知识范围内


🔄 Agent的编排流程

导览 Agent 的编排核心,不是让大模型一上来直接回答,而是让它先充当任务总控:先理解用户意图,再决定要不要查知识库、读记忆、调工具,最后再组织答案输出。你的项目本身就是围绕“本地知识库 + 多轮记忆 + 工具调用”来做个性化讲解、旅行咨询与内容推荐的,所以编排目标并不是生成一段看起来合理的话,而是把游客的模糊需求稳定地拆成一条可执行链路。 具体来说,这套编排采用的是 Plan-Execute-Replan + ReAct 的组合:Plan-Execute-Replan 放在总控层,负责“这件事要怎么拆”;ReAct 放在执行层,负责“当前这一步到底怎么做”。在你的简历里,这一点已经写得很明确:系统会先把游客的模糊需求拆成景点知识检索、工具调用和结果生成等可执行步骤,再根据中间结果动态调整计划,而不是一轮 Prompt 直接硬答。 一轮典型请求进入系统后,第一步不是直接生成,而是先做任务识别和上下文装配。系统会结合当前问题、会话状态和已有记忆,判断这次请求到底属于单轮问答、连续讲解,还是需要多步骤完成的导览任务。与此同时,主链路会优先读取短期上下文和用户状态:短期对话与 Session 状态由 Redis 承载,强事实和确定性约束由 MySQL 提供,长期偏好和模糊语义经验由 Milvus 补充。这样大模型拿到的不是一堆原始历史消息,而是已经按优先级整理好的任务上下文。 在此基础上,Planner 负责生成计划。如果用户的问题比较简单,比如只问某件展品的背景信息,计划可能只包含“检索资料 → 组织讲解 → 返回结果”这几步;如果用户的问题更开放,比如“这个展厅还值得看什么”“有没有适合带小朋友重点看的”,Planner 就会把目标拆成多步,例如先查当前展品或展厅资料,再结合场馆信息和用户偏好补充推荐,必要时继续追加说明。这种编排方式特别适合文旅场景,因为用户需求天然口语化、上下文强,而且中间结果会直接影响下一步怎么走。 到了执行阶段,Executor 并不是机械跑计划,而是配合 ReAct 做“边推理、边行动、边观察”的循环。也就是说,执行器会先根据当前步骤决定要调用哪类能力:如果需要事实依据,就走知识库检索;如果需要结构化信息,就调场馆信息工具;如果需要个性化推荐,就结合用户状态和工具结果继续推进。 在执行过程中,如果某一步结果不理想,系统不会硬着头皮继续往下走,而是交给 Replanner 做动态重规划。例如第一轮检索结果太少、召回内容和当前问题不匹配,或者用户在对话中临时改变了关注点,Replanner 就会根据中间结果调整计划:扩大关键词范围、切换检索对象、补调场馆信息工具,甚至直接改写后续步骤。 这个 Agent 的编排本质上可以概括成一句话:先用 Planner 把游客问题拆成步骤,再由 Executor 结合 RAG、工具和记忆逐步执行,执行中通过 ReAct 感知反馈,必要时交给 Replanner 动态改写路径,回答完成后再异步更新记忆。 这套方式让系统不只是“能回答”,而是真正具备了在复杂文旅场景中持续推进任务的能力。

最后更新于 2026-04-17 03:08 UTC
그 경기 끝나고 좀 멍하기 있었는데 여러분 이제 살면서 여러가
使用 Hugo 构建
主题 StackJimmy 设计