SmartCall源码解析:实时对话轮次拦截器RealtimeTurnInterceptor实现原理

前言

在端到端全双工实时语音对话场景,通话会话拥有完整生命周期:会话启动、每一轮问答交互、会话结束。很多业务需要在对话的各个节点植入横切逻辑:通话敏感词过滤、会话日志埋点、风险检测、自定义变量改写、对话内容审计、会话结束后业务回调。

如果直接修改通话主业务代码实现上述逻辑,会大量侵入核心会话逻辑,版本升级时产生大量代码冲突,不利于维护扩展。

该机制的核心价值在于:把"会话生命周期中的横切关注点"从主业务流程中剥离出来,通过"钩子 + Spring Bean 自动发现"的方式,让开发者以极低侵入性扩展通话能力,无需改动核心编排代码。

基于Spring Bean自动发现机制,零侵入业务主流程 ,开发者新增业务逻辑,只需要实现拦截器接口并标注@Component,框架自动加载执行,无需修改原有通话编排代码,完美遵循开闭原则。

一、端到端会话整体执行链路回顾

端到端实时对话完整流程:

  1. 来电/外呼接通,AgiHandler 检测agentId,进入ProcessServiceImpl.realtime()实时会话编排
  2. 加载智能体配置,解析变量占位符,通过适配器工厂创建模型会话
  3. 建立AudioSocket全双工音频流,初始化RealtimeCallSession通话会话
  4. 会话启动,执行拦截器onSessionStart
  5. 用户说话→模型应答,每一轮问答前后执行拦截器beforeTurnafterTurn
  6. 会话结束、挂机,执行拦截器onSessionEnd
  7. 释放音频、WebSocket、线程全部资源

拦截器就是嵌入在会话生命周期各个钩子点的扩展插槽,不改变原有通话、媒体流、打断、挂机核心逻辑。

二、RealtimeTurnInterceptor核心接口定义

RealtimeTurnInterceptor为顶层拦截器接口,提供四个生命周期钩子,同时支持order()指定执行顺序,数字越小优先级越高。

java 复制代码
public interface RealtimeTurnInterceptor {

    /**
     * 会话开始回调:模型连接就绪,会话正式启动
     * @param turnContext 通话上下文对象,携带会话全部信息
     */
    default void onSessionStart(TurnContext turnContext) {}

    /**
     * 每一轮大模型应答生成【之前】执行
     * @param turnContext 通话上下文
     */
    default void beforeTurn(TurnContext turnContext) {}

    /**
     * 每一轮大模型应答生成【结束之后】执行
     * @param turnContext 通话上下文
     */
    default void afterTurn(TurnContext turnContext) {}

    /**
     * 整个通话会话完全结束,准备释放资源
     * @param turnContext 通话上下文
     */
    default void onSessionEnd(TurnContext turnContext) {}

    /**
     * 拦截器执行顺序,数值越小越优先执行
     * @return 排序order
     */
    default int order() {
        return 0;
    }
}

TurnContext 通话上下文

TurnContext是拦截器最重要的入参,承载单次会话全部运行时信息:

  • 智能体基础配置、通话通道ID、来电/去电号码
  • 当前轮次:用户转写文本、模型输出应答文本
  • 会话变量集合,可以读取、修改会话内业务变量
  • 通话状态、会话ID、相关工具调用信息

业务开发可以从TurnContext拿到通话全量上下文,完成日志、过滤、改写变量等操作。

三、框架如何自动加载、执行拦截器

1. Bean自动收集

RealtimeCallSession初始化阶段,直接从Spring上下文获取全部实现RealtimeTurnInterceptor接口的Bean,根据order()进行升序排序,形成拦截器调用链。

开发者自定义拦截器,只需要加上@Component,不需要手动注册,框架自动扫描识别。

2. 调用链执行时机

  1. onSessionStart:模型WebSocket会话连接建立完成,对话会话刚刚启动时执行全部拦截器;
  2. beforeTurn :每一轮AI生成回答之前执行,适合做提示词改写、敏感词前置校验;
  3. afterTurn:一轮AI应答完整结束后执行,适合做应答内容审计、保存对话业务记录;
  4. onSessionEnd:会话即将销毁,通话准备挂机释放资源,适合会话结束回调、业务数据上报。

注意:拦截器运行在通话业务线程,禁止长时间阻塞,耗时IO操作需要丢到异步线程池,否则会阻塞实时对话。

执行顺序规则

多个拦截器共存:order()值越小越先执行。

  • beforeTurn / onSessionStart:按order从小到大执行
  • afterTurn / onSessionEnd:按order从大到小执行(类似过滤器的责任链回滚)

四、自定义拦截器开发示例

示例1:会话全链路日志审计拦截器

实现RealtimeTurnInterceptor,添加@Component,即可自动生效。

java 复制代码
@Component
@Slf4j
public class CallAuditInterceptor implements RealtimeTurnInterceptor {

    @Override
    public int order() {
        return 1;
    }

    @Override
    public void onSessionStart(TurnContext turnContext) {
        log.info("实时会话启动,通话ID:{},来电号码:{}",
                turnContext.getChannelId(),
                turnContext.getPhone());
    }

