一天一个开源项目

一天一个开源项目(第227篇):Strands Agents Harness SDK —— 从「手写 Agent 循环」到「一行代码拿到生产级 Agent」

Strands Agents(strands-agents/harness-sdk)是 AWS 团队开源的 Agent 开发 SDK,提供 Python/TypeScript 双语言实现。核心亮点是 Strands Harness——一个通过 create_harness() 单次调用即可组装出的"全副武装"生产级 Agent,内置上下文管理、会话持久化、长期记忆、技能加载与多模型支持,且返回的仍是一个完全可定制的原生 Agent 对象。8,300+ Stars,Apache-2.0 协议。

·约 17 分钟阅读·AI 工程

引言

"选择 Strands 的场景,通常是你原本打算自己写一套 Agent 循环——它在你的进程里运行,没有托管的控制面,而且覆盖了手写循环最终都会长出来的那些能力。"

这是"一天一个开源项目"系列的第 227 篇。今天的项目是 Strands Agents(仓库名 harness-sdk)。

写一个能真正跑起来的 AI Agent,往往不是"调用模型 + 执行工具"这么简单。真实场景里,你很快会撞上一堆琐碎但绕不开的问题:对话轮次太长怎么办?工具结果把上下文撑爆了怎么办?会话中断了怎么恢复?换一个模型供应商要不要重写一遍?大多数团队的答案是:自己攒一套 Agent 循环,然后在使用过程中不断给它打补丁——直到这套自造的循环长出了会话管理、上下文压缩、多模型适配、护栏机制等一堆本该是基础设施的能力。

Strands Agents 是 AWS 团队开源的一套 Agent SDK,提供 Python 和 TypeScript 两套实现,想解决的正是这个问题。它分两个层次:底层是 Strands SDK,一套模型驱动、可定制的 Agent 循环、工具系统和多模型支持;上层是 Strands Harness,通过一次 create_harness()(或 TypeScript 里的 createHarness())调用,就能拿到一个已经配好上下文管理、会话持久化、长期记忆、技能系统的"全副武装"Agent——而且返回的仍然是一个普通的 strands.Agent,意味着 Harness 帮你配置的一切,你都可以随时打开、修改或替换。

8,300+ Stars,1,200+ Forks,Apache-2.0 协议,由 Strands 团队(AWS)主导开发和维护。

你将学到什么

  • Strands SDK 与 Strands Harness 的分层关系:"自己搭 Agent 循环" vs "拿一个预配好的生产级 Agent"
  • create_harness() 默认给你的能力:上下文管理、会话持久化、长期记忆、技能加载
  • 内置工具体系:shell、文件操作、programmatic_tool_caller、subagent 委派
  • 多模型可移植性:Bedrock、Anthropic、OpenAI、Gemini 之间如何用同一套代码切换
  • MCP 集成、拦截机制(interventions)与子 Agent 委派模式

前置知识

  • 具备 Python 或 TypeScript 基础开发经验
  • 了解 LLM Agent 的基本概念(工具调用、多轮对话)
  • 可选:了解 MCP(Model Context Protocol)的基本概念

项目背景

项目简介

Strands Agents 的官方定位是"一种以模型为驱动的方式,用几行代码构建 AI Agent"。项目 README 里的表述很直接:"当你原本打算自己写一套 Agent 循环时,就该选 Strands——它在你的进程里运行,没有托管的控制面,而且覆盖了手写循环最终都会长出来的那些能力"。这句话点出了这个项目的核心价值主张:它不是又一个"Agent 框架皮层",而是把手写 Agent 循环过程中反复重新发明的那些基础设施(生命周期控制、工具、结构化输出、MCP、多 Agent 模式、记忆、会话、模型可移植性、流式输出、护栏、可观测性、评估)提前做好。

这个仓库(harness-sdk)是一个 Monorepo,包含:

  • harness-py/、harness-ts/:Python/TypeScript 的 Strands Harness,通过 create_harness() / createHarness() 组装出一个已配置好的 Agent
  • strands-cli/:命令行工具,可以直接在终端里跟 Harness Agent 对话
  • strands-py/、strands-ts/:底层 SDK 本体——Agent 循环、模型供应商、工具系统
  • site/:官方文档站源码(基于 Astro/Starlight)

团队与项目信息

  • 所属组织:strands-agents(由 AWS 团队主导)
  • 协议:Apache License 2.0
  • 语言支持:Python 3.10+、TypeScript(Node.js 22+)
  • 发行渠道:PyPI(strands-agents、strands-harness)、npm(@strands-agents/sdk、@strands-agents/harness、@strands-agents/cli)

