ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

AI原生工作流引擎Kiro:从Anthropic理念到AWS落地的关键实践

AI原生工作流引擎Kiro:从Anthropic理念到AWS落地的关键实践 最近团队在 AWS 上搭 Kiro 这套 AI 原生工作流引擎说实话一开始我是有点低估它的。流程引擎我见过不少从 AWS Step Functions 到 Temporal但 Kiro 这种把 LLM 当成一等公民、把 Anthropic 那套模型只是推理引擎的理念直接揉进工作流定义的玩法确实给了我不小冲击。这篇文章不打算讲 PPT 层面的架构图只想把从理念到落地的关键路径以及我们踩过的那些坑原原本本记下来。如果你正在评估或者已经在用 Kiro 做 AI 工作流编排下面这些内容应该能帮你省下不少调试时间。先说明一下背景。Kiro 是我们内部对这套基于 AWS 的 AI 原生工作流编排服务的代号它不只是一个调模型的工具而是一个把模型调用、工具调用、状态传递、校验重试、可观测性全部打通的工作流运行时。我们选择它是因为传统的 Step Functions 在编排确定性任务上很成熟但面对模型输出不稳定、上下文有长度限制、工具结果要反馈给模型这类 AI 场景时总感觉是在硬凑。Kiro 的设计思路更接近 Anthropic 官方推荐的应用框架先定义好输入输出再让模型在约束里做推理。这篇文章的核心就是拆解这套设计并给出可直接抄作业的工程实现。1. 从 Anthropic 设计理念到 Kiro先搞清楚AI 原生到底原生在哪1.1 Anthropic 的设计哲学模型是引擎不是数据库很多人用 Claude 这类模型时还停留在我写个 prompt你帮我生成答案的阶段。Anthropic 官方文档里反复强调的其实是另一件事模型是一个推理引擎它的输出质量高度依赖你给它什么样的上下文、工具和约束。你把所有资料都塞进 prompt它就给幻觉你让它自由发挥它就给你一篇格式乱七八糟的长文你只在出错后重试它大概率会重复犯同样的错。Anthropic 在应用层的设计理念可以浓缩成三句话显式定义输入输出的 schema让模型知道你必须按照这个 JSON 结构返回而不是靠 prompt 里一句请用 JSON 格式。把工具当作模型的手模型负责判断该调用哪个工具、传什么参数而工具本身要有一份严格的参数定义JSON Schema模型只是参数的填充者。上下文是稀缺资源你给模型看的每段文字都在占用它的注意力。上下文应该像数据库查询结果一样按需取用而不是把整个文档库都丢给它。这些理念听起来不算复杂但真正落到工程上绝大多数团队还是在做一个 prompt 走天下的事。Kiro 的价值在于它把这些理念强制变成了工作流定义里的结构字段。1.2 Kiro 把理念翻译成了工程结构我们第一次拿到 Kiro 的工作流定义文件时第一反应是这怎么长得有点像 CI 的 pipeline但仔细看就发现节点类型多了个llm节点并且这个节点要求你必须声明schema和tools。这不是为了让 YAML 变长而是把 Anthropic 的理念翻译成了约束。对比一下传统工作流和 AI 原生工作流的差异维度传统工作流Kiro/AI 原生工作流核心计算单元确定性的函数/任务非确定性的 LLM 工具失败模式异常、超时可预测输出不符合 schema、幻觉、上下文溢出状态传递显式传参类型固定需要携带上下文切片且要管理 token 消耗重试策略直接重跑同一步可能需要换模型、改 prompt、回退到规则逻辑可观测性日志记录参数和结果需要记录 prompt、completion、tool call 全过程Kiro 的工作流定义里llm节点必须要配一个schema这个 schema 不仅是输出校验用的它还会被塞进模型的 system prompt 里让模型从第一眼就知道自己该产出什么。同时llm节点可以声明toolsKiro 会自动把工具定义序列化成模型可以理解的格式。这些设计都不是 Kiro 发明的新东西而是把 Anthropic 反复强调的最佳实践做成了平台默认能力。我们团队后来的经验总结就一句话如果工作流里有个 LLM 节点却看不到 schema那十有八九是要返工的。2. Kiro 工作流设计的五个核心层次2.1 模型网关层路由规则与 fallbackAI 原生工作流要做的第一件事不是写 prompt而是把模型访问收敛到一个网关上。Kiro 的模型网关非常像一个微服务网关客户端不直接指定我要调 claude-3-opus而是指定一个路由名比如anthropic-main。网关根据路由名去查配置决定真正请求哪个供应商的哪个模型。这套设计解决了两个问题。第一个是供应商锁定你今天用 Claude明天想换成别的模型只需要改网关配置不用逐个改工作流文件。第二个是故障转移模型服务总有不稳定的时候网关可以根据路由规则自动 fallback 到备用模型。我们在生产环境里就遇到过 Anthropic API 区域性的超时如果没有 fallback整条工作流都会挂掉。一个典型的路由配置长这样gateway: routes: - name: anthropic-main provider: anthropic model: claude-3-5-sonnet-20241022 timeout: 30s fallback: - name: kiro-local provider: local model: llama-3.1-8b - name: kiro-local provider: local model: llama-3.1-8b这里有个细节值得注意timeout一定要设置。我们在初期没配超时结果某些情况下请求会挂着两分钟才报错整条工作流的执行时间被拖垮。后续我们统一把默认超时定为 30 秒fallback 之后如果还是失败才允许工作流进入重试或失败分支。2.2 状态管理层把上下文当作一等公民工作流跑起来以后最容易被忽视的就是状态管理。Kiro 把一次工作流执行看作一个有状态的run每个节点都可以读写这个 run 的全局状态。但关键是Kiro 并不会默认把所有状态都传给模型这违背了 Anthropic 的上下文节约理念。正确的做法是在每个 LLM 节点里显式声明这个节点需要看到哪些状态字段。我们用过一个真实的例子一个文档摘要工作流前置节点已经用工具抽出了原始文本、作者、时间戳等一堆字段但摘要节点其实只需要原始文本的前 8000 字符。如果你直接把全部字段拼接进 prompttoken 消耗会非常惊人而且模型注意力会被无关信息稀释。Kiro 里的做法是给状态打切片。比如- id: summarize type: llm inputs: excerpt: {{state.raw_text | truncate(8000)}} doc_title: {{state.title}}这样模型真正收到的上下文只有excerpt和doc_title而不是整个 state。这种按需组装上下文的思路就是 Anthropic 强调的 context engineering 在工作流层面的落地。此外状态管理还意味着要处理好执行上下文。每一条工作流执行都应该有独立的run_id所有日志、指标、工具调用记录都绑定到这个run_id上。这样回头排查问题时你可以完整回放一次执行的每一步而不是靠各处日志里的时间戳去脑补。2.3 工具接入层schema 即契约AI 工作流和传统工作流最大的区别之一是模型会主动去调用工具。我们说主动其实并不神秘你可以在 LLM 节点的配置里声明tools然后填一个合适的 prompt比如如果你觉得需要查询订单信息就调用 get_order 工具。模型收到工具定义后会在它的输出中生成一个 tool call。Kiro 对工具定义的要求非常严格必须使用 JSON Schema。你可以手动写也可以让 Kiro 从 OpenAPI 文档里自动转换。重要的是工具参数必须有明确的类型、必填项和描述。描述尤其关键因为模型是靠描述来判断何时调用工具的。比如{ name: get_order, description: 根据订单号查询订单状态、金额和物流信息。当用户询问订单相关问题时使用。, parameters: { type: object, properties: { order_id: { type: string, description: 订单编号格式如 ORD-2025-001 } }, required: [order_id] } }这段描述比你自己读给模型听更有效因为它以结构化方式进入模型上下文。我们踩过的坑是工具定义里有一项参数是布尔型但 description 里写了请传是或否结果模型真的传了字符串是导致校验失败。后来我们把 description 改成true 表示是false 表示否问题立刻消失。所以工具描述要避免自然语言模棱两可尽量用枚举或者明确的值。2.4 校验与重试层接受模型会犯错AI 工作流必须以模型会输出错误结果为前提来设计。这个前提听起来简单但很多刚接触的人还是习惯性地认为只要 prompt 写得足够好模型就不会出错。实际上哪怕是最强的模型在复杂的输出格式上也时不时会漏掉一个字段。Kiro 的做法是在每个 LLM 节点后自动做一次 schema 校验。校验失败时可以选择重试、走 fallback 模型或者直接进入人工处理队列。我们采用过的策略是第一次失败带着校验错误信息重试一次把错误信息拼进 prompt让模型自我修正。第二次失败切换 fallback 模型再试一次。仍然失败把这条执行标记为failed_validation写入死信队列。这套策略的灵感也来自 Anthropic 官方文档里提到的 self-correction 模式。附带一个经验重试的 prompt 里务必附上你刚才的输出没通过校验错误信息是……而不是简单让它再来一遍。这样做效果立竿见影。2.5 可观测性层每次执行都要能回放排错是 AI 工作流绕不开的日常。Kiro 默认会把每次执行的所有关键事件记录下来模型请求和响应全文、工具调用参数和返回值、每个节点的耗时、状态切片的变化。这些记录统一以 span 形式导出到 OpenTelemetry可以和 AWS X-Ray、CloudWatch 打通。这部分的收益在使用前几天还感受不到直到线上出现一次模型返回了一个合法但完全错误的 JSON 字段靠日志很难定位是哪个环节出的问题因为工作流整体是成功的。后来我们用 OpenTelemetry 的 trace 把那次执行的每一步展开发现是工具节点返回的数据本身就不对模型只是按照错误数据生成了看似合理的摘要。如果没有完整的回放能力这种问题基本没法查。可观测性不是锦上添花而是 AI 工作流的必需品。3. 从零搭一条可上线的文档摘要归档工作流3.1 场景定义与前置条件前面讲了不少设计层面的东西现在进入实操。我们拿一个最常见的场景练手上传一份 PDF抽取文本生成结构化摘要提取关键字段写入数据库。这个流程很多团队都做过但用 Kiro 来做最大的好处是每一步的输入输出都遵循 schema模型乱输出的概率会大幅降低。前置条件有这些一个 AWS 账号并在目标区域开通了 Kiro 服务实际部署时请按照真实服务名和区域查询。客户端安装了 Kiro CLI或具备调用其 SDK 的权限。已经有 Anthropic API Key或至少有一个可用的模型网关地址。我们在演示中会使用anthropic-main这个路由名它指向 Claude 3.5 Sonnet。如果你用的是不同模型记得把路由配置改成你自己的。3.2 用 YAML 定义工作流Kiro 的工作流定义通常是一个 YAML 文件。以我们的文档摘要归档为例workflow: id: doc-summary-archive version: 1 description: 从PDF抽取文本生成摘要提取结构化字段存入数据库 nodes: - id: extract type: tool tool: pdf-extractor params: source: {{trigger.uri}} output: raw_text - id: summarize type: llm route: anthropic-main inputs: excerpt: {{state.raw_text | truncate(12000)}} prompt: | 你是文档分析助手。请阅读下面的文档片段输出摘要和要点。 文档片段 {{excerpt}} schema: type: object properties: summary: type: string description: 不超过200字的摘要 key_points: type: array items: type: string description: 3-5个核心要点 title: type: string description: 文档标题 required: [summary, key_points, title] output: doc_summary - id: archive type: tool tool: db-write params: table: doc_summaries row: {{state.doc_summary}}几个关键点说明一下route: anthropic-main指向网关路由而不是写死模型 ID。这样后续换模型不用改这个文件。inputs.excerpt从状态里取出原始文本并截断到 12000 字符防止上下文超长。schema定义了输出结构。这个 schema 会同时用于两件事注入模型 prompt、校验模型输出。这就是我前面说AI 原生的意义你的工作流描述的是意图和契约而不是具体的函数调用链条。模型节点负责把自然语言文本变成符合 schema 的 JSON工具节点负责真实世界里的副作用。3.3 配置模型网关路由要让上面的工作流跑通网关里必须先有anthropic-main这个路由。配置方法一般不直接在 YAML 里写而是通过 Kiro 的网关管理命令注册。命令行大致长这样kiro gateway routes create \ --name anthropic-main \ --provider anthropic \ --model claude-3-5-sonnet-20241022 \ --timeout 30s \ --fallback kiro-local创建完路由后可以用kiro gateway routes list验证。如果路由没创建成功后面工作流执行时会报expected a gateway model route referee之类的错误。这个我们放到下一节详细排查。另外API Key 之类的敏感信息不要写在 YAML 里。Kiro 支持从 AWS Secrets Manager 读取密钥也可以从环境变量读取。我们团队的选择是 Secrets Manager这样密钥轮换不需要改动工作流文件。3.4 设置中文输出和本地化界面关于中文设置这是一个非常常见的问题。Kiro 的默认界面语言是英文但如果你在 AWS 控制台里使用可以在个人偏好设置里把语言切成中文如果你用的是 Kiro CLI可以通过环境变量指定export KIRO_LOCALEzh-CNCLI 的日志、提示信息都会显示为中文。如果你是在自己开发的应用里嵌入 Kiro SDK也可以初始化时传 locale 参数。但需要区分的是界面语言和模型输出语言是两回事。界面中文只是 UI 层面而模型返回的摘要是否用中文取决于你的 prompt 和 schema。我们在上面那个工作流里的 prompt 并没有明确要求中文所以模型可能根据文档语言自动选择。为了稳定建议在 schema 描述里写明summary 字段请使用简体中文或者在 prompt 里加一句请始终用简体中文输出。最稳妥的做法是在 few-shot 示例里给一个中文的例子。单纯靠请用中文这种指令在长文本场景下偶尔还是会失效。3.5 运行、验证与上线检查工作流定义和网关配置都就位后执行一次测试运行kiro runs start doc-summary-archive \ --param uris3://bucket/input/sample.pdf执行过程中可以用kiro runs get run_id查看每个节点的状态。如果成功你会在状态里看到doc_summary是一个符合 schema 的 JSON 对象{ summary: 本文介绍了一种基于AWS的AI原生工作流设计方法……, key_points: [模型网关是AI工作流的核心, 上下文管理决定成本和效果, 可观测性必须内置], title: AWS Kiro AI原生工作流设计解析 }上线前我们还会做三件检查schema 校验是否开启确保每个 LLM 节点都有schema否则宁可多加一步人工校验也不裸奔。fallback 是否有效手动把网关路由改成一个错误的模型名确认工作流会降级到备用模型而不是直接失败。预算控制给每次执行设置 token 上限。Kiro 允许在路由上配置max_tokens建议设置防止异常输入导致成本飙升。这三件是我们在生产上吃过亏后才总结出来的。4. 连接与路由问题排查实录4.1 unable to connect to anthropic services failed to connect to api.anthropic.com 的根治思路这个错误几乎是所有接 Anthropic API 的人都会遇到的。报错信息很直白TCP 连接api.anthropic.com失败。但在不同环境下根因差别很大。我们团队遇到过的几种情况VPC 内无法访问公网Kiro 跑在 AWS 私有子网时如果子网没有 NAT 网关就无法访问 Anthropic API。解决方法是配置 NAT 网关或者使用 AWS PrivateLink 接入 Anthropic 的终端节点。我们最终选了 PrivateLink因为更稳而且不用维护 NAT 的公网 IP。出口 IP 不在白名单有些企业账号在 Anthropic 控制台配置了 IP 白名单只有白名单里的 IP 才能调用 API。此时需要在 VPC 上绑一个固定 EIP并把它加进白名单。DNS 解析异常在有些环境里内网 DNS 劫持了外网域名。排查方法很简单先试curl -v https://api.anthropic.com看能否连通如果连接失败再试dig api.anthropic.com看解析结果是否正常。代理配置冲突如果系统环境变量里有HTTP_PROXY/HTTPS_PROXYKiro 的底层 SDK 可能会走代理而代理本身又不稳定。我们踩过这个坑最后的处理是显式地在 Kiro 服务的环境变量里把代理清空或者设置NO_PROXY包含api.anthropic.com。排查这个错误时我建议先从网络连通性入手不要一头扎进 Kiro 配置里。先证明你这条机器能访问 Anthropic API再谈其他。如果机器用 curl 能拿到响应那问题大概率在 Kiro 的配置如果 curl 也超时那就是网络层问题。4.2 expected a gateway model route referee 到底在说什么这是我见过最让新手困惑的报错。完整错误像这样doesnt look like an anthropic model: expected a gateway model route referee。拆开来看Kiro 的网关在做路由决策时需要一个裁判referee来判断当前请求应该走哪条路。这个裁判就是路由规则。你工作流或代码里指定的模型引用方式应该是一个已注册的路由名而不是裸的模型 ID。当 Kiro 看到model: anthropic/claude-3-5-sonnet或model: claude-3-opus-4这种字符串而它的路由表里又没有这个名字时它就会说这东西看起来不像一个 anthropic 模型我需要的是一个网关路由裁判。换句话说这个错误不是说你调用了不存在的 Anthropic 模型而是说你没有用网关能识别的路由名。解决步骤查看当前已有的路由kiro gateway routes list对比你的工作流或 API 请求里写的模型名。应该写路由名例如anthropic-main而不是provider/model-id。如果你确实想用某个新模型先在网关里创建路由kiro gateway routes create \ --name claude-opus \ --provider anthropic \ --model claude-opus-4-20250514再去改工作流里的route: claude-opus。这个错误还有个变种就是 YAML 里route字段写对了但网关配置里这个路由的provider字段写成了anthropic而模型名是 Kiro 本地模型的 ID导致网关无法建立一个匹配关系。所以创建路由时一定要保证provider、model与你的模型服务商一致。4.3 高频坑位速查表最后把我们在 Kiro 实战中碰到过的问题整理成一张表方便你排查时对照。现象可能原因处理方式模型返回内容完全符合 JSON 但语义不对schema 描述写得太宽泛在 schema 的 description 里增加语义约束和示例同一条工作流有时成功有时失败上下文达到模型窗口上限对文本字段做 truncate或改用支持更长上下文的模型重试仍然得到同样的错误输出重试 prompt 没有附上错误信息把上一次的校验错误拼接进重试 prompt工具调用总是失败工具参数描述不明确给参数加 enum 约束或改写 description 中的自然语言歧义fallback 没生效fallback 路由不存在或配置错误先手动调用 fallback 模型确认可用CLI 显示英文未设置 locale设置KIRO_LOCALEzh-CN并重启进程网关路由创建报错 route name exists同名路由已存在用update而不是create这张表的共性经验是AI 工作流里的大多数问题都不是模型不够聪明而是边界没画清楚。你给模型的 schema、工具描述、路由约束越明确模型的表现就越可预期。反过来说上游任何一处模棱两可都会在某个不确定的时刻以奇怪的方式暴露出来。从 Anthropic 那套设计理念到 Kiro 的工程实现我最大的感受是AI 原生工作流的重点不在AI而在原生。Kiro 没有把 LLM 当做一个黑盒函数来调用而是把它放进工作流的每一个环节同时用网关、状态、schema、可观测性这些经典的工程手段去约束它。这种做法看起来多写了很多配置但长期维护下来的成本远比一个灵光一现的巨型 prompt 低得多。如果你也在搭建类似的工作流不妨先花一个下午把你的节点、schema、路由定义清楚再去纠结 prompt 的措辞。顺序对了后面会顺很多。
返回列表