协同办公

Odoo Live Chat 为什么会先让机器人接待、再把访客转给坐席:chatbot 接管与 operator 路由链路讲透

很多人以为 Odoo Live Chat 只是“访客进来后随机分给一个客服”,但官方源码实际把机器人脚本、坐席可用性、会话重启和人工接管拆成了多层链路。看懂这些边界,才能解释为什么有的访客先收到机器人问题,有的却直接落到人工坐席。

协同办公 网站
进阶 开发者 2 分钟阅读
0 评论 0 点赞 0 收藏 5 阅读

先说结论

Odoo Live Chat 并不是“访客一进来,系统随便挑个在线客服”。

源码里的真实设计更像三段式:

  1. 先判断这条渠道能不能接待:有没有 chatbot,或者有没有可用坐席;
  2. 如果配置了 chatbot,就优先让脚本充当第一接触层
  3. 只有在需要人工介入时,才进入 operator 选择逻辑,并且这个选择不是简单随机,而是尽量避开忙碌坐席、通话中的坐席,以及不匹配语言/国家/专长的人员。

所以你在现场看到的“同一个 Live Chat 渠道,有时先机器人,有时先人工,有时重开对话后流程又不一样”,基本都不是玄学,而是源码设计使然。


这篇主要看哪里

核心源码在:

  • addons/im_livechat/models/im_livechat_channel.py
  • addons/im_livechat/models/discuss_channel.py

重点方法:

  • im_livechat.channel._get_operator_info()
  • im_livechat.channel._get_operator()
  • im_livechat.channel._get_less_active_operator()
  • discuss.channel._chatbot_find_customer_values_in_messages()
  • discuss.channel._post_current_chatbot_step_message()
  • discuss.channel._chatbot_restart()
  • discuss.channel.livechat_join_channel_needing_help()

这几段组合起来,基本就是“访客进入 → 机器人提问 → 记录答案 → 需要人工时挑选坐席 → 会话重开或转接”的主链路。


第一层:渠道是否可用,先看的是“机器人或人工”二选一

im_livechat.channel 里有一个很关键但容易被忽视的判断:

  • _is_livechat_available() 返回的是:有 chatbot,或者有可用 operator,就算渠道可用

这意味着:

在 Odoo 的产品设计里,chatbot 不是人工客服的附属物,而是可以单独构成“渠道可接待能力”的第一层。

这也是为什么某些站点明明没客服在线,Live Chat 按钮仍然能亮:

  • 不是系统误判;
  • 而是该渠道还有 chatbot 可以先接住访客。

如果你把“在线可接待”理解成“必须有人类坐席在线”,你会误判很多现场问题。


第二层:谁先接待,取决于 _get_operator_info() 的优先级

_get_operator_info() 的作用不是单纯“找个 operator”,而是先决定本次会话由哪种 operator model 接管

它大致做了两步:

情况 A:规则里指定了 chatbot script

如果传入的 chatbot_script_id 在该渠道规则允许的脚本列表里,源码会:

  • sudo 读取 chatbot script;
  • 切到 chatbot 对应语言上下文;
  • operator_partner 指向 chatbot 的 operator partner;
  • 并把 operator_model 标为 chatbot.script

这说明 Odoo 的想法很明确:

机器人并不是“假装成系统消息”的特殊分支,而是一个真正进入 operator 选择层的接待主体。

情况 B:没有 chatbot,或者当前流程不再由 chatbot 接管

这时才调用 _get_operator() 去找真人坐席,并把 operator_model 标成 res.users

所以“机器人优先还是人工优先”,不是前端按钮逻辑,而是这里的 operator model 决定的。


第三层:人工路由并不随机,而是尽量选“当前最空的人”

很多人把 Live Chat 分配想成 round-robin,但 _get_less_active_operator() 暴露的逻辑更细。

它的思路大概是:

1. 先只看候选名单里的 operator

也就是:

  • 语言匹配后剩下的人;
  • 国家规则匹配后剩下的人;
  • 专长过滤后剩下的人;
  • 或者当前渠道允许的 available operators。

2. 优先挑“没有活跃状态”的坐席

源码会先看 operator status 里哪些人最近没有活跃聊天。

如果有这种人,直接在这些“当前最空”的人里随机一个。

3. 如果所有人都忙,再比较负载和通话状态

这里很关键:

  • 不只比较 active chat 数量;
  • 还比较 in_call
  • 并显式避免“正在打电话且已有多条会话的人”拿到不合理优先级。

这意味着:

Odoo Live Chat 的分配核心不是绝对公平,而是尽量避免把新访客继续塞给已经最忙、而且可能正在通话的那个人。

这是一种很实用的协同优化,而不是数学上最平均的调度器。


第四层:chatbot 不是只会发话术,它还会从消息里抽取客户信息

_chatbot_find_customer_values_in_messages() 很值得看,因为它暴露了 Odoo 对 chatbot 的定位。

它会遍历当前频道里和脚本步骤相关的消息,把用户输入回填成结构化字段,例如:

  • 邮箱;
  • 手机号;
  • 其他脚本提问对应的客户信息。

