# ============================================================ # LambdaAgentPaaS — Windows 一键启动脚本 (PowerShell) # # 用法: # .\deploy\start.ps1 # 正常启动 # .\deploy\start.ps1 -Build # 强制重新构建镜像 # .\deploy\start.ps1 -Reset # 清除所有数据重新初始化 # # 要求: Docker Desktop for Windows 已安装并运行 # PowerShell 5.1 或 PowerShell 7+ # ============================================================ param( [switch]$Build, [switch]$Reset ) $ErrorActionPreference = "Stop" # ── 路径常量 ──────────────────────────────────────────────── $ScriptDir = Split-Path -Parent $MyInvocation.MyCommand.Path $ProjectDir = Split-Path -Parent $ScriptDir $DataDir = Join-Path $env:USERPROFILE ".agentpaas\data" $EnvFile = Join-Path $env:USERPROFILE ".agentpaas\.env" $AppPort = if ($env:AGENTPAAS_PORT) { $env:AGENTPAAS_PORT } else { "8000" } $AppUrl = "http://localhost:$AppPort" # ── 颜色输出辅助函数 ───────────────────────────────────────── function Write-Info { param($msg) Write-Host "ℹ $msg" -ForegroundColor Cyan } function Write-Success { param($msg) Write-Host "✅ $msg" -ForegroundColor Green } function Write-Warn { param($msg) Write-Host "⚠️ $msg" -ForegroundColor Yellow } function Write-Err { param($msg) Write-Host "❌ $msg" -ForegroundColor Red } function Write-Header { param($msg) Write-Host "`n=== $msg ===`n" -ForegroundColor Magenta } # ── 检查 Docker ────────────────────────────────────────────── function Check-Docker { Write-Header "检查 Docker 环境" if (-not (Get-Command docker -ErrorAction SilentlyContinue)) { Write-Err "未找到 Docker。请先安装 Docker Desktop:" Write-Host " https://docs.docker.com/desktop/install/windows-install/" $open = Read-Host "是否现在打开下载页面? (Y/n)" if ($open -ne 'n' -and $open -ne 'N') { Start-Process "https://docs.docker.com/desktop/install/windows-install/" } exit 1 } $dockerRunning = $false try { docker info 2>&1 | Out-Null $dockerRunning = $true } catch {} if (-not $dockerRunning) { Write-Info "Docker Desktop 未运行,尝试启动..." $dockerDesktopPaths = @( "$env:ProgramFiles\Docker\Docker\Docker Desktop.exe", "$env:LOCALAPPDATA\Programs\Docker\Docker\Docker Desktop.exe" ) $launched = $false foreach ($path in $dockerDesktopPaths) { if (Test-Path $path) { Start-Process $path $launched = $true break } } if (-not $launched) { Write-Warn "无法自动启动 Docker Desktop,请手动启动后重试。" exit 1 } Write-Host -NoNewline "等待 Docker 就绪" $waited = 0 do { Start-Sleep -Seconds 2 $waited += 2 Write-Host -NoNewline "." if ($waited -gt 60) { Write-Host "" Write-Err "Docker 启动超时(60s)。请手动启动 Docker Desktop 后重试。" exit 1 } try { docker info 2>&1 | Out-Null; break } catch {} } while ($true) Write-Host "" Write-Success "Docker 已就绪" } # 检测 compose 命令 $script:ComposeCmd = $null try { docker compose version 2>&1 | Out-Null; $script:ComposeCmd = "docker compose" } catch {} if (-not $script:ComposeCmd) { if (Get-Command docker-compose -ErrorAction SilentlyContinue) { $script:ComposeCmd = "docker-compose" } else { Write-Err "未找到 docker compose。请升级 Docker Desktop 到最新版本。" exit 1 } } Write-Success "Docker 环境检查通过" } # ── 初始化数据目录 ──────────────────────────────────────────── function Init-DataDir { $dirs = @( $DataDir, (Join-Path $DataDir "instances"), (Join-Path $DataDir "knowledge_bases"), (Join-Path $DataDir "logs") ) foreach ($dir in $dirs) { if (-not (Test-Path $dir)) { New-Item -ItemType Directory -Path $dir -Force | Out-Null } } } # ── 初始化 .env 配置 ───────────────────────────────────────── function Init-Env { $configDir = Split-Path -Parent $EnvFile if (-not (Test-Path $configDir)) { New-Item -ItemType Directory -Path $configDir -Force | Out-Null } if ((Test-Path $EnvFile) -and (-not $Reset)) { return } Write-Header "🔧 首次配置初始化" # 复制模板 Copy-Item (Join-Path $ProjectDir ".env.template") $EnvFile -Force # 生成 MASTER_KEY $masterKey = -join ((1..32) | ForEach-Object { [System.Security.Cryptography.RandomNumberGenerator]::GetBytes(1) | ForEach-Object { $_.ToString("x2") } }) # 更新 .env 文件 $envContent = Get-Content $EnvFile $envContent = $envContent -replace "^AGENTPAAS_DATA_DIR=.*", "AGENTPAAS_DATA_DIR=$DataDir" $envContent = $envContent -replace "^AGENTPAAS_MASTER_KEY=.*", "AGENTPAAS_MASTER_KEY=$masterKey" $envContent | Set-Content $EnvFile -Encoding UTF8 Write-Success "配置文件已创建: $EnvFile" Write-Host "" Write-Warn "请编辑配置文件,填写至少一个 LLM API Key:" Write-Host " DASHSCOPE_API_KEY= (阿里云百炼,国内推荐)" Write-Host " ANTHROPIC_API_KEY= (Claude)" Write-Host " OPENAI_API_KEY= (GPT)" Write-Host "" $open = Read-Host "是否现在打开配置文件编辑? (Y/n)" if ($open -ne 'n' -and $open -ne 'N') { # 尝试用记事本打开 Start-Process notepad $EnvFile Write-Host "配置完成后,请重新运行此脚本。" exit 0 } } # ── 加载 .env 文件为环境变量 ───────────────────────────────── function Load-EnvFile { if (-not (Test-Path $EnvFile)) { return } Get-Content $EnvFile | ForEach-Object { if ($_ -match "^\s*([^#][^=]+)=(.*)$") { $name = $matches[1].Trim() $value = $matches[2].Trim() if ($value -ne "" -and -not [System.Environment]::GetEnvironmentVariable($name)) { [System.Environment]::SetEnvironmentVariable($name, $value, "Process") } } } } # ── 检查 API Keys ──────────────────────────────────────────── function Check-ApiKeys { $keyVars = @("DASHSCOPE_API_KEY","OPENAI_API_KEY","ANTHROPIC_API_KEY", "DEEPSEEK_API_KEY","ZHIPU_API_KEY","MOONSHOT_API_KEY") $hasKey = $false foreach ($var in $keyVars) { $val = [System.Environment]::GetEnvironmentVariable($var) if ($val -and $val.Trim() -ne "") { $hasKey = $true; break } } if (-not $hasKey) { Write-Warn "未检测到任何 LLM API Key。Agent 功能将不可用。" Write-Host "请在 $EnvFile 中配置至少一个 API Key。" Write-Host "" $cont = Read-Host "继续启动? (y/N)" if ($cont -ne 'y' -and $cont -ne 'Y') { exit 0 } } } # ── 启动服务 ───────────────────────────────────────────────── function Start-Services { Write-Header "🚀 启动 LambdaAgentPaaS" # 将 Windows 路径转换为 Docker 可接受格式 # Docker Desktop (WSL2) 可以直接处理 Windows 路径,但统一转换更安全 $env:AGENTPAAS_DATA_DIR = $DataDir Set-Location $ProjectDir if ($Reset) { Write-Info "清除旧容器..." Invoke-Expression "$($script:ComposeCmd) down --remove-orphans" 2>$null docker rmi lambdagentpaas:latest 2>$null } $buildArg = if ($Build -or $Reset) { "--build" } else { "" } Write-Info "构建并启动容器(首次构建约 5-10 分钟)..." Invoke-Expression "$($script:ComposeCmd) --env-file `"$EnvFile`" up -d $buildArg" } # ── 等待健康检查 ───────────────────────────────────────────── function Wait-ForHealth { Write-Host -NoNewline "等待服务就绪" $waited = 0 do { Start-Sleep -Seconds 2 $waited += 2 Write-Host -NoNewline "." if ($waited -gt 120) { Write-Host "" Write-Err "服务启动超时(120s)" Write-Host "查看日志: docker logs lambdagentpaas" exit 1 } try { $resp = Invoke-WebRequest -Uri "$AppUrl/health" -UseBasicParsing -TimeoutSec 3 if ($resp.StatusCode -eq 200) { break } } catch {} } while ($true) Write-Host "" } # ── 打印成功信息 ───────────────────────────────────────────── function Print-Success { Write-Host "" Write-Host "╔══════════════════════════════════════════════╗" -ForegroundColor Green Write-Host "║ 🎉 LambdaAgentPaaS 已成功启动! ║" -ForegroundColor Green Write-Host "╠══════════════════════════════════════════════╣" -ForegroundColor Green Write-Host "║ Web 界面: $AppUrl ║" -ForegroundColor Green Write-Host "║ API 文档: $AppUrl/docs ║" -ForegroundColor Green Write-Host "╠══════════════════════════════════════════════╣" -ForegroundColor Green Write-Host "║ 数据目录: $DataDir" -ForegroundColor Green Write-Host "║ 配置文件: $EnvFile" -ForegroundColor Green Write-Host "╠══════════════════════════════════════════════╣" -ForegroundColor Green Write-Host "║ 停止服务: deploy\stop.bat ║" -ForegroundColor Green Write-Host "║ 查看日志: docker logs -f lambdagentpaas ║" -ForegroundColor Green Write-Host "╚══════════════════════════════════════════════╝" -ForegroundColor Green Write-Host "" } # ── 主流程 ─────────────────────────────────────────────────── Write-Header "LambdaAgentPaaS 启动器 (Windows)" Check-Docker Init-DataDir Init-Env Load-EnvFile Check-ApiKeys Start-Services Wait-ForHealth Print-Success # 自动打开浏览器 Start-Process $AppUrl