feat: Agent 批量测试、作业助手与上传预览;Windows 启动脚本与文档- 新增 run_agent_test_cases 与示例 JSON、(红头)agent测试用例文档
- 扩展 test_agent_execution(--homework、UTF-8 控制台) - 后端:uploads 预览、file_read、工作流与对话落盘等 - 前端:AgentChatPreview 与设计器相关调整 - 忽略 redis二进制、agent_workspaces、uploads、tessdata 等本机产物 Made-with: Cursor
This commit is contained in:
156
backend/scripts/test_homework_agent_hello.py
Normal file
156
backend/scripts/test_homework_agent_hello.py
Normal file
@@ -0,0 +1,156 @@
|
||||
"""
|
||||
测试“学生作业管理助手”最小对话链路:
|
||||
1) 登录
|
||||
2) 按名称查找 Agent
|
||||
3) 创建执行并发送“你好”
|
||||
4) 轮询直到完成,打印助手回复
|
||||
|
||||
示例:
|
||||
python scripts/test_homework_agent_hello.py --password 123456
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import argparse
|
||||
import sys
|
||||
import time
|
||||
from typing import Any, Dict, List, Optional
|
||||
|
||||
import requests
|
||||
|
||||
|
||||
def parse_args() -> argparse.Namespace:
|
||||
parser = argparse.ArgumentParser(description="测试学生作业管理助手发送“你好”")
|
||||
parser.add_argument("--base-url", default="http://127.0.0.1:8037", help="后端地址")
|
||||
parser.add_argument("--username", default="admin", help="登录用户名")
|
||||
parser.add_argument("--password", default="123456", help="登录密码")
|
||||
parser.add_argument("--agent-name", default="学生作业管理助手", help="目标 Agent 名称")
|
||||
parser.add_argument("--message", default="你好", help="发送内容")
|
||||
parser.add_argument("--timeout-seconds", type=int, default=90, help="轮询超时秒数")
|
||||
parser.add_argument("--poll-interval", type=float, default=1.5, help="轮询间隔秒")
|
||||
parser.add_argument("--request-timeout", type=int, default=30, help="单次HTTP请求超时秒数")
|
||||
return parser.parse_args()
|
||||
|
||||
|
||||
def login(base_url: str, username: str, password: str, timeout: int = 20) -> str:
|
||||
url = f"{base_url}/api/v1/auth/login"
|
||||
resp = requests.post(
|
||||
url,
|
||||
data={"username": username, "password": password},
|
||||
headers={"Content-Type": "application/x-www-form-urlencoded"},
|
||||
timeout=timeout,
|
||||
)
|
||||
resp.raise_for_status()
|
||||
data = resp.json()
|
||||
token = data.get("access_token")
|
||||
if not token:
|
||||
raise RuntimeError(f"登录成功但未返回 access_token: {data}")
|
||||
return token
|
||||
|
||||
|
||||
def pick_agent_id(base_url: str, headers: Dict[str, str], agent_name: str, timeout: int = 20) -> str:
|
||||
url = f"{base_url}/api/v1/agents"
|
||||
resp = requests.get(url, headers=headers, params={"search": agent_name, "limit": 100}, timeout=timeout)
|
||||
resp.raise_for_status()
|
||||
agents: List[Dict[str, Any]] = resp.json() or []
|
||||
|
||||
exact = [a for a in agents if (a.get("name") or "").strip() == agent_name]
|
||||
target = exact[0] if exact else (agents[0] if agents else None)
|
||||
if not target:
|
||||
raise RuntimeError(f"未找到 Agent: {agent_name}")
|
||||
return str(target["id"])
|
||||
|
||||
|
||||
def create_execution(
|
||||
base_url: str, headers: Dict[str, str], agent_id: str, message: str, timeout: int = 30
|
||||
) -> Dict[str, Any]:
|
||||
url = f"{base_url}/api/v1/executions"
|
||||
payload = {
|
||||
"agent_id": agent_id,
|
||||
"input_data": {
|
||||
"USER_INPUT": message,
|
||||
"query": message,
|
||||
"user_id": f"preview_{agent_id}",
|
||||
"attachments": [],
|
||||
},
|
||||
}
|
||||
resp = requests.post(url, headers=headers, json=payload, timeout=timeout)
|
||||
resp.raise_for_status()
|
||||
return resp.json()
|
||||
|
||||
|
||||
def extract_reply(exec_data: Dict[str, Any]) -> str:
|
||||
output_data = exec_data.get("output_data")
|
||||
if not output_data:
|
||||
return ""
|
||||
if isinstance(output_data, str):
|
||||
return output_data
|
||||
if isinstance(output_data, dict):
|
||||
for key in ("result", "output", "response", "text"):
|
||||
value = output_data.get(key)
|
||||
if value is not None:
|
||||
return value if isinstance(value, str) else str(value)
|
||||
return str(output_data)
|
||||
return str(output_data)
|
||||
|
||||
|
||||
def get_execution(base_url: str, headers: Dict[str, str], execution_id: str, timeout: int = 20) -> Dict[str, Any]:
|
||||
url = f"{base_url}/api/v1/executions/{execution_id}"
|
||||
resp = requests.get(url, headers=headers, timeout=timeout)
|
||||
resp.raise_for_status()
|
||||
return resp.json()
|
||||
|
||||
|
||||
def main() -> int:
|
||||
args = parse_args()
|
||||
base_url = args.base_url.rstrip("/")
|
||||
|
||||
try:
|
||||
token = login(base_url, args.username, args.password, timeout=args.request_timeout)
|
||||
headers = {"Authorization": f"Bearer {token}"}
|
||||
print(f"[OK] 登录成功: {args.username}")
|
||||
|
||||
agent_id = pick_agent_id(base_url, headers, args.agent_name, timeout=args.request_timeout)
|
||||
print(f"[OK] 找到 Agent: {args.agent_name} ({agent_id})")
|
||||
|
||||
created = create_execution(
|
||||
base_url, headers, agent_id, args.message, timeout=args.request_timeout
|
||||
)
|
||||
execution_id = str(created["id"])
|
||||
print(f"[OK] 已发送消息: {args.message}")
|
||||
print(f"[INFO] execution_id: {execution_id}")
|
||||
|
||||
deadline = time.time() + max(1, args.timeout_seconds)
|
||||
while time.time() < deadline:
|
||||
detail = get_execution(base_url, headers, execution_id, timeout=args.request_timeout)
|
||||
status = detail.get("status")
|
||||
if status in ("completed", "failed", "cancelled", "awaiting_approval"):
|
||||
print(f"[INFO] 最终状态: {status}")
|
||||
if status == "completed":
|
||||
reply = extract_reply(detail)
|
||||
print("[AGENT_REPLY]")
|
||||
print(reply or "(空回复)")
|
||||
return 0
|
||||
print(detail.get("error_message") or "(无错误信息)")
|
||||
return 2
|
||||
print(f"[POLL] status={status}")
|
||||
time.sleep(max(0.2, args.poll_interval))
|
||||
|
||||
print("[TIMEOUT] 轮询超时,执行尚未完成")
|
||||
return 3
|
||||
except requests.HTTPError as e:
|
||||
body = ""
|
||||
if e.response is not None:
|
||||
try:
|
||||
body = e.response.text[:500]
|
||||
except Exception:
|
||||
body = "<无法读取响应内容>"
|
||||
print(f"[HTTP_ERROR] {e} {body}")
|
||||
return 4
|
||||
except Exception as e: # noqa: BLE001
|
||||
print(f"[ERROR] {e}")
|
||||
return 5
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
sys.exit(main())
|
||||
Reference in New Issue
Block a user