引言
"选择 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()组装出一个已配置好的 Agentstrands-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 配置的一切都可以覆盖、扩展或替换使用场景
-
快速搭建一个能处理长任务的编码/运维 Agent
- 例如官方示例中的
agent("Find the slowest test in this repo and explain why it's slow")——需要读文件、跑 Shell、分析结果的多步骤任务
- 例如官方示例中的
-
需要多模型可移植性的生产系统
- 团队可能同时用 Bedrock、Anthropic、OpenAI,或者未来需要切换供应商,Strands 的
provider/model字符串写法让这种切换只是改一个参数
- 团队可能同时用 Bedrock、Anthropic、OpenAI,或者未来需要切换供应商,Strands 的
-
需要长期记忆和会话恢复的助手类产品
- Harness 默认把每次对话持久化到磁盘,并通过后台任务提炼跨对话的长期记忆,适合"记得住用户偏好"的客服/个人助理场景
-
需要委派子任务、避免主上下文被搜索结果或多步探索淹没的复杂任务
- 内置的
subagent工具让主 Agent 可以把"搜索很多文件""多步骤修改""开放式探索"这类任务甩给一个干净的子 Agent,只拿回最终结论
- 内置的
快速开始
最简 SDK 用法(Python):
pip install strands-agents strands-agents-toolsfrom 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/sdkimport { 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-harnessfrom 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/harnessimport { 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、拦截机制、自定义会话后端,而不需要"逃离框架”这种代价高昂的重构。
项目地址与资源
官方资源
- 🌟 GitHub:https://github.com/strands-agents/harness-sdk
- 📚 官方文档:https://strandsagents.com
- 📄 协议:Apache License 2.0
- 🐛 Issue Tracker:GitHub Issues
- 💬 社区:Discord
相关资源
- Model Context Protocol —— Strands 原生支持接入的工具协议标准
- Agent Skills —— Harness 的技能系统所遵循的规范
- Strands Samples —— 官方提供的实践示例仓库
总结与展望
核心要点回顾
- 分层架构:底层 SDK 提供可完全自定义的 Agent 循环与工具原语,上层 Harness 提供一次调用即可用的生产级默认配置,两层之间没有断层
- 默认能力覆盖手写循环的常见痛点:上下文管理、会话持久化、长期记忆、缓存优化都是开箱即用
- 多模型可移植性是一等公民:统一的
provider/model语法和 reasoning effort 等级,让切换模型供应商不需要重写业务逻辑 - 两种子 Agent 委派模式服务不同意图:内置
subagent面向模型自主委派,Agent.as_tool()面向工程师预设的专家角色 - AWS 团队主导,活跃度高:8,300+ Stars、837 个 open issue,说明这是一个正在被真实使用且持续迭代的项目
适合谁
- 打算自己写 Agent 循环、但还没写到会话/记忆/上下文压缩这一步的团队:可以直接跳过重新发明基础设施的阶段
- 需要在多个模型供应商之间保持灵活性的团队:统一的模型切换语法降低了供应商锁定风险
- 想快速搭一个能处理长任务、多步骤操作的编码/运维 Agent 的开发者:Harness 的默认工具集(shell、文件操作、编排沙箱)覆盖了大多数场景
- Python 与 TypeScript 技术栈混合的团队:两套 SDK 保持一致的 API 设计,不需要维护两套心智模型
一句话评价
Strands Agents 没有把"写一个 Agent”这件事包装成一个封闭的黑盒,而是先老老实实把手写循环最终都会补的那些基础设施做好,再让你决定要不要拿它当起点。
欢迎访问 PrimeSkills —— 一个精心策划的 AI Agent 与技能市场,所有内容均经过真实企业级工作流验证。没有噱头,只有真正有效的东西。
更多实用知识和有趣产品,欢迎访问我的个人主页