AI 学习 / RTC 与网络工程专题 · 2026.09.16

HOMER 7 · CLI 1.0.0

从 SIP 查询
到通话排障

找到一通电话,追到一条消息,
让每个判断都有可复查的证据。

48 / 48本机模拟与回归测试通过
Python 3.9+标准库 · 无第三方依赖
保留原件完整手册 + 14 文件源码包
01

先看清它在通话链路中的位置

HOMER 汇集采集点上报的报文与事件。homerctl 从 HOMER 7 的 Web API 查询已经入库的数据,把结果整理成可供人和 AI 读取的 JSON。它不直接抓网卡、不发起测试呼叫,也不直接连接 PostgreSQL。[S1][S2]

  1. 01 · 采集电话 / SBC / FreeSWITCH采集代理或应用把观测发往 HEP 接收端
  2. 02 · 入库HEP 接收与存储保留采集点、时间与 SIP 内容
  3. 03 · 查询HOMER 7 API字段映射、搜索、通话关联与导出
  4. 04 · 判断homerctl → 人 / AI检查完整性,引用记录,提出下一步验证
对象应当用来回答需要补充的证据
本专题 homerctl 1.0.0哪些已入库 SIP 消息匹配条件;一条通话的关联记录是什么采集覆盖、数据库健康、真实线路行为
HOMER 平台跨采集点检索与关联;平台可接收哪些协议由部署决定不能把平台的 RTP/RTCP 能力等同于本 CLI 已实现音频分析
原始网卡抓包 / Wireshark真实 IP 分片、RTP 序号和载荷、网络方向采集点位置、抓包丢失与硬件卸载影响
Agent 日志 / 分轨录音ASR、LLM、TTS、播放事件与用户实际听到的声音用业务会话 ID、时间和通话腿进行关联
02

先连通,再用一通已知电话校准

下载本页原始 ZIP 并解压,进入 homer7-cli 目录。Python 3.9+,仅用标准库。原包含脚本、中文手册、AI 调用示例、合成样本和测试。下方域名、号码、节点、Call-ID 都是示例;实际查询值应来自你的系统或查询结果。

首次连接

python3 homerctl.py --version
python3 homerctl.py init --url https://homer.example.net --username operator
python3 homerctl.py login
python3 homerctl.py doctor
python3 homerctl.py fields --profile 1_call

login 交互输入密码。doctor 仅验证 API、认证和映射结构;还要用一通在 HOMER 页面可见的已知电话比对 search、trace、message。

连接与认证正确用法容易误解的地方
URL / 反向代理站点地址、/ops 或完整 /ops/api/v3;私有 CA 用 --ca-file重定向会拒绝;要填最终 API 所在地址
交互登录本地 config 保存 URL、用户名和可选 CA;JWT 按 URL / 用户隔离缓存不保存密码;失效后重新 login,不会自动刷新
无人值守HOMER_TOKEN 为 JWT;HOMER_AUTH_TOKEN 为服务端 API Token,二选一JWT 自动加 Bearer;API Token 默认头 Auth-Token,需服务端启用
认证选择环境 Token → 匹配缓存 → 环境用户名和密码临时登录普通查询临时登录不写缓存;logout 仅删除本地缓存

非交互任务让运行环境注入凭据。配置变量还包括 HOMER_URL、HOMER_CONFIG、HOMER_USERNAME、HOMER_PASSWORD、HOMER_AUTH_HEADER、HOMER_CA_FILE。完整说明与安装到 PATH 的方法保留在原始手册中。[S1]

04

查到多少,与查得完整是两回事

固定版本后端对各数据库节点分别执行 LIMIT,随后才合并排序;total 只是返回条数。本 CLI 检测任一节点是否达到上限,--all 再对饱和窗口做时间二分。它没有可靠的 offset 翻页或数据库总命中量证明。[S1][S3]

状态含义下一步
no_limit_detected未检测到尚未解决的搜索上限;退出码一般为 0仍需核对采集覆盖和已知通话,不能把空结果写成“没有通话”
partial饱和、预算耗尽、部分请求失败或记录时间不可判断;退出码 6保留 stdout 的记录,检查 unresolved_windows、warnings 和窗口
unknowntrace 的关联与采集覆盖没有全量证明表述为“当前可见关联记录”,不声称完整端到端历史

