atanus1502/cma-sre-agent
GitHub: atanus1502/cma-sre-agent
基于 Claude Managed Agents 构建的 SRE 事件响应智能体,通过关联日志、指标和部署信息自动定位故障根因。
Stars: 0 | Forks: 0
# 事件-4813
这是一个为虚构的电子商务技术栈构建的可用的故障仪表板。Metrics、Logs 和 Deploys 页面在开箱即用的 mock 数据下即可运行。在每个页面的侧边都有一个 **SRE Agent** 聊天面板,它基于 [Claude Managed Agents](https://platform.claude.com/docs/en/managed-agents/overview) 构建。
问它*“是什么导致了延迟飙升?”*,然后看着它在自己的云端沙箱中对 7 万行日志进行 grep,调用本地工具拉取指标和部署信息,关联时间戳,获取出问题的代码差异,并指出具体的 commit。
## 设置说明
你需要 Python **3.10+** 和一个 [Anthropic API key](https://console.anthropic.com/settings/keys)。
```
python -m venv .venv
source .venv/bin/activate # Windows: .venv\Scripts\activate
pip install -r requirements.txt
cp .env.example .env # then put your ANTHROPIC_API_KEY in .env
streamlit run app.py
```
仪表板将在 `localhost:8501` 打开。随便点击看看 —— Metrics、Logs、Deploys 以及右侧的 SRE Agent 面板都是开箱即用的。
## Agent 是如何连接的
`agent.py` 包含七个函数,每个都是一次 Managed Agents API 调用:
| # | 函数 | API 调用 |
|---|---|---|
| 1 | `setup_agent()` | `client.beta.agents.create` |
| 2 | `setup_environment()` | `client.beta.environments.create` |
| 3 | `upload_log()` | `client.beta.files.upload` |
| 4 | `start_session()` | `client.beta.sessions.create` |
| 5 | `stream_reply()` | `client.beta.sessions.events.stream` + `.send` |
| 6 | `handle_tool()` | 本地运行 —— 读取 `data/*.json` |
| 7 | `delete_session()` | `client.beta.sessions.delete` |
其他所有内容 —— system prompt、工具 schema、聊天 UI、session 选择器 —— 都存放在 `provided.py` 中。
## 故障事件
`data/` 提供了一个非常逼真的宕机事件:在 **14:31:18 UTC**,commit `a3f9c21` 被部署到了结账服务(checkout service),将批量查询替换为了逐行循环。几分钟之内,p99 延迟就从 65 毫秒攀升到了 3,600 毫秒,数据库连接池(DB connection pool)饱和,并且 20% 的结账开始失败。
证据分布在以下文件中:
- `app.log` —— 70,000 行 JSON 日志,agent 必须在其沙箱中进行 grep
- `metrics.json` / `deploys.json` / `diff.txt` —— 当 agent 调用 `get_metrics`、`get_recent_deploys` 和 `get_diff` 时返回的内容(这些处理程序在**你的**机器上运行,而不是在云端 —— 这正是关键所在)
Agent 必须将这四者关联起来才能指出根本原因。它做到了。
## 这展示了什么
- **Agent → Environment → Session → Events** —— 四个 Managed Agents 资源,按照 [快速入门](https://platform.claude.com/docs/en/managed-agents/quickstart) 中介绍的顺序
- **沙箱代码执行** —— agent 在你无需配置的托管容器中编写并运行 Python
- **自定义工具(Custom tools)** —— 云端的 agent 通过事件流(event stream)调用你笔记本上的函数;将 mock 的 JSON 替换为 Datadog 客户端,它就可以用于生产环境了
- **有状态的 session** —— 聊天框上方的下拉菜单通过 `sessions.list()` 列出了过去的所有 session;选择一个,对话就会从 `events.list()` 重新加载。不需要数据库,也不需要本地状态。
## 仓库布局
```
agent.py ← the agent: seven functions, one Managed Agents call each
agent_complete.py ← reference implementation
provided.py ← system prompt, tool schemas, chat UI, session picker
e2e.py ← headless test of the full path
app.py ← incident overview
pages/ ← Metrics, Logs, Deploys
data/ ← log + metrics + deploys + diff fixtures
ui.py, assets/ ← styling
```
## 代码库详解
### 启动序列
`streamlit run app.py` 在绘制任何内容之前会做四件事:
1. `load_dotenv()` 读取 `.env`,以便 `anthropic.Anthropic()`(在 `agent.py` 的导入阶段仅实例化一次)能够获取 `ANTHROPIC_API_KEY`。
2. `inject_style()`(`ui.py`)将 `assets/style.css` 内联到页面中。
3. 如果 `data/app.log` 尚不存在,`data/generate_log.py` 会构建它 —— 这是一个确定性的(带有随机种子)、约 6 万行、每行一个 JSON 的测试数据,时间跨度为 14:00–15:00 UTC,其中 N+1 回归问题被设定为从 14:31:18 开始。
这只运行一次;之后的每次启动都只会执行一次 `Path.exists()` 检查。
4. `st.navigation([...])` 注册四个页面 —— **Overview**(`app.py` 本身)、**Metrics**、**Logs**、**Deploys**(`pages/*.py`)—— 并运行当前处于活动状态的页面。
每个页面都遵循相同的布局:一个包含仪表板内容的宽 `main` 列,以及一个从 `provided.py` 调用 `chat_panel()` 的窄 `side` 列。从应用中的任何位置都可以访问该 agent,因为每个页面只需要进行那一次函数调用即可。
### 四个 Managed Agents 资源
`agent.py` 刻意保持精简 —— 七个函数,每个对应一次 API 调用,建立起一条生命周期长于单次聊天轮次的资源链:
```
agent (model + system prompt + tools) ─┐
environment (cloud sandbox) ├─▶ session ─▶ events (stream)
uploaded log file (app.log) ─┘
```
- `setup_agent()` / `setup_environment()` / `upload_log()` 被包装在 `@st.cache_resource` 中,因此它们在每个 Streamlit 服务器进程中只运行一次,而不是每次页面加载或每条聊天消息时都运行 —— agent 定义、沙箱和上传的日志在该进程的每个 session 和每个用户之间都是共享复用的。
- `start_session()` 将一个新的 `agent` 和 `environment` 对绑定在一起,并将上传的日志挂载到沙箱内的 `/mnt/session/uploads/app.log`。仅当用户在聊天面板中点击 **+** 时才会创建新的 session —— 从不自动创建 —— 因此刷新页面不会产生云端资源。
- `stream_reply()` 是单次聊天轮次的请求/响应循环:它打开 session 的事件流(event stream),将用户的消息作为 `user.message` 事件发送,然后遍历该流。两种工具服务同时存在:
- `agent_toolset_20260401` —— 沙箱自带的代码执行工具。
agent 在其托管容器内编写并运行 Python(例如用于对 `app.log` 进行 `grep` 或解析);这些 `agent.tool_use` 事件永远不会离开云端,也不需要在这边进行处理。
- `get_metrics` / `get_recent_deploys` / `get_diff` —— 在 `provided.TOOLS` 中被声明为 `type: "custom"` 工具。当 agent 调用其中一个时,事件会以 `agent.custom_tool_use` 的形式返回;`stream_reply()` 将其路由到 `handle_tool()`,后者根据在 `provided.py` 中从 `data/` 加载的 JSON/文本做出回答,并将结果作为 `user.custom_tool_result` 事件发回,以便 agent 可以继续运行。这就是上面提到的“将 mock 的 JSON 替换为 Datadog 客户端”的切入点 —— agent 通过这些工具看到的所有内容,都是由在你机器上运行的代码(而不是在沙箱中运行的代码)所获取的。
- `delete_session()` 在用户点击垃圾桶图标时销毁 session —— session 是需要计费的云端资源,而不是本地对象。
### 一次完整的聊天轮次
```
user types in st.chat_input
│
▼
agent.stream_reply(session_id, text)
│ events.send({"type": "user.message", ...})
▼
events.stream() yields:
agent.message → append text, live-render in st.empty()
agent.tool_use → sandbox code exec; shown as a collapsed status box
agent.custom_tool_use → handle_tool() runs locally, result sent back
user.custom_tool_result → status box filled in with the result
session.status_idle → stop_reason == "end_turn" ⇒ break the loop
│
▼
provided.chat_panel() appends the assistant turn to st.session_state.hist
```
`provided.py` 拥有所有 UI 形状的内容,从而使 `agent.py` 保持纯粹的 API 调用:构建 agent 所使用的 system prompt(`SYSTEM`)和工具 schema(`TOOLS`)、在导入时仅加载一次的 `data/*.json` 固定数据(fixtures),以及 `chat_panel()` 本身 —— session 下拉菜单(`sessions.list()`)、为恢复 session 而进行的历史记录重放(`sessions.events.list()`,折叠连续的 `agent.message` 增量并内联渲染工具调用),以及上面描述的实时流式传输渲染循环。
除了当前浏览器标签页的 `st.session_state` 之外,聊天状态被刻意不保存在任何本地位置 —— session 选择器通过从 Managed Agents API 重放 `events.list()` 来重新加载对话,因此关闭标签页不会丢失任何内容。
标签:AIOps, Claude, CVE检测, Kubernetes, LLM Agent, SRE, 偏差过滤, 根因分析, 运维监控, 逆向工具