跳到正文

故障排查与典型症状

按服务分组的排查清单。每条包含“现象—优先确认—处理方式”,用于联调和生产应急。

callflow-esl / FreeSWITCH 链路

  • 现象:callflow-esl 启动时报 config businessConfig...

    • 确认已删除旧顶层 ollamaChat / knowledgeBase,并把配置迁入对应稳定业务编码子项。
    • ollama-chat-business 子项必填;kb-audio-chat-business 可省略,但一旦存在就必须包含 有效 HTTP(S) endpoint、非空 strategy 与正整数 requestTimeoutMs。
    • 未注册业务编码通常是拼写错误;数据库 businessConfig / mappingConfig 不包业务编码。
  • 现象:通话记录 business_config_invalid 且未请求 Ollama / 知识库

    • 按“文件业务子项 < call_businesses.businessConfig < 号码 mappingConfig”检查最终字段; 显式 business_code 路由没有号码映射层。
    • 知识库文件配置可缺省,但路由命中后若数据库层仍未补齐 endpoint / strategy / timeout, 会在业务 handler 执行前播放“系统错误”并结束。
  • 现象:5G 软电话能注册和接通,但页面提示“WebRTC 媒体连接失败”,双方无声

    • 检查 FreeSWITCH 的 200 OK SDP。若 c= 和本地 candidate 仍是 192.168.2.198,说明 FRP 回送的 WebSocket 信令被 localnet.auto 误判为本地;WebRTC profile 应设置 local-network-acl=none,让 ext-rtp-ip 参与 SDP。
    • 若日志先保存了 srflxrelay,却出现 Choose rtp candidate ... srflx,说明 FreeSWITCH 1.10 按默认 wan.auto 优先选择了运营商 NAT 候选。配置只允许 coturn 公网 IP 的 softphone-turn-relay ACL,并在 Sofia profile 使用 apply-candidate-acl=softphone-turn-relay
    • 修改 ACL 后除了 reloadxml 还必须执行 reloadacl;修改 Sofia profile 后重启对应 profile。正确的新通话应选择 123.57.205.60:31000–31040 relay,本地 SDP 应广告 123.57.205.60:30000–30199,DTLS 不应长期停在 HANDSHAKE
  • 现象:外呼接通后未进入通话业务

    • 确认 freeswitch.callbackHost 与监听端口能被 FreeSWITCH 回连。
    • 确认拨号计划 socket 指向 callflow-eslESL 监听端口且 async full 生效。
    • 确认 call_businesses 已有业务并已通过 syncRegisteredCallBusinesses 同步。
  • 现象:uuid_audio_fork 一直未返回识别

    • 确认 ASR WebSocket 地址可达且 mod_audio_fork 使用 16kHz mono PCM16。
    • 检查 ASR 健康:GET /health,并抓一次原始链路(metadata + 二进制帧)。
    • 回退 audioFork 参数:sampleRate / mixType 是否与输入一致。
  • 现象:业务常见命令报错/挂断后报错

    • 对端挂断下部分 execute 命令会被拒绝,属于正常,runtime 会做容错。
    • 查看是否是配置文件变更导致通道变量/主叫变量缺失,或调用顺序错误。

C++ ASR 服务(sherpa-asr-online-server)

  • 现象:GET /health 200,但 WebSocket 无法识别

    • 优先确认 server.wsPathmaxSessions,是否命中连接数上限。
    • 验证客户端首帧元数据 JSON 是否可解析(uuid / channel_uuid 约定字段)。
    • concurrency 调参:提高 ioWorkers/sessionPoolSize 需要配合 CPU/负载评估。
  • 现象:音频内容明显识别错乱

    • 确认音频是 16kHz 单声道 PCM16,ASR 不做自动重采样。
    • 检查是否误发送了分片帧(服务不支持分片)。
    • 开启录音排查:临时打开 recording.enabled=true 校验 Wav 输入。
  • 现象:并发稍大即出现 503

    • maxSessions 是会话上限,先观察 GET /healthactiveSessions/maxSessions
    • 处理时先调 ioWorkers/sessionPoolSizemaxSessions,再评估上游调度并发。