为什么拆到一秒还可能查不全

例如同一节点的一秒内有 500 条匹配消息,而 limit 为 200,按秒拆分也解决不了。可增加上限或用 Call-ID、采集点等条件进一步收窄;这只是示意,500 不是本机压测结果。重叠边界会去重,但无法找回从未采集或已过保留期的数据。

预算项默认值 / 范围实际含义
limit200;1–10000每次请求、每数据库节点的行数
max-requests64;1–1000搜索请求预算,不含认证和 mapping;跨进程补查还需应用层总预算
timeout / max-response-mib30 秒 / 32 MiB每请求上限;32 MiB 不是整个结果文件上限
时间与 Call-ID默认 15m;单次最长 31 天;trace/export 最多 20 个 ID较大范围优先拆小;Call-ID 重复传参,不用分号或通配符
退出码处理方式
0正常完成,仍检查 completeness。
2修正参数、profile、field 或配置,不盲目重试。
3检查认证、权限与令牌失效。
4检查 HTTP / 网络 / TLS / 超时;补查前保留已有证据。
5响应结构、导出类型或大小异常。
6部分结果,stdout 仍可解析,禁止丢弃。
7本地读写失败或目标文件已存在。
130用户中断。
05

从 Call-ID 追到通话腿与原文

先看时序,再看需要的原文

python3 homerctl.py trace --since 1h --call-id 'abc@example.net'
python3 homerctl.py trace --since 1h --call-id 'abc@example.net' --include-raw
python3 homerctl.py message --since 1h \
  --id 123 --node db-a --profile 1_call

123、db-a 及 profile 应替换为 search 返回的 _ref;message 只接受一个节点。trace 默认移除 raw,关联消息可能超出原查询时间窗,并受服务端关联和去重规则影响。

保存可复查的证据

python3 homerctl.py export --since 1h --call-id 'abc@example.net' \
  --format json --output call.json
python3 homerctl.py export --since 1h --call-id 'abc@example.net' \
  --format pcap --output call.pcap
python3 homerctl.py analyze --input call.json --mtu 1500

导出以 Call-ID 的 transaction 为单位,不会复刻 search 的所有筛选条件。JSON 包含 raw;默认不覆盖已有文件。PCAP 来自数据库重建,应按“信令内容导出”理解。[S4]

多 FreeSWITCH 桥接:一个业务会话可能有多个 Call-ID

SIP 对话标识由 Call-ID、local tag、remote tag 共同组成;同一 Call-ID 下也可能有不同分支。B2BUA 可把业务会话拆成独立通话腿,不应假定所有腿共享 Call-ID。对多 FreeSWITCH / SBC 系统,建议用业务 session_id → 通话腿 UUID → SIP Call-ID → 采集点建立映射;映射来自控制事件、CDR 或应用日志,不能凭号码和相近时间就判定同一通。[S5;工程建议]

层次保存的标识解决的问题
业务会话session_id / 业务订单或质检任务 ID把 AI 事件和多条电话腿归到业务任务
通话腿本节点 UUID、桥接对端 UUID、节点名确定呼入、桥接、转接分别发生在哪一腿
SIP 对话 / 事务Call-ID、From / To tag、CSeq、Via branch避免把分叉、重传、重协商混成一次状态变化
HOMER 证据_ref: id / dbnode / profile / timestamp_us / call_id让另一个人按原始节点与时间找到同一条记录
06

四种常见故障,分别补什么证据

