返回博客列表

写 Agent 不用再写循环:AWS AgentCore harness 把编排层做成了配置

2026-10-15T23:45:00+08:00
AWSAgentCoreAI AgentBedrockMCP云服务

写 Agent 不用再写循环:AWS AgentCore harness 把编排层做成了配置

Agent 框架又多了一个,这次 AWS 直接把"框架"这一层收编了。

每个 Agent 都有一个编排层:一个循环,调模型、选工具、把结果塞回上下文、管理会话状态、处理失败。这个循环本身不难写,Strands、LangGraph、Claude Agent SDK 都能干。真正让团队掉头发的是循环底下的东西——生产环境要的沙箱、安全工具连接、文件系统、记忆、身份、可观测性,一样都不能少。本地跑通只要一下午,上线服务多个用户的那一刻,并发、隔离、状态、扩缩容全冒出来。

AWS Bedrock AgentCore harness 的思路是:这些活儿别自己干了。你声明 Agent 是什么(模型、工具、Skills、指令),AgentCore 负责把它变成一个真的在跑的 Agent——环境、算力、记忆、身份、网络、可观测性全托管。换个模型或加个工具是改配置,不是改代码重部署。底层编排循环由 AWS 开源的 Strands Agents 驱动,harness 本身已 GA,不单独收费,只按用到的 AgentCore 能力计费。

这篇把我读官方文档拆出来的东西整理给你:它到底管了什么、怎么上手、哪些设计值得学、以及什么时候你该选 Runtime 而不是它。

本文提纲

  1. harness 是什么:Agent 代码之外的另一半
  2. 五分钟上手:一条 CLI 到流式响应
  3. 配置驱动的编排:默认值加调用时覆盖
  4. 工具、Skills 与生命周期钩子
  5. harness vs Runtime:同一道题的两种答案
  6. 边界与冷静判断

一、harness 是什么:Agent 代码之外的另一半

"harness"这个词在 Claude Code、Codex 这类产品走红之后被讲得越来越多,指的是包住模型的整套运行系统:编排循环加底下的基础设施。AgentCore 文档把它拆成两层——循环本身(调模型、选工具、回填结果、管上下文、处理失败),和生产化需要的地基(沙箱、工具连接、文件系统、记忆、身份、可观测性)。

AgentCore harness 做的事,是把这两层全部托管:

graph LR
    A["Your config: model, tools, skills, memory"] --> B["AgentCore harness: managed agent loop"]
    B --> C["microVM per session: filesystem, shell"]
    B --> D["Tools: Gateway, MCP, Browser, Code Interpreter"]
    B --> E["Memory: short-term and long-term"]
    C --> F["Event stream: text, toolUse, hookEvent"]
    D --> F
    E --> F
    F --> G["Your app consumes the stream"]

三个设计值得单独说:

每个会话一个隔离 microVM

Agent 有自己的文件系统和 shell,可以写代码、执行、改文件。会话默认有状态,短期和长期记忆、文件都能跨会话保留——哪怕底层 microVM 过期销毁、被新实例顶替,记忆和文件还在。

模型随便换,会话不丢

Amazon Bedrock、OpenAI、Google Gemini、任何 LiteLLM 兼容的模型都能接,而且可以在同一个会话的不同轮次之间切换供应商,上下文照常延续。规划用一个模型、执行用另一个,或者拿两个模型做性价比对比,都不用重建对话。

配置即部署

环境变量、执行上限(maxIterations、timeoutSeconds、maxTokens)、VPC 网络、入站 IAM/OAuth 认证、出站身份的 token vault,全是 harness 配置字段。CloudTrail 里 harness 操作记录在 AWS::BedrockAgentCore::Runtime 下面——它跑在 Runtime 之上,这层关系后面细说。

二、五分钟上手:一条 CLI 到流式响应

两条路:AgentCore CLI(Node.js 20+)或 boto3 SDK(Python 3.10+)。CLI 最快:

npm install -g @aws/agentcore

agentcore create --name myresearchagent --model-provider bedrock
agentcore deploy
agentcore invoke --harness myresearchagent \
  --session-id "$(uuidgen)" \
  "Research three tropical vacation options under $3k, within five hours of NYC."

响应直接流式打到终端。复用同一个 --session-id,就在同一个环境里继续对话。本地开发用 agentcore dev:它先把 harness 资源(IAM 角色、harness、memory)部署到 AWS,然后起一个本地 dev server,在浏览器里打开 agent inspector,可以对话、看 trace、改配置。

走 SDK 的话,核心是三个 API 调用:

