文旅Agent(三)对话Agent

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

💬 对话Agent简介

你可以把它看作是一个能够像真人一样理解问题、调用知识库并给出精准回答的中台助手。它最重要的使命就是帮助团队挡掉高频的重复咨询,加速问题解决,从而提高整体的工作效率。

简单来说,对话Agent核心就是AI+知识库的模式。它把团队中散落的文档、经验和历史数据,转化成可随时调用的活知识,让你的经验和知识不再因为人员流动而流失。

🎯 核心定位

对话Agent的核心定位是团队知识的一站式查询入口。无论是值班人员想了解某个错误码的含义,还是运维新人想查询服务接入文档,只需用自然语言提问,即可获得准确、专业的回答。主要服务场景:

  • 业务方支持

    • 传统模式:业务方→中台同学(反复提问)→手动翻文档→回复
    • Agent模式:业务方→对话Agent(自动回复)→解决不了再找中台
    • 效果:自动解答接入文档、接口规范等问题,将中台同学从人工客服中解放出来
  • 值班自救

    • 传统模式:值班人员收到告警→凌晨迷糊查手册→尝试修复→可能延误
    • Agent模式:值班人员将告警复制给Agent→Agent自动检索《故障处理手册》并推送解决方案→人工快速确认
    • 效果:在不到10秒内返回修复步骤,大大压缩了值班处理告警的时间,降低了响应延误风险
  • 工单预处理

    • 传统模式:新工单→研发逐条查看→简单问题占用时间
    • Agent模式:新工单→Agent检索历史案例库→简单问题自动回复/自动总结→复杂问题再流转给人工
    • 效果:提前过滤掉简单问题,让团队能将精力聚焦在真正需要人工解决的疑难杂症上

🔗 与知识库的关系

Agent与知识库形成底层支撑与上层应用的关系:

  • 知识库:负责文档的加载、分片、向量化和索引构建,是整个系统的数据底座
  • Agent:负责接收用户Query、调度检索、构建上下文、调用LLM生成回答,是面向用户的交互窗口

知识库既是“基础知识源”,又是“执行时按需查询的操作手册”。因此知识库有两个使用入口:

  • 作为主链路的一部分:把内部文档检索放进对话主链路,作为默认上下文注入。这样能保证 agent 默认回答就尽量基于内部文档,而不是先自由发挥再决定要不要查

  • 作为工具化查询:计划执行到某一步时,需要按告警名、服务名、错误码精准查询相关文档,以获取修复建议


🏗️ Agent的系统架构

从系统架构角度,Agent的实现可以分为以下几个部分:

  • 调度层:通过Plan-Executor模式和React模式,利用LLM生成计划,协调检索层和LLM层,生成最终回答

  • 工具层:负责调用内部工具,如知识库查询、API调用等,以获取额外的信息。同时支持外部MCP调用

  • 记忆层:负责存储和检索用户上下文,支持多轮对话

🧠 记忆层

工作记忆

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

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

短期记忆

Agent的短期记忆是在LLM的上下文窗口不够用时,提供快速的补充检索。用于存储承载当前会话的完整历史和近期(比如过去 7 天)的高频记忆。

存储方案

在 Redis 里维护两层结构化存储,从根源上解决核心信息丢失的问题:

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

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

长期记忆

如果说短期记忆解决的是"当前对话怎么记"的问题,那长期记忆解决的就是"跨对话怎么记、怎么用“的问题。

异构存储架构

长期记忆方案,不能纯向量库,而是一套异构混合存储架构,不同类型的记忆,用不同的存储承载,严格划分优先级,从根源上规避幻觉风险:

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

  • 半结构化长文本:历史对话总结、长文本需求、过往方案、关键字强相关内容,用 BM25 算法做精确召回,召回优先级高(关键字匹配准确率远超单纯向量检索)

  • 非结构化模糊语义数据:比如发散性经验、聊天风格、情绪片段、隐性偏好等无法结构化的内容,仅做语义补充,用向量数据库存储。召回优先级最低,允许有误差

记忆检索

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

  • 查强事实标签(MySQL):根据 UserID,并发去 MySQL 查询用户的确定性画像标签,比如 allergy=seafood、destination=Tokyo,这部分数据零容错,必须 100% 准确,优先级最高

  • 查经验与补充知识(ES + 向量库):对用户输入做意图识别,如果涉及历史经验查询,同时向 ES 发起关键字检索、向向量库发起语义检索,两路结果返回后,做 Rerank 重排和截断,只保留高相关度的内容

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

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

记忆落盘

异步记忆更新