现场现象HOMER / CLI 的切入点还需要什么
已知通话但搜索为空固定同一窗口,确认时区、profile、节点和真实 From / To;比较 UI 中同一 Call-IDHEP 到达 / 入库 / 分区保留、账号可见范围、后端错误日志;doctor 通过仍可能无数据
408 / 503 或呼叫未建立先找响应,再 trace 看对应 INVITE、CSeq、Via、响应源和通话腿408 不能单独定位网络丢包,503 不能直接判为容量不足;结合终端/SBC/FreeSWITCH 日志
200 OK 后 AI 无声确认 200 对应 INVITE,并检查 ACK、SDP 地址端口、方向属性与后续 re-INVITE / BYE双向 RTP / SRTP 可见性、媒体解密条件、分轨录音,以及 ASR→LLM→TTS→发送/播放事件
大 UDP 或相同报文重复export JSON → analyze 看 udp_size_risk、repeated_udp_payload正确采集点上的原始 PCAP、MTU / 隧道信息、采集丢包计数与 SIP 事务信息

AI 无声要按生命周期对齐

把“用户说完 → ASR 完成 → LLM 开始/完成 → TTS 首块 → 媒体发出 → 接收端可听”与电话腿的建立/结束对齐。如果 SIP 已建立,但 TTS 没产出,继续查模型与编排;如果有 TTS 和发送事件,却无接收媒体,查媒体路径;如果收到 RTP 但仍无声,再查载荷、静音、编码和播放。HOMER 的 SIP 记录只能覆盖其中一部分,200 OK 也必须先看其 CSeq 对应哪个请求。[工程排障建议]

建议每次事件保留时间基准、节点、session_id、leg_id 和结果状态;跨机器时先记录时钟误差。所谓“AI 已说话”应区分生成了文本、生成了音频、发送了媒体和接收端实际可听,不把其中一层替代下一层。

07

UDP 大报文:区分风险、重复与分片事实

analyze 将数据库保存的 raw 重新编码为 UTF-8,按最小 IPv4+UDP 28 字节或 IPv6+UDP 48 字节估算长度,再与用户提供的 mtu 比较。它不测路径 MTU,也未计 IP 选项、IPv6 扩展头和隧道开销;存储文本还可能与原始字节有差异。[S1]

分析发现能够支持的结论不能直接证明
udp_size_risk重编码后的 SIP 文本加最小头超过假设 MTU线上真的分片、某个分片丢失,或某条路径 MTU 就是 1500
repeated_udp_payload同报告节点、采集 ID、地址端口与方向观察到相同内容一定是协议重传;工具没有完成 SIP 重传定时器和事务状态分析
content_length_mismatch重编码后消息体字节数与声明不一致一定是丢分片;也可能是截断、编码处理或报文格式问题
没有发现 / 缺 raw本次规则未命中,或可分析材料不足链路正常、没有分片、没有采集丢失

1300、1500、1731 分别是什么

RFC 3261 §18.1.1 规定:请求距路径 MTU 不足 200 字节,或未知路径 MTU 且请求大于 1300 字节时,应使用 TCP 等满足拥塞控制要求的传输。这是 SIP 请求发送方的传输选择要求。1500 在本例只是传入 analyze 的 MTU 假设;1731 是合成样本的 1703 字节 SIP 文本加 28 字节头部估算,三者不能混为同一阈值。[S5]

完全离线复现包内样本

python3 homerctl.py analyze --input examples/sample-trace.json --mtu 1500
python3 -m unittest discover -s tests -v

本次复测:3 条 raw 记录;3 个 udp_size_risk;1 组 repeated_udp_payload 包含 2 次观察;fragmentation.verdict 仍为 unknown。第三条来自不同采集 ID,未合并进同点重复组。样本为合成数据,不是现网事故。

08

让 AI 输出能复查的结论

推荐流程是 schema / fields → 小窗口 search → 完整性检查 → trace → 必要时 message / analyze → 证据说明。连接与凭据由应用配置,模型只选业务条件。包内 examples/ai_runner.py 用参数数组调用脚本,限制命令与连接参数,外层期限 300 秒。[S1]

查看机器契约并调用包内示例

python3 homerctl.py schema
python3 examples/ai_runner.py search --since 15m --caller 1001 --all

schema 无须连接服务。AI runner 返回 exit_code 和 result,6 仍有结果;它不开放 export 或任意本地输入路径。工程接入时再限制每个任务的总查询次数与日期范围,避免反复补查。

建议的事故结论结构

