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, 事故响应, 偏差过滤, 自动化攻击, 运维自动化