Skip to content

[Proposal] LLM-channel hardening: provider-config audit + completion smoke in post-install verify #1346

Open

Description

@LUOSENGWA

Summary

We propose to harden the LLM-channel verification surface in two small steps, plus one docs note:

  1. LLM smoke check in install/agentteams-verify.sh — one minimal completion request through the gateway, using the Manager's own gateway key and configured model, so a broken model route fails the post-install check instead of staying silent.
  2. Provider-config audit for install/upgrade — warn on gateway provider configs whose openaiCustomUrl host/port cannot work (internal aliases, embedded ports, missing /v1) before they become a silent outage.
  3. Docs — a short note documenting the openaiCustomUrl contract and how to attribute LLM errors (gateway-local vs upstream).

Why: a field incident where every existing check stayed green

On one of our self-hosted deployments, a single LLM route was silently broken for ~12 days. The post-install verifier passed every check: the Manager container was running, MinIO and Matrix were healthy, the gateway and console were "reachable", and the agent health endpoint was fine — while 100% of completion requests through that route failed.

What it took to find the root cause:

Two things exposed it: issuing a real (minimal) completion request, and reading the gateway access log. Both are cheap and could be automated.

Proposal 1 — an "LLM channel smoke" check in install/agentteams-verify.sh

  • New check Update hosts hint: domains now resolve to 127.0.0.1 by default #8: POST /v1/chat/completions with max_tokens: 1 through the gateway, Authorization: Bearer $AGENTTEAMS_MANAGER_GATEWAY_KEY, model = $AGENTTEAMS_DEFAULT_MODEL (fallback: the documented default).
    • This mirrors the controller's own welcome-readiness probe (IsManagerLLMAuthReady in provisioner.go), which already issues a tiny chat-completions request with the manager's key — same request shape, same cost class (~10–20 tokens).
  • PASS on 2xx; SKIP when the key is absent from the container env or the check is explicitly disabled; FAIL otherwise, with a hint pointing at the provider base-URL host/port and the gateway logs.
  • Overrides for split/embedded topologies: AGENTTEAMS_VERIFY_LLM_URL (probe URL) and AGENTTEAMS_VERIFY_SKIP_LLM=1 (disable).
  • We can contribute this as a PR — including the mock-based matrix we used to exercise PASS/FAIL/SKIP/override paths, if useful.

Proposal 2 — provider-config audit at install/upgrade

