AegisOps:具备四层记忆结构的自主SRE智能体
基于pgvector的情景记忆、策略控制的自主级别、十六种工具以及完整的审计追踪,LangGraph ReAct智能体如何解决Kubernetes故障。
来源: I Built an Autonomous SRE Agent That Resolves Production Incidents While I Sleep
现在是凌晨3点14分,PagerDuty响个不停。Prometheus发出了严重警报:支付服务的错误率上升到了34%,容器因内存不足而崩溃,距离SLA违约时间仅剩六分钟。此时要么亲自起床通过SSH连接到集群处理,要么让自动化代理来处理。
AegisOps正是为这种时刻而设计的自主式SRE代理。它无需人工干预即可诊断、处理并解决生产环境中的故障,同时会记录下它所做的每一个决策及其原因。它并非只是套在上的聊天机器人,而是拥有真正的内存管理机制、分层的自主控制功能,以及从已处理的故障中学习的能力。它的设计目标从来不是取代值班工程师,而是为他们提供一个不知疲倦的应急响应者,这个响应者早已熟悉操作手册,记得最近的十起故障,并且在处理生产环境问题前会先检查相关策略。
为何在 LangGraph 上使用 ReAct
ReAct(推理加行动)非常适合用于事件响应。单纯的流程会盲目执行各步骤,而 ReAct 智能体则会先进行思考、选择行动、观察结果,然后再循环执行。在处理故障时,这种思维方式非常恰当,因为此时关键的问题是已掌握的信息、当前观察到的情况以及下一步该尝试什么。
LangGraph 提供带状态管理的图执行机制。每个节点都能看到完整的 AegisState,这是一个 TypedDict,用于存储消息、内存数据、事件详情、策略决策、工具调用结果以及验证结果。由于每执行一步后状态都会被同步到 PostgreSQL 中,因此可以随时暂停、检查流程,然后再继续执行。
该图结构包含四个节点,刻意保持简单以避免过度设计:
-
memory_node先被加载,会在任何推理开始之前准备好智能体所需的所有信息。
agent_node是LLM的推理循环部分。tools是LangGraph自带的ToolNode,用于执行模型要求的各项操作。resolution_node负责处理整个事件:它保存内存数据、计算平均修复时间并发送Slack消息。
四层记忆结构
大多数智能体系统要么省略记忆架构,要么仅使用两层记忆结构。人类SRE在处理事件时会运用四种类型的记忆,而AegisOps则实现了所有这些记忆功能。
- 情景记忆(pgvector、余弦相似度)将过去已解决的事件以嵌入形式存储。当有新事件出现时,系统会检索出与之最相似的三个历史案例,并将其根本原因、采取的措施及最终结果一同注入系统提示中。
- 语义记忆(基于pgvector的知识库的RAG技术)用于存储分块处理的操作手册、架构文档及事后分析报告。
retrieve_runbook工具可通过语义搜索这些内容,为智能体提供团队的机构知识。
params.yml加载到Redis中,并在任何会改变状态的操作执行前被评估。可将其视为智能体为确保安全操作而形成的训练有素的反射机制。实际应用中的情景记忆
在系统启动时,memory_node会使用当前事件的症状列表调用retrieve_similar_incidents函数。一个768维的句子编码器会对这些症状进行嵌入处理,随后pgvector的余弦距离算法会将它们与IncidentMemory表中的数据进行比对。相似度高于0.72阈值的过往事件会被格式化后插入系统提示中,位于智能体首次生成思路之前。
在问题解决后,resolution_node会调用save_incident_memory函数,从而使智能体能够保存自己的记忆记录。这些嵌入数据是由症状信息与根本原因假设结合而成的,因此后续出现类似症状的事件就能找到这条记录。
像 Pinecone 或 Weaviate 这样的专用向量数据库也是一个选择。将所有数据存储在 PostgreSQL 中可以减少一种基础设施依赖,同时确保事件记录与其嵌入向量之间的事务一致性。在当前规模下,pgvector 已经完全足够。
自主等级 L0 至 L3
这是最难的设计问题:如何在不引发灾难风险的情况下赋予智能体对生产环境的实际控制权?答案是一种分层自主模型,即每个变更操作在执行前都会经过策略审核。
每个操作工具(restart_deployment、scale_deployment、update_deployment_image)都会首先调用retrieve_policy函数。策略引擎会结合params.yml中的规则,对操作类型、服务类型、严重程度以及当前的自主决策级别进行综合评估。如果评估结果为否,该工具会立即返回拒绝响应,此时代理程序必须寻找其他处理方式,通常是通过升级权限来处理。
requires_approval字段值得重视。即便在L3级别,某些具有破坏性的操作,比如对关键支付服务中的镜像进行回滚,仍然需要人工明确批准。代理程序会将相关请求发布到Slack上并等待回复,这能让值班团队确信,那些风险最高的操作始终有人类在监督之中。
十六种工具
AegisOps提供了分为四类的十六种工具,其中六种尤为突出:
- get_logs是日志收集工具。它会提取服务日志文件中最后的500行,保留所需级别的信息,并过滤掉每行中的IP地址、UUID以及普通数字。因此,来自不同主机的两次匹配会被视为一组模式。Python的
Counter函数会对这些模式进行排序,返回出现频率最高的模式。终端读取器与代理的推理循环会收到相同结构化的结果,整个过程无需Elasticsearch集群,仅需一个日志文件以及几行Python代码即可完成。 - get_pod_status会通过Kubernetes CoreV1Api查询带有
app={deployment}标签的容器节点,然后报告容器的重启次数、就绪状态以及容器本身的状态。当无法连接到集群时,它会以优雅的方式降级处理,转而让代理执行get_logs功能。
kubectl.kubernetes.io/restartedAt注解来启动滚动重启,随后等待所有副本就绪并执行健康检查。可选的流量引流步骤可在重启期间隔离外部访问。True。从始至终处理一次事件
以下是该智能体在凌晨3点14分针对支付服务OOMKill问题所采取的行动:
[MEMORY] Loading episodic context for payment-service...
[MEMORY] Found 2 similar past incidents (similarity: 0.89, 0.76)
[MEMORY] Loaded 3 procedural policies for payment-service/critical
[THOUGHT] Incident: payment-service OOMKill, 3 pods CrashLooping.
Past incident INC-2801 had identical symptoms — root cause was
a memory leak in the gRPC connection pool after a deploy.
Starting with get_logs to confirm before acting.
[ACTION] Calling tool: get_logs with {'service_name': 'payment-service', 'log_level': 'error'}
→ top_errors: [{"pattern": "out of memory: kill process", "count": 47},
{"pattern": "grpc connection pool exhausted", "count": 23}]
[THOUGHT] OOM confirmed. gRPC pool exhaustion matches INC-2801 pattern.
Retrieve runbook before acting — want the fix procedure.
[ACTION] Calling tool: retrieve_runbook with {'query': 'payment service grpc oom memory leak fix'}
→ [runbooks / payment-service-oom.md] Recommended action: rolling restart
resets connection pool. If recurs within 1h, rollback to previous image.
[THOUGHT] Runbook confirms rolling restart. Checking policy for autonomy L2...
[ACTION] Calling tool: restart_deployment with {'service': 'payment-service',
'deployment': 'payment-worker', 'namespace': 'production',
'severity': 'critical', 'autonomy_level': 'L2'}
→ policy: ALLOWED (L2 ≥ min_level L2 for restart_deployment)
→ draining pods... restarting... polling rollout...
→ health_check: healthy=True, pods_ready=3/3, error_rate=0.008
[THOUGHT] Restart succeeded. Error rate 0.8% — below 5% threshold.
Verifying with check_service_health before closing.
[ACTION] Calling tool: check_service_health with {'service': 'payment-service',
'deployment': 'payment-worker', 'namespace': 'production'}
→ healthy=True, pods_total=3, pods_ready=3, error_rate=0.007
[THOUGHT] Service fully recovered. Writing audit log and resolving.
[ACTION] Calling tool: write_audit_log ...
→ audit_log written: restart_deployment for incident INC-2847
RESOLVED: payment-service recovered after rolling restart. Root cause: gRPC
connection pool OOM — matched pattern from INC-2801. All 3 pods healthy,
error rate 0.7%. MTTR: 187 seconds.
[MEMORY] Saving incident INC-2847 to episodic memory...
[NOTIFY] Sending resolution to Slack channel: #all-aegisops ✅
从警报发出到问题解决,整个过程仅耗时187秒,也就是三分钟多一点,而且没有惊动任何人。在类似之前的故障中,这已经成了常规的处理时间。这名技术人员首先像资深工程师那样参考了上次有效的处理方法,这就是情景记忆在发挥作用。
为便于理解,该流程被重新构建了出来。在普通的本地环境中运行时,只有一个Kind集群且没有Prometheus,情况会有所不同。此次故障是由一个简单的PowerShell webhook调用引发的:
Invoke-RestMethod -Uri "http://localhost:8000/webhook/incident" `
-Method Post `
-ContentType "application/json" `
-Body '{
"source": "webhook",
"severity": "critical",
"service": "payment-service",
"symptoms": ["High 500 errors", "DB connection timeouts"],
"autonomy_level": "L2"
}'
该代理对整个流程进行了端到端处理。它检索了类似的事件,并推测流量激增导致节点容量不堪重负,这一情况与内存中的过往案例相符。它调用了get_pod_status,发现5个节点中有2个已准备就绪,于是将部署规模扩大到4个副本,再通过check_service_health确认情况后,将该事件标记为“已解决”。随后一条Slack消息被发送到#all-aegisops频道,该事件也被记录到事件记忆库中。
这虽然比凌晨3点发生的gRPC内存溢出崩溃要温和得多,但处理流程依然不变:同样的思考、行动、观察循环,扩展规模前的相同策略检查,以及处理结束时的相同内存写入操作。只是所处的环境更为简单。该代理无法区分由笔记本电脑组成的集群和由50个节点构成的集群。只要更改kubeconfig配置,让Prometheus采集真实的指标,同样的代码就能在真实环境中正常运行。
Slack作为输出渠道
重要的操作会发送Slack消息。当某个事件处理完毕时,解决节点会向#all-aegisops发送消息,其中包含严重程度标识、平均修复时间以及完整的解决摘要,这样值班工程师看到的就是绿色对勾,而非呼叫警报。
技术架构
整个系统基于较为简单的架构运行。PostgreSQL配合pgvector用于存储事件相关数据及LangGraph的检查点。Redis用于保存策略,未来还将用于实现速率限制功能。Prometheus负责将实际的错误率数据传递给check_service_health,而Grafana则用于生成监控仪表板。
version: "3.9"
services:
postgres:
image: ankane/pgvector:latest
ports:
- "5445:5432"
environment:
POSTGRES_USER: postgres
POSTGRES_PASSWORD: admin123
POSTGRES_DB: aegisops
volumes:
- postgres_data:/var/lib/postgresql/data
redis:
image: redis:alpine
ports:
- "6380:6379"
app:
build: .
ports:
- "8000:8000"
env_file: .env
depends_on:
- postgres
- redis
prometheus:
image: prom/prometheus:latest
ports:
- "9090:9090"
volumes:
- ./infra/prometheus.yml:/etc/prometheus/prometheus.yml
grafana:
image: grafana/grafana:latest
ports:
- "3000:3000"
volumes:
postgres_data:
该应用是基于uvicorn的FastAPI框架。事件会发送到webhook端点,该端点会创建一个IncidentEvent对象并调用run_agent()函数。由于采用异步执行方式,多个事件可以同时处理而不会相互阻塞。用于与Kubernetes集群通信的客户端是kubernetes_asyncio,它能确保对集群的调用不会造成阻塞。
需要注意的一点是:get_pod_status和check_service_health函数会在模块被导入时加载Kubernetes配置,而非在异步函数内部。如果启动时无法连接到集群,这些函数会静默失败并返回警告信息,因此请确保在应用启动前已正确配置KUBECONFIG或集群内的服务账户。
审计追踪
每次工具调用都会被记录在 ToolInvocation TypedDict 中:包括执行了什么操作、使用了哪些参数、返回了什么结果、是否成功、耗时多少、执行时间以及是哪项策略决策允许该操作。这些记录会在运行过程中累积在 state["tool_invocations"] 中,而在任务结束时会保存到阶段性内存中。还有一个独立的 write_audit_log 工具,会为每一个重要操作生成结构化的 JSON 行数据。
这样一来,任何事件都可以在事后重新复现:包括操作步骤的顺序、当时有效的权限以及每项权限的设定原因。合规团队正是需要这类记录。
一个设计决策会决定其他所有方面。每一次变更操作都会同时反馈策略决策与健康检查结果,这样智能体就能立刻了解三件事:调用是否成功、是否被允许以及服务当前是否正常。这三点都会影响它的下一步决策。
仍缺失的内容
上述所有功能都是端到端运行的。进一步发展仅受限于本地机器在运行完整系统的同时还要承载 Ollama 的负担。若拥有更多资源,首先需要解决三个问题。
审批流程是当前最亟需解决的缺陷。系统中已存在approval_status字段,且requires_approval也已设置,但实际上并未有任何机制阻止流程继续。目前的计划是添加一个Slack按钮,暂停图表处理,直到有人点击后才会恢复,从而避免执行任何L3级操作。LangGraph可以通过检查点在运行过程中暂停图表,因此剩下的只是实现相关逻辑,而非整体重新设计。
前后指标对比是第二个问题。check_service_health只能提供修复后的某一时间点的快照。实际上代理需要的是Prometheus的增量数据,即修复前五分钟与修复后五分钟的错误率对比,这样才能确定问题确实得到了解决,而非只是得益于时间上的巧合。
运行手册自动生成是长期目标。目前,两类知识存储——历史事件记录与运行手册——之间从未实现相互关联。在完成特殊问题的修复后,操作人员应当编写新的运行手册内容并将其添加到知识库中,这样下次调用retrieve_runbook时就能获取到这些内容。这样才能将这两层记忆系统紧密结合起来。
该项目带来的启示
事实证明,自主基础设施操作工具面临的难题并非模型的推理能力,而是围绕它的安全机制。记忆层、策略引擎、审计追踪以及审批流程,正是让团队愿意在凌晨3点仍让工具独立运行的关键因素。
AegisOps秉持这样的观点:具有明确权限边界的结构化状态机,优于能够即兴发挥的自由形式智能体。这一观点至今依然有效,因为它能生成更详尽的事故日志,且智能体在处理每个新案例后都会不断改进。LangGraph中的检查点功能、诊断工具与操作工具之间的清晰分离,以及TypedDict状态机制,使得在系统出问题时能够轻松进行检查、调试和审计,从而弄清楚智能体为何会做出特定选择。
如果你正在开发类似系统,应尽早重视内存架构的设计。拥有良好内存管理的智能体,其价值远超那些仅靠稍好提示词就能运行的智能体。Transformer模型需要注意力机制,而现实世界中的智能体则需要上下文信息。
相关阅读
- 智能体内存快照、技能、衰减与分支作用域 — 为编程智能体设计的嵌入式向量数据库内存层新增的四种功能:可合并的便携式快照、技能激活、带冲突检测的衰减机制,以及基于分支的作用域内存。
- 智能体在生产环境中的工具使用与函数调用 — 一家银行的智能体错误调用了付费API并编造了电话号码。本文介绍了最基本的工具组合、参数来源追踪、三级重试机制以及针对不同工具的监控指标。