C++ TTS 服务(sherpa-tts-server)

  • 现象:流式播报在 mod_shout 上失败

    • 确认 FreeSWITCH 已加载 mod_shout
    • 确认 mp3EncoderPath 可执行,或 ffmpeg 在 PATH 中可见。
    • 检查 listenHost 与返回 publicBaseUrl 是否一致(调用方是否能回源访问)。
  • 现象:请求偶发 503 / 超时

    • maxQueuedRequests 过小会导致排队拒绝,先看调用方重试策略与峰值并发。
    • 查日志里的 stream busy / request timed out,结合调用并发和上游连接稳定性分析。
  • 现象:文件增长过快

    • TTS 无内建 TTL 清理;需要外部清理 public/wav/
    • 长期高并发场景优先复用文本(命中缓存)或配置额外归档策略。

情绪分析服务(emotion-analysis-server)

  • 现象:POST /analyze 成功率低

    • 确认 recordingUrl 可访问(只支持 http 与支持的 WAV 采样格式)。
  • 现象:返回统一情绪分数异常

    • 记录 reason / available 字段,判断文本/音频哪一侧缺失。
    • 确认通话录音声道映射是否正确(audio.channelRoles)。
  • 现象:前端情绪复核音频无法播放

    • 确认情绪分析服务返回的是短文件名或短路径,callout 前端会通过 media.emotionAudioBaseUrl 拼完整 URL。
    • 检查 emotion-analysis-serveraudio.processedDir 是否可写、 audio.processedPublicBaseUrl 是否与 callout media.emotionAudioBaseUrl 对齐。
    • 浏览器访问最终 URL,确认静态服务、反代和 MIME 类型可用。

llm-nlu-server

  • 现象:GET /api/v1/nlu/capabilities 返回 401

    • 确认 server.authTokenLLM_NLU_AUTH_TOKEN 是否启用。
    • 请求头必须带 X-Callout-Internal-Token,并命中配置中的 token。
  • 现象:NLU 请求超时或返回 fallback 结果

    • 确认 Ollama 服务可访问:llm.ollamaUrl 默认是 http://127.0.0.1:11434/api/chat
    • 确认已拉取 llm.model 配置的模型(出厂为 qwen3.5:2b),例如 ollama pull qwen3.5:2b
    • 根据模型耗时调大 llm.timeoutMs 或对应 profile 的策略超时。
  • 现象:业务 profile 不生效

    • 先访问 /api/v1/nlu/capabilities,确认 action 下存在对应 profile。
    • 请求体里的 action 只能是当前注册能力,例如 decisionextract

callout-server / 外呼系统