    @Override
    public void beforeTurn(TurnContext turnContext) {
        // 每一轮模型生成应答前
        String userText = turnContext.getUserTranscript();
        log.info("用户输入内容:{}", userText);
    }

    @Override
    public void afterTurn(TurnContext turnContext) {
        // AI应答结束,执行审计逻辑
        String botAnswer = turnContext.getBotTranscript();
        log.info("模型应答内容:{}", botAnswer);
        // 可以在这里做敏感词检测,命中后设置会话结束,转接人工
    }

    @Override
    public void onSessionEnd(TurnContext turnContext) {
        log.info("会话结束,通话ID:{}", turnContext.getChannelId());
        // 异步上报通话业务记录到外部CRM、工单系统
    }
}

示例2:会话变量动态修改拦截器

会话启动时,从外部接口拉取用户业务数据,写入会话上下文,后续智能体提示词可以直接读取变量。

java 复制代码
@Component
public class CustomerInfoInterceptor implements RealtimeTurnInterceptor {

    @Override
    public void onSessionStart(TurnContext turnContext) {
        String phone = turnContext.getPhone();
        // 异步调用外部CRM接口获取客户信息
        CustomerDTO customer = remoteCrmApi.getCustomerByPhone(phone);
        // 写入会话上下文,智能体提示词${customerName}即可直接读取
        turnContext.setVariable("customerName", customer.getName());
        turnContext.setVariable("customerLevel", customer.getLevel());
    }
}

五、拦截器典型业务落地场景

  1. 通话安全审计、敏感词过滤 会话每轮应答前后抓取用户和AI输出文本,做敏感词、风险内容检测,命中风险可以触发转人工、结束通话。

  2. 会话生命周期日志埋点 记录会话启动、每轮对话、会话结束全流程日志,用于问题排查、通话复盘。

  3. 动态注入会话业务变量 会话启动时拉取CRM、工单系统数据,注入会话上下文,提示词直接使用变量,实现千人千面话术。

  4. 会话结束业务回调上报 通话挂机之后,自动把对话结果、通话摘要推送给业务系统,不需要修改底层通话代码。

  5. 业务规则控制 例如:同一个号码最多对话轮次限制,达到轮次自动引导转人工。

⚠️开发注意事项

  1. 拦截器所有钩子方法禁止同步阻塞IO,数据库、HTTP远程调用,必须切换异步线程池,否则直接影响实时对话时延;
  2. 不要在拦截器内直接操作底层音频、模型连接,所有会话操作通过TurnContext提供的API;
  3. 异常务必捕获,拦截器内部异常不能导致整个通话会话崩溃;
  4. order()合理设置,控制多个拦截器执行先后顺序。

六、拦截器和FunctionCallHandler区别

很多开发者容易混淆RealtimeTurnInterceptor轮次拦截器和FunctionCallHandler工具调用处理器:

组件 作用 触发时机
RealtimeTurnInterceptor 会话生命周期钩子,会话启动、每轮问答、会话结束横切扩展 会话完整生命周期,不管是否调用工具都会执行
FunctionCallHandler 专门处理模型下发function‑call工具调用请求 只有模型发起工具调用的时候才触发,执行业务接口并返回结果给大模型

二者可以搭配使用:工具调用完成后,拦截器afterTurn可以拿到工具调用结果做日志审计。

七、资源地址

📘官方开发文档:qidiangk.com/docs/develo...

⭐ Gitee开源仓库:gitee.com/gdzWork/Sma...

🌐官网地址:qidiangk.com

小结:RealtimeTurnInterceptor拦截器机制,是SmartCall端到端实时对话重要的扩展点。通过钩子+Spring Bean自动发现,以极低侵入性,实现通话会话横切业务逻辑,开发者不用修改核心通话、媒体流、打断挂机代码,就可以实现审计、变量注入、风险检测等丰富业务,这也是开源呼叫中心可扩展架构设计的典型实践。

相关推荐
zzzll11112 小时前
新手如何使用 GitHub?从零开始的完整入门指南
github
CoderJia程序员甲3 小时前
GitHub 热榜项目 - 周榜(2026-09-06)
ai·大模型·llm·github·ai教程
zzzzzz3107 小时前
picoclaw:从“迷你部署代理”看轻量化项目该怎样被理解
人工智能·开源·github
DeepAgent20 小时前
AI Agent 项目赏析:DeerFlow 2.0 —— 一个真正“长跑“的 SuperAgent 是怎么设计出来的?
github·agent
重生之我来学Python21 小时前
Docker套装的简介、安装、超级详细教程
linux·docker·容器·eureka·github
粥里有勺糖1 天前
视野修炼-技术周刊第132期 | 一些有趣的组件
前端·github·aigc
智碳能碳管理平台1 天前
企业能碳管理系统的月度锁账、防篡改与留痕怎么架构
架构·github·能碳管理系统·智碳能碳管理平台·企业能碳管理系统·绿色工厂申报saas·能碳管理平台
mjhcsp1 天前
Github Copilot 新手极速上手指南
github·copilot
重生之我来学Python1 天前
Git-SVN 混合开发,从入门到精通!
开发语言·git·svn·github