101 lines
3.8 KiB
Python
101 lines
3.8 KiB
Python
"""圆桌后台作业真网关 —— headless 验证脚本(Phase 3b)。
|
||
|
||
用法(在能起完整后端栈 + 配好真模型的环境):
|
||
|
||
1) 用真网关启动后端:
|
||
ROUNDTABLE_JOB_GATEWAY=inprocess make gateway
|
||
(或 docker 里给 gateway 容器加该环境变量)
|
||
|
||
2) 跑本脚本,它会:POST 启动一个作业 → 轮询 GET 打印进度 → 跑到 done 打印报告长度。
|
||
PYTHONPATH=. uv run python scripts/probe_roundtable_job.py
|
||
|
||
环境变量:
|
||
GATEWAY_URL 默认 http://127.0.0.1:8001
|
||
AUTH_COOKIE 若后端开启鉴权,传 "session=xxx" 之类的 Cookie 头
|
||
PROBE_INTENT 自定义任务意图
|
||
PROBE_MODE recommend(默认)| chain
|
||
|
||
说明:鉴权关闭的 dev 模式无需 AUTH_COOKIE。真网关会进程内驱动 roundtable-coordinator /
|
||
各席位 / roundtable-report 真模型,耗时取决于模型,可能数分钟。
|
||
"""
|
||
|
||
from __future__ import annotations
|
||
|
||
import asyncio
|
||
import os
|
||
import time
|
||
|
||
import httpx
|
||
|
||
GATEWAY_URL = os.getenv("GATEWAY_URL", "http://127.0.0.1:8001").rstrip("/")
|
||
AUTH_COOKIE = os.getenv("AUTH_COOKIE", "")
|
||
INTENT = os.getenv("PROBE_INTENT", "为一家中型制造企业设计一套数字化转型的整体方案")
|
||
MODE = os.getenv("PROBE_MODE", "recommend")
|
||
|
||
# 用 3 个内置圆桌席位(确保可见、已 seed)。
|
||
AGENTS = [
|
||
{"agentId": "roundtable-intelligence", "name": "情报收集"},
|
||
{"agentId": "roundtable-solution-design", "name": "方案设计"},
|
||
{"agentId": "roundtable-summary", "name": "总结陈述"},
|
||
]
|
||
|
||
TERMINAL = {"done", "error", "cancelled"}
|
||
|
||
|
||
def _headers() -> dict[str, str]:
|
||
h = {"Content-Type": "application/json"}
|
||
if AUTH_COOKIE:
|
||
h["Cookie"] = AUTH_COOKIE
|
||
return h
|
||
|
||
|
||
async def main() -> None:
|
||
async with httpx.AsyncClient(timeout=30.0, trust_env=False) as client:
|
||
print(f"[probe] POST {GATEWAY_URL}/api/roundtable-jobs mode={MODE}")
|
||
resp = await client.post(
|
||
f"{GATEWAY_URL}/api/roundtable-jobs",
|
||
headers=_headers(),
|
||
json={"intent": INTENT, "agents": AGENTS, "orchestrationMode": MODE},
|
||
)
|
||
if resp.status_code != 201:
|
||
print(f"[probe] start failed: HTTP {resp.status_code}: {resp.text[:500]}")
|
||
return
|
||
job = resp.json()
|
||
job_id = job["id"]
|
||
print(f"[probe] started job {job_id}")
|
||
|
||
last = ""
|
||
t0 = time.perf_counter()
|
||
while True:
|
||
await asyncio.sleep(2.0)
|
||
r = await client.get(f"{GATEWAY_URL}/api/roundtable-jobs/{job_id}", headers=_headers())
|
||
if r.status_code != 200:
|
||
print(f"[probe] get failed: HTTP {r.status_code}: {r.text[:300]}")
|
||
return
|
||
j = r.json()
|
||
line = (
|
||
f"status={j['status']} phase={j['phase']} cycle={j['cycle']} "
|
||
f"active={j.get('activeAgentId')} consensus={j['consensusPercentage']}%"
|
||
)
|
||
if line != last:
|
||
print(f"[probe] +{time.perf_counter() - t0:5.0f}s {line}")
|
||
last = line
|
||
if j["status"] in TERMINAL:
|
||
print(f"[probe] terminal: {j['status']}")
|
||
if j["status"] == "error":
|
||
print(f"[probe] error detail: {j.get('error')}")
|
||
# 读草稿 step3 验证报告已落库
|
||
if j.get("draftId"):
|
||
dr = await client.get(
|
||
f"{GATEWAY_URL}/api/roundtable-drafts/{j['draftId']}", headers=_headers()
|
||
)
|
||
if dr.status_code == 200:
|
||
step3 = dr.json().get("step3")
|
||
html_len = len((step3 or {}).get("html") or "")
|
||
print(f"[probe] draft.step3 html length = {html_len}")
|
||
return
|
||
|
||
|
||
if __name__ == "__main__":
|
||
asyncio.run(main())
|