80 lines
3.1 KiB
Python
80 lines
3.1 KiB
Python
"""扫最近的 task,定位「bad arguments to run_python: code or script_path must be
|
|
provided」到底什么时候真正触发。
|
|
|
|
两条线:
|
|
A. 直接在 tool-result 消息里搜这句错误 —— 这是运行时真的报了的铁证。
|
|
B. 看产生它的那条 assistant run_python 调用,arguments 到底长啥样。
|
|
排除 `_compacted`(那是入库后上下文压缩留下的历史占位,运行时是有 code 的,不算)。
|
|
"""
|
|
import json
|
|
import os
|
|
from collections import Counter
|
|
from pathlib import Path
|
|
|
|
env = Path(__file__).resolve().parent.parent / ".env"
|
|
for line in env.read_text(encoding="utf-8").splitlines():
|
|
if line.strip().startswith("ZCBOT_DB_URL="):
|
|
os.environ["ZCBOT_DB_URL"] = line.split("=", 1)[1].strip()
|
|
|
|
from sqlalchemy import create_engine, text # noqa: E402
|
|
|
|
engine = create_engine(os.environ["ZCBOT_DB_URL"])
|
|
ERR = "bad arguments to run_python: code or script_path must be provided"
|
|
|
|
with engine.connect() as conn:
|
|
tasks = conn.execute(
|
|
text("select task_id, created_at from tasks order by created_at desc limit 60")
|
|
).fetchall()
|
|
|
|
per_task = Counter()
|
|
shapes = Counter()
|
|
samples = []
|
|
for tid, created in tasks:
|
|
msgs = conn.execute(
|
|
text("select idx, payload from messages where task_id=:t order by idx"),
|
|
{"t": tid},
|
|
).fetchall()
|
|
# 建 tool_call_id -> arguments 映射(看错误对应的调用 args)
|
|
call_args = {}
|
|
for idx, payload in msgs:
|
|
if payload.get("role") == "assistant":
|
|
for tc in payload.get("tool_calls") or []:
|
|
call_args[tc.get("id")] = (tc.get("function") or {}).get("arguments")
|
|
for idx, payload in msgs:
|
|
if payload.get("role") != "tool":
|
|
continue
|
|
content = payload.get("content") or ""
|
|
if isinstance(content, list):
|
|
content = json.dumps(content, ensure_ascii=False)
|
|
if ERR not in content:
|
|
continue
|
|
per_task[(str(tid)[:8], str(created)[:16])] += 1
|
|
raw = call_args.get(payload.get("tool_call_id"))
|
|
# 归类 args 形态
|
|
try:
|
|
args = json.loads(raw) if raw else {}
|
|
except Exception:
|
|
shape = "MANGLED(非法JSON)"
|
|
else:
|
|
if args == {}:
|
|
shape = "空 {}"
|
|
elif "_compacted" in args:
|
|
shape = "_compacted(历史占位)"
|
|
else:
|
|
shape = "其他: " + repr(raw)[:80]
|
|
shapes[shape] += 1
|
|
if len(samples) < 25:
|
|
samples.append((str(tid)[:8], idx, shape, repr(raw)[:140]))
|
|
|
|
print(f"扫了最近 {len(tasks)} 个 task")
|
|
print(f"真正触发该错误的 tool-result 条数: {sum(per_task.values())}\n")
|
|
print("=== 按 task 分布(task / 创建时间 / 次数)===")
|
|
for (t, c), n in per_task.most_common():
|
|
print(f" {t} {c} -> {n} 次")
|
|
print("\n=== 触发时 run_python 的 arguments 形态 ===")
|
|
for s, n in shapes.most_common():
|
|
print(f" {n:>3}x {s}")
|
|
print("\n=== 样本 ===")
|
|
for t, idx, shape, raw in samples:
|
|
print(f" [{t} #{idx}] {shape}: {raw}")
|