fix(health): drop live LLM ping — scan agent.log instead (38s -> 0.1s)
Every /api/xmpp/health fetch ran a real LLM call (22k token system prompt each). Dashboard refreshes every 10s -> thousands of paid LLM calls/day, plus 38s latency hanging the health tab on '加载中...'. LLM health is now derived from the gateway's own agent.log (zero cost, more accurate than synthetic ping — real traffic results): - last 'API call #N latency=Xs' -> ok - last 'API call failed ... HTTP 429...' -> error with summary - health() runtime 38s -> 0.1s; endpoint 38s -> 0.097s
This commit is contained in:
+58
-14
@@ -338,20 +338,9 @@ def health():
|
||||
except Exception: pass
|
||||
result["gateways"][name] = {"port": port, "alive": ok}
|
||||
|
||||
# 测试知微的 LLM 调用是否可达
|
||||
if result["gateways"].get("zhiwei", {}).get("alive"):
|
||||
try:
|
||||
import urllib.request
|
||||
payload = json.dumps({"model": "deepseek-v4-flash", "messages": [{"role": "user", "content": "ping"}],
|
||||
"max_tokens": 5, "stream": False}).encode()
|
||||
req = urllib.request.Request("http://127.0.0.1:8643/v1/chat/completions",
|
||||
data=payload, headers={"Content-Type": "application/json",
|
||||
"Authorization": "Bearer hermes123"})
|
||||
urllib.request.urlopen(req, timeout=90)
|
||||
result["llm_provider"] = {"status": "ok", "latency": "fast"}
|
||||
except Exception as e:
|
||||
result["llm_provider"] = {"status": "timeout" if "timeout" in str(e).lower() else "error",
|
||||
"error": str(e)[:150]}
|
||||
# LLM 健康:扫 gateway agent.log 最近一次真实调用结果(零成本,不发 LLM 请求)
|
||||
# agent.log 里每次真实调用都有记录:成功 "API call #N: ... latency=Xs" / 失败 "HTTP 429..."
|
||||
result["llm_provider"] = _scan_agent_log(now_epoch)
|
||||
except Exception as e:
|
||||
result["gateways"] = {"error": str(e)[:100]}
|
||||
|
||||
@@ -376,6 +365,61 @@ def health():
|
||||
return result
|
||||
|
||||
|
||||
AGENT_LOG = Path("/home/hmo/.hermes/profiles/position-analyst/logs/agent.log")
|
||||
|
||||
|
||||
def _scan_agent_log(now_epoch, tail_lines=300):
|
||||
"""扫 gateway agent.log 尾部,取最近一次真实 LLM 调用的结果。
|
||||
|
||||
成功行: "2026-07-19 20:04:42,880 INFO ... API call #4: ... latency=16.0s ..."
|
||||
失败行: "2026-07-19 19:35:59 WARNING ... API call failed ... HTTP 429: Weekly usage limit reached ..."
|
||||
返回 {"status": "ok"|"error"|"unknown", "latency"/"error", "age_sec"}
|
||||
"""
|
||||
if not AGENT_LOG.exists():
|
||||
return {"status": "unknown", "error": "agent.log not found"}
|
||||
try:
|
||||
# 只读尾部(大文件不全读)
|
||||
size = AGENT_LOG.stat().st_size
|
||||
with open(AGENT_LOG, "rb") as f:
|
||||
f.seek(max(0, size - 64 * 1024))
|
||||
chunk = f.read().decode("utf-8", errors="replace")
|
||||
lines = [l for l in chunk.splitlines() if l.strip()][-tail_lines:]
|
||||
except Exception as e:
|
||||
return {"status": "unknown", "error": str(e)[:80]}
|
||||
|
||||
last_ok = None # (epoch, latency_str)
|
||||
last_fail = None # (epoch, summary)
|
||||
for line in lines:
|
||||
m_ts = _re.search(r"(\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2})", line)
|
||||
if not m_ts:
|
||||
continue
|
||||
try:
|
||||
ts = datetime.strptime(m_ts.group(1), "%Y-%m-%d %H:%M:%S").timestamp()
|
||||
except Exception:
|
||||
continue
|
||||
m_ok = _re.search(r"API call #\d+.*latency=([\d.]+)s", line)
|
||||
if m_ok:
|
||||
last_ok = (ts, m_ok.group(1))
|
||||
continue
|
||||
if "API call failed" in line and ("summary=" in line or "after" in line):
|
||||
m_err = _re.search(r"summary=(.+?)$", line)
|
||||
summary = (m_err.group(1) if m_err else line)[:150]
|
||||
last_fail = (ts, summary)
|
||||
|
||||
if not last_ok and not last_fail:
|
||||
return {"status": "unknown", "error": "no LLM calls in log"}
|
||||
|
||||
if last_fail and (not last_ok or last_fail[0] > last_ok[0]):
|
||||
return {"status": "error",
|
||||
"error": last_fail[1],
|
||||
"age_sec": int(now_epoch - last_fail[0]),
|
||||
"source": "agent.log"}
|
||||
return {"status": "ok",
|
||||
"latency": f"{last_ok[1]}s",
|
||||
"age_sec": int(now_epoch - last_ok[0]),
|
||||
"source": "agent.log"}
|
||||
|
||||
|
||||
def _fetch_keys():
|
||||
"""从 AgentsMeeting Dashboard 获取可用 API Key 列表"""
|
||||
try:
|
||||
|
||||
Reference in New Issue
Block a user