Tracecat自动化最佳实践 是做什么的?
对于面向Slack的自动化,请使用 /skill:tracecat-slackbot-best-practices。在Tracecat工作区聊天中,先加载 /skill:tracecat-workspace-chat;其特定主机工具映射会覆盖以下外部MCP步骤。按需参考:图形形状、表达式、run-python、表格、触发器输入、案例触发器、密钥、代理输出、代理预设、工作流编辑。
工作流
对于外部Tracecat MCP连接,从实时上下文开始,而不是猜测:
- 使用
list_workspaces发现工作区。 - 当需要DSL语法或示例时,读取
tracecat://platform/dsl-reference。 - 使用
get_workflow_authoring_context获取动作模式、变量和密钥。 - 对于现有工作流,使用
get_workflow,然后进行有针对性的edit_workflow补丁——请参阅 工作流编辑。在添加或编辑任何run_if、depends_on或join_strategy之前,先调用主机暴露的get_workflow_graph,并首先读取每个上游动作及其gated_by列表。 - 使用
validate_workflow进行验证,在适当时运行草稿或已发布执行,然后使用list_workflow_executions和get_workflow_execution检查失败情况。
其他主机可能暴露不同的工具接口。请遵循其适配器,而不是机械地使用这些裸MCP名称。
阐明会改变工作流合约的生产决策:工作区、集成/提供商、密钥来源、发布/运行行为、破坏性副作用、审批或验收标准。如果请求已经足够具体,请直接进行。
图形形状
在编写之前勾勒形状,并尽可能保持在一行内。首选线性而非并行,可读性优于完全连接:边越少越好。
depends_on是执行顺序,而不是数据连线。 动作可以读取任何祖先中的ACTIONS.<ref>.result,而不仅仅是直接父级——验证检查的是引用是否存在于工作流中,而不是它是否是父级。仅在动作必须等待时添加边,而不是为了使值可达。- 只守卫一次。 动作上的
run_if也会跳过链上其下的每个动作,因此不要在后续重复。每个动作都带有相同TRIGGER.enabled && ...守卫的链是错误的;只有第一个动作需要它。下游动作只有当引入新条件时,才需要自己的run_if,且单独编写。例外情况是join,这是一个陷阱:一个具有多个父级的任务不会因为一个父级存活而被强制跳过,但默认的join_strategy: all要求每个父级都被访问过,因此一个分支被跳过会使join不可达并导致工作流失败。使用join_strategy: any,或者在join上重复分支的条件,使其首先跳过自身。 - 默认使用单链。仅在需要真正独立的工作值得并发运行时才分支,并且仅当后续动作需要来自多个分支的结果时才重新join。
- 一个父级是常态。多于一个意味着有意的join——请有目的地选择
join_strategy。 - 保持每个
run_if简短:针对一个新条件进行一次可读的比较。长&&/||链通常重复了上游守卫,或者应放在更早的转换中。 - 保持普通工作流大约20个节点或更少,基于代理的工作流大约6个节点或更少。首选可读的从上到下流程,按照过程读取的顺序排列,并使用人类可读的引用。Tracecat MCP在动作或边发生变化时会自动格式化画布,因此省略
layout而不是手动放置节点。
请参阅 图形形状 获取一个关于过度连接的重写、join策略、错误边以及为什么散布不是分支的详细说明。
动作优先级
选择最适合任务的最具体动作:
- 集成动作 (
tools.<integration_slug>.*) 用于被调用的产品。在编写API调用之前,先用简短的产品或动作名称子字符串搜索list_actions(例如query="okta"),或浏览已知的tools.<integration_slug>命名空间。搜索匹配的是字面子字符串,而不是单独的关键词。当第一页没有合适的动作时,在has_more为真时跟随next_cursor。使用get_action_context检查候选动作,并比较它们所需的凭据和参数。 - 核心动作:
core.http_request/core.http_paginate用于没有集成动作的产品或端点,core.transform.*用于数据整形,core.table.*/core.cases.*用于平台数据。 core.script.run_python仅用于没有动作覆盖的自包含步骤。当集成或HTTP动作可以发出调用时,永远不要从Python调用API。
永远不要发明 tools.* 名称。如果一个通用请求适用于多个集成,首先展示候选动作。
选择代理还是Python
根据工作的类型做决定,优化整个工作流的可维护性和可读性——用最少的动作和最少的代码完成工作。
- 代理式工作 → 使用代理 (
ai.agent/ai.preset_agent)。任何需要判断、调查、路由、丰富选择、摘要、编写消息或发布到Slack的工作。在预设的actions允许列表或技能的metadata.tools上授予工具,然后信任代理使用它们。首选代理、提示和技能——它们以远少于确定性节点图的移动部件承载创造性思维。 - 确定性数据管道 → 使用Python (
core.script.run_python)。转换、规范化、编辑、合并和将行批处理到表中。这正是Python的用途——它不是坏味道。一个清晰的run_python动作胜过将相同工作分散到许多节点上。API调用不是数据管道:它们放在集成或core.http_*动作中(参见 动作优先级)。
坏味道是用Python来处理代理式部分——例如编写或发送代理的Slack消息,而不是给代理Slack工具。
提示大小防护: 将行为推入提示中,直到合理大小。当单个提示变得太大而难以保持可读性时,分解为子代理或技能,而不是膨胀为一个巨型提示。
代理优先自动化
当用户要求基于代理的工作流、代理预设或说要使用代理时,让代理成为工作的主要所有者。给它需要的工具,信任它去调查、决策、路由、编写消息和行动。默认使用简洁的形状:trigger -> reshape/redact -> upsert event record -> ai.agent(或 ai.preset_agent)。
在代理运行之前持久化标准化事件。当事件源自SIEM、日志平台、SaaS webhook流、审计追踪或云服务时,先用确定性的upsert将标准化载荷和审查状态存储在Tracecat表中。这为重试、重复webhook和重放提供了持久的真相来源。将代理指向保存的行,这样工作流——而不是代理——拥有事件的第一个持久记录。
确定性节点通过保持精简、直接和易于审计,以及执行代理不应拥有的工作来赢得自己的位置:在代理看到数据之前编辑密钥、标准化模式、upsert事件行、用去重检查守卫昂贵的代理运行、准备有界批次或检查点持久状态。将判断、路由、丰富、消息编写、软审批决策和最终通知行为保留在代理中。当审批问题本身需要判断时,让代理决定或起草请求。
两种不同的机制覆盖风险,它们不与预设拥有的工具冲突。对工作流本身执行的不可逆外部效果使用确定性门——图形决定该节点是否运行。对代理持有的风险工具使用预设上的每工具 tool_approvals:代理保留该工具,运行会在该特定调用通过之前暂停等待人工。
优先选择一个有良好指令的代理或可复用的预设,而不是许多小的确定性节点。代理的工具通常放在预设的 actions 允许列表上,或者当多个代理共享该组时,放在附加技能的 metadata.tools 上。这样代理在工作区聊天和每次调用它的工作流中都有相同的工具。指令承载行为而非权限:输出合约、Slack风格、去重规则、租户边界和允许的副作用都放在预设指令中,代理读取它们而不是仓库文件。当代理需要工具时,在那里授予狭窄的工具通常胜过在同一个工作流动作中包装相同的调用。
一个 ai.preset_agent 节点通常只携带 preset 和 user_prompt,加上一个可选的 instructions 追加用于运行特定的上下文。它的 actions 参数替换预设及其技能的注册表工具用于该运行,而不是添加到它们——MCP工具保持附加,空列表被忽略——所以它适合在测试或评估中尝试带有不同工具集的预设。留在生产工作流中的列表也会丢弃预设技能贡献的注册表工具,这很少是作者想要的。
将代理指令编写为目标、上下文和原因,而不是禁止。一个一刀切的规则可能会取消赋予代理的工具:一个调用者追加了“仅使用提供的证据”,结果代理跳过了它已被授予工具的单个策略查找。为不可逆或面向外部的操作保留硬性规则,并在这些规则后面放置 tool_approvals 或确定性门,而不是依赖提示的措辞。
预设的运行时拥有比 list_actions 显示的更多能力:真正的shell和文件工具、Python、curl、jq 和DuckDB。在添加工作流辅助来补偿假定的限制之前,先检查预设/运行时上下文——参见 代理预设。
编写默认值
- 对于基于代理的工作流,将大部分行为推入代理提示/预设。对于事件驱动的工作流,代理之前的一个reshape/redact/upsert动作通常是正确的确定性边界。
- 使用
ai.agent/ai.preset_agent用于代理式工作;产品的tools.*动作(或当没有时使用core.http_request)用于确定性API调用;core.script.run_python用于确定性数据处理,前提是已排除了内联表达式、run_if或core.transform.*动作——参见 表达式 和 run-python。 - 对于批量表写入,当行已整形时(每批最多1000行),优先使用一个原生的
core.table.insert_rows动作。如果需要整形、分块或混合表/案例写入,使用core.script.run_python配合导入的辅助函数和有界批次,而不是分散许多数据库支持的动作。 - 不要将
core.http_request交给代理,除非用户明确接受广泛的网络能力。将确定性HTTP放在工作流图形或紧密作用域的子工作流中。 - 只有在存在真正的编排边界、可复用的子工作流、单独的执行历史、审批、长时间运行的动作或独立的检查点时,才拆分为子工作流。使用
core.workflow.execute,并优先使用workflow_alias而不是硬编码的ID。子工作流批量默认值:loop_strategy: batch、batch_size: 32、fail_strategy: isolated、wait_strategy: wait(仅当父级不需要子级结果时使用detach)。 - 保持run-python和代理输出小巧:下游行、汇总计数、有界错误样本。
- 优先使用可复用的代理预设而不是内联
ai.agent,并使用model对象而不是已弃用的顶层model_name/model_provider——参见 代理预设。
常见错误
- 使用Python处理代理式部分——编写或发布代理的Slack消息,或在脚本中做路由/判断调用。代理拥有消息编写、发布(通过Slack工具)和判断;Python拥有确定性数据管道。
- 过度连接图形:从每个生产者到每个消费者都添加边。从祖先读取并保持一条链(参见 图形形状)。
- 在链上重复
run_if,重复祖先已经强制过的条件。跳过会自行传播——只守卫一次,并且仅当后续动作引入它独有的新条件时才给它run_if(参见 图形形状)。 - 工作流动作名称不是MCP工具名称。使用MCP工具如
create_workflow来管理工作流,动作名称如core.http_request仅在工作流YAML内部使用。 - 发明
tools.*动作名称。使用list_actions发现动作,然后用get_action_context检查精确模式。 - 当存在合适的
tools.*动作时,从core.script.run_python(requests、httpx)或裸core.http_request中调用产品的API。先搜索并翻页list_actions查找该产品。 - 使用
for_each进行普通循环管理,或使用scatter/gather进行数据密集的批处理、过滤、join或表写入。默认使用scatter进行工作流级循环;仅当下游步骤需要合并结果时才添加gather,否则省略。要特别小心超过10个分散的数据库支持的表/案例动作,这可能会耗尽PostgreSQL连接槽。scatter的可选间隔可以错开工作,但它不会批量数据库写入;对批量写入使用一个core.table.insert_...