"""E2E:知你客服16号 单轮「你好」(需 API + Celery + LLM)。 环境变量: USE_TESTCLIENT=1 走 FastAPI TestClient(不经 HTTP),仅校验创建执行 201。 API_BASE 默认 http://127.0.0.1:8037;若该端口上 /health 无 checks,可改用本仓库单独起的实例,例如 http://127.0.0.1:8040。 E2E_AGENT_NAME / E2E_QUERY """ from __future__ import annotations import json import os import sys import time import uuid BACKEND_DIR = __file__.rsplit("scripts", 1)[0] API_BASE = os.environ.get("API_BASE", "http://127.0.0.1:8037") AGENT_NAME = os.environ.get("E2E_AGENT_NAME", "知你客服16号") QUERY = os.environ.get("E2E_QUERY", "你好") def main() -> int: os.chdir(BACKEND_DIR) sys.path.insert(0, BACKEND_DIR) if os.environ.get("USE_TESTCLIENT") == "1": from fastapi.testclient import TestClient from app.main import app from app.core.database import SessionLocal from app.core.security import create_access_token from app.models.agent import Agent from app.models.user import User db = SessionLocal() try: agent = db.query(Agent).filter(Agent.name == AGENT_NAME).first() if not agent: print(f"数据库中未找到「{AGENT_NAME}」", file=sys.stderr) return 1 owner = db.query(User).filter(User.id == agent.user_id).first() user = owner or db.query(User).first() if not user: print("无可用用户", file=sys.stderr) return 1 token = create_access_token(data={"sub": user.id, "username": user.username}) h = {"Authorization": f"Bearer {token}"} finally: db.close() c = TestClient(app) er = c.post( "/api/v1/executions", headers=h, json={ "agent_id": str(agent.id), "input_data": {"query": QUERY, "user_id": f"e2e_z16_tc_{uuid.uuid4().hex[:8]}"}, }, ) print("TestClient POST /executions:", er.status_code, er.text[:800]) if er.status_code not in (200, 201): return 2 print("OK — 本仓库 API 创建执行成功(异步需 Celery Worker 才会跑完)") return 0 import httpx from app.core.database import SessionLocal from app.core.security import create_access_token from app.models.agent import Agent from app.models.user import User db = SessionLocal() try: agent = db.query(Agent).filter(Agent.name == AGENT_NAME).first() if not agent: print(f"数据库中未找到「{AGENT_NAME}」", file=sys.stderr) return 1 owner = db.query(User).filter(User.id == agent.user_id).first() user = owner or db.query(User).first() if not user: print("无可用用户", file=sys.stderr) return 1 token = create_access_token(data={"sub": user.id, "username": user.username}) headers = {"Authorization": f"Bearer {token}"} uid = f"e2e_z16_{uuid.uuid4().hex[:10]}" print(f"agent_id={agent.id} name={agent.name} Q={QUERY!r} user_id={uid}\n") def poll(client: httpx.Client, execution_id: str, timeout: float = 300.0) -> dict: t0 = time.time() while time.time() - t0 < timeout: r = client.get(f"/api/v1/executions/{execution_id}", headers=headers) r.raise_for_status() data = r.json() st = data.get("status") if st == "completed": return data if st == "failed": print("error:", data.get("error_message"), file=sys.stderr) raise RuntimeError("执行失败") time.sleep(1) raise TimeoutError("超时") with httpx.Client(base_url=API_BASE, timeout=300.0) as client: r = client.post( "/api/v1/executions", json={"agent_id": str(agent.id), "input_data": {"query": QUERY, "user_id": uid}}, headers=headers, ) if r.status_code >= 400: print(r.text, file=sys.stderr) r.raise_for_status() eid = r.json()["id"] out = poll(client, eid) od = out.get("output_data") or {} rtxt = od.get("result") if isinstance(od, dict) else None print("--- 回复 ---") print((rtxt or json.dumps(od, ensure_ascii=False))[:4000]) finally: db.close() print("\n完成") return 0 if __name__ == "__main__": raise SystemExit(main())