网站客服

Odoo 网站在线聊天为什么不是“挂个按钮就行”:访客识别、主动邀聊与坐席接力主链路讲透

很多人把 Odoo Livechat 理解成网站右下角的一个聊天按钮,但 website_livechat 实际把访客身份、聊天会话、主动邀聊、坐席绑定、历史轨迹和访客重新关联串成了一套完整机制。

网站
进阶 开发者 1 分钟阅读
0 评论 0 点赞 0 收藏 5 阅读

先说结论

Odoo 的网站在线聊天,从来不是“网页里放一个聊天浮窗”这么简单。

website_livechat 真正在处理的,是一条完整的访客沟通链路:

  • 先把网站访问者识别成 website.visitor
  • 再把聊天会话落到 discuss.channel
  • 坐席可以被动接待,也可以主动发起 chat request;
  • 访客换设备、刷新页面、从匿名变成已登录用户时,系统还要尽量把身份和会话重新串起来。

所以这个模块的核心价值,不是“能聊天”,而是:

让网站访客、客服坐席和历史上下文尽可能保持同一条业务线。

这也是为什么源码里同时出现了 website.visitordiscuss.channel、guest、operator、history 这些看起来横跨多个子系统的对象。


一、为什么 Odoo 先管理“访客”,再管理“聊天”

website_livechat/models/website_visitor.py 里,Odoo 给 website.visitor 扩展了几类关键字段:

  • 当前正在对话的坐席 livechat_operator_id
  • 访客关联的聊天会话 discuss_channel_ids
  • 有消息记录的会话数量 session_count

这说明在 Odoo 眼里,聊天并不是孤立窗口,而是附着在“访客对象”上的互动历史。

这有几个直接后果:

  1. 客服看到的不是一条消息,而是一个访客。
  2. 访客关闭窗口后,历史会话还能回挂到同一个 visitor。
  3. 后续做转化、回访、统计时,可以从 visitor 维度继续延展。

很多轻量客服工具只关心 message stream;Odoo 则更像把在线聊天做成了网站访客运营的一部分。


二、为什么“主动邀聊”本质上是在创建待激活会话

action_send_chat_request() 很值得看。

它不是简单给前端弹个窗,而是先做几件非常实在的事:

  • 检查访客当前是否已在活跃聊天中,避免重复邀聊;
  • 检查当前网站是否配置了可用的 livechat channel;
  • 把当前用户加入该频道的可服务用户里;
  • 创建 discuss.channel,并标记 is_pending_chat_request = True
  • 给该会话写入 livechat_operator_idlivechat_visitor_id、国家、展示名等上下文;
  • 必要时为匿名访客补一个 mail.guest 成员。

这里最关键的点是:

主动邀聊不是“即时发送一条前端通知”,而是“先把一条可落地的聊天会话建好,再等访客在网站端接住它”。

因此 Odoo 的主动聊天更稳定,也更适合和后续会话记录、客服工作台联动。


三、为什么访客下一次打开页面时,邀聊还能被“重新捡起来”

controllers/webclient.py 里的 _link_visitor_to_livechat() 解释了这个机制。

当网站端初始化 livechat 时,系统会去找:

  • 当前请求对应的 website.visitor
  • 同一网站 livechat channel
  • 还没结束的会话 livechat_end_dt = False
  • 已经有消息 has_message = True
  • 但仍处于待访客接收状态 is_pending_chat_request = True

如果命中,Odoo 就会把这条 chat request 重新挂回当前访客上下文,并打开聊天窗口。

这意味着什么?

  • 坐席先发起邀聊,访客不一定当场回应;
  • 访客只要继续浏览网站,系统就有机会把这条请求补挂回来;
  • 这不是纯前端临时态,而是服务端维护的“待接管会话”。

对业务来说,这个设计非常重要:

客服动作不会因为用户刷新一下页面就全部丢失。


四、为什么 Odoo 还要区分匿名 guest 和已识别 partner

源码里有一个很容易被忽视的细节:匿名访客和已登录用户的会话绑定方式并不一样。

如果访客尚未登录,系统可能通过 mail.guest 挂接到 livechat channel; 如果访客后来被识别、登录,或者 visitor 被重新 upsert/merge,Odoo 会尝试把旧会话重新关联到新的 visitor 或 partner。