llm-chat-server / chat 节点

  • 现象:对话节点保存时提示 profile 未注册

    • X-Callout-Internal-Token 请求 GET :9931/api/v1/chat/capabilities,确认 chat_profile 存在。
    • 检查 callout-server 的 chat.capabilitiesEndpoint / chat.authToken
  • 现象:通话进入 error 出口

    • 检查 callflow-esl 的 callout.chat.baseUrl / callout.chat.token、Ollama 可达性和 SSE complete 事件。
    • 非法 exitKey、SSE 解析失败、LLM 超时和 TTS 播放失败都会走 error,可结合 routeTrace[].chat.reason 排查。
  • 现象:连续无声后进入 timeout

    • 首次静默会播 silence_prompt,第二次静默或达到 max_turns 才进入 timeout,属于节点契约的预期行为。
  • 现象:活动不派发或卡住

    • 检查活动状态必须是 running、有可调度联系人且线路已启用。
    • 检查策略(尤其工作时段/号码阻断)是否返回拦截原因。
    • 查看锁竞争日志:是否存在多实例并发调度冲突。
  • 现象:坐席转人工失败/会议会话不收敛

    • 先确认 /api/transfers/route 返回已预占坐席并成功 originate
    • 检查坐席号码与拨号模板、坐席状态、originateDialStringTemplate
  • 现象:呼叫明细里有 recordingUrl,但前端不能播放录音

    • 当前 call_attempts.recordingUrl 与 API 响应保存短文件名,例如 call-123.wav, 不再保存完整公网 URL。
    • 检查 GET /api/media/config 返回的 freeswitchRecordingBaseUrl 是否是浏览器可访问地址。
    • 用浏览器直接访问 <freeswitchRecordingBaseUrl>/<encodeURIComponent(recordingUrl)>
    • 若数据库里仍有完整 URL 或 Windows 路径,新的 /api/call-results 会归一为最后一级文件名; 历史数据需要按同一规则迁移或兼容展示。
  • 现象:情绪分析 worker 找不到录音

    • worker 会用 media.freeswitchRecordingBaseUrl + recordingUrl 短文件名拼完整 URL。
    • 确认 FreeSWITCH / callflow 侧已经真实落盘录音并通过静态服务暴露。
    • recordingUrl 不应写成本机绝对路径或带 token 的临时 URL。
  • 现象:导入或结果回写字段不清楚

    • 先看 apps/callout-server/docs/result-schemas.md,其中记录 /api/call-results 推荐字段、payload.result、transcript 和 NLU 摘要结构。
    • 当前接口保留 resultSchemaCode 等业务标识字段,但不要求依赖结果模板管理接口。

使用部署配置时

  • 现象:照搬 deploy/config 后服务启动失败

    • deploy/config/*.config.json 是配置样例,不是一体化部署包;先核对服务工作目录、模型、 日志、录音和媒体目录等相对路径是否能在目标主机解析。
    • 检查样例端口与本地开发默认端口的差异,并确认所有调用方使用相同的最终地址。
    • 确认 PostgreSQL、Redis、Ollama、FreeSWITCH、ffmpeg 和动态库等外部依赖已由部署方安装并启动。
  • 现象:ONNX 服务启动失败或立即退出

    • 确认对应 target/<platform> 产物、模型目录和 ONNX Runtime / sherpa-onnx 动态库完整。
    • Linux 上检查构建环境与目标主机的 glibc / C++ 运行库兼容性,并从服务实际工作目录启动一次 以发现相对路径错误。
  • 现象:部署 FreeSWITCH 配置后原有线路或分机异常

    • deploy/freeswitch/ 是参考配置树,不应无差别覆盖现场 conf_dir;从备份恢复后逐项合并 dialplan、directory、SIP profile、ESL、模块和 TLS 配置。
    • 检查 event_socket.conf.xml 的密码与 ACL、outbound socket 地址、外网 SIP/RTP 地址和证书。
  • 现象:部署后前端仍请求旧 API 地址

    • Quasar / Vite 前端 API 地址在构建期固化。
    • 修改 VITE_CALLFLOW_API_BASE_URL / VITE_CALLOUT_API_BASE_URL 后必须重新构建对应前端, 只改运行期环境变量不会改变已构建 JS。

网关服务(阿里云 / Azure)

  • 现象:TTS/ASR 接口超时或 5xx
    • 确认凭据注入(环境变量优先,避免配置文件硬编码)。
    • 检查网络出口与对端 endpoint 可达性。
    • 比较本地日志中的 tts.stream / asr activeSessions 与调用量趋势。

统一排障步骤(建议)

  1. 先确认健康接口:ASR/TTS/Emotion 是否可用。
  2. 再确认网络链路(callbackHost/listenHost/publicBaseUrl/端口映射)。
  3. 再确认协议输入(音频格式、WebSocket 订阅路径、JSON 字段)。
  4. 最后确认业务流(拨号计划、业务路由、回铃与回写)。

证据留存

  • 保留:服务日志、健康检测日志、失败请求参数、故障时间点、并发快照。
  • 链路类问题建议附:
    • 配置片段(脱敏)
    • 关键 cURL/请求样例
    • 时间轴(起止时间、重试次数、错误码分布)

文档与代码在同一仓库维护,现有 Markdown 是唯一内容源。