wip: qa7920 sidecar + rag stream timeout
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,43 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
from fastapi import FastAPI
|
||||
|
||||
|
||||
PROJECT_ROOT = Path(__file__).resolve().parents[1]
|
||||
QA_SERVICE_ROOT = PROJECT_ROOT / "services" / "qa_v1_1_73"
|
||||
if str(QA_SERVICE_ROOT) not in sys.path:
|
||||
sys.path.insert(0, str(QA_SERVICE_ROOT))
|
||||
|
||||
from src.rag.qa_v1_1_73 import __version__
|
||||
from src.rag.qa_v1_1_73.api import router
|
||||
from src.rag.qa_v1_1_73.backend_guard import validate_backends
|
||||
|
||||
|
||||
app = FastAPI(
|
||||
title="Plant Biology QA V1.1.73",
|
||||
version=__version__,
|
||||
description=(
|
||||
"Production full-graph QA with assertion-anchored Qdrant recall, "
|
||||
"bounded canonical Neo4j expansion, BGE reranking, and citation validation."
|
||||
),
|
||||
)
|
||||
app.include_router(router)
|
||||
|
||||
|
||||
@app.on_event("startup")
|
||||
def validate_production_backends() -> None:
|
||||
app.state.kb_backend_identity = validate_backends()
|
||||
|
||||
|
||||
@app.get("/health")
|
||||
def health():
|
||||
return {
|
||||
"status": "ok",
|
||||
"service": "qa_v1_1_73",
|
||||
"version": __version__,
|
||||
"source": "plantai_git_repository",
|
||||
"backend": app.state.kb_backend_identity,
|
||||
}
|
||||
Executable
+84
@@ -0,0 +1,84 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
PROJECT_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
||||
QA_SERVICE_ROOT="$PROJECT_ROOT/services/qa_v1_1_73"
|
||||
APP_MODULE="scripts.qa_v1_1_73_server:app"
|
||||
RUNTIME_ENV="${QA_V1_RUNTIME_ENV:-/home/xzq/5090/PlanAI-cooperate/RAG/runtime/qa_v1_1_73.env}"
|
||||
PYTHON="${QA_V1_PYTHON:-/home/xzq/miniconda3/envs/gfpy312/bin/python}"
|
||||
PORT="${QA_V1_1_73_PORT:-7920}"
|
||||
RUNTIME_DIR="${QA_V1_RUNTIME_DIR:-$PROJECT_ROOT/.runtime/qa_v1_1_73}"
|
||||
LOG="$RUNTIME_DIR/qa_$PORT.log"
|
||||
PIDFILE="$RUNTIME_DIR/qa_$PORT.pid"
|
||||
|
||||
mkdir -p "$RUNTIME_DIR"
|
||||
|
||||
if [[ ! -x "$PYTHON" ]]; then
|
||||
echo "ERROR: Python interpreter is missing: $PYTHON" >&2
|
||||
exit 1
|
||||
fi
|
||||
if [[ ! -r "$RUNTIME_ENV" ]]; then
|
||||
echo "ERROR: Runtime environment is missing: $RUNTIME_ENV" >&2
|
||||
exit 1
|
||||
fi
|
||||
if [[ ! -f "$QA_SERVICE_ROOT/src/rag/qa_v1_1_73/api.py" ]]; then
|
||||
echo "ERROR: Versioned QA source is missing from $QA_SERVICE_ROOT" >&2
|
||||
exit 1
|
||||
fi
|
||||
if ss -ltn | awk '{print $4}' | grep -qE ":$PORT$"; then
|
||||
echo "ERROR: Port $PORT is already in use." >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
set -a
|
||||
source "$RUNTIME_ENV"
|
||||
set +a
|
||||
|
||||
export GENE_FAMILY_ROOT="$QA_SERVICE_ROOT"
|
||||
export PYTHONPATH="$QA_SERVICE_ROOT:$PROJECT_ROOT"
|
||||
export NEO4J_URI="bolt://127.0.0.1:18788"
|
||||
export NEO4J_USER="${NEO4J_USER:-neo4j}"
|
||||
export QA_V1_GRAPH_SCHEMA="canonical"
|
||||
export V15_QDRANT_URL="http://127.0.0.1:26333"
|
||||
export V15_QDRANT_COLLECTION="plant_srt_direct_v1_bge_m3_20260702"
|
||||
export QA_V1_EMBED_URL="http://127.0.0.1:11434/api/embed"
|
||||
export QA_V1_EMBED_MODEL="bge-m3:567m"
|
||||
export QA_V1_BGE_RERANKER_MODEL="/home/xzq/5090/PlantAI-rag/bge-reranker-base"
|
||||
export QA_V1_BGE_DEVICE="cuda"
|
||||
export QA_PAPER_METADATA_REGISTRY="/home/xzq/5090/PlantAI-dev4090-7/gene-family-mas-v2_qa_v1_1_73_current/data/knowledge_base/paper_metadata_registry_v1_20260717/paper_metadata_registry_full.jsonl"
|
||||
export QA_V1_ENABLE_PROVISIONAL_DRAFT="0"
|
||||
export QA_V1_MAX_ROUNDS="1"
|
||||
export QA_V1_ENABLE_AGENTIC_CONTROLLER="1"
|
||||
export QA_V1_AGENTIC_MAX_REPLANS="1"
|
||||
export QA_V1_ALLOW_AGENTIC_REVIEW_FALLBACK="1"
|
||||
export QA_V1_ENABLE_AGENTIC_HOP_GATE="1"
|
||||
export QA_V1_AGENTIC_HOP_GATE_MAX_HOPS="3"
|
||||
export QA_ENABLE_QUESTION_DECOMPOSITION="1"
|
||||
export QA_V1_SUBQUESTION_WORKERS="3"
|
||||
export QA_V1_VECTOR_QUERY_WORKERS="2"
|
||||
export QA_V1_BOUNDED_MAX_FRONTIER="24"
|
||||
export QA_V1_BOUNDED_PER_NODE="12"
|
||||
export QA_V1_BOUNDED_MAX_HOPS="3"
|
||||
export QA_V1_BOUNDED_NEO4J_TIMEOUT="8"
|
||||
export QA_V1_BOUNDED_QDRANT_TIMEOUT="30"
|
||||
export QA_V1_BOUNDED_EMBED_TIMEOUT="30"
|
||||
export LD_LIBRARY_PATH="/home/xzq/miniconda3/envs/gfpy312/lib:${LD_LIBRARY_PATH-}"
|
||||
|
||||
nohup "$PYTHON" -m uvicorn "$APP_MODULE" \
|
||||
--app-dir "$PROJECT_ROOT" \
|
||||
--host 127.0.0.1 \
|
||||
--port "$PORT" > "$LOG" 2>&1 < /dev/null &
|
||||
echo $! > "$PIDFILE"
|
||||
|
||||
for _ in $(seq 1 90); do
|
||||
if curl --max-time 2 -fsS "http://127.0.0.1:$PORT/health" >/dev/null 2>&1; then
|
||||
echo "QA service started on http://127.0.0.1:$PORT"
|
||||
echo "PID file: $PIDFILE"
|
||||
echo "Log: $LOG"
|
||||
exit 0
|
||||
fi
|
||||
sleep 1
|
||||
done
|
||||
|
||||
echo "ERROR: QA service failed to become healthy. See $LOG" >&2
|
||||
exit 1
|
||||
Executable
+52
@@ -0,0 +1,52 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
PROJECT_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
||||
SIDECAR_PORT="${QA_V1_SIDECAR_PORT:-7945}"
|
||||
EVIDENCE_DIR="$PROJECT_ROOT/.runtime/qa_v1_1_73/formal_sidecar_$SIDECAR_PORT"
|
||||
QUESTION="In which species was tissue-specific expression of CAMTA3 (SR1) examined?"
|
||||
|
||||
mkdir -p "$EVIDENCE_DIR"
|
||||
|
||||
QA_V1_1_73_PORT="$SIDECAR_PORT" \
|
||||
QA_V1_RUNTIME_DIR="$EVIDENCE_DIR" \
|
||||
bash "$PROJECT_ROOT/scripts/start_qa_v1_1_73_7920.sh" \
|
||||
> "$EVIDENCE_DIR/launch.txt" 2>&1
|
||||
|
||||
curl -fsS --max-time 15 \
|
||||
"http://127.0.0.1:$SIDECAR_PORT/health" \
|
||||
> "$EVIDENCE_DIR/health.json"
|
||||
curl -fsS --max-time 15 \
|
||||
"http://127.0.0.1:$SIDECAR_PORT/api/v1/qa-v1-1-73/info" \
|
||||
> "$EVIDENCE_DIR/info.json"
|
||||
curl -sS --max-time 150 \
|
||||
-H "Content-Type: application/json" \
|
||||
-d "{\"question\":\"$QUESTION\",\"debug\":false,\"use_llm\":true,\"chain_top_k\":3,\"chain_hops\":2,\"chain_max_edges\":12,\"chain_max_nodes\":10,\"native_chain_enabled\":true,\"native_chain_max_hops\":3,\"native_chain_top_k\":5}" \
|
||||
-o "$EVIDENCE_DIR/response.json" \
|
||||
-w "status=%{http_code} total=%{time_total}s bytes=%{size_download}\\n" \
|
||||
"http://127.0.0.1:$SIDECAR_PORT/api/v1/qa-v1-1-73/chat" \
|
||||
> "$EVIDENCE_DIR/timing.txt"
|
||||
|
||||
"${QA_V1_PYTHON:-/home/xzq/miniconda3/envs/gfpy312/bin/python}" - "$EVIDENCE_DIR" <<'PY'
|
||||
import json
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
evidence_dir = Path(sys.argv[1])
|
||||
health = json.loads((evidence_dir / "health.json").read_text(encoding="utf-8"))
|
||||
info = json.loads((evidence_dir / "info.json").read_text(encoding="utf-8"))
|
||||
response = json.loads((evidence_dir / "response.json").read_text(encoding="utf-8"))
|
||||
timing = (evidence_dir / "timing.txt").read_text(encoding="utf-8")
|
||||
|
||||
assert health["status"] == "ok"
|
||||
assert health["source"] == "plantai_git_repository"
|
||||
assert "sandbox" not in json.dumps(health).lower()
|
||||
assert "sandbox" not in json.dumps(info).lower()
|
||||
assert info["config"]["graph_schema"] == "canonical"
|
||||
assert "status=200" in timing
|
||||
assert response.get("success", True) is True
|
||||
assert "Solanum lycopersicum" in response.get("answer", "")
|
||||
assert response.get("native_graph_chains")
|
||||
|
||||
(evidence_dir / "PASS").write_text("sidecar validation passed\n", encoding="utf-8")
|
||||
PY
|
||||
Reference in New Issue
Block a user