作者:来自 Elastic Alex Salgado
构建 AI agent 编排,让工作流等待人工审批,然后自行执行修复操作,无需额外配置任何资源,并且整个决策过程都可以在 Elasticsearch 中进行查询。
Agent Builder 现已正式发布(GA)。开始使用 Elastic Cloud 试用版,并查看 Agent Builder 的文档这里。
AI agent 接收到一个问题后,会在几秒钟内完成处理。agent 会在会话过期之前给出响应。这种模式非常适合问答或代码生成,也适合进行某个时间点的分析。但是,当 agent 需要等待人工审批,而此时审批人正在开会或处理另一个故障事件时,会发生什么?会话过期,上下文丢失,工作只能从头开始。
Elasticsearch Workflows 通过持久化的执行状态解决了这个问题。工作流可以在人工审批节点暂停数天,然后从中断的位置准确恢复。每个决策都会作为可搜索的数据持久化到 Elasticsearch 中。
在本文中,我们将通过一个真实场景实践这一过程:在数据流摄取过程中失败的文档会滞留在其失败存储中。
在这个场景中,每一步都可以复现。最终,你将拥有一个由告警触发的端到端工作流,其中包括执行前审批、自动修复、执行后验证,以及拒绝并修改的流程。
你将学到什么
我们将介绍如何:
-
使用失败存储捕获并修复摄取失败的文档。
-
使用 waitForInput 和 waitForApproval 构建具有结构化审批和二元审批节点的长时间运行工作流。
-
在人工审批后自动调用 Elastic Agent Builder AI agent。
-
根据告警规则自动触发工作流。
-
处理审批和拒绝流程,实现真正的人工参与环节,而不仅仅是一个复选框。
什么是长时间运行的 AI agent?
会话绑定型 agent 与长时间运行 agent 之间的区别,在于工作本身的性质,而不是大语言模型( LLM )的处理速度。
会话绑定型 agent 存在于一个会话中:它接收问题并进行处理,然后回答问题。如果进程终止,上下文也会随之消失。
数据修复、基础设施配置或变更审核等运营流程则有所不同。处理本身很快,但真正耗时的是在不可预测的时间点等待人工决策。需要批准重新索引的人员可能正在处理故障事件,或者身处不同的时区,也可能只是正在午餐。长时间运行的 agent 通常通过额外搭建一套基础设施来处理这些工作流中断:使用数据库存储执行状态,使用服务器运行编排器,使用 UI 处理审批,并使用集成来发送通知。
Elasticsearch Workflows 在数据已经存在的位置运行。工作流的长期执行状态会持久化到 Elasticsearch 中,即使重启也不会丢失,并且可以在步骤之间等待数天。AI agent 来自 Agent Builder,并且只在每个步骤执行期间维持会话,例如直到步骤结束或会话结束。工作流负责保存跨越多个步骤和多天的上下文,而告警则来自已经在监控数据的相同规则。审批 UI 位于 Kibana 中,无需额外配置基础设施。
工作流的内部执行状态由 Kibana 管理。remediation-runs 索引是工作流自身写入的审计记录,你可以像查询其他 Elasticsearch 索引一样对其进行查询。
什么是 Elasticsearch 失败存储?
当 Elasticsearch 收到一个无法建立索引的文档时,有两种选择:拒绝该文档并返回错误,或者将其安全地存储起来以供后续分析。失败存储就是第二种方式。
假设有一个 logs-demo-app 数据流,其中的 price 字段映射为 float。如果源应用发送 "price": "N/A" 而不是数字,Elasticsearch 就无法为该文档建立索引。启用失败存储后,该文档会被重定向到数据流内部的专用索引,而不会丢失。
失败存储中的文档会保留原始内容,并包含有关错误的信息,包括异常类型、错误消息、发生失败的管道和处理器,甚至还包括堆栈跟踪。你可以使用 data_stream::failures 语法查询失败存储。
典型文档如下:
`
1. {
2. "@timestamp": "2026-07-16T14:45:02.111Z",
3. "document": {
4. "id": "AZ9rY09teEMlWkReFa9e",
5. "index": "logs-demo-app",
6. "source": {
7. "user_id": "u-test-1",
8. "price": "INVALID",
9. "message": "Order failed"
10. }
11. },
12. "error": {
13. "type": "document_parsing_exception",
14. "message": "failed to parse field [price] of type [float]"
15. }
16. }
`AI写代码
document.source 字段包含导致失败的原始文档,而 error 字段描述了具体发生的问题。这正是 failure-analyst agent 将读取并用于诊断问题的结构。
但这些文档仍然滞留在那里。有人需要诊断问题并修复管道或映射,还需要将这些文档重新索引回数据流。这正是将 AI 自动化与人工审批结合起来的典型工作,也是我们接下来要构建的内容。
AI agent 编排如何从告警到问题解决工作
该工作流连接了四个构建模块:一条告警规则、两个 AI agent、人工审批节点,以及一个审计索引。下图展示了这些组件如何进行交互。
告警规则每分钟监控 logs-demo-app::failures。当它发现过去五分钟内写入的文档时,就会启动一次工作流执行。
工作流首先运行 read_failures 来获取失败的文档。然后通过 diagnose 步骤将这些文档传递给 failure-analyst agent。该 agent 检查目标映射并确定根本原因,然后生成结构化的修复方案,但不会进行任何更改。
工作流将该方案以 awaiting_fix_approval 状态记录到 remediation-runs 索引中,并在 Gate 1 处暂停。
Gate 1 使用 waitForInput,这是一个用于收集审核人员决定和可选备注的结构化表单。工作流等待期间,其状态会持续保存在 Elasticsearch 中。无需保持任何 agent 会话或轮询循环处于活动状态,这意味着审批节点可以等待数小时甚至数天,而不会持续消耗计算资源。
如果审核人员批准该方案,工作流会通过 execute_fix 步骤调用 remediation-executor agent。该 agent 调用 execute-failure-store-fix skill 并创建摄取管道。同时,它还会执行有界范围的重新索引,并返回详细的执行报告。
只有在执行完成后,Gate 2 才会出现。它使用 waitForApproval 展示 agent 的报告,并要求审核人员在 Yes, mark as resolved 和 No, escalate 之间进行选择。随后,工作流会将最终结果记录到 remediation-runs 中,并将完整报告包含在 agent_report 中。
如果审核人员在 Gate 1 拒绝初始方案,工作流会将诊断结果和审核人员的反馈发送回 failure-analyst agent,由该 agent 生成修改后的方案,并在 Gate 1b 中呈现。如果获得批准,修改后的方案会沿用相同的自动执行和验证流程。如果再次被拒绝,工作流会将该案例记录为 fix_rejected,然后结束执行,不进行任何更改。
remediation-runs 索引会将诊断结果、修改请求、修改后的方案、执行报告和最终结果记录为可搜索的审计文档。共享的工作流 execution_id 用于关联属于同一次修复运行的记录。
生产环境注意事项:基于异常的验证
上图展示了本教程中刻意采用的保守实现:每次完成修复后都会在 Gate 2 处暂停,包括那些看起来已经完全成功的执行。这使人工验证机制更加明确,对于低流量或高风险环境可能比较合适,但在大规模场景下可能造成审核疲劳。生产环境中的扩展方案可以在执行后增加一个确定性验证步骤。当目标位置存在预期文档,并且重新索引没有报告任何失败或符合策略定义的错误时,工作流可以自动记录为已解决。只有部分成功、失败或存在歧义的结果才应在 Gate 2 处暂停,交由站点可靠性工程(SRE)人员审核,并根据需要进行升级处理。
接下来的部分将逐一介绍每个组成部分:数据流设置、agent 和 skill、告警规则以及工作流。
前提条件
要按照本教程进行操作,你需要:
-
一个 Elastic Cloud Serverless 项目,或一个 Elastic Stack 9.4+ 部署。
-
Agent Builder(在 Elasticsearch 项目中已正式发布(GA),默认启用)。
-
配置以下环境变量:
`export ES_URL="https://<your-project>.es.<region>.gcp.elastic.cloud:443"`AI写代码
`
1. export ES_API_KEY="<your-api-key>"
2. export KIBANA_ENDPOINT="https://<your-project>.kb.<region>.gcp.elastic.cloud"
`AI写代码
设置启用失败存储的数据流
本教程中的所有代码,包括工作流 YAML、设置脚本和 agent 指令,都可以在此代码仓库中找到。
首先,从代码仓库获取代码:
`
1. # Clone the repository without checking out all files
2. git clone --filter=blob:none --sparse https://github.com/elastic/elasticsearch-labs.git
3. cd elasticsearch-labs
5. # Check out only this companion folder
6. git sparse-checkout set supporting-blog-content/ai-agent-orchestration-human-approval-workflow
7. cd supporting-blog-content/ai-agent-orchestration-human-approval-workflow
`AI写代码
然后运行设置脚本:
`./scripts/01-setup-failure-store.sh`AI写代码
该脚本会准备测试环境:删除之前的测试资源,创建启用失败存储的索引模板,写入三个有效的基准文档,初始化失败存储,并创建 remediation-runs 审计索引。price 字段映射为 float,并设置 ignore_malformed: false;非数字值会产生解析错误,并被重定向到失败存储,而不是被静默丢弃。数据流本身会在第一个文档建立索引时自动创建。
失败存储是在索引模板级别启用的,而不是直接在数据流上启用。模板包含一个 data_stream_options 块,用于告知 Elasticsearch 为从该模板创建的任何数据流启用失败存储:
`
1. "data_stream_options": {
2. "failure_store": {
3. "enabled": true
4. }
5. }
`AI写代码
数据流会在第一次摄取请求时自动创建,并从索引模板继承失败存储配置。从这一刻起,任何无法建立索引的文档都会被重定向到失败存储,而不是因为索引错误而被拒绝。
该脚本还会写入三个 price 为数值的有效文档。这些文档构成健康基线:在发生任何摄取失败之前,数据流已经存在并且包含有效数据。
执行完 01-setup-failure-store.sh 脚本后,环境就准备好了:
`
1. logs-demo-app → 3 valid documents
2. logs-demo-app::failures → 0 documents (empty, index initialized)
3. remediation-runs → created with explicit keyword mappings
`AI写代码
触发告警规则并启动工作流的无效文档会在测试部分运行 02-trigger-test.sh 时稍后写入。这一顺序展示了一个真实的故障场景:数据流最初使用有效数据正常运行,随后上游发生变化,导致格式错误的文档开始到达。
将 agent 和 skill 导入 Agent Builder
运行恢复脚本,将两个 agent、两个 skill 以及工作流导入你的 Kibana 实例:
`pip install requests python-dotenv`AI写代码
`python3 scripts/restore.py`AI写代码
预期输出:
`
1. Restoring skills
2. created failure-store-remediation-planner
3. created execute-failure-store-fix
4. Skills: created=2, updated=0
5. Restoring agents
6. created failure-analyst
7. created remediation-executor
8. Agents: created=2, updated=0
9. Restoring workflow
10. imported failure_store_remediation
11. Restore completed successfully
`AI写代码
再次运行该脚本会更新现有组件,而不会创建重复项。
诊断并执行修复的 AI agent
运行 restore 脚本后,Agent Builder 中会提供两个 agent:一个用于诊断故障,另一个用于应用已批准的修复。在 Kibana 中,进入 Agent Builder,确认两个 agent 及其关联的 skill 都已正确创建。
failure-analyst,只读诊断 agent
该 agent 从失败存储中读取失败文档,并检查目标映射。它会生成一个结构化的修复计划,其中包括摄取管道定义和有界重放指令。该计划还包括风险评估。该 agent 不会执行所提出的修复操作。
该 agent 的指令定义了它的目标和只读边界。关键指令包括:
`
1. ## Description
3. Analyzes failed documents from the failure store, identifies root causes, and proposes remediation pipelines.
5. ## Instructions
7. # Role
9. You are a cautious Elasticsearch data quality analyst specializing in data
10. stream failure stores.
12. # Goal
14. Analyze a batch of related failure-store documents and produce a safe,
15. evidence-based remediation plan for human review.
17. Do not execute any changes.
19. # Required approach
21. - Identify the common root cause and the affected document pattern.
22. - Propose the smallest bounded remediation that addresses the demonstrated failure.
23. - Do not propose an executable remediation when required context is missing.
24. - Do not create pipelines, change mappings, update templates, run reindex,
25. or perform any write operation.
27. ...
`AI写代码
其关联的 failure-store-remediation-planner skill 提供了用于构建安全重放的专门规则。例如:
``
1. ...
3. - A remediation pipeline that replays indexing or mapping failures from a failure store must use `recover_failure_document` as its first processor.
4. - For a small human-reviewed batch, filter the reindex source using the exact failure-store document `_id` values supplied in the input.
5. - Mapping changes, template changes, failure-store deletion, and upstream application changes must be listed only as manual follow-up recommendations.
7. ...
``AI写代码
响应契约也进行了约束,以便工作流能够可靠地使用该计划:
`
1. Return exactly one JSON object and no additional explanatory text.
2. Do not use Markdown code fences, preambles, summaries, or attachments.
`AI写代码
通过 agent 指令和 skill 的配合,failure-analyst 能够生成可执行但有边界的修复计划,同时将执行操作保留在工作流及其人工审批节点的控制之下。
remediation-executor,执行已批准修复的 agent
工作流会在修复计划通过 Gate 1 审批后调用该 agent。与第一个 agent 不同,remediation-executor 可以执行应用已批准修复所需的写入操作。
其 agent 指令有意将这一角色限定在即时执行范围内:
`
1. ## Description
2. Executes Elasticsearch operations: creates pipelines and runs reindex.
4. ## Instructions
5. You execute Elasticsearch remediation operations.
7. When asked to run a remediation, invoke the skill
8. "execute-failure-store-fix" directly and immediately.
10. Do not ask for confirmation. Do not ask clarifying questions.
12. After the skill completes, write a plain-text summary as your final message.
13. Include: whether the pipeline was created, how many documents were matched,
14. how many were successfully reindexed, and how many failed. This message is
15. captured by the workflow and shown to the human reviewer.
`AI写代码
其关联的 execute-failure-store-fix skill 定义了如何获取并执行已批准的计划。关键指令包括:
`
1. ## Name
3. execute-failure-store-fix
5. ## Description
7. 1. The prompt will include a "Workflow execution ID". Use it to search the
8. remediation-runs index for the approved plan for this specific execution.
10. 2. Determine which field contains the remediation plan:
11. - If status is "awaiting_fix_approval", read the "diagnosis" field.
12. - If status is "awaiting_fix_approval_v2", read the
13. "revised_diagnosis" field.
15. 3. From that JSON object, extract:
16. - remediation_pipeline.pipeline_id
17. - remediation_pipeline.pipeline_definition
18. - remediation_pipeline.reindex_request
19. - affected_docs.data_stream
21. 4. Create the ingest pipeline in Elasticsearch using the extracted
22. pipeline_definition.
24. 5. Execute the reindex_request exactly as specified in the approved plan.
25. Do not substitute or hardcode the destination — use
26. affected_docs.data_stream from the approved plan.
28. 6. Report how many documents were matched, successfully reindexed,
29. and failed..
`AI写代码
该 skill 会同时根据 execution_id 和审批状态进行搜索。这可以确保执行 agent 获取的是当前工作流执行所批准的计划,而不是其他无关的修复运行。状态决定它使用原始的 diagnosis,还是在修订路径中生成的 revised_diagnosis。
这种职责分离让两个 agent 各司其职:failure-analyst 调查故障并提出有边界的计划,但不会进行任何更改;remediation-executor 只有在工作流完成所需的人工审批步骤后,才会应用选定的计划。
设置脚本会导入完整的 agent 指令和 skill 定义。上面的摘录重点展示了最有助于理解每个 agent 的职责和行为的指令。完整定义位于代码仓库中的 backup/save_agents.json 和 backup/save_skills.json。
验证 agent 及其 skill 已正确导入后,下一步是配置告警规则,用于检测失败存储中的新文档并启动修复工作流。
如何从 Elasticsearch 告警触发工作流
修复流程从一条 Elasticsearch 告警规则开始。该规则监控失败存储,并在检测到新故障时启动工作流。由于 restore.py 脚本已经导入并启用了 failure_store_remediation,你可以在创建规则时将工作流连接起来。
创建监控失败存储的告警规则
该规则每分钟检查一次失败存储,并在发现配置的五分钟时间窗口内写入的文档时创建告警。
-
进入 Management → Rules → Create rule。
-
选择 Elasticsearch query。
-
配置:
-
Query type:
ES|QL。 -
Query:
` 1. FROM logs-demo-app::failures 2. | WHERE @timestamp > NOW() - 5 minutes 3. | STATS failure_count = COUNT(*) 4. | WHERE failure_count > 0 `AI写代码 -
选择时间字段:
@timestamp。 -
选择告警分组:Create an alert if matches are found.
-
时间窗口:
5 minutes。 -
检查频率:
1 minute。
-
-
在 Actions 部分,点击 Add action → Workflows。
-
选择
failure_store_remediation工作流。 -
在 Run workflow 中,选择 New alerts。
-
将 Action frequency 设置为 Run per alert。
-
保存并启用该规则。
每当该规则创建一个新告警时,它都会针对该告警启动一次 failure_store_remediation 工作流执行。此时失败存储仍然为空;无效文档会在之后通过02-trigger-test.sh写入。
告警触发器配置完成后,下面来看看负责执行诊断、审批、修复和验证步骤的工作流。
逐步构建 agentic 工作流
到这里,工作流已经由前面运行的 restore.py 脚本在 Kibana 中创建。为了理解该工作流的运行方式,我们将逐步分析它,并使用相关的 YAML 片段来解释修复流程中每个步骤的作用。完整的工作流定义可在本教程的代码仓库中找到。
声明告警触发器和 7 天超时
该工作流声明了一个告警触发器,因此可以由前面创建的告警规则启动。
`
1. version: "1"
2. name: failure_store_remediation
3. description: >
4. Long-running workflow that remediates failed documents in a data stream's
5. failure store. Triggered by an alerting rule when failures are detected.
6. An AI agent diagnoses the root cause and proposes a fix. After human
7. approval, the remediation-executor agent runs the fix automatically,
8. then pauses for verification.
9. enabled: true
10. tags: [failure-store, remediation, agentic]
11. settings:
12. timeout: 7d
14. triggers:
15. - type: alert
`AI写代码
这里有两个重要细节。首先,timeout: 7d 定义了工作流最多可以保持活动状态七天。我们显式设置这一参数,是因为工作流会在人工审批节点暂停,而审批可能需要数小时甚至数天才能完成。
其次,声明 type: alert 会使工作流可用于告警。规则中配置的工作流操作建立了告警与 failure_store_remediation 之间的连接。
从失败存储中读取失败文档
工作流首先使用 ::failures 语法获取失败文档:
`
1. steps:
2. - name: read_failures
3. type: elasticsearch.search
4. with:
5. index: "logs-demo-app::failures"
6. query:
7. range:
8. "@timestamp":
9. gte: "now-5m"
10. lte: "now"
11. size: 50
12. sort:
13. - "@timestamp": "desc"
`AI写代码
范围查询将搜索范围限制为告警规则所监控的同一个五分钟时间窗口内创建的失败存储文档。在该时间窗口内,size: 50 将批次限制为最近匹配的 50 个文档。对于更大的数据量,可以使用 search_after 或分页。
AI agent 如何诊断根本原因
下一步会将失败文档发送给 failure-analyst agent:
`1. - name: diagnose
2. type: ai.agent
3. agent-id: failure-analyst
4. timeout: 300s
5. with:
6. message: |
7. Analyze these failed documents from the "logs-demo-app" failure store.
9. Failed documents:
10. {{ steps.read_failures.output.hits.hits | json }}
12. Identify the root cause, classify the failure type, propose a concrete
13. fix with ingest pipeline processors, generate a remediation pipeline to
14. reindex the failed documents, and assess the risk.
16. YOUR RESPONSE MUST BE A SINGLE JSON OBJECT ONLY.
17. Do not write any explanation, preamble, markdown, or commentary.
18. Start your response with { and end with }.
19. Use exactly these top-level keys: root_cause, failure_type, affected_docs,
20. proposed_fix, remediation_pipeline, risk_assessment.`AI写代码
{{ steps.read_failures.output.hits.hits | json }} 模板会将上一步获取的文档注入 agent 的提示词中。该 agent 会分析错误模式,并识别出 price 字段接收了字符串值,而预期应该是浮点值。然后,它会提出一个修复管道。
agent 的输出会以单个 JSON 对象的形式出现在 steps.diagnose.output.message 中。由于诊断、建议的修复方案、管道定义和重建索引请求都是 AI agent 根据接收到的失败文档生成的,因此每次执行的具体内容可能有所不同。在我们的测试中,该 agent 能够持续识别根本原因,并生成可正常工作的修复管道。
尽管存在这种自然的变化,响应契约仍保持固定,这样工作流就可以持久化该计划,而执行 agent 也可以可靠地提取其中可执行的组件。响应始终包含六个必需的顶级键:root_cause、failure_type、affected_docs、proposed_fix、remediation_pipeline 和 risk_assessment。
记录诊断结果以供审计
在请求人工审批之前,工作流会将诊断结果和建议的修复计划写入 remediation-runs 索引。这会创建一个持久的审计记录,如果计划获得批准,remediation-executor 随后可以获取该记录:
`
1. - name: record_diagnosis
2. type: elasticsearch.index
3. with:
4. index: remediation-runs
5. document:
6. "@timestamp": "{{ now | date_to_xmlschema }}"
7. execution_id: "{{ execution.id }}"
8. data_stream: "logs-demo-app"
9. triggered_by_rule: "{{ event.rule.name }}"
10. failure_count: "{{ steps.read_failures.output.hits.hits | size }}"
11. failure_count_total: "{{ steps.read_failures.output.hits.total.value }}"
12. diagnosis: "{{ steps.diagnose.output.message }}"
13. status: awaiting_fix_approval
`AI写代码
execution_id 将诊断结果与当前工作流执行关联起来。该记录同时存储加载到有界批次中的失败文档数量,以及与查询匹配的失败总数。人工审批通过后,执行 agent 会结合 execution_id 和审批状态来获取正确的修复计划。
Elasticsearch Workflows 中的人工审批节点如何工作?
该工作流使用两种暂停步骤来处理不同类型的人工决策。Gate 1 使用 waitForInput 收集结构化的审批决定和审核人员反馈。Gate 2 使用 waitForApproval,因为验证需要一个二选一的决定:将案例标记为已解决,或者进行升级。
| Gate 1 | Gate 1b | Gate 2 |
|---|---|---|
| 步骤名称 | 步骤名称 | 步骤名称 |
gate_fix | gate_fix_revised | gate_verify(已批准路径)/ gate_verify_v2(修订路径) |
| 步骤类型 | 步骤类型 | 步骤类型 |
waitForInput | waitForInput | waitForApproval |
| 超时 | 超时 | 超时 |
| 72h | 72h | 72h |
| 决策形式 | 决策形式 | 决策形式 |
| 批准或拒绝,并附带备注 | 批准或拒绝,并附带备注 | 是,标记为已解决 / 否,进行升级 |
| 展示内容 | 展示内容 | 展示内容 |
| AI 诊断和建议的计划 | 修订后的计划 | remediation-executor 报告 |
| 出现时机 | 出现时机 | 出现时机 |
| 始终 | 仅在 Gate 1 被拒绝后 | 仅在执行完成后 |
Gate 1 定义如下:
`
1. - name: gate_fix
2. type: waitForInput
3. timeout: 72h
4. with:
5. message: |
6. GATE 1/2 - Fix Approval
7. Data stream: logs-demo-app
8. Failed documents: {{ steps.read_failures.output.hits.total.value }}
9. The AI agent has diagnosed the failures. Review the full diagnosis
10. in the 'diagnose' step output above, then approve or reject.
11. schema:
12. type: object
13. properties:
14. approved:
15. type: boolean
16. title: "Approve fix"
17. default: true
18. notes:
19. type: string
20. title: "Feedback (required if rejecting)"
`AI写代码
当工作流到达此步骤时,执行会暂停,其状态会持久化到 Elasticsearch 中。在审批节点等待期间,无需保持 agent 会话处于活动状态,也无需运行轮询循环。每个审批节点最多接受 72 小时的响应,但仍受工作流整体七天超时的限制。
该 schema 会收集审批决定和一个可选的 notes 字段。当方案被拒绝时,工作流会将备注传递给 failure-analyst agent,作为修订修复计划的上下文。测试部分会展示每次提交审批决定时所使用的批准和拒绝负载。
审核人员批准或拒绝计划后会发生什么
提交 Gate 1 后,route_fix 会恢复工作流,而不会重新运行已经完成的步骤。下面的简化片段展示了每个分支中的第一个转换步骤。(完整的可执行 YAML 可在本教程的代码仓库中找到。)
`
1. - name: route_fix
2. type: if
3. condition: "steps.gate_fix.output.response.approved: true"
4. steps:
5. - name: execute_fix
6. type: ai.agent
7. agent-id: remediation-executor
8. timeout: 300s
9. with:
10. message: |
11. Run remediation for the "logs-demo-app" failure store.
12. Workflow execution ID: {{ execution.id }}
13. The fix has been approved by a human reviewer. Execute the skill
14. 'execute-failure-store-fix' immediately without asking for confirmation.
`AI写代码
批准后,当前工作流的 execution_id 会传递给 remediation-executor。执行 agent 会结合该标识符和审批状态,获取与此次特定执行关联的修复计划,然后应用该计划并继续执行到 Gate 2。
如果 Gate 1 被拒绝,工作流会保存审核人员的反馈,并要求 failure-analyst agent 生成修订后的方案。随后,Gate 1b(gate_fix_revised)会展示该方案,供审核人员再次决定。当修订后的计划获得批准后,execute_fix_revised 会将相同的工作流执行 ID 发送给执行 agent:
`
1. - name: execute_fix_revised
2. type: ai.agent
3. agent-id: remediation-executor
4. timeout: 300s
5. with:
6. message: |
7. Run the revised remediation for the "logs-demo-app" failure store.
8. Workflow execution ID: {{ execution.id }}
9. The revised fix has been approved by a human reviewer. Execute the skill
10. 'execute-failure-store-fix' immediately without asking for confirmation.
`AI写代码
执行 agent 会使用审批状态来确定当前路径对应的计划:与 awaiting_fix_approval 关联的原始 diagnosis,或者与 awaiting_fix_approval_v2 关联的 revised_diagnosis。两条路径随后都会继续执行到 Gate 2。如果修订后的方案在 Gate 1b 被拒绝,工作流会记录 fix_rejected,然后结束,不应用任何更改。
在关闭案例之前通过 Gate 2 验证结果
Gate 2 显示 remediation-executor 报告,并等待“标记为已解决”或“进行升级”的决定。
Gate 2 是一个验证检查点。到达这里时,remediation-executor agent 已经创建了摄取管道并运行了重建索引操作,同时返回了一份详细报告。该审批节点会嵌入执行 agent 的报告:批准路径使用 steps.execute_fix.output.message,修订计划执行时则使用 steps.execute_fix_revised.output.message,并要求审核人员选择 Yes (mark as resolved) 或 No (escalate)。
Gate 2 使用 waitForApproval,因为工作流只需要一个二选一的验证决定。包括管道 ID、匹配并重建索引的文档数量、版本冲突、失败数量和执行错误在内的操作详情,都来自 remediation-executor agent 的报告,而不是由审核人员手动输入。
在我们验证过的执行中,agent 创建了 logs-demo-app-price-remediation 管道,并匹配和重建索引了全部五个获批准的文档。报告显示版本冲突为零,失败数量也为零。logs-demo-app 数据流中的文档数量从三个增加到八个,而原来的五条记录仍保留在 logs-demo-app::failures 中。这是预期行为,因为重建索引会复制文档,而不会将它们从失败存储中删除。
如果审核人员选择 Yes, mark as resolved,route_verify 会向 remediation-runs 写入一条新文档,将状态设置为 resolved,并将完整的 agent 报告存储在 agent_report 中。如果审核人员选择 No, escalate,工作流会写入一条状态为 escalated、包含相同报告的记录。修订路径通过 route_verify_v2 实现相同的流程,生成相同的状态以及相同的 agent_report 字段。
之所以设置 Gate 2,是因为一次技术上已经完成的重建索引操作仍然可能产生部分结果或非预期结果。选择升级而不是自动将修复标记为已解决,可以让审计记录准确反映实际情况。是否保留第二个审批节点取决于你的环境和风险承受程度。
完整工作流
查看完工作流后,请记住,完整代码位于代码仓库的failure-store-remediation.yaml文件中。
根据 Gate 1、Gate 1b 和 Gate 2 中做出的决定,工作流最终可以通过五种方式之一结束。下图展示了原始修复路径和修订修复路径如何最终进入 resolved、escalated 或 fix_rejected 状态。
每个终端结果都会追加到 remediation-runs 审计历史中。在整个工作流路径中,审计记录会保留诊断结果、请求修订时的审核人员反馈、执行 agent 报告以及最终结果。
规则及其工作流操作已经配置完成后,端到端流程就可以开始测试了。
端到端测试工作流
启用告警规则后,运行触发脚本,以写入五个 price 值无效且带有当前时间戳的文档:
`./scripts/02-trigger-test.sh`AI写代码
该规则会搜索前五分钟内的数据,因此会在下一次评估时检测到新写入 failure-store 的文档。进入 Workflows → Executions,打开新的执行记录。确认 read_failures、diagnose 和 record_diagnosis 均已完成,并且 gate_fix 正在等待输入。
在 Gate 1 批准修复
在 Gate 1 中,通过提交以下内容来批准建议的修复方案:
`{ "approved": true }`AI写代码
工作流会从 route_fix 恢复,并通过 execute_fix 调用 remediation-executor agent。随后,工作流会在 Gate 2 暂停,并显示执行报告。
下面的视频片段展示了 Gate 1 获得批准后,工作流如何自动在 route_fix 和 execute_fix 处恢复执行。
在完成 Gate 2 之前,验证五个经过修复的文档是否已经添加到数据流中:
`GET logs-demo-app/_count`AI写代码
预期结果:
`
1. {
2. "count": 8
3. }
`AI写代码
数据流最初包含三个有效文档,因此成功重放后,总数会增加到八个。原始记录仍然保留在失败存储中,因为重建索引会将文档复制到目标位置,而不会删除源记录。
通过选择 Yes, mark as resolved 或 No, escalate 来完成 Gate 2。工作流会将所选结果和执行报告存储在 remediation-runs 中。
拒绝计划并审核修订后的计划
要测试拒绝路径,请重置环境并启动另一次执行:
`
1. ./scripts/03-reset-full-test-environment.sh --apply
2. ./scripts/01-setup-failure-store.sh
3. ./scripts/02-trigger-test.sh
`AI写代码
在 Gate 1 中,通过提供具体反馈来拒绝方案:
`
1. {
2. "approved": false,
3. "notes": "The proposed remediation should distinguish numeric strings from non-numeric strings. Convert numeric strings to a float, preserve non-numeric values in price_raw, and remove price only when conversion fails."
4. }
`AI写代码
虽然当前 schema 中 notes 是可选的,但每当你拒绝一个方案时,都应提供具体反馈。工作流会在请求修订计划时,将该值传递给 failure-analyst agent。
工作流会记录反馈,并要求 agent 修订方案。随后,它会在 Gate 1b 暂停。要批准修订后的计划,请提交:
`
1. {
2. "approved": true
3. }
`AI写代码
要最终拒绝该方案,请提交:
`
1. {
2. "approved": false,
3. "notes": "Explain why the revised proposal should not be executed."
4. }
`AI写代码
批准修订后的方案后,它会按照上面介绍的相同执行和 Gate 2 验证路径运行。拒绝修订后的方案会记录 fix_rejected,并结束工作流,而不会应用修复。
结论
本教程构建的模式结合了三个要素:持久化的工作流状态、专用 AI agent,以及在需要判断的环节保留人工控制。failure-analyst agent 负责诊断问题并提出有边界的修复方案。Gate 1 在执行任何更改之前暂停,让审核人员控制是否执行。获得批准后,remediation-executor agent 会自动应用修复,而 Gate 2 再次暂停,以便在将案例标记为已解决或升级之前验证结果。
持久化执行状态解决的不只是 agent 会话过期的问题。诊断结果、审核人员反馈、执行报告和最终决定都会作为可搜索的数据存储在 Elasticsearch 中,并通过工作流的 execution_id 进行关联。这种关联使执行 agent 能够获取当前工作流运行所批准的计划,即使 remediation-runs 中同时存在多个修复案例也是如此。它还可以用于分析首次获得批准的修复数量、最常被拒绝的故障类型,以及审批节点保持打开状态的时间和需要升级处理的案例。
这种工作流模式同样适用于索引升级、映射变更、数据丰富管道验证、基础设施操作,以及其他需要自动化与人工判断共存的流程:诊断问题、暂停等待审批、自动执行已批准的操作、暂停进行验证,并记录最终结果。
资源
原文:AI agent orchestration: pause and resume where it stopped | Elasticsearch Labs