<# .SYNOPSIS 启动金融 Agent 平台:依赖检查 → API → Agent Worker。 .NOTES ⚠️ 本文件必须保存为 **UTF-8 with BOM**。 Windows PowerShell 5.1 在缺少 BOM 时按系统 ANSI 解析脚本(简体中文下是 GBK), 中文注释与输出会变成乱码并直接抛语法错误(实测报 `Unexpected token '[璀﹀憡]'`)。 用编辑器改完本文件后,务必另存为「UTF-8 带 BOM」。 .DESCRIPTION 平台需要**两个进程**才能完整工作,本脚本把它们一起起在独立窗口里: · API —— 所有 HTTP 接口与前端页面(/portal/) · Worker —— 消费队列:Agent 对话、知识向量同步、记忆抽取、风控扫描 **没有 Worker 的后果**(这也是最容易踩的坑): · 客服对话会一直停在 queued,前端显示"客服繁忙/超时"; · 新灌的知识写不进 Milvus,客服照旧答不上,且**没有任何报错**。 .PARAMETER Port API 监听端口,默认 8000。 .PARAMETER SkipChecks 跳过依赖端口检查(MySQL / Redis / Milvus)。 .PARAMETER ApiOnly 只起 API,不起 Worker(仅在明确不需要 Agent 能力时使用)。 .PARAMETER SkipPriceSync 跳过启动时的行情刷新。仅在外部数据源不可用、或不想联网时使用。 .EXAMPLE powershell -ExecutionPolicy Bypass -File start.ps1 powershell -ExecutionPolicy Bypass -File start.ps1 -Port 8100 #> param( [int]$Port = 8000, [switch]$SkipChecks, [switch]$ApiOnly, [switch]$SkipPriceSync ) $ErrorActionPreference = "Stop" $Root = $PSScriptRoot Set-Location $Root Write-Host "=== 金融 Agent 平台 · 启动 ===" -ForegroundColor Cyan Write-Host "工作目录:$Root" # ---------------------------------------------------------------- 解释器 # 逐个尝试:项目虚拟环境 → 常见 conda 环境 → PATH 上的 python。 # 不写死任何一个,因为各人机器的环境不同(.venv 被 gitignore,不进仓库)。 $candidates = @( (Join-Path $Root ".venv\Scripts\python.exe"), "D:\conda\envs\jr_py313\python.exe", "python" ) $Python = $null foreach ($candidate in $candidates) { try { if ($candidate -eq "python") { $version = & python --version 2>&1 } else { if (-not (Test-Path $candidate)) { continue } $version = & $candidate --version 2>&1 } if ($LASTEXITCODE -eq 0) { $Python = $candidate Write-Host "解释器:$candidate($version)" -ForegroundColor Green break } } catch { continue } } if (-not $Python) { Write-Host "[失败] 找不到可用的 Python。请先建虚拟环境,或把解释器路径加进本脚本的候选列表。" -ForegroundColor Red exit 1 } # ---------------------------------------------------------------- 依赖检查 if (-not $SkipChecks) { Write-Host "`n--- 依赖服务检查 ---" -ForegroundColor Cyan $services = @( @{ Name = "MySQL"; HostName = "127.0.0.1"; Port = 3306; Required = $true }, @{ Name = "Redis"; HostName = "127.0.0.1"; Port = 6379; Required = $false }, @{ Name = "Milvus"; HostName = "127.0.0.1"; Port = 19530; Required = $false } ) foreach ($service in $services) { $reachable = $false try { $reachable = (Test-NetConnection -ComputerName $service.HostName -Port $service.Port ` -InformationLevel Quiet -WarningAction SilentlyContinue) } catch { $reachable = $false } if ($reachable) { Write-Host (" [OK] {0,-7} {1}:{2}" -f $service.Name, $service.HostName, $service.Port) -ForegroundColor Green } elseif ($service.Required) { Write-Host (" [缺失] {0,-7} {1}:{2} —— 平台起不来,请先启动它" -f $service.Name, $service.HostName, $service.Port) -ForegroundColor Red exit 1 } else { Write-Host (" [警告] {0,-7} {1}:{2} 不可达:相关知识检索会降级、Docker 未运行时常见" -f $service.Name, $service.HostName, $service.Port) -ForegroundColor Yellow } } } # ---------------------------------------------------------------- 刷新行情 # ⚠️ 为什么放在启动流程里:下单要求行情快照落在 **15 分钟**有效期内 # (`app/service/trade_service.py` 的 `MAX_QUOTE_AGE`),超时后**所有委托直接 503 # 「行情已过期」**,而系统**没有任何自动刷新机制** —— 演示时讲到一半下单就会失败。 # 所以默认在启动时刷一次:15 分钟窗口从此刻重新计时。 # 同步是按产品 upsert 的幂等操作;失败只警告不阻断(仍可手动重跑)。 if (-not $SkipPriceSync) { Write-Host "`n--- 刷新行情(下单前置,有效期 15 分钟)---" -ForegroundColor Cyan $syncOutput = & $Python "tools\sync_market_prices.py" 2>&1 if ($LASTEXITCODE -eq 0) { Write-Host " [OK] 行情已刷新,15 分钟内可正常下单" -ForegroundColor Green } else { Write-Host " [警告] 行情刷新失败(退出码 $LASTEXITCODE):下单可能返回 503" -ForegroundColor Yellow Write-Host " 可手动重跑:$Python tools\sync_market_prices.py" -ForegroundColor Yellow $syncOutput | Select-Object -Last 8 | ForEach-Object { Write-Host " $_" -ForegroundColor DarkGray } } } # ---------------------------------------------------------------- 启动进程 # 用独立窗口起,方便分别看两边的日志(Worker 的日志是排查问题的第一现场)。 function Start-PlatformWindow { param([string]$Title, [string[]]$Arguments) $shell = if (Get-Command pwsh -ErrorAction SilentlyContinue) { "pwsh" } else { "powershell" } $command = "`$host.UI.RawUI.WindowTitle = '$Title'; & '$Python' " + ($Arguments -join " ") Start-Process -FilePath $shell -ArgumentList "-NoExit", "-Command", $command | Out-Null } Write-Host "`n--- 启动进程 ---" -ForegroundColor Cyan Start-PlatformWindow -Title "平台 API :$Port" -Arguments @( "-m", "uvicorn", "app.main:app", "--host", "127.0.0.1", "--port", "$Port" ) Write-Host " [已启动] API 窗口(uvicorn,端口 $Port)" -ForegroundColor Green if (-not $ApiOnly) { Start-PlatformWindow -Title "平台 Agent Worker" -Arguments @("-m", "app.worker") Write-Host " [已启动] Worker 窗口(Agent 对话 / 知识向量 / 记忆抽取)" -ForegroundColor Green } else { Write-Host " [跳过] Worker(-ApiOnly):客服对话会一直 queued、新知识不会进 Milvus" -ForegroundColor Yellow } # ---------------------------------------------------------------- 访问入口 Start-Sleep -Seconds 3 Write-Host "`n=== 访问入口 ===" -ForegroundColor Cyan Write-Host " 门户首页 http://127.0.0.1:$Port/portal/" Write-Host " 访客页 http://127.0.0.1:$Port/portal/guest/home/" Write-Host " 客户登录 http://127.0.0.1:$Port/portal/customer/login/ (cust_t / 123456)" Write-Host " 员工登录 http://127.0.0.1:$Port/portal/employee-console/login/(见下)" Write-Host " 接口文档 http://127.0.0.1:$Port/docs" Write-Host "`n=== 演示账号 ===" -ForegroundColor Cyan Write-Host " 客户 cust_t / 123456" Write-Host " 风控专员 risk_t / 666666" Write-Host " 管理员 admin_t / 88888888" Write-Host " 投顾 advisor_t / abc12345" Write-Host " 运营 offsite_t / offsite123" Write-Host "`n提示:" -ForegroundColor Yellow Write-Host " · 首次使用先准备数据:python tools/seed_demo_data.py" Write-Host " · 行情有效期只有 15 分钟:演示中途下单若报 503,在新窗口重跑" Write-Host " python tools/sync_market_prices.py (立即生效,无需重启服务)" Write-Host " · 体检:python tools/e2e_smoke_test.py" Write-Host " · 演示流程见 docs/44-演示流程.md"