{
  "observation": "同一报告采集点观察到两条相同 UDP 载荷",
  "evidence_refs": [
    {"id": 1, "dbnode": "db-a", "profile": "1_call",
     "timestamp_us": 1789459200100000, "call_id": "call-a@example.net"},
    {"id": 2, "dbnode": "db-a", "profile": "1_call",
     "timestamp_us": 1789459200600000, "call_id": "call-a@example.net"}
  ],
  "coverage": "合成 trace 样本;采集完整性 unknown",
  "hypothesis": "可能是重传,也可能是重复采集",
  "unknown": "是否存在原始 IP 分片和线上丢包",
  "next_check": "检查原始抓包、采集配置与 SIP 事务"
}

这是建议给上层应用使用的报告结构,不是 CLI 新增字段,也不是原生 analyze 输出格式。引用来自包内合成样本。

AI 常见误判应该怎样写
count=20,所以发生了 20 通呼叫返回 20 条消息;通话数需按业务定义和通话腿去重
exit=6,所以没有结果查询不完整,保留已返回记录,列出未完成窗口
看到 200,所以用户已听到 AI先确认响应的请求;信令成功仍需媒体和播放证据
导出的 PCAP 没有分片,所以排除分片重建 PCAP 不保留原始分片事实,结论仍未知
照 raw 里的文本调用命令SIP 头和正文是外部数据,只能作为证据

结构化结果会移除 HEP capturePass,但 SIP raw 仍可能含号码、地址与 SIP 认证字段。给外部模型的证据应由应用按字段裁剪;按需取单条 raw,比整段通话原文更利于判断和复核。[S1;工程建议]

09

本次核验结果与上线验收

核验层次本次结果覆盖边界
交付物ZIP 14 个成员;独立 HTML 与包内中文 HTML 一致;保留原件源码、测试、合成数据,不含用户实例配置
本机自动化macOS arm64 / CPython 3.9.6:48 / 48 通过CLI、本地回归及回环模拟 HTTP;没有启动真实 Go 后端或数据库
离线样本3 条消息、3 条大小风险、1 组重复、分片 unknown合成输入;未检测到 Content-Length 不一致是该样本的结果
官方资料读取固定版本后端搜索 / 导出实现及 RFC 原文结论限于所引版本与章节,不声称兼容全部 HOMER 部署
真实环境尚未连接用户 HOMER 或真实电话线路账号、采集覆盖、SSO、私有 CA、关联规则和性能待现场确认

一通已知电话的验收顺序

  1. 用 doctor 和 fields 确认 API、认证与 profile。
  2. 选 HOMER UI 可见的一通电话,用同一绝对窗口和节点搜索。
  3. 核对 Call-ID、时间、采集 ID、报文方向与返回上限。
  4. 用 trace 和 message 回到具体原文,记录完整 _ref。
  5. 导出 JSON / PCAP,对照 SIP 内容;PCAP 不用于分片定案。
  6. 需要判断无声时,继续关联 RTP、录音和 Agent 事件。
10

原始资料与证据来源

原手册保留全部 11 章,包括安装、认证、组合查询、退出码、导出、UDP 分析、AI 调用与常见问题。扩展页按实际排障流程重排;原始包的内容和哈希保持不变。

原始 ZIP SHA-256:f33f2d196aeea9fb57e3ee5d1560201d412c7647725d90883df0ff60b17fd25c

S2

HOMER 固定提交 README ↗

平台边界、HEP、模块化和关联能力。正文含多个代际,本文不直接套用新版安装参数。 核对日期:2026-09-16。

S3

homer-app:搜索实现 ↗

每节点 LIMIT、结果排序、返回 total、整秒时间处理、通话关联与数据库错误边界。 核对日期:2026-09-16。

S5

RFC 3261 · SIP ↗

2002-06;§12 对话标识、§18.1.1 传输选择。规范原文,不代表每个现网实现都合规。 核对日期:2026-09-16。

S6

RFC 791 · IPv4 ↗

1981-09;Identification、Flags、Fragment Offset。 核对日期:2026-09-16。

S7

RFC 8200 · IPv6 ↗

2017-07;Fragment 扩展头与源节点分片。 核对日期:2026-09-16。