也就是说,chatbot 在 Odoo 里不是单纯“自动回复器”,而是一个访客预采集层

  • 先问;
  • 再从历史消息里抽值;
  • 然后把这些值用于后续客户创建、更新或转人工时的上下文补全。

这就是为什么很多企业会觉得 Odoo 的 Live Chat 看起来像“客服”和“表单”混合在一起:源码上它本来就是这么设计的。


第五层:机器人发消息,本质上仍然是往 discuss channel 里 message_post

_post_current_chatbot_step_message() 并没有造一套独立的机器人消息系统。

它最终还是调用 _chatbot_post_message(),而后者会以 chatbot operator partner 的身份,在 channel 上执行:

  • message_post()
  • message_type='comment'
  • subtype_xmlid='mail.mt_comment'

这意味着两件事:

1. 机器人消息和人工消息共用 discuss / mail 基础设施

好处是:

  • UI 渲染统一;
  • 已读、未读、时间线、bus 推送机制统一;
  • 后续转人工不用迁移消息结构。

2. 机器人并不是“系统提示条”

它在协作语义上是一位特殊操作员。

所以你在调试时如果只盯着前端 widget,不去看 message_post() 落出来的 mail.message,会漏掉很多核心问题。


第六层:重启会话不是清前端状态,而是清频道里的 chatbot 轨迹

_chatbot_restart() 非常能体现 Odoo 的设计边界。

它做的不是简单重载页面,而是:

  • 清掉 chatbot_current_step_id
  • 清空 livechat_end_dt
  • 删除 chatbot_message_ids
  • 再重新发一条“Restarting conversation...”消息。

也就是说:

在 Odoo 看来,重启 Live Chat 是一件后端状态重置动作,而不是前端重新打开窗口。

这解释了一个很常见的现象:

  • 用户刷新浏览器,有时流程不会重置;
  • 但调用正式的 restart 逻辑后,脚本会真正从头开始。

因为决定流程位置的是频道状态和 chatbot message 记录,而不是浏览器页面本身。


第七层:人工接管本质上是“有人加入需要帮助的 channel”

livechat_join_channel_needing_help() 的命名已经把这件事说透了:

  • 不是新建另一个会话;
  • 也不是把访客拷贝给某个客服;
  • 而是让真人加入一个已经存在、而且“正在请求帮助”的 channel。

这很关键,因为它决定了转人工时哪些东西会被保留:

  • 机器人已经发过的话;
  • 访客已经回答过的信息;
  • 当前 livechat 状态;
  • channel 本身的上下文。

所以 Odoo 的人工接管是在同一条协作线程里续接,而不是“机器人阶段”和“人工阶段”两张皮。


实战里最容易误解的 3 个点

误解 1:有 chatbot 就一定不会走人工分配

不对。

正确理解是:

  • chatbot 可以先成为 operator model;
  • 但在脚本结束、访客请求人工、或规则需要人工介入时,仍会进入 _get_operator() 路由真人。

误解 2:人工分配就是随机

不对。

随机只是最后一层平局裁决。

在那之前,源码已经做了:

  • 候选过滤;
  • 活跃度比较;
  • 通话状态规避;
  • 前 operator 复用等考虑。

误解 3:重启对话只和前端有关

不对。

真正控制流程的是:

  • chatbot_current_step_id
  • chatbot_message_ids
  • livechat_end_dt

只刷新前端,不一定等于重启对话。


二开时最值得注意的边界

1. 不要绕开 _get_operator_info() 直接硬塞某个 user

你会跳过:

  • chatbot 优先级;
  • 语言/国家/专长过滤;
  • 负载均衡;
  • 前 operator 延续逻辑。

最后看起来只是“指定了一个客服”,实际上会破坏整条接待链路。

2. 不要把 chatbot 当独立消息系统改

它本质上依赖 discuss channel 的 message_post()

如果你单独做一套消息表或只在前端追加假消息,后续人工接管、bus 同步、消息追踪很容易出问题。

3. 排查“为什么一直不转人工”时,不要只看前端按钮

优先检查:

  • 当前渠道规则里有没有 chatbot;
  • operator 是否真的 available;
  • _get_operator() 的候选是否被语言、国家或专长过滤空了;
  • channel 是否还停在 chatbot 当前步骤。

结论

Odoo Live Chat 的核心,不是“聊天窗口长什么样”,而是它把一次在线接待拆成了三层职责:

  • chatbot 负责前置采集与分流
  • operator 路由负责把人分给合适且不太忙的坐席
  • discuss channel 负责承载整条会话线程

理解这三层以后,你就能解释很多现场现象:

  • 为什么没客服在线按钮还能亮;
  • 为什么机器人结束后还能无缝接给人工;
  • 为什么重启脚本要清后端状态;
  • 为什么“随机分配客服”其实并不随机。

一句话总结:

Odoo Live Chat 不是把机器人和客服拼在一起,而是用同一条会话线程,把“预接待、分流、人工协作”串成了一条连续链路。

DISCUSSION

评论区

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