采用完全异步的事件驱动架构,主线程只负责核心对话链路,记忆更新全走旁路,不影响主接口响应:

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

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

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

    • MySQL 更新:针对强事实状态变更,直接执行 UPDATE 操作
    • 向量库更新:如果是长文本的发散性经验,重新做 Embedding(向量化)后存入向量库
  • 短期记忆清理:长期记忆落盘成功后,通过 ACK 机制,清理 Redis 中不必要的临时数据,释放缓存空间

⚡ 事件驱动的惰性更新机制

在对话流中引入轻量级的意图识别,只有当识别到特定的 “状态变更”“新事实新增” 事件时,才异步丢进 MQ,触发记忆的解析和落盘。这套方案,能把记忆更新的算力成本降低一个数量级,同时彻底避免了无效的存储读写,这就是后端架构里经典的 “读写分离、惰性更新” 思想,在 Agent 领域的完美落地。

🛡️ 一致性兜底

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

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

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

  • 关键数据同步更新,非关键数据异步更新:过敏史、手机号、安全禁忌这类零容错数据,直接同步更新 MySQL,不经过 MQ 异步,保证更新成功后再返回;非核心偏好走异步更新,兼顾一致性与性能

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

规划层

Agent采用Plan-Executor模式配合ReAct架构,通过LLM生成计划,协调检索层和LLM层,生成最终回答。

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

总控层:

在运维Agent替代人工处理告警排查的需求中,传统人工方式存在四大痛点:

  • 流程无结构化导致效率低下:人工排查依赖经验,新人易步骤混乱(如告警时不知先查日志还是监控)

  • 动态异常应对能力弱:人工遇到无结果场景(如日志无异常)易停滞

  • 数据孤岛跨系统联动麻烦:人工需在日志、监控、告警群间切换

而Plan-Execute-Replan模式完美匹配运维Agent的需求特性:

  • 结构化规划解决流程混乱:Planner将模糊需求转化为清晰步骤,对应人工步骤无序的痛点

  • 动态调整应对异常场景:Replanner的反馈环可实时校准方向,解决人工停滞问题

  • 组件协同打破数据孤岛:Executor统一调用工具,实现跨系统联动,对应人工跨平台切换的低效

Plan-Execute-Replan也靠三个核心智能体(Agent)协同:

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

  • Executor(执行器):步骤行动,严格执行计划中的当前第一步,调用工具(数据库、计算器、API等)完成具体任务,返回执行结果。准确调用工具、处理单步任务(不负责整体规划,只专注做好眼前事)

  • Replanner(重规划器):进度监理,评估Executor的执行结果,判断是否需要调整计划。判断任务进度、识别执行问题、动态优化计划:

    • 若步骤完成且结果有效:推进到下一个步骤
    • 若结果缺失/错误(如数据不全、工具调用失败):修改计划(补充步骤、调整顺序)
    • 若所有步骤完成:终止任务,返回最终结果

在运维场景下:

  • 计划生成(Planner):基于告警类型和召回的运维手册,生成可执行的多步骤排查计划,替代人工凭经验梳理流

    • 输入:告警信息(alertname、description)+召回的处理文档
    • 输出:结构化计划(JSON格式),包含步骤描述、工具调用参数、预期结果
  • 执行计划(Executor):通过集成监控/日志工具,自动执行计划中的步骤,替代人工查日志/查监控的操作

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

    • 成功条件:当前步骤结果符合预期(如步骤1返回error日志,步骤2明确原因为context cancel),执行下一步
    • 调整条件:结果不符合预期(如日志查询无结果),触发计划修正(如扩大时间范围、更换关键词)
    • 终止条件:达到目标(如确认下游发版导致临时超时,无需处理)或无法继续(如需人工介入下游沟通)

此模式通过规划-执行-调整的闭环,让运维Agent像资深工程师一样高效处理告警,成为替代人工的核心方案。

执行层

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

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

在运维场景下,ReAct核心优势是让Agent能实时决策、动态调用工具,处理需要外部信息支撑的复杂问题。例如对话Agent中,用户问某个reqid的error日志,ReAct能拆分步骤并调用日志工具获取日志信息。

工具层

设计tool就是要思考Agent需要哪些功能。目前的工具集合包含以下工具:

  • 知识库召回工具:从向量数据库中召回最相关的份片段

  • 日志查询工具:日志查询是通过腾讯云日志平台的MCP实现的,他们的MCP支持用自然语言查询日志

  • 告警查询工具:对接监控系统的/alerts接口,直接获取当前活跃告警信息提供实时时间信息

  • 联网查询工具:集成外部搜索引擎,让大模型也有搜谷歌的能力


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