行动副驾驶网格
一个可重用的企业级多代理平台,将操作数据(电子表格)+SOP转化为Azure上可审计的见解和基于角色的操作。
核心技术
- 微软Foundry(路由器模型)
- Microsoft代理框架(多代理编排)
- MCP(工具感知代理)
- Azure部署(容器应用程序)+可观察性
本地跑
API(FastAPI)
cd apps/api
copy .env.example .env
python -m venv .venv
.\.venv\Scripts\Activate.ps1
pip install -r requirements.txt
python -m uvicorn app.main:app --reload --port 8000WEB(Next.js)
cd apps/web
copy .env.example .env.local
npm install
npm run dev网站将在 http://localhost:3000 并将API调用代理到 API_BASE_URL.
所需的环境变量
APIapps/api/.env)
AZURE_SEARCH_ENDPOINT=https://.search.windows.net
AZURE_SEARCH_KEY=
AZURE_SEARCH_INDEX=ops-sop
AZURE_STORAGE_CONNECTION_STRING=
APP_ENV=localWEB(apps/web/.env.local)
API_BASE_URL=http://127.0.0.1:8000建筑
待定
演示脚本
看 docs/demo.md 进行2分钟的法官演练。
Azure部署运行手册(PowerShell)
使用辅助脚本在ACR中构建映像并更新两个容器应用程序:
.\scripts\azure-deploy.ps1 `
-ResourceGroup "rg-ops-copilot-mesh" `
-AcrName "acropscopilotmesh2390" `
-ApiApp "api-ops-copilot-mesh" `
-WebApp "web-ops-copilot-mesh" `
-SearchEndpoint "https://.search.windows.net" `
-SearchIndex "ops-sop" `
-SearchKey "" `
-StorageConnectionString "" `
-RestartRevisions笔记:
AZURE_SEARCH_KEY和AZURE_STORAGE_CONNECTION_STRING作为容器应用程序机密应用(search-key,storage-conn).AZURE_SEARCH_INDEX云中不能空无一物。- 更新机密通常需要重新启动活动修订版:
az containerapp revision restart -n api-ops-copilot-mesh -g rg-ops-copilot-mesh --revision
az containerapp revision restart -n web-ops-copilot-mesh -g rg-ops-copilot-mesh --revision 如果 AZURE_SEARCH_INDEX API容器应用程序中缺少或为空,请显式修补:
az containerapp update `
-n api-ops-copilot-mesh `
-g rg-ops-copilot-mesh `
--set-env-vars AZURE_SEARCH_INDEX=ops-sop云奇偶校验(必需envs)
az containerapp show -n api-ops-copilot-mesh -g rg-ops-copilot-mesh `
--query "properties.template.containers[0].env[?name=='AZURE_SEARCH_ENDPOINT' || name=='AZURE_SEARCH_KEY' || name=='AZURE_SEARCH_INDEX' || name=='AZURE_STORAGE_CONNECTION_STRING'].{name:name,value:value,secretRef:secretRef}" `
-o table
az containerapp show -n web-ops-copilot-mesh -g rg-ops-copilot-mesh `
--query "properties.template.containers[0].env[?name=='API_BASE_URL'].{name:name,value:value}" `
-o table冒烟测试
将此有效负载用于所有操作分类检查:
$payload = @{ incident="Users report 500 errors after deployment"; role="operator"; top=5 } | ConvertTo-Json -Compress黑客马拉松演示烟雾测试
中性事件示例:
Users report intermittent 500 errors after deploymentAPI latency spike above 2s in one regionAuthentication failures increased for admin usersDatabase connection pool exhausted in checkout service
本地闭环烟雾:
$payload = @{ incident="API latency spike above 2s in one region"; role="operator"; top=5 } | ConvertTo-Json -Compress
$proposed = Invoke-RestMethod -Method Post -Uri "http://127.0.0.1:8000/v1/actions/propose" -ContentType "application/json" -Body $payload
$actionId = $proposed.id
Invoke-RestMethod -Method Post -Uri "http://127.0.0.1:8000/v1/actions/approve" -ContentType "application/json" -Body (@{ actionId=$actionId; approverRole="manager"; decision="APPROVE"; note="demo" } | ConvertTo-Json -Compress) | ConvertTo-Json -Depth 12
Invoke-RestMethod -Method Post -Uri "http://127.0.0.1:8000/v1/actions/execute" -ContentType "application/json" -Body (@{ actionId=$actionId; executorRole="operator" } | ConvertTo-Json -Compress) | ConvertTo-Json -Depth 12
Invoke-RestMethod -Method Get -Uri "http://127.0.0.1:8000/v1/audit/recent?actionId=$actionId&limit=50" | ConvertTo-Json -Depth 12Azure闭环烟雾:
$RG="rg-ops-copilot-mesh"
$API_APP="api-ops-copilot-mesh"
$WEB_APP="web-ops-copilot-mesh"
$API_FQDN = az containerapp show -n $API_APP -g $RG --query "properties.configuration.ingress.fqdn" -o tsv
$WEB_FQDN = az containerapp show -n $WEB_APP -g $RG --query "properties.configuration.ingress.fqdn" -o tsv
$payload = @{ incident="Authentication failures increased for admin users"; role="operator"; top=5 } | ConvertTo-Json -Compress
Invoke-RestMethod -Method Post -Uri "https://$API_FQDN/v1/actions/propose" -ContentType "application/json" -Body $payload | ConvertTo-Json -Depth 12
Invoke-RestMethod -Method Post -Uri "https://$WEB_FQDN/api/actions/propose" -ContentType "application/json" -Body $payload | ConvertTo-Json -Depth 121) 本地API直接调用
Invoke-RestMethod -Method Post -Uri "http://127.0.0.1:8000/v1/actions/propose" -ContentType "application/json" -Body $payload | ConvertTo-Json -Depth 121.1)批准和执行(API直接)
$proposed = Invoke-RestMethod -Method Post -Uri "http://127.0.0.1:8000/v1/actions/propose" -ContentType "application/json" -Body $payload
$actionId = $proposed.id
Invoke-RestMethod -Method Post -Uri "http://127.0.0.1:8000/v1/actions/approve" -ContentType "application/json" -Body (@{ actionId=$actionId; approverRole="manager"; decision="APPROVE" } | ConvertTo-Json -Compress) | ConvertTo-Json -Depth 12
Invoke-RestMethod -Method Post -Uri "http://127.0.0.1:8000/v1/actions/execute" -ContentType "application/json" -Body (@{ actionId=$actionId; executorRole="operator" } | ConvertTo-Json -Compress) | ConvertTo-Json -Depth 12
Invoke-RestMethod -Method Get -Uri "http://127.0.0.1:8000/v1/audit/recent?limit=20" | ConvertTo-Json -Depth 122) 本地Web代理调用(Next.js->neneneba API)
Invoke-RestMethod -Method Post -Uri "http://localhost:3000/api/actions/propose" -ContentType "application/json" -Body $payload | ConvertTo-Json -Depth 122.1)本地Web代理批准/执行
$proposed = Invoke-RestMethod -Method Post -Uri "http://localhost:3000/api/actions/propose" -ContentType "application/json" -Body $payload
$actionId = $proposed.id
Invoke-RestMethod -Method Post -Uri "http://localhost:3000/api/actions/approve" -ContentType "application/json" -Body (@{ actionId=$actionId; approverRole="manager"; decision="APPROVE" } | ConvertTo-Json -Compress) | ConvertTo-Json -Depth 12
Invoke-RestMethod -Method Post -Uri "http://localhost:3000/api/actions/execute" -ContentType "application/json" -Body (@{ actionId=$actionId; executorRole="operator" } | ConvertTo-Json -Compress) | ConvertTo-Json -Depth 12
Invoke-RestMethod -Method Get -Uri "http://localhost:3000/api/audit/recent?limit=20" | ConvertTo-Json -Depth 123) 已部署的Web代理调用(Azure容器应用程序)
替换 `` 使用您部署的web应用程序主机名:
Invoke-RestMethod -Method Post -Uri "https:///api/actions/propose" -ContentType "application/json" -Body $payload | ConvertTo-Json -Depth 123.1)直接部署API(Azure容器应用程序)
$RG="rg-ops-copilot-mesh"
$API_APP="api-ops-copilot-mesh"
$API_FQDN = az containerapp show -n $API_APP -g $RG --query "properties.configuration.ingress.fqdn" -o tsv
$payload = @{ incident="Users report 500 errors after deployment"; role="operator"; top=5 } | ConvertTo-Json -Compress
$proposed = Invoke-RestMethod -Method Post -Uri "https://$API_FQDN/v1/actions/propose" -ContentType "application/json" -Body $payload
$actionId = $proposed.id
Invoke-RestMethod -Method Post -Uri "https://$API_FQDN/v1/actions/approve" -ContentType "application/json" -Body (@{ actionId=$actionId; approverRole="manager"; decision="APPROVE"; note="judge demo" } | ConvertTo-Json -Compress) | ConvertTo-Json -Depth 12
Invoke-RestMethod -Method Post -Uri "https://$API_FQDN/v1/actions/execute" -ContentType "application/json" -Body (@{ actionId=$actionId; executorRole="operator" } | ConvertTo-Json -Compress) | ConvertTo-Json -Depth 12
Invoke-RestMethod -Method Get -Uri "https://$API_FQDN/v1/audit/recent?limit=20" | ConvertTo-Json -Depth 123.2)已部署的WEB代理(Azure容器应用程序)
$RG="rg-ops-copilot-mesh"
$WEB_APP="web-ops-copilot-mesh"
$WEB_FQDN = az containerapp show -n $WEB_APP -g $RG --query "properties.configuration.ingress.fqdn" -o tsv
$payload = @{ incident="Users report 500 errors after deployment"; role="operator"; top=5 } | ConvertTo-Json -Compress
$proposed = Invoke-RestMethod -Method Post -Uri "https://$WEB_FQDN/api/actions/propose" -ContentType "application/json" -Body $payload
$actionId = $proposed.id
Invoke-RestMethod -Method Post -Uri "https://$WEB_FQDN/api/actions/approve" -ContentType "application/json" -Body (@{ actionId=$actionId; approverRole="manager"; decision="APPROVE"; note="judge demo" } | ConvertTo-Json -Compress) | ConvertTo-Json -Depth 12
Invoke-RestMethod -Method Post -Uri "https://$WEB_FQDN/api/actions/execute" -ContentType "application/json" -Body (@{ actionId=$actionId; executorRole="operator" } | ConvertTo-Json -Compress) | ConvertTo-Json -Depth 12
Invoke-RestMethod -Method Get -Uri "https://$WEB_FQDN/api/audit/recent?limit=20" | ConvertTo-Json -Depth 12等效卷曲示例:
curl -sS -X POST "http://127.0.0.1:8000/v1/actions/propose" -H "Content-Type: application/json" -d '{"incident":"Users report 500 errors after deployment","role":"operator","top":5}'
curl -sS -X POST "http://localhost:3000/api/actions/propose" -H "Content-Type: application/json" -d '{"incident":"Users report 500 errors after deployment","role":"operator","top":5}'
curl -sS -X POST "https:///api/actions/propose" -H "Content-Type: application/json" -d '{"incident":"Users report 500 errors after deployment","role":"operator","top":5}'脚本烟雾测试(推荐)
# Local only (requires local API+WEB running)
.\scripts\azure-smoke-test.ps1 -SkipCloud
# Cloud only (auto-discovers FQDN from Container Apps)
.\scripts\azure-smoke-test.ps1 -SkipLocal
# Full (local + cloud)
.\scripts\azure-smoke-test.ps1