SushanthKS06/opsgenie-slack-agent

GitHub: SushanthKS06/opsgenie-slack-agent

基于 Slack 平台和 Claude 大模型构建的自主 L1 SRE 事件响应 Agent,实现从告警分诊、自动呼叫到复盘报告的全流程自动化编排。

Stars: 0 | Forks: 0

# OpsGenie — Slack Workflow 自动化响应机器 ### AI 事件指挥中心 ## 目录 1. [架构概述](#architecture-overview) 2. [项目结构](#project-structure) 3. [前置条件](#prerequisites) 4. [环境变量](#environment-variables) 5. [安装与设置](#installation--setup) 6. [部署](#deployment) 7. [配置入站 Webhook](#configuring-inbound-webhooks) 8. [事件生命周期](#incident-lifecycle) 9. [MCP Client 参考](#mcp-client-reference) 10. [Block Kit UI 参考](#block-kit-ui-reference) 11. [运行测试](#running-tests) 12. [扩展 SWARM](#extending-swarm) 13. [故障排除](#troubleshooting) ## 架构概述 ``` ┌──────────────────────────────────────────────────────────────────────────┐ │ SWARM Architecture │ │ │ │ PagerDuty / Datadog │ │ │ Webhook POST │ │ ▼ │ │ ┌─────────────┐ /incident declare ┌──────────────────┐ │ │ │ Webhook │◄───────────────────────►│ Slash Command │ │ │ │ Trigger │ │ Trigger │ │ │ └──────┬──────┘ └────────┬─────────┘ │ │ │ │ │ │ └────────────────┬────────────────────────┘ │ │ ▼ │ │ ┌───────────────────────┐ │ │ │ incident_workflow │ ← Slack Orchestrator │ │ └───────────┬───────────┘ │ │ │ │ │ ┌───────────────┼───────────────┐ │ │ │ │ │ │ │ ▼ ▼ ▼ │ │ ┌───────────┐ ┌─────────────┐ ┌────────────┐ │ │ │ triage.ts │ │channel_ │ │ (parallel) │ │ │ │ Claude │ │ create.ts │ │ │ │ │ │ 3.5 │ │ │ │notify_ + │ │ │ │ Sonnet │ │#inc-{svc}- │ │enrich_ │ │ │ │ P1–P4 │ │{timestamp} │ │context.ts │ │ │ └───────────┘ └─────────────┘ └────────────┘ │ │ │ │ │ ┌───────────────────┤ │ │ │ │ │ │ ┌───────▼──────┐ ┌───────▼──────┐ │ │ │ PagerDuty │ │ Datadog MCP │ │ │ │ MCP Client │ │ + Slack RTS │ │ │ │ + GitHub MCP │ │ + GitHub │ │ │ └──────────────┘ │ Deployments │ │ │ └──────────────┘ │ │ │ │ "Resolve" button ──► post_mortem.ts │ │ │ │ │ ┌───────────────┴──────────────┐ │ │ │ │ │ │ ┌──────▼──────┐ ┌────────▼──────┐ │ │ │ GitHub MCP │ │ Jira MCP │ │ │ │ Post-Mortem │ │ Follow-up │ │ │ │ PR (Draft) │ │ Ticket │ │ │ └─────────────┘ └───────────────┘ │ └──────────────────────────────────────────────────────────────────────────┘ ``` ### 关键设计决策 | 决策 | 理由 | |---|---| | **在主工作流之外进行复盘** | 事件可能持续数小时;Slack 工作流有时间限制。`post_mortem` 函数由“解决”按钮操作触发,而不是由工作流触发,从而保持两条路径的生命周期都很短。 | | **步骤 3a + 3b 并行运行** | `notify_responders` 和 `enrich_context` 之间没有数据依赖性。Slack 平台检测到这一点并并发执行它们,从而将 P1 响应时间缩短了约 10 秒。 | | **所有信息扩充源都是非致命的** | 如果 Datadog、GitHub Deployments 或 Slack RTS 失败,事件频道仍会打开,响应者仍会被呼叫。部分扩充总比没有事件频道好。 | | **MCP client 目前是 HTTP 包装器** | 真正的 MCP server 仍在不断成熟中。每个 client 的结构与未来的 MCP 工具调用完全相同,因此可以使用 `mcpCall()` 替换 `fetch()` 内部实现,而无需更改任何 API 表面。 | ## 项目结构 ``` opsgenie-slack-agent/ ├── manifest.ts # App manifest: scopes, functions, workflow, domains ├── slack.json # Runtime config: Deno permissions, env var declarations ├── import_map.json # Pinned Deno module versions │ ├── functions/ │ ├── triage.ts # Claude 3.5 Sonnet → P1–P4 + routing_team │ ├── channel_create.ts # channels.create → #inc-{service}-{timestamp} │ ├── notify_responders.ts # PagerDuty Events API + Slack @mention + incident card │ ├── enrich_context.ts # Datadog MCP + Slack RTS + GitHub Deployments │ ├── timeline_updater.ts # Pinned timeline: init / ack / escalate / resolve │ └── post_mortem.ts # Claude RCA doc → GitHub PR + Jira ticket │ ├── triggers/ │ ├── webhook_trigger.ts # PagerDuty/Datadog inbound webhook + filter rules │ └── slash_command.ts # /incident declare shortcut │ ├── workflows/ │ └── incident_workflow.ts # 5-step orchestrator (steps 3a+3b parallel) │ ├── mcp/ │ ├── pagerduty.ts # 6 tools: trigger/ack/resolve/oncall/detail/alerts │ ├── github.ts # 3 tools: createPostMortemPR/commits/deployments │ ├── jira.ts # 4 tools: create/search/transition/comment │ └── datadog.ts # 5 tools: monitors/dashboards/metrics/events/sendEvent │ ├── blocks/ │ ├── incident_card.ts # Incident header + metadata + 3 action buttons w/ confirms │ └── postmortem_card.ts # Resolution summary + conditional PR/Jira buttons │ └── tests/ ├── triage.test.ts # 20 unit tests: parsing, routing, sanitisation └── e2e_incident.test.ts # 18 E2E tests: full lifecycle with fetch stubs ``` ## 前置条件 | 工具 | 版本 | 安装 | |---|---|---| | [Slack CLI](https://api.slack.com/automation/cli/install) | ≥ 2.x | `curl -fsSL https://downloads.slack-edge.com/slack-cli/install.sh \| bash` | | [Deno](https://deno.land/) | ≥ 1.40 | `curl -fsSL https://deno.land/install.sh \| sh` | | Slack 工作区 | 管理员权限 | 部署应用所必需 | ## 环境变量 通过 Slack CLI 设置所有密钥 —— **切勿将值提交到源代码控制**: ``` slack env add ANTHROPIC_API_KEY sk-ant-... slack env add PAGERDUTY_API_KEY your-pd-api-key slack env add PAGERDUTY_ROUTING_KEY your-pd-routing-key slack env add DATADOG_API_KEY your-dd-api-key slack env add DATADOG_APP_KEY your-dd-app-key slack env add GITHUB_TOKEN ghp_... slack env add GITHUB_ORG your-org-name slack env add GITHUB_POSTMORTEM_REPO postmortems slack env add JIRA_API_TOKEN your-jira-token slack env add JIRA_EMAIL you@your-org.com slack env add JIRA_BASE_URL https://your-org.atlassian.net slack env add JIRA_PROJECT_KEY OPS ``` **可选 —— 每个团队的 PagerDuty 升级策略 ID:** ``` slack env add PD_POLICY_PLATFORM PXXXXXX slack env add PD_POLICY_CHECKOUT PXXXXXX slack env add PD_POLICY_PAYMENTS PXXXXXX slack env add PD_POLICY_DATA PXXXXXX slack env add PD_POLICY_INFRA PXXXXXX slack env add PD_POLICY_SECURITY PXXXXXX slack env add PD_POLICY_ML PXXXXXX slack env add PD_POLICY_FRONTEND PXXXXXX ``` ## 安装与设置 ``` # 1. Clone repo git clone https://github.com/your-org/opsgenie-slack-agent cd opsgenie-slack-agent # 登录 Slack CLI slack login # 本地运行(热重载开发模式) slack run # 在一个新终端中,检查 trigger URL slack triggers list --app ``` ### 首次设置工作区 `slack run` 成功后,配置你的 Slack 用户组,以便 SWARM 可以 @提及它们: 1. 创建与 `triage.ts` 中的 handle 相匹配的用户组: `oncall-platform`, `oncall-checkout`, `oncall-payments`, `oncall-data`, `oncall-infra`, `oncall-security`, `oncall-ml`, `oncall-frontend` 2. 将相关的工程师添加到每个用户组中。 3. 使用你从 PagerDuty 获取的实际升级策略 ID 更新 `notify_responders.ts` 中的 `PAGERDUTY_POLICY_MAP`。 ## 部署 ``` # 部署到生产环境 slack deploy # 验证已部署的函数 slack functions list # 检查环境变量是否已设置 slack env list # 查看日志 slack activity --tail ``` ## 配置入站 Webhook ### PagerDuty 1. 前往 **PagerDuty → Services → [Your Service] → Integrations → Add Integration** 2. 选择 **Generic Webhook (v3)** 3. 将 **Webhook URL** 设置为来自 `slack triggers list` 的 URL 4. 在 **Events to send** 下,启用:`incident.triggered`, `incident.acknowledged`, `incident.resolved` 5. 设置 **Method**:POST,**Content-Type**:application/json PagerDuty 将发送具有以下结构的 body: ``` { "event": { "event_type": "incident.triggered", "data": { "title": "High error rate on checkout-api", "status": "triggered", "service": { "name": "checkout-api" }, ... } } } ``` ### Datadog 1. 前往 **Datadog → Integrations → Webhooks → New Webhook** 2. 将 **URL** 设置为 webhook 触发器 URL 3. 将 **Payload** 设置为: ``` { "service_name": "$SERVICE", "error_message": "$ALERT_TITLE", "raw_payload": "$EVENT_MSG", "alert_id": "$ALERT_ID", "alert_status": "$ALERT_STATUS", "priority": "$PRIORITY", "tags": "$TAGS", "alert_url": "$LINK" } ``` 4. 在你的监视器上,将 `@webhook-swarm` 添加到 **Notify your team** 部分。 ## 事件生命周期 ``` 1. Alert fires (PagerDuty/Datadog webhook) OR /incident declare │ ▼ 2. [triage.ts] Claude 3.5 Sonnet classifies → P1/P2/P3/P4 + routing_team │ ▼ 3. [channel_create.ts] #inc-{service}-{YYYYMMDD-HHMM} created + topic set │ ┌────┴────┐ ▼ ▼ (parallel) 4a. [notify_responders.ts] 4b. [enrich_context.ts] PagerDuty Events API v2 Datadog monitors in Alert → @mention routing_team Slack RTS: recent mentions → Post incident card GitHub: recent deploys │ │ └────────────┬──────────────────┘ ▼ 5. [timeline_updater.ts] init Pinned timeline header posted + pinned to channel │ │ < Responders join, investigate > │ ┌────┴──────────────────┐ │ Button Actions │ │ (async handlers) │ │ Acknowledge │ → timeline entry │ Escalate │ → re-pages, severity bump, timeline entry │ Resolve │ → triggers post_mortem.ts └───────────────────────┘ │ ▼ 6. [post_mortem.ts] Claude generates 8-section RCA doc → GitHub PR (draft) in postmortems repo → Jira follow-up ticket created → Resolution summary card posted to channel ``` ## MCP Client 参考 `mcp/` 中的每个 client 结构完全相同,以确保未来的 MCP server 兼容性。 ### `PagerDutyMCPClient` | 方法 | 厂商 API | 描述 | |---|---|---| | `triggerIncident(payload)` | Events API v2 | 触发事件 | | `acknowledgeIncident(dedupKey)` | Events API v2 | 通过 dedup key 确认 | | `resolveIncident(dedupKey)` | Events API v2 | 通过 dedup key 解决 | | `getOncallUsers(policyId)` | REST v2 `/oncalls` | 获取值班工程师 | | `getIncidentDetail(id)` | REST v2 `/incidents/{id}` | 完整的事件元数据 | | `listRecentAlerts(serviceId)` | REST v2 `/alerts` | 服务最近的告警 | ### `GitHubMCPClient` | 方法 | 描述 | |---|---| | `createPostMortemPR(params)` | 8 步:branch → commit → labels → PR → reviewers | | `getRecentCommits(repo, branch)` | 分支上最近的提交 | | `listDeployments(repo, env)` | repo 的生产环境部署 | ### `DatadogMCPClient` | 方法 | Datadog API | 描述 | |---|---|---| | `searchMonitors(params)` | `/api/v1/monitor/search` | 处于告警状态的服务的监视器 | | `searchDashboards(query)` | `/api/v1/dashboard` | 通过关键字查找仪表板 | | `queryMetrics(params)` | `/api/v1/query` | 时间序列指标查询 | | `getEventStream(params)` | `/api/v1/events` | 服务的事件流 | | `sendEvent(params)` | `/api/v1/events` POST | 用事件标记注释仪表板 | ### `JiraMCPClient` | 方法 | Jira API | 描述 | |---|---|---| | `createIssue(params)` | `/rest/api/3/issue` | 创建带有 ADF 描述的问题 | | `searchIssues(jql)` | `/rest/api/3/search` | JQL 搜索 | | `transitionIssue(key, name)` | `/rest/api/3/issue/{key}/transitions` | 移动到新状态 | | `addComment(key, text)` | `/rest/api/3/issue/{key}/comment` | 添加 ADF 评论 | ## Block Kit UI 参考 ### `buildIncidentCard(params)` → `KnownBlock[]` ``` P1 CRITICAL — INC-20240315-1423-A3F2 ───────────────────────────────────────── Service: checkout-api │ Team: @oncall-checkout Declared: 14:23Z │ Status: Triaged · Paged ───────────────────────────────────────── AI Triage Summary: > Critical: checkout-api is experiencing a 40% error rate... ───────────────────────────────────────── Paged: alice@example.com, bob@example.com ───────────────────────────────────────── [ Acknowledge] [ Escalate] [ Resolve] ───────────────────────────────────────── ID: INC-20240315-1423-A3F2 · 📟 PagerDuty Incident ``` ### `buildPostMortemCard(params)` → `KnownBlock[]` ``` RESOLVED — INC-20240315-1423-A3F2 ───────────────────────────────────────── Service: checkout-api │ Severity: P1 Duration: 47m │ Resolved By: @alice ───────────────────────────────────────── Resolved At: 15:10Z │ Team: @oncall-checkout ───────────────────────────────────────── Incident Summary: > Critical: checkout-api experienced... ───────────────────────────────────────── Resolution Notes: Rolled back deployment v2.5.1... ───────────────────────────────────────── [ Review Post-Mortem PR] [ Jira Follow-Up] [ Copy Key] ───────────────────────────────────────── Generated by SWARM · Post-mortem PR: view · Jira: view ``` ## 运行测试 ``` # Unit tests(无需网络,无需环境变量) deno test --allow-env tests/triage.test.ts # E2E integration tests(使用 fetch stubs,不调用真实 API) deno test --allow-env tests/e2e_incident.test.ts # 所有测试 deno test --allow-env tests/ # 显示详细输出 deno test --allow-env --reporter=verbose tests/ ``` ### 测试覆盖率摘要 | 测试文件 | 测试套件 | 测试用例 | 网络调用 | |---|---|---|---| | `triage.test.ts` | 8 | 20 | 无 (纯函数) | | `e2e_incident.test.ts` | 8 | 18 | 通过 mock fetch 打桩 | ## 扩展 SWARM ### 添加新的路由团队 1. 将团队添加到 `functions/triage.ts` 中的 `TEAM_ROUTING_MAP` 2. 将 PagerDuty 策略 ID 添加到 `functions/notify_responders.ts` 中的 `PAGERDUTY_POLICY_MAP` 3. 运行 `slack env add PD_POLICY_ ` 4. 创建 Slack 用户组 `oncall-` ### 添加新的 MCP 集成 1. 按照现有 client 的模式创建 `mcp/.ts` 2. 将厂商域名添加到 `manifest.ts` 的 `outgoingDomains` 中 3. 将域名添加到 `slack.json` 的 `net` 权限中 4. 从相关函数中导入并调用该 client ### 更改 AI 模型 在 `functions/triage.ts` 和 `functions/post_mortem.ts` 中: ``` const CLAUDE_MODEL = "claude-3-5-sonnet-20241022"; // ← change this ``` 支持的值:`claude-3-5-sonnet-20241022`, `claude-3-opus-20240229`, `claude-3-haiku-20240307` ## 故障排除 | 症状 | 可能的原因 | 修复方法 | |---|---|---| | `ANTHROPIC_API_KEY not set` | 缺少环境变量 | `slack env add ANTHROPIC_API_KEY sk-ant-...` | | 未创建频道 | Bot 缺少 `channels:manage` 权限 | 重新安装应用:`slack install` | | PagerDuty 未呼叫 | 路由 key 或策略 ID 错误 | 检查 `PD_POLICY_*` 环境变量 | | `outgoing_domain_not_allowed` | manifest 中缺少域名 | 添加到 `manifest.ts` 的 `outgoingDomains` 中 | | 时间线未固定 | Bot 缺少 `pins:write` 权限 | 重新安装应用 | | 未创建 GitHub PR | repo 不存在或组织错误 | 检查 `GITHUB_ORG` + `GITHUB_POSTMORTEM_REPO` | | Claude 返回非 JSON | 模型改变了行为 | 检查 `parseTriageDecision` 的 fence 剥离 | | 创建频道时出现 `name_taken` | 快速重复的 webhook | 通过 `conversations.list` 回退自动处理 | ### 查看实时日志 ``` # 流式传输所有函数执行日志 slack activity --tail # 按函数过滤 slack activity --tail | grep triage # 查看特定运行的输出 slack activity --run ``` ## 许可证 MIT —— 请参阅 [LICENSE](LICENSE) *使用 Slack 下一代平台、Anthropic Claude 和 Model Context Protocol 构建。*
标签:Deno, Slack, SRE, 事故响应, 偏差过滤, 自动化攻击, 运维自动化