项目数据

  • ⭐ GitHub Stars:8,300+
  • 🍴 Forks:1,246
  • 📄 协议:Apache-2.0
  • 🐛 Open Issues:837(活跃度较高,社区反馈频繁)
  • 📅 创建时间:2025-05

主要功能

解决什么问题

自己手写 Agent 循环的典型演化路径:
  第一版:model.generate() + 工具调用的简单循环
  ↓ 对话变长 → 手动截断历史,容易丢关键信息
  ↓ 工具结果太大 → 手动写摘要逻辑塞进 prompt
  ↓ 需要换模型供应商 → 重写调用层和参数映射
  ↓ 需要断点续聊 → 自己实现会话存储和恢复
  ↓ 需要记住用户偏好 → 自己实现一套"记忆"存储和检索
  ↑ 每一步都是重新发明基础设施,且团队各自实现,互不兼容
 
Strands 的做法:
  底层 SDK:模型驱动的 Agent 循环 + 工具系统 + 多模型支持,开箱即可用
  ↓
  上层 Harness:create_harness() 一次调用
  ↓
  拿到已配置好上下文管理/会话/记忆/技能的 Agent
  ↑ 返回值仍是一个普通 Agent,Harness 配置的一切都可以覆盖、扩展或替换

使用场景

  1. 快速搭建一个能处理长任务的编码/运维 Agent

    • 例如官方示例中的 agent("Find the slowest test in this repo and explain why it's slow")——需要读文件、跑 Shell、分析结果的多步骤任务
  2. 需要多模型可移植性的生产系统

    • 团队可能同时用 Bedrock、Anthropic、OpenAI,或者未来需要切换供应商,Strands 的 provider/model 字符串写法让这种切换只是改一个参数
  3. 需要长期记忆和会话恢复的助手类产品

    • Harness 默认把每次对话持久化到磁盘,并通过后台任务提炼跨对话的长期记忆,适合"记得住用户偏好"的客服/个人助理场景
  4. 需要委派子任务、避免主上下文被搜索结果或多步探索淹没的复杂任务

    • 内置的 subagent 工具让主 Agent 可以把"搜索很多文件""多步骤修改""开放式探索"这类任务甩给一个干净的子 Agent,只拿回最终结论

快速开始

最简 SDK 用法(Python):

pip install strands-agents strands-agents-tools
from strands import Agent
from strands_tools import calculator
 
agent = Agent(tools=[calculator])
agent("What is the square root of 1764")

最简 SDK 用法(TypeScript):

npm install @strands-agents/sdk
import { Agent } from '@strands-agents/sdk'
 
const agent = new Agent()
const result = await agent.invoke('What is the square root of 1764?')
console.log(result)

用 Harness 直接拿到生产级 Agent(Python):

pip install strands-harness
from strands_harness import create_harness
 
agent = create_harness()
agent("Find the slowest test in this repo and explain why it's slow")

用 Harness 直接拿到生产级 Agent(TypeScript):

npm install @strands-agents/harness
import { createHarness } from '@strands-agents/harness'
 
const agent = await createHarness()
await agent.invoke("Find the slowest test in this repo and explain why it's slow")

不想写代码?还可以直接装一个 CLI:npm install -g @strands-agents/cli,得到一个 strands 终端命令,直接在终端里跟 Harness Agent 对话。

核心特性

1. 分层设计:SDK 负责底座,Harness 负责组装

底层 strands.Agent 是可以完全自己拼装的原语;上层 create_harness() 把这些原语按经过验证的默认配置组装成一个即用的 Agent。两层之间没有断层——Harness 返回的就是一个普通 Agent,拿到手之后仍可以逐项覆盖。

2. 默认自带的生产级能力

能力默认行为
模型默认跑在 Amazon Bedrock 上的 Claude Opus,支持 Bedrock/Anthropic/OpenAI/Google 等多家供应商
工具自带 shell、文件读写编辑、web_fetch、programmatic_tool_caller(沙箱化的工具编排)
上下文管理自动摘要旧对话轮次,把体积大的工具结果挪到存储中,只留一个引用
会话每次对话默认落盘到 ./.agent/sessions,可按 session id 恢复
长期记忆跨对话提炼用户偏好和项目事实,存成 Markdown,自动折回上下文
缓存系统提示词、工具定义、历史对话在供应商支持的情况下自动走缓存

3. 灵活的模型选择语法

