diff --git a/apps/web/vue3/index.html b/apps/web/vue3/index.html
index 6c09c6113..d87445fe9 100644
--- a/apps/web/vue3/index.html
+++ b/apps/web/vue3/index.html
@@ -1368,6 +1368,7 @@
拓展分析阶段
+ 运行结果
已写阶段
@@ -1428,7 +1429,6 @@
运行已发布
- 运行结果
diff --git a/apps/web/vue3/main.py b/apps/web/vue3/main.py
index d8499c7c5..22962c7f0 100644
--- a/apps/web/vue3/main.py
+++ b/apps/web/vue3/main.py
@@ -4191,6 +4191,9 @@ def _attach_agent_manifest_status(task: Dict) -> None:
print(f"[API DEBUG] Failed to attach agent manifest status: {e}")
app = FastAPI(title="BotanicalBaseAgent API")
+from gfa_core.extension_stage_lightweight.api import create_lightweight_extension_router
+
+app.include_router(create_lightweight_extension_router())
# MainAgent runtime state. Analysis planning and execution remain owned by
# the original IntentAgent/PlanningAgent/frontend flow below.
llm_manager = None
diff --git a/manage_plantai.sh b/manage_plantai.sh
new file mode 100755
index 000000000..52b893ae5
--- /dev/null
+++ b/manage_plantai.sh
@@ -0,0 +1,185 @@
+#!/bin/bash
+# PlantAI-dev 9000 服务管理脚本
+# 用法: bash manage_plantai.sh {start|stop|restart|status} [--port PORT]
+# 默认端口: 9000
+#
+# 项目: /home/xzq/5090/teamWorkspace/zh/PlantAI-dev
+# 端口: 9000 (web), Redis DB 14 (queue prefix: plantai_dev_9002)
+
+set -euo pipefail
+
+# 解析命令行参数:第一个参数是命令,后面可选 --port / -p
+CMD=""
+WEB_PORT="9000"
+for arg in "$@"; do
+ case "$arg" in
+ start|stop|restart|status)
+ CMD="$arg"
+ ;;
+ --port|-p)
+ WEB_PORT=""
+ ;;
+ *)
+ if [ -z "$WEB_PORT" ] && [[ "$arg" =~ ^[0-9]+$ ]]; then
+ WEB_PORT="$arg"
+ elif [ -z "$CMD" ]; then
+ echo "错误: 未知命令 '$arg'"
+ echo "用法: bash manage_plantai.sh {start|stop|restart|status} [--port PORT]"
+ exit 1
+ fi
+ ;;
+ esac
+done
+CMD="${CMD:-status}"
+
+# Conda 环境:启动脚本内部也依赖这个环境
+CONDA_ENV="${CONDA_ENV:-/home/xzq/miniconda3/envs/test4py311}"
+export PATH="$CONDA_ENV/bin:$PATH"
+
+# 项目配置(与 .env 和启动脚本保持一致)
+PROJECT_DIR="/home/xzq/5090/teamWorkspace/zh/PlantAI-dev"
+QUEUE_PREFIX="plantai_dev_9002"
+WEB_LOG="/tmp/plantai_${WEB_PORT}.log"
+CELERY_LOG="/tmp/celery_${WEB_PORT}.log"
+
+red() { echo -e "\033[31m$*\033[0m"; }
+green(){ echo -e "\033[32m$*\033[0m"; }
+cyan() { echo -e "\033[36m$*\033[0m"; }
+
+status() {
+ echo ""
+ cyan "=== PlantAI-dev ${WEB_PORT} 服务状态 ==="
+ echo ""
+
+ # Web 服务
+ WEB_PID=$(ss -tlnp 2>/dev/null | grep ":$WEB_PORT " | grep -oP 'pid=\K\d+' || true)
+ if [ -n "${WEB_PID:-}" ]; then
+ green "[✓] Web 服务运行中 (端口 $WEB_PORT, PID $WEB_PID)"
+ else
+ red "[✗] Web 服务未启动 (端口 $WEB_PORT)"
+ fi
+
+ # Redis
+ if redis-cli ping > /dev/null 2>&1; then
+ green "[✓] Redis 运行中 (localhost:6379)"
+ else
+ red "[✗] Redis 未启动"
+ fi
+
+ # Celery workers
+ CELERY_COUNT=$(pgrep -fc "$QUEUE_PREFIX" || echo 0)
+ if [ "$CELERY_COUNT" -gt 0 ]; then
+ green "[✓] Celery workers 运行中 (${CELERY_COUNT} 进程, 队列前缀: $QUEUE_PREFIX)"
+ echo " Worker 列表:"
+ ps aux | grep "$QUEUE_PREFIX" | grep -v grep | grep -oP "queues=\K\S+" | sort | while read q; do
+ echo " - $q"
+ done
+ else
+ red "[✗] Celery workers 未启动 (队列前缀: $QUEUE_PREFIX)"
+ fi
+ echo ""
+}
+
+stop() {
+ echo ""
+ cyan "=== 停止 PlantAI-dev ${WEB_PORT} 服务 ==="
+ echo ""
+
+ # 停止 Web 服务
+ WEB_PID=$(ss -tlnp 2>/dev/null | grep ":$WEB_PORT " | grep -oP 'pid=\K\d+' || true)
+ if [ -n "${WEB_PID:-}" ]; then
+ echo "正在停止 Web 服务 (PID $WEB_PID)..."
+ kill "$WEB_PID" 2>/dev/null || true
+ sleep 1
+ # 如果还没死,强制 kill
+ if ss -tlnp 2>/dev/null | grep -q ":$WEB_PORT"; then
+ kill -9 "$WEB_PID" 2>/dev/null || true
+ fi
+ green "[✓] Web 服务已停止"
+ else
+ echo "[ ] Web 服务未运行"
+ fi
+
+ # 停止 Celery workers
+ CELERY_PIDS=$(pgrep -f "$QUEUE_PREFIX" 2>/dev/null) || true
+ if [ -n "${CELERY_PIDS:-}" ]; then
+ echo "正在停止 Celery workers..."
+ echo "$CELERY_PIDS" | xargs -r kill 2>/dev/null || true
+ sleep 2
+ # 清理残留
+ REMAIN=$(pgrep -f "$QUEUE_PREFIX" 2>/dev/null) || true
+ if [ -n "${REMAIN:-}" ]; then
+ echo " 强制清理残留进程..."
+ echo "$REMAIN" | xargs -r kill -9 2>/dev/null || true
+ fi
+ green "[✓] Celery workers 已停止"
+ else
+ echo "[ ] Celery workers 未运行"
+ fi
+ echo ""
+}
+
+start() {
+ echo ""
+ cyan "=== 启动 PlantAI-dev ${WEB_PORT} 服务 ==="
+ echo ""
+
+ # 检查是否已在运行
+ if ss -tlnp 2>/dev/null | grep -q ":$WEB_PORT"; then
+ red "[!] 端口 $WEB_PORT 已被占用,请先停止服务"
+ exit 1
+ fi
+
+ if ! redis-cli ping > /dev/null 2>&1; then
+ red "[!] Redis 未运行,请先启动 Redis"
+ exit 1
+ fi
+
+ cd "$PROJECT_DIR"
+
+ # 启动 Celery workers
+ echo "正在启动 Celery workers..."
+ nohup bash start_celery_9000.sh > "$CELERY_LOG" 2>&1 &
+ sleep 3
+ CELERY_COUNT=$(pgrep -fc "$QUEUE_PREFIX" || echo 0)
+ if [ "$CELERY_COUNT" -gt 0 ]; then
+ green " [✓] Celery workers 已启动 (${CELERY_COUNT} 进程)"
+ else
+ red " [✗] Celery workers 启动失败,查看 $CELERY_LOG"
+ fi
+
+ # 启动 Web 服务
+ echo "正在启动 Web 服务..."
+ nohup bash start_plantai_9000.sh --port "$WEB_PORT" > "$WEB_LOG" 2>&1 &
+ sleep 3
+ if ss -tlnp 2>/dev/null | grep -q ":$WEB_PORT"; then
+ green " [✓] Web 服务已启动 (http://0.0.0.0:$WEB_PORT)"
+ else
+ red " [✗] Web 服务启动失败,查看 $WEB_LOG"
+ fi
+
+ # 最终状态
+ echo ""
+ echo "日志文件:"
+ echo " Web: $WEB_LOG"
+ echo " Celery: $CELERY_LOG"
+ echo " Worker: $PROJECT_DIR/logs/celery_${QUEUE_PREFIX}/"
+ echo ""
+}
+
+restart() {
+ stop
+ sleep 1
+ start
+}
+
+case "$CMD" in
+ start) start ;;
+ stop) stop ;;
+ restart) restart ;;
+ status) status ;;
+ *)
+ echo "用法: bash manage_plantai.sh {start|stop|restart|status} [--port PORT]"
+ exit 1
+ ;;
+esac
diff --git a/restart_plantai_9000.sh b/restart_plantai_9000.sh
new file mode 100755
index 000000000..06e7bab13
--- /dev/null
+++ b/restart_plantai_9000.sh
@@ -0,0 +1,24 @@
+#!/bin/bash
+# Project restart script — called by /api/admin/restart-project
+# 用法: bash restart_plantai_9000.sh [--port PORT]
+# 从环境变量 PLANTAI_WEB_PORT 或参数获取端口,默认 9000
+
+set -euo pipefail
+
+SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
+
+PORT="${PLANTAI_WEB_PORT:-9000}"
+while [[ $# -gt 0 ]]; do
+ case "$1" in
+ --port|-p)
+ PORT="${2:?错误: --port 需要指定端口号}"
+ shift 2
+ ;;
+ *)
+ shift
+ ;;
+ esac
+done
+
+cd "$SCRIPT_DIR"
+exec bash manage_plantai.sh restart --port "$PORT"
diff --git a/start_celery_9000.sh b/start_celery_9000.sh
index 50a257db2..2496254f8 100755
--- a/start_celery_9000.sh
+++ b/start_celery_9000.sh
@@ -25,13 +25,13 @@ fi
if [ -n "$EXTERNAL_BBAV5_WORKER_NAME_PREFIX" ]; then
BBAV5_WORKER_NAME_PREFIX="$EXTERNAL_BBAV5_WORKER_NAME_PREFIX"
fi
-if [ -z "$EXTERNAL_BBAV5_QUEUE_PREFIX" ]; then
+if [ -z "${BBAV5_QUEUE_PREFIX-}" ]; then
BBAV5_QUEUE_PREFIX="plantai_dev_9000"
fi
-if [ -z "$EXTERNAL_BBAV5_REDIS_URL" ]; then
+if [ -z "${BBAV5_REDIS_URL-}" ]; then
BBAV5_REDIS_URL="redis://localhost:6379/10"
fi
-if [ -z "$EXTERNAL_BBAV5_CELERY_LOG_DIR" ]; then
+if [ -z "${BBAV5_CELERY_LOG_DIR-}" ]; then
BBAV5_CELERY_LOG_DIR="logs/celery_plantai_dev_9000"
fi
if [ -z "$EXTERNAL_BBAV5_WORKER_NAME_PREFIX" ]; then
diff --git a/start_plantai_9000.sh b/start_plantai_9000.sh
index e907169fa..93050a096 100755
--- a/start_plantai_9000.sh
+++ b/start_plantai_9000.sh
@@ -1,8 +1,26 @@
#!/bin/bash
-# Start the PlantAI-dev web service on port 9000.
+# Start the PlantAI-dev web service.
+# 用法: bash start_plantai_9000.sh [--port PORT]
+# 默认端口: 9000
set -euo pipefail
+# 解析命令行参数
+PORT="9000"
+while [[ $# -gt 0 ]]; do
+ case "$1" in
+ --port|-p)
+ PORT="${2:?错误: --port 需要指定端口号}"
+ shift 2
+ ;;
+ *)
+ echo "未知参数: $1"
+ echo "用法: bash start_plantai_9000.sh [--port PORT]"
+ exit 1
+ ;;
+ esac
+done
+
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
cd "$SCRIPT_DIR"
@@ -15,13 +33,19 @@ export PATH="$CONDA_ENV/bin:$PATH"
# the caller's shell; GWAS/other sandboxes have dedicated restart scripts.
export BBAV5_PROJECT_ROOT="$SCRIPT_DIR"
export PLANTAI_PROJECT_ROOT="$SCRIPT_DIR"
+if [ -f "$SCRIPT_DIR/.env" ]; then
+ set -a
+ . "$SCRIPT_DIR/.env"
+ set +a
+fi
export BBAV5_PROJECT_ENV_FILE="${BBAV5_PROJECT_ENV_FILE:-$SCRIPT_DIR/.env}"
export BBAV5_LIGHTWEIGHT_EXTENSION_STORE="${BBAV5_LIGHTWEIGHT_EXTENSION_STORE:-$SCRIPT_DIR/.runtime/lightweight-extension/store}"
export BBAV5_LIGHTWEIGHT_INPUT="${BBAV5_LIGHTWEIGHT_INPUT:-$SCRIPT_DIR/input}"
export BBAV5_LIGHTWEIGHT_WORKSPACE="${BBAV5_LIGHTWEIGHT_WORKSPACE:-$SCRIPT_DIR/workspace}"
-export BBAV5_QUEUE_PREFIX="plantai_dev_9000"
-export BBAV5_REDIS_URL="redis://localhost:6379/10"
-export PLANTAI_WEB_PORT="9000"
+export BBAV5_QUEUE_PREFIX="${BBAV5_QUEUE_PREFIX:-plantai_dev_9000}"
+export BBAV5_REDIS_URL="${BBAV5_REDIS_URL:-redis://localhost:6379/10}"
+export PLANTAI_WEB_PORT="$PORT"
+export PLANTAI_RESTART_SCRIPT="$SCRIPT_DIR/restart_plantai_9000.sh"
export GENE_FAMILY_MAS_API="http://127.0.0.1:7926"
export DUAL_KB_QA_BASE_URL="http://127.0.0.1:7926"
export RAG_API_URL="http://127.0.0.1:7926/api/v1/qa-v1-1-73/chat"