aws bedrock-agentcore-control create-harness \
  --harness-name "MyHarness" \
  --execution-role-arn "arn:aws:iam::123456789012:role/MyHarnessRole"

轮询 get-harness 到 READY,拿到 ARN,然后 invoke_harness:

response = client.invoke_harness(
    harnessArn="arn:aws:bedrock-agentcore:us-west-2:123456789012:harness/MyHarness-XyZ123",
    runtimeSessionId="1234abcd-12ab-34cd-56ef-1234567890ab",  # 至少 33 字符
    messages=[{"role": "user", "content": [{"text": "Research three tropical vacation options under $3k."}]}],
)

for event in response["stream"]:
    if "contentBlockDelta" in event:
        delta = event["contentBlockDelta"].get("delta", {})
        if "text" in delta:
            print(delta["text"], end="", flush=True)

不指定模型时,harness 默认用 Amazon Bedrock 上的 Anthropic Claude Sonnet 4.6(global.anthropic.claude-sonnet-4-6)。流式事件里有几个 stopReason 值值得记住:tool_use、tool_result、max_iterations_exceeded、timeout_exceeded、hook_stopped——最后一个来自生命周期钩子,后面讲。

三、配置驱动的编排:默认值加调用时覆盖

harness 的配置模型是一句话:创建时定默认值,调用时做覆盖。model、systemPrompt、tools、maxIterations、maxTokens、timeoutSeconds、skills、allowedTools、actorId 全部可以在单次 InvokeHarness 里临时覆盖,harness 资源本身不动。按官方文档的说法,一次重新部署的工夫,你能测 N 组模型/prompt/工具组合。

最有意思的是模型热切换。同一个会话里,三轮流式调用可以分别走不同供应商,上下文全程携带:

# Turn 1: Bedrock Converse API, Claude
model={"bedrockModelConfig": {"modelId": "us.anthropic.claude-sonnet-4-5-20250514-v1:0"}}

# Turn 2: Bedrock Mantle, OpenAI Responses 格式
model={"bedrockModelConfig": {"modelId": "openai.gpt-4o", "apiFormat": "responses"}}

# Turn 3: OpenAI 模型,走 Bedrock Mantle 端点,不需要 OpenAI API key
model={"openAiModelConfig": {"modelId": "gpt-5.4", "apiFormat": "responses", "endpoint": {"bedrockMantle": {}}}}

Turn 3 那种写法值得展开说:endpoint: bedrockMantle 让你通过 Amazon Bedrock Mantle 端点调 OpenAI 模型,用执行角色的凭证,不碰 OpenAI API key。要走自己的网关或自托管端点,配 apiKeyArn(从 AgentCore Identity 的 token vault 引用)加 apiBase,密钥在调用时才被拉取,Agent 代码从头到尾看不到原始凭证。

API 格式也是可选的:Bedrock 模型默认走 converse_stream,也可以切到 OpenAI 兼容的 responses 或 chat_completions(由 bedrock-mantle 端点服务);OpenAI 配置支持 responses 和 chat_completions。换句话说,你可以让 Claude 模型说 OpenAI 的"方言",应用侧只用对接一种协议。

四、工具、Skills 与生命周期钩子

工具是声明的,不是代码。 五种类型加两个内置工具:

工具 说明
remote MCP 任意远程 MCP 端点,URL 直连,认证头支持 ${arn:...} 引用 token vault
AgentCore Gateway 托管工具面,带出入站认证、访问控制、策略执行,引用 gateway ARN 即接入全部工具
AgentCore Browser 托管浏览器自动化
AgentCore Code Interpreter 沙箱里跑 Python/JavaScript/TypeScript
inline function 在你的客户端执行,harness 暂停等结果——人在环审批就靠它
shell(内置) bash,每个会话默认可用
file_operations(内置) 查看、创建、编辑文件

allowedTools 控制模型能用哪些工具,支持 glob 和 @server/tool 语法(比如 "@git/git_status" 只放行某个 MCP 服务器的特定工具)。这里有个容易忽略的成本细节:内置 shell 和 file_operations 的工具定义加起来约 900 input tokens,每个模型请求都会带一遍,一次调用可能发生多次。工具挂得越多,底噪越高,按需用 allowedTools 裁剪是实打实的省钱手段。

