wip: qa7920 sidecar + rag stream timeout

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
sj
2026-08-21 11:04:28 +08:00
co-authored by Claude Opus 5
parent b725a9c125
commit 90033214b4
66 changed files with 18990 additions and 68 deletions
+43
View File
@@ -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,
}
+84
View File
@@ -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
+52
View File
@@ -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