外观
故障排查与典型症状
按服务分组的排查清单。每条包含“现象—优先确认—处理方式”,用于联调和生产应急。
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。 - 若日志先保存了
srflx和relay,却出现Choose rtp candidate ... srflx,说明 FreeSWITCH 1.10 按默认wan.auto优先选择了运营商 NAT 候选。配置只允许 coturn 公网 IP 的softphone-turn-relayACL,并在 Sofia profile 使用apply-candidate-acl=softphone-turn-relay。 - 修改 ACL 后除了
reloadxml还必须执行reloadacl;修改 Sofia profile 后重启对应 profile。正确的新通话应选择123.57.205.60:31000–31040relay,本地 SDP 应广告123.57.205.60:30000–30199,DTLS 不应长期停在HANDSHAKE。
- 检查 FreeSWITCH 的 200 OK SDP。若
现象:外呼接通后未进入通话业务
- 确认
freeswitch.callbackHost与监听端口能被 FreeSWITCH 回连。 - 确认拨号计划
socket指向callflow-esl的ESL监听端口且async full生效。 - 确认
call_businesses已有业务并已通过syncRegisteredCallBusinesses同步。
- 确认
现象:
uuid_audio_fork一直未返回识别- 确认 ASR WebSocket 地址可达且
mod_audio_fork使用 16kHz mono PCM16。 - 检查 ASR 健康:
GET /health,并抓一次原始链路(metadata + 二进制帧)。 - 回退
audioFork参数:sampleRate/mixType是否与输入一致。
- 确认 ASR WebSocket 地址可达且
现象:业务常见命令报错/挂断后报错
- 对端挂断下部分 execute 命令会被拒绝,属于正常,runtime 会做容错。
- 查看是否是配置文件变更导致通道变量/主叫变量缺失,或调用顺序错误。
C++ ASR 服务(sherpa-asr-online-server)
现象:
GET /health200,但 WebSocket 无法识别- 优先确认
server.wsPath与maxSessions,是否命中连接数上限。 - 验证客户端首帧元数据 JSON 是否可解析(
uuid/channel_uuid约定字段)。 - 按
concurrency调参:提高ioWorkers/sessionPoolSize需要配合 CPU/负载评估。
- 优先确认
现象:音频内容明显识别错乱
- 确认音频是 16kHz 单声道 PCM16,ASR 不做自动重采样。
- 检查是否误发送了分片帧(服务不支持分片)。
- 开启录音排查:临时打开
recording.enabled=true校验 Wav 输入。
现象:并发稍大即出现 503
maxSessions是会话上限,先观察GET /health的activeSessions/maxSessions。- 处理时先调
ioWorkers/sessionPoolSize与maxSessions,再评估上游调度并发。
C++ TTS 服务(sherpa-tts-server)
现象:流式播报在
mod_shout上失败- 确认 FreeSWITCH 已加载
mod_shout。 - 确认
mp3EncoderPath可执行,或ffmpeg在 PATH 中可见。 - 检查
listenHost与返回publicBaseUrl是否一致(调用方是否能回源访问)。
- 确认 FreeSWITCH 已加载
现象:请求偶发 503 / 超时
maxQueuedRequests过小会导致排队拒绝,先看调用方重试策略与峰值并发。- 查日志里的
stream busy/request timed out,结合调用并发和上游连接稳定性分析。
现象:文件增长过快
- TTS 无内建 TTL 清理;需要外部清理
public/wav/。 - 长期高并发场景优先复用文本(命中缓存)或配置额外归档策略。
- TTS 无内建 TTL 清理;需要外部清理
情绪分析服务(emotion-analysis-server)
现象:
POST /analyze成功率低- 确认
recordingUrl可访问(只支持 http 与支持的 WAV 采样格式)。
- 确认
现象:返回统一情绪分数异常
- 记录
reason/available字段,判断文本/音频哪一侧缺失。 - 确认通话录音声道映射是否正确(
audio.channelRoles)。
- 记录
现象:前端情绪复核音频无法播放
- 确认情绪分析服务返回的是短文件名或短路径,callout 前端会通过
media.emotionAudioBaseUrl拼完整 URL。 - 检查
emotion-analysis-server的audio.processedDir是否可写、audio.processedPublicBaseUrl是否与 calloutmedia.emotionAudioBaseUrl对齐。 - 浏览器访问最终 URL,确认静态服务、反代和 MIME 类型可用。
- 确认情绪分析服务返回的是短文件名或短路径,callout 前端会通过
llm-nlu-server
现象:
GET /api/v1/nlu/capabilities返回 401- 确认
server.authToken或LLM_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 的策略超时。
- 确认 Ollama 服务可访问:
现象:业务 profile 不生效
- 先访问
/api/v1/nlu/capabilities,确认 action 下存在对应 profile。 - 请求体里的
action只能是当前注册能力,例如decision或extract。
- 先访问
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 可达性和 SSEcomplete事件。 - 非法
exitKey、SSE 解析失败、LLM 超时和 TTS 播放失败都会走error,可结合routeTrace[].chat.reason排查。
- 检查 callflow-esl 的
现象:连续无声后进入
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。
- worker 会用
现象:导入或结果回写字段不清楚
- 先看
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/asractiveSessions与调用量趋势。
统一排障步骤(建议)
- 先确认健康接口:ASR/TTS/Emotion 是否可用。
- 再确认网络链路(callbackHost/listenHost/publicBaseUrl/端口映射)。
- 再确认协议输入(音频格式、WebSocket 订阅路径、JSON 字段)。
- 最后确认业务流(拨号计划、业务路由、回铃与回写)。
证据留存
- 保留:服务日志、健康检测日志、失败请求参数、故障时间点、并发快照。
- 链路类问题建议附:
- 配置片段(脱敏)
- 关键 cURL/请求样例
- 时间轴(起止时间、重试次数、错误码分布)