比如:

  • _upsert_visitor() 会把 guest 现有 livechat channel 回写到新 visitor;
  • _merge_visitor() 会把次级访客历史合并到主访客;
  • 合并时还会把频道成员从公共访客调整成真正 partner。

这背后的产品思路很清晰:

网站沟通往往从匿名开始,但业务转化需要尽量走向可识别身份。

Odoo 不会假设用户一开始就愿意登录,但它又尽量不让匿名阶段的聊天历史白白蒸发。


五、为什么客服看到“最近访问页面”非常关键

_get_visitor_history() 会从 website.track 里抓取最近访问的页面,并在会话 store 中返回给客服端。

这不是锦上添花,而是客服效率的核心上下文。

因为对坐席来说,下面这些问题常常决定回复质量:

  • 访客刚刚看的是产品页、价格页还是帮助页?
  • 他是不是反复在某一个页面停留?
  • 这是第一次接触,还是已经来回浏览几次?

如果客服只能看到一句“你好,在吗”,判断几乎全靠猜。 而如果客服能看到最近访问轨迹,回复就会从通用客服话术,变成更像销售顾问或解决方案咨询。

这也是为什么 Odoo 不是只存 message,还要把 visitor history 一并塞进 store。


六、为什么空会话会被清理掉

discuss.channel.channel_pin() 的覆写也很有意思。

如果这是一个 livechat channel,坐席取消固定/关闭窗口,而且频道里还没有消息,系统会直接把这个空频道删掉。

这背后的逻辑非常务实:

  • 主动邀聊可能创建了会话;
  • 但如果坐席根本没真正开聊;
  • 留下一个空壳频道,只会污染后续可用状态判断;
  • 甚至会影响再次向同一访客发起邀请。

所以 Odoo 干脆把“没有实际对话内容的空 livechat 会话”视为可回收对象。

这说明它不是把 channel 当作永恒记录,而是把它当成一个要为业务流程服务的会话容器。


七、为什么 visitor last visit 会随着消息流更新

message_post() 的扩展里有个小而关键的动作:

如果消息不是由操作员发出,而是访客或系统侧发出,Odoo 会更新 visitor 的最后活跃时间。

这能带来两个实际价值:

  1. 客服列表里访客活跃度更真实。
  2. 运营判断“人还在不在页面上”时更靠谱。

这类细节虽然不显眼,但会直接影响客服体验。 因为在线聊天最大的敌人之一,就是“数据看起来在线,实际上人早走了”。


八、实施时最容易踩的坑

如果你要把 Odoo 在线聊天用于官网获客,不要只盯着按钮样式,真正容易出问题的是这些地方:

1. 网站和 Livechat Channel 没有配干净

源码明确要求网站上要有 channel_id,否则坐席连主动邀聊都发不出去。

2. 只关注客服对话,不关注 visitor 身份连续性

如果访客跨页面、跨会话、从匿名到登录的链路没想清楚,你会以为“聊天数据都在”,其实业务上下文已经断了。

3. 把主动邀聊理解成前端弹窗,而不是待激活会话

这样会低估服务端状态管理的重要性,也会误判为什么刷新后还能接住会话。

4. 忽略最近页面历史

客服效率差,往往不是不会回复,而是根本没有上下文。


最后总结

Odoo 的 website_livechat 真正解决的问题,不是“网站能不能聊天”,而是:

  • 能不能把网站访客沉淀成可持续识别的对象;
  • 能不能让客服主动发起接触,而不是只等用户先开口;
  • 能不能在匿名、刷新、重进页面、后续登录这些变化里,尽量保住会话连续性;
  • 能不能让客服带着访问轨迹去沟通,而不是盲聊。

所以如果你把它看成一个聊天插件,很容易低估它。

更准确地说,它是:

Odoo 在官网侧把“访客识别 + 客服会话 + 上下文延续”合并成的一套互动路由系统。

这也解释了为什么它在源码层面既碰 visitor,又碰 discuss,又碰 guest 与会话清理逻辑——因为真正难的,从来不是发出一条消息,而是让整条沟通链不断线。

DISCUSSION

评论区

想参与讨论?先 登录 再发表评论。
还没有评论,你可以成为第一个留言的人。