用一个 provider/model 字符串就能在供应商之间切换,写法统一,reasoning effort 也统一成一套等级(off/minimal/low/medium/high/xhigh/max),由 SDK 负责映射到每家供应商各自的参数:

create_harness(model="anthropic/claude-opus-5")
create_harness(model="openai/gpt-5.6-sol")
create_harness(model="bedrock/global.anthropic.claude-opus-5")  # 默认值

4. 内置工具可精细调整

builtin_tools 支持两种写法:传列表是"精确钉死"这几个工具,传字典是"在默认集合上做增删改"——False 移除、True 添加、配置字典既启用又配置:

create_harness(builtin_tools=["read"])                     # 只留 read
create_harness(builtin_tools={"subagent": False})          # 默认集合去掉子 Agent 委派
create_harness(builtin_tools={"web_fetch": {"model": "openai/gpt-5-mini"}})  # 给 web_fetch 单独配模型

5. 两种子 Agent 委派模式

内置的 subagent 工具让主 Agent 把子任务交给一个继承了主 Agent 模型、工具、技能、拦截策略的完整 Harness 子成员;另一种是用 Agent.as_tool() 把任意专用 Agent 包装成工具,适合需要固定角色(如"只负责审查代码的 reviewer”)的场景。两者可以同时存在。

6. MCP 与 Web 访问原生支持

指向标准的 mcpServers 配置(JSON 文件或内联字典),Harness 就会自动连接每个 MCP 服务器、发现其工具并加入工具列表;web_fetch 默认开启,web_search 视模型供应商是否原生支持自动开关,也可以显式接入 Exa 作为第三方搜索后端。

7. Agent Skills 与拦截机制(Interventions)

把 Agent Skills 放进 ./.agent/skills 目录,Harness 会自动加载;interventions 参数支持 "ask"、"smart" 或自定义策略字符串(甚至 .cedar 策略文件),用来在工具调用前设一道审批/校验闸门。

项目优势

对比项从零手写 Agent 循环只用底层 SDK(strands-py/ts)Strands Harness
上手速度慢,要重新发明一堆基础设施中等,循环和工具原语已就位快,一次调用拿到全套默认配置
可定制程度完全自由高高(返回值仍是原生 Agent,可逐项覆盖)
上下文/会话/记忆管理需要自己实现需要自己接入默认自带
多模型可移植性需要自己封装适配层SDK 层已支持多供应商一个字符串参数切换
生产就绪度因团队而异取决于自己补齐多少能力默认即是"经过验证的默认值”

为什么选择这个项目?

  • AWS 团队主导开发,更新和 Issue 响应活跃(837 个 open issue 侧面说明用户基数和使用深度)
  • Python/TypeScript 双语言一致的 API 设计,团队技术栈混合时不需要维护两套心智模型
  • "分层不锁死"的设计理念——Harness 给你默认值,而不是把你框进一个封闭的框架

项目详细剖析

Harness 到底组装了什么

create_harness() 的参数列表本身就是一份"生产级 Agent 需要什么"的清单:

create_harness(
    model="bedrock/global.anthropic.claude-opus-5",  # 模型供应商与型号
    effort="auto",                          # 推理强度
    instructions=None,                      # 附加到系统提示词的领域指令
    tools=None,                             # 自定义工具
    mcp_servers=None,                       # MCP 服务器配置
    plugins=None,                           # 自定义插件
    builtin_tools=None,                     # 内置工具集的增删改
    background_tasks=None,                  # 后台任务策略
    builtin_plugins=["todos", "environment"],  # 内置功能插件
    caching="auto",                         # 上下文缓存
    context_manager="auto",                 # 上下文管理策略
    session=True,                           # 会话持久化
    skills=True,                            # 技能加载
    memory=True,                            # 长期记忆
    interventions=None,                     # 工具调用拦截策略
    **agent_kwargs,
)

这份清单背后的思路很清楚:凡是"手写 Agent 循环最终都会长成"的能力——生命周期控制、上下文压缩、会话恢复、跨对话记忆、审批闸门——都被提前实现并给了一个经过验证的默认值,而不是留给每个使用者各自摸索。

上下文管理:摘要 + 外部化存储

长任务里最容易失控的是上下文窗口。Harness 的默认策略是双管齐下:自动摘要较早的对话轮次,同时把体积大的工具结果(比如一次搜索返回的大量文件内容)挪到外部存储,只在上下文里留一个简短的引用。这个设计意味着即使任务跑很多轮,上下文也不会线性膨胀——真正需要引用旧结果时,Agent 可以按引用拉回来,而不是让每一轮都携带全部历史。

子 Agent 委派:两种模式服务两种需求

项目里区分了两种委派方式,对应两种不同的使用意图:

  • 内置 subagent 工具:模型自主决定把任务委派给一个继承主 Agent 全部配置(模型、内置工具、插件、技能、拦截策略)的子 Harness 成员。子 Agent 可以收窄父 Agent 授予的工具集,但不能扩大——这是一条安全边界。委派深度默认有上限,避免无限递归委派。
  • Agent.as_tool() 包装的专用 Agent:适合角色固定、职责单一的场景(比如一个只做代码审查的 reviewer),每次调用都是全新会话,是一个干净、专注的委派者而非共享会话。

两者可以共存:内置 subagent 处理通用的"探索型"委派,as_tool() 处理需要固定角色和 prompt 的专家型委派。这种区分体现了项目对"委派"这件事的两种理解——一种是让模型自己判断何时该甩锅,另一种是工程师预先固定好角色边界。

内置工具与沙箱化编排:programmatic_tool_caller

Harness 的默认工具集里有一个值得注意的设计:programmatic_tool_caller。这是一个沙箱,让 Agent 自己写代码来串联、循环、并行调用其他工具,而不是每次工具调用都要走一轮"模型生成调用参数 → 执行 → 模型看结果 → 决定下一步"的完整推理循环。对于"读取 50 个文件并统计某个模式出现次数"这类批量、机械的操作,这种编排方式比逐个工具调用高效得多,也省了不必要的模型推理开销。

多模型可移植性的实现方式

provider/model 字符串是一层薄的别名映射(bedrock、bedrock-mantle、anthropic、openai、google、ollama、litellm),对于列表之外的供应商,直接传一个 Model 实例即可,SDK 按原样使用。effort 参数的处理也遵循同样的哲学:统一到一套等级枚举,由 SDK 负责映射到每家供应商各自的原生参数命名——但如果请求的等级某个供应商根本不提供,SDK 会直接抛错而不是静默降级,避免"以为开了高强度推理,实际上悄悄没生效"这种隐藏故障。

与从零构建的对比:分层但不锁死

Strands 的设计哲学可以概括为"分层但不锁死"。多数 Agent 框架要么给你一套完全自由但什么都要自己搭的原语,要么给你一个高度集成但很难跳出框架去自定义的黑盒。Strands 试图两者兼得:Harness 层给你一个经过验证、可以立刻投产的默认配置,但它返回的对象是完全普通的 Agent——这意味着你随时可以绕开 Harness 的默认值,直接操作底层 SDK 的 Hooks、拦截机制、自定义会话后端,而不需要"逃离框架”这种代价高昂的重构。


项目地址与资源

官方资源

相关资源


总结与展望

核心要点回顾

  1. 分层架构:底层 SDK 提供可完全自定义的 Agent 循环与工具原语,上层 Harness 提供一次调用即可用的生产级默认配置,两层之间没有断层
  2. 默认能力覆盖手写循环的常见痛点:上下文管理、会话持久化、长期记忆、缓存优化都是开箱即用
  3. 多模型可移植性是一等公民:统一的 provider/model 语法和 reasoning effort 等级,让切换模型供应商不需要重写业务逻辑
  4. 两种子 Agent 委派模式服务不同意图:内置 subagent 面向模型自主委派,Agent.as_tool() 面向工程师预设的专家角色
  5. AWS 团队主导,活跃度高:8,300+ Stars、837 个 open issue,说明这是一个正在被真实使用且持续迭代的项目

适合谁

  • 打算自己写 Agent 循环、但还没写到会话/记忆/上下文压缩这一步的团队:可以直接跳过重新发明基础设施的阶段
  • 需要在多个模型供应商之间保持灵活性的团队:统一的模型切换语法降低了供应商锁定风险
  • 想快速搭一个能处理长任务、多步骤操作的编码/运维 Agent 的开发者:Harness 的默认工具集(shell、文件操作、编排沙箱)覆盖了大多数场景
  • Python 与 TypeScript 技术栈混合的团队:两套 SDK 保持一致的 API 设计,不需要维护两套心智模型

一句话评价

Strands Agents 没有把"写一个 Agent”这件事包装成一个封闭的黑盒,而是先老老实实把手写循环最终都会补的那些基础设施做好,再让你决定要不要拿它当起点。


欢迎访问 PrimeSkills —— 一个精心策划的 AI Agent 与技能市场,所有内容均经过真实企业级工作流验证。没有噱头,只有真正有效的东西。

更多实用知识和有趣产品,欢迎访问我的个人主页