Skills 走渐进式披露。 每个 Skill 是符合 AgentSkills.io 标准的 markdown 加脚本包,元数据约 100 tokens 注入 system prompt,完整指令按需加载。四个来源可以混搭:AWS 官方技能目录(core-skills/* 这类 glob 直接开启)、Git 仓库(支持 monorepo 子目录 sparse checkout,私库用 token vault 里的 PAT)、S3 桶(单 skill 上限 1GB)、文件系统路径(烤进容器镜像)。Skill 在会话首次调用时拉取一次,VM 过期重建后自动重新拉取保证新鲜度。拉取失败会让整个调用失败,绝不静默跳过——这个错误处理哲学我喜欢。

生命周期钩子是治理的抓手。 四个事件点(before_invocation、before_tool_call、after_tool_call、after_invocation),三种目标(Lambda、SNS、EventBridge)。只有 Lambda 能改变 Agent 循环行为:返回 deny 可以拦下整个调用、跳过某个工具调用、或在工具执行后终止调用。SNS 和 EventBridge 只做通知,不阻塞循环。每个 harness 最多 20 个钩子,Lambda 超时 1 到 900 秒,failureMode 决定钩子挂了算 allow 还是 deny(默认 deny,安全取向)。钩子上下文上限 64 KiB,超了会打截断标记,文档明确提醒:after_tool_call 对 inline function 的确认只说明 harness 收到了客户端回传的结果,不代表客户端真的执行了外部操作——这种把安全假设写在明面上的措辞,比大多数文档诚实。

五、harness vs Runtime:同一道题的两种答案

这是选型时最该搞清楚的问题。两者解决同一问题的不同部分:

AgentCore harness AgentCore Runtime
本质 托管的编排循环(Strands 驱动) 无服务器托管环境
你提供 配置:模型、prompt、工具、记忆、上限 代码:任意框架写的 Agent,打成 ARM64 容器推 ECR
编排循环 AgentCore 提供 你自己写
换模型/加工具 改配置,不用重新部署 改代码,重新构建部署
自定义容器 支持(配置加代码混合) 支持
框架选择 不行,就是 Strands 那套循环 任意框架或无框架
双向流式、图/工作流模式 不支持 自己实现
记忆、网关、浏览器、代码解释器 配置即用 SDK 里自己调
计费 无单独 harness 费用,按底层能力计费 按 Runtime 计费

选型判断其实就一句:编排循环里没有你的秘密,就用 harness;循环里有你的核心逻辑(自定义图结构、特殊调度、双向流式),用 Runtime 自己写。两者不互斥——harness 跑在 Runtime 上,导出的 Strands 代码也能跑在 Runtime 上,迁移路径是留了后门的。

六、边界与冷静判断

先说它做不到的。harness 的编排循环是 Strands 的,你没法换框架,也写不了循环内的自定义 hook(Lambda 钩子在循环外围,管拦截不管循环内部逻辑)。双向流式、graph/工作流这类非 Agent-loop 模式不支持,需要就回 Runtime。inline function 要写客户端代码处理回传,属于配置加代码的混合模式。

平台层面也有几个注意点。Web 搜索工具目前只在 us-east-1 可用,得通过 Gateway 挂 Web Search connector。allowedTools 只约束 InvokeHarness 里 LLM 的工具选择,管不住 InvokeAgentRuntimeCommand——那是另一个直接执行 shell 命令的 API,有独立 IAM action,不想让人绕过 LLM 直接执行命令,就别把这个权限授出去。第三方模型配置里的 additionalParams 会原样透传给供应商,文档专门警告可能影响端点路由和凭证处理,如果你的应用把调用方传入的配置转发给 InvokeHarness,得自己校验。

锁定问题值得想一下,但没到劝退的程度。harness 的配置格式是 AWS 自家的,不过官方提供了"导出为 Strands 代码"的出口(Claude Agent SDK 支持在路上),Strands 又是开源框架——真要搬家,循环逻辑可以带走,托管的那部分基础设施(microVM、记忆、身份、可观测性)带不走,那本来也是你买它的原因。

我的整体判断:如果你们的 Agent 需求落在"标准 Agent loop 加工具加记忆"的框框里,harness 把最脏的活儿(隔离、状态、凭证、trace)收走了,剩下的都是业务决策,这买卖划算。需求越怪,harness 的抽象漏得越多,Runtime 加自选框架反而是更短的路。拿不准的话,先 agentcore create 起一个跑跑看,成本就是几次模型调用。


参考文档与链接

你在用什么搭 Agent 的生产环境?评论区聊聊你的选型。觉得有用就点个赞,让更多人看到。


作者: itech001
来源: 公众号:AI人工智能时代(the-ai-era)
网站: https://www.theaiera.top/ 关注每日最新AI新闻和技术博客,主页有更多的文章的AI 技术参考:https://www.theaiera.top

本文首发于 AI人工智能时代,转载请注明出处。

分享给朋友