用户提供的 homerctl 1.0.0 包 ↗
2026-09-15 的源码基线、手册、AI_USAGE、测试与合成样本;2026-09-16 本机复测。 核对日期:2026-09-16。
HOMER 7 · CLI 1.0.0
找到一通电话,追到一条消息,
让每个判断都有可复查的证据。
HOMER 汇集采集点上报的报文与事件。homerctl 从 HOMER 7 的 Web API 查询已经入库的数据,把结果整理成可供人和 AI 读取的 JSON。它不直接抓网卡、不发起测试呼叫,也不直接连接 PostgreSQL。[S1][S2]
| 对象 | 应当用来回答 | 需要补充的证据 |
|---|---|---|
| 本专题 homerctl 1.0.0 | 哪些已入库 SIP 消息匹配条件;一条通话的关联记录是什么 | 采集覆盖、数据库健康、真实线路行为 |
| HOMER 平台 | 跨采集点检索与关联;平台可接收哪些协议由部署决定 | 不能把平台的 RTP/RTCP 能力等同于本 CLI 已实现音频分析 |
| 原始网卡抓包 / Wireshark | 真实 IP 分片、RTP 序号和载荷、网络方向 | 采集点位置、抓包丢失与硬件卸载影响 |
| Agent 日志 / 分轨录音 | ASR、LLM、TTS、播放事件与用户实际听到的声音 | 用业务会话 ID、时间和通话腿进行关联 |
下载本页原始 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_calllogin 交互输入密码。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]
python3 homerctl.py search --since 30m \
--caller 1001 --callee 1002 --transport udp --allcaller / callee 是 SIP From / To 的用户部分;Request-URI 用户用 --ruri-user。CLI 的 count 是消息条数,不是通话数。业务号码可能经过改写,先核对实际字段。
python3 homerctl.py search --since 15m \
--capture-id 101 --node db-a --status '408;503' --allcapture-id 是 HEP 上报的采集编号,node 是 HOMER 数据库节点。SIP 报文 src-ip / dst-ip 也是另一层概念;三者不能互相替代。
python3 homerctl.py search \
--from '2026-09-15T16:00:00+08:00' \
--to '2026-09-15T16:05:00+08:00' \
--caller 1001 --limit 500 --all --max-requests 64search 使用 [from,to);后端按整秒查询,CLI 向外取整后再按返回时间过滤。绝对时间必须带时区,起止同时提供;不要与 --since 混用。日期为教学示例。
| 查询需求 | 可用写法 | 语义与边界 |
|---|---|---|
| 同字段多值 | --status '408;503' | 适用于字符串精确值;整数多值不能用分号 |
| 字符串模糊 | --caller '100%' | % 是通配符;raw-contains 的 % / _ 也参与 LIKE 匹配 |
| 拓展字段 | --where 'data_header.user_agent=FreeSWITCH%' | 先 fields,字段名和类型以当前 profile 返回为准 |
| 字符串排除 | --exclude 'data_header.from_user=1001' | 本版本拒绝整数排除,避免后端类型处理造成静默误查 |
| 任一报文字段满足 | --logic or | 作用于所有报文字段;时间、节点仍约束整个查询 |
| 预览 API 请求 | --dry-run | 仍会认证和读取字段映射;不发搜索 POST,不是纯离线命令 |
python3 homerctl.py search --since 15m --caller 1001 --src-port 5060 --all
python3 homerctl.py search --since 15m --caller 1001 --src-port 5080 --all当前 CLI 不支持嵌套条件。两次查询分别保留 caller 限制,再在应用层取并集;固定绝对时间能让窗口严格一致。去重用 dbnode、profile、id、timestamp_us,不只用 id。直接加 --logic or 会把 caller 也变成可选条件。
固定版本后端对各数据库节点分别执行 LIMIT,随后才合并排序;total 只是返回条数。本 CLI 检测任一节点是否达到上限,--all 再对饱和窗口做时间二分。它没有可靠的 offset 翻页或数据库总命中量证明。[S1][S3]
| 状态 | 含义 | 下一步 |
|---|---|---|
| no_limit_detected | 未检测到尚未解决的搜索上限;退出码一般为 0 | 仍需核对采集覆盖和已知通话,不能把空结果写成“没有通话” |
| partial | 饱和、预算耗尽、部分请求失败或记录时间不可判断;退出码 6 | 保留 stdout 的记录,检查 unresolved_windows、warnings 和窗口 |
| unknown | trace 的关联与采集覆盖没有全量证明 | 表述为“当前可见关联记录”,不声称完整端到端历史 |
例如同一节点的一秒内有 500 条匹配消息,而 limit 为 200,按秒拆分也解决不了。可增加上限或用 Call-ID、采集点等条件进一步收窄;这只是示意,500 不是本机压测结果。重叠边界会去重,但无法找回从未采集或已过保留期的数据。
| 预算项 | 默认值 / 范围 | 实际含义 |
|---|---|---|
| limit | 200;1–10000 | 每次请求、每数据库节点的行数 |
| max-requests | 64;1–1000 | 搜索请求预算,不含认证和 mapping;跨进程补查还需应用层总预算 |
| timeout / max-response-mib | 30 秒 / 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 | 用户中断。 |
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_call123、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]
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 | 让另一个人按原始节点与时间找到同一条记录 |
| 现场现象 | HOMER / CLI 的切入点 | 还需要什么 |
|---|---|---|
| 已知通话但搜索为空 | 固定同一窗口,确认时区、profile、节点和真实 From / To;比较 UI 中同一 Call-ID | HEP 到达 / 入库 / 分区保留、账号可见范围、后端错误日志;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 事务信息 |
把“用户说完 → ASR 完成 → LLM 开始/完成 → TTS 首块 → 媒体发出 → 接收端可听”与电话腿的建立/结束对齐。如果 SIP 已建立,但 TTS 没产出,继续查模型与编排;如果有 TTS 和发送事件,却无接收媒体,查媒体路径;如果收到 RTP 但仍无声,再查载荷、静音、编码和播放。HOMER 的 SIP 记录只能覆盖其中一部分,200 OK 也必须先看其 CSeq 对应哪个请求。[工程排障建议]
建议每次事件保留时间基准、节点、session_id、leg_id 和结果状态;跨机器时先记录时钟误差。所谓“AI 已说话”应区分生成了文本、生成了音频、发送了媒体和接收端实际可听,不把其中一层替代下一层。
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 | 本次规则未命中,或可分析材料不足 | 链路正常、没有分片、没有采集丢失 |
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,未合并进同点重复组。样本为合成数据,不是现网事故。
推荐流程是 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 --allschema 无须连接服务。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;工程建议]
| 核验层次 | 本次结果 | 覆盖边界 |
|---|---|---|
| 交付物 | 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、关联规则和性能待现场确认 |
原手册保留全部 11 章,包括安装、认证、组合查询、退出码、导出、UDP 分析、AI 调用与常见问题。扩展页按实际排障流程重排;原始包的内容和哈希保持不变。
原始 ZIP SHA-256:f33f2d196aeea9fb57e3ee5d1560201d412c7647725d90883df0ff60b17fd25c
2026-09-15 的源码基线、手册、AI_USAGE、测试与合成样本;2026-09-16 本机复测。 核对日期:2026-09-16。
平台边界、HEP、模块化和关联能力。正文含多个代际,本文不直接套用新版安装参数。 核对日期:2026-09-16。
每节点 LIMIT、结果排序、返回 total、整秒时间处理、通话关联与数据库错误边界。 核对日期:2026-09-16。
从存储字段与 raw 重建 Ethernet / IP / 传输头,不保留原始 IP 分片。 核对日期:2026-09-16。
2002-06;§12 对话标识、§18.1.1 传输选择。规范原文,不代表每个现网实现都合规。 核对日期:2026-09-16。
1981-09;Identification、Flags、Fragment Offset。 核对日期:2026-09-16。
2017-07;Fragment 扩展头与源节点分片。 核对日期:2026-09-16。