When install/upgrade flows touch gateway provider config, validate and warn (non-blocking):

  • openaiCustomUrl host must be a real routable domain — flag internal-alias forms (host equal to the provider's openaiCustomServiceName, or *.dns-style aliases) and URLs with an embedded :port (the port belongs to the service source);
  • for OpenAI-compatible providers, hint when the URL path lacks /v1;
  • cross-check the URL host against the matching service-sources entry's domain;
  • report legacy names (hiclaw-*) for review.

Proposal 3 — docs

Document the openaiCustomUrl contract (real routable domain; /v1 in the path; port handled by the service source) and add a short "where is my LLM error coming from" note: gateway-local errors vs upstream responses, using access-log fields (response_code_details, upstream_service_time) and common edge fingerprints (e.g. an empty body with an unusual 4xx from an edge CDN/WAF).

Notes & scope

  • This is not a bug report against a component: our audit of the repository history shows the generator paths produce correct values (.dns appears only in openaiCustomServiceName, never in openaiCustomUrl). The gap is detection, not generation.
  • The smoke check is deliberately minimal and skippable; it does not change any existing check's behavior. After correcting the config value in our incident, the same route returned a real completion — the proposed check would have caught it at install time.
  • Topology note: agentteams-verify.sh currently assumes a single-container deployment; the new check is written to be overridable/skippable so it can follow whatever direction the embedded-topology routing (fix(verify): route embedded checks to controller #1046, closed) evolves into.

Related / overlap

We're happy to start with Proposal 1 as a PR and iterate on scope — raw logs and the mock harness are available if useful.


摘要

我们提议从两个小步 + 一条文档入手,加固 AgentTeams 的 LLM 通道验证面:

  1. install/agentteams-verify.sh 增加「LLM 冒烟」检查 —— 用 Manager 自己的网关 key 和所配模型,向网关发一条最小 completion 请求;模型路由坏掉时安装后检查直接失败,而不是保持沉默。
  2. 安装/升级时的 provider 配置审计 —— 对 openaiCustomUrl 主机/端口不可能工作的配置(内网别名、URL 内嵌端口、缺 /v1)给出警告,避免它们变成静默故障。
  3. 文档 —— 一页说明 openaiCustomUrl 契约,以及如何归因 LLM 错误(网关本地 vs 上游)。

为什么:一次「现有检查全绿」的现场事故

在我们一台自部署实例上,一条 LLM 路由静默损坏了约 12 天。安装后验证器全部通过:Manager 容器在跑、MinIO 与 Matrix 健康、网关与控制台「可达」、agent 健康端点正常 —— 而该路由 100% 的 completion 请求全部失败。

定位根因的代价:

暴露它的只有两件事:发一条真实的(最小)completion 请求;读网关访问日志。两者都很便宜,都可以自动化。

提案 1 —— install/agentteams-verify.sh 增加「LLM 通道冒烟」检查

  • 新增检查 Update hosts hint: domains now resolve to 127.0.0.1 by default #8:经网关 POST /v1/chat/completions,max_tokens: 1,Authorization: Bearer $AGENTTEAMS_MANAGER_GATEWAY_KEY,模型取 $AGENTTEAMS_DEFAULT_MODEL(缺省时用文档默认值)。
    • 这与 controller 自己的欢迎就绪探针(provisioner.go 的 IsManagerLLMAuthReady)同构 —— 同样的请求形态、同样的成本量级(约 10–20 token)。
  • 2xx → PASS;容器 env 中无 key、或显式关闭时为 SKIP;其余 FAIL,并在提示里指向 provider base URL 的主机/端口与网关日志。
  • 为拆分/嵌入式拓扑提供开关:AGENTTEAMS_VERIFY_LLM_URL(探针 URL)与 AGENTTEAMS_VERIFY_SKIP_LLM=1(关闭)。
  • 我们可以把它做成 PR 贡献 —— 如有需要,连我们用来覆盖 PASS/FAIL/SKIP/override 四路的 mock 矩阵一并提供。

提案 2 —— 安装/升级时的 provider 配置审计

当安装/升级流程接触网关 provider 配置时,做非阻塞校验与警告:

  • openaiCustomUrl 的主机必须是真实可路由域名 —— 标记内网别名形态(主机等于该 provider 的 openaiCustomServiceName,或 *.dns 式别名)与 URL 内嵌 :port(端口应归 service source 管);
  • OpenAI 兼容 provider,路径缺 /v1 时给出提示;
  • 用 URL 主机对应 service-sources 条目的 domain 做交叉核对;
  • 把遗留命名(hiclaw-*)列出来供复核。

提案 3 —— 文档

说明 openaiCustomUrl 契约(真实可路由域名;路径带 /v1;端口由 service source 承载),并加一节「我的 LLM 错误从哪来」:网关本地错误 vs 上游响应,附访问日志字段(response_code_details、upstream_service_time)与常见边缘特征(例如边缘 CDN/WAF 返回的异常 4xx + 空 body)。

说明与范围

  • 这不是针对某个组件的 bug 报告:我们审计了仓库历史,生成器路径都产出正确值(.dns 只出现在 openaiCustomServiceName,从未出现在 openaiCustomUrl)。缺的是检测,不是生成。
  • 冒烟检查刻意做到最小化、可跳过,不改变任何现有检查的行为。我们事故里修正配置值后,同一条路由即恢复真实补全 —— 本提案的检查本可在安装时就抓住它。
  • 拓扑说明:agentteams-verify.sh 目前假定单容器部署;新检查写成可覆盖/可跳过,以跟随嵌入式拓扑路由方向(fix(verify): route embedded checks to controller #1046,已关闭)的后续演进。

关联与查重

我们乐意先以提案 1 的 PR 起步、再按需迭代范围 —— 原始日志与 mock 矩阵随时可以分享。

Activity

  1. shiyiyue1102 commented on Oct 16, 2026

    @shiyiyue1102
    Collaborator

    抱歉回复晚了,这里补充处理进展:提案 1 的 LLM 通道冒烟检查已通过 PR #1347 合入 main,并补充了可执行回归测试及 CI 覆盖。最终实现沿用 controller 的最小 completion 请求,不发送 max_tokens,以兼容拒绝该参数的模型服务,同时支持显式跳过和探测地址覆盖。提案 2 的 provider 配置审计及提案 3 的说明文档尚未随该 PR 落地,本 Issue 继续保留讨论这两部分,感谢贡献。


    Sorry for the late reply, here is the processing progress: the LLM channel smoke check of Proposal 1 has been merged into main through PR #1347, and executable regression testing and CI coverage have been added. The final implementation follows the controller's minimum completion request and does not send max_tokens to be compatible with model services that reject this parameter. It also supports explicit skipping and detection of address overrides. The provider configuration audit of Proposal 2 and the documentation of Proposal 3 have not yet been implemented with this PR. This issue will continue to discuss these two parts. Thank you for your contribution.

  2. added this to the 1.2.6 milestone on Oct 19, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions