harness 正在变得不稀缺
过去一年,Agent 框架的竞争重心发生了一次迁移。提示词怎么写、上下文怎么裁、工具怎么接,这些问题的答案正在被大量开源实现覆盖。当基础设施变得容易获得之后,差异化的位置就会往两边移动:一边是模型能力,另一边是执行环境。
开源框架 PraisonAI 在 9 月 7 日发布的一篇技术说明里,把这个判断写成了一个具体设计:它把 Agent 拆成五层,然后在五层之外单独加一层,用来回答一个此前很少被显式提出的问题——这段代码到底在哪台机器上跑。
先说清楚定位。PraisonAI 是一个 Python 优先的 Agent 框架,核心 SDK 包名为 praisonaiagents,命令行工具是 praisonai,另有 JavaScript 版本。项目在 GitHub 上有约 9,000 个 Star、1,400 余个 Fork,采用 MIT 许可,建仓时间是 2024 年 3 月。它的目标用户是「想快速搭多 Agent 流水线,但不想自己写 MCP 客户端、记忆层、检索与沙箱调度」的团队。
五层各回答一个问题
这套分层最值得借鉴的地方,不在于它把 Agent 切成了几块,而在于每一层被赋予了一个明确的、可以用自然语言回答的问题。
Prompt 层回答的是「我说清楚了吗」,对应 instructions、角色与目标设定、输出格式要求。Context 层回答的是「窗口里放的是对的东西吗」,对应记忆、知识库、上下文注入与交接。Harness 层回答的是「它能动手吗,动完能被检查吗」,对应工具、MCP 接入、护栏、审批与沙箱。Loop 层回答的是「什么时候该停」,对应执行配置、反思机制与死循环检测。Graph 层回答的是「谁先跑谁后跑,谁检查谁」,对应流程编排、路由、并行与循环。
框架给出的价值主张是:当 Agent 行为异常时,层数告诉你该去哪儿找。配套的故障定位映射也很实用——输出格式不对,看 Prompt 层;该记住的没记住,看 Context 层;工具调错了,看 Harness 层;转圈停不下来,看 Loop 层;顺序错了,看 Graph 层。
这套映射并不高深,但它把一个常见的工程困境变成了可操作的问题。Agent 出问题时的典型症状是「它就是不听话」,而「不听话」这个描述无法定位。把它拆成五类具体症状之后,排查范围会立刻收窄。这也是作者建议的做法:即便不采用这个框架,也可以先把这张表抄下来当调试清单。
Loop 层:把刹车做成显式配置
五层里最容易被低估的是循环控制。Agent 失控的典型形态不是报错,而是持续运行——反复调用同一个工具、在两条路径之间来回震荡、或者把预算烧在一个方向上。
这个框架给出的方案是三个显式刹车。硬迭代上限由 max_iter 控制;预算天花板由 max_budget 控制,单位是钱;无进展检测负责识别「一直在动但没有推进」的状态。配置写法大致如下。
from praisonaiagents import Agent, ExecutionConfig
agent = Agent(
instructions="Fix the failing tests.",
execution=ExecutionConfig(max_iter=30, max_budget=0.50,
on_budget_exceeded="stop"),
autonomy=True,
)
result = agent.run_autonomous("Refactor the auth module", max_iterations=5)
print(result.completion_reason)
其中 completion_reason 的取值设计得比较克制,共有七种:goal 表示目标达成,no_tool_calls 表示模型不再调用工具,max_iterations 表示撞到迭代上限,timeout 表示超时,doom_loop 表示检测到死循环,needs_help 表示需要人工介入,error 表示执行出错。
把这七种状态分开,好处是调用方能写出不同的处理逻辑。撞到上限和真正完成目标都返回「结束」,但前者需要人工复核,后者可以直接交付。很多自研 Agent 循环只区分成功与失败,结果就是上限触发被当成成功,错误被静默吞掉。
死循环检测的细节也值得一提。它识别两类模式:重复的相同工具调用,以及 A 到 B 再到 A 再到 B 的震荡。同时明确了一条不误伤的边界——如果输出一直在变化,即使反复调用同一个工具,也不算死循环。这条边界很关键,因为轮询类任务天然会重复调用,如果检测规则写得粗暴,正常业务会被误杀。
外层:两个参数回答两个问题
五层之外的那层,是这套设计里比较有辨识度的部分。它把「在哪执行」拆成两个不同的参数,分别回答不同的问题。
tools_run_on 只挪工具。也就是说,shell、文件、代码这三类内置工具被放进沙箱,而模型调用与 Agent 循环仍然留在本机。它的适用场景是:不希望 Agent 在本机执行命令或改文件,但可以接受推理过程在本机完成。
run_on 挪整个 Agent。模型调用、循环与工具全部在托管运行时上执行。适用场景是:整段执行都不应落在本机,包括推理过程。
from praisonaiagents import Agent, AgentFlow
# A. 只有工具挪走,思考留在本机
agent = Agent(name="builder", instructions="...", tools_run_on="docker")
# B. 整个 agent 挪走——模型调用、循环、工具都在远端
agent = Agent(name="teacher", instructions="...", run_on="anthropic")
# 多个 Agent 共享同一个沙箱:第 1 步写的文件第 2 步能读到
writer = Agent(name="Writer", instructions="You write files.")
reader = Agent(name="Reader", instructions="You read files.")
flow = AgentFlow(tools_run_on="docker", steps=[writer, reader])
flow.run("Write 'hello' to /workspace/note.txt, then read it back")
tools_run_on 的候选值包括 docker、e2b、modal、daytona 与 flyio。共享沙箱的用法解决了多 Agent 流水线里的一个具体问题:如果每个步骤各自开一个隔离环境,前一步产出的文件后一步读不到,流程会断在中间。
这里有一个容易踩的坑,框架选择在运行期主动告知,而不是等开发者调试几个小时才发现。可以直接问对象它在哪里跑,返回的是一段人话:思考(模型调用)发生在当前这台机器上;工具跑在一个 Docker 容器里;你自己写的工具(例如一个数据库检查函数)仍然留在本机,只有 shell、文件与代码这三类内置工具会被移走。
最后一句是重点。很多人的直觉是「工具都挪走了」,实际只有内置的三类会移动,自研工具仍在本地执行。如果自研工具会读取敏感文件或访问内网,把它留在本机等于隔离并不完整。这个设计选择是否合理可以讨论,但把答案显式打印出来,至少避免了认知错位。
报错即文档
另一个细节是参数校验的写法。如果误用,框架报的不是含糊的错误,而是直接给出正确写法。
>>> Agent(name="x", instructions="i", run_on="e2b")
TypeError: Agent(run_on='e2b') is not valid: run_on= places the whole agent
-- model calls, loop and tools -- on a managed runtime, and 'e2b' runs
commands but cannot host an agent loop.
To run only the tools there: Agent(tools_run_on='e2b')
这段报错的信息密度比多数框架高。它解释了为什么不行——e2b 只能执行命令,无法承载 Agent 循环;也给出了替代方案——如果只想把工具放过去,应该用 tools_run_on。把「错在哪、为什么错、怎么改」三件事写进一条报错,对降低上手成本的作用比文档更大。
配套还有沙箱生命周期管理:闲置时自动关闭,支持闲置超时配置;复用装好依赖后的快照,下次运行跳过拉镜像与安装依赖;把环境定义文件提交进仓库,让执行环境随代码走。最后一条对可复现性影响很大——环境配置进入版本管理之后,本地跑通、换机器失败这类问题会明显减少。
框架也支持纯 YAML 描述流程,命令行提供执行、研究、规划、工作流、记忆、知识库、会话、工具、MCP、调度等子命令,其中 praisonai managed ps 可以查看当前有哪些沙箱在运行,managed stop --all 用于批量停止。这类命令对控制成本有实际作用——被遗忘的沙箱会持续计费。
中立思辨
这套设计并非没有短板,而且作者自己在文章里泼了三盆冷水,这反而提高了材料的可信度。
其一,某些宣传数字没有信息量。例如「14 微秒完成实例化」这类指标,测的是构造一个 Python 对象的耗时,与真实性能无关。真实开销几乎全部来自模型调用与工具执行,量级在几百毫秒到几十秒之间。把不重要的维度包装成卖点,是这类项目常见的宣传习惯。
其二,社区背书不等于技术背书。文章提到项目带有某位知名企业家的转发徽章,作者明确指出这与代码质量无关。判断一个框架是否适合生产,要看的是它的测试覆盖、issue 处理速度与版本策略,而不是转发量。
其三,功能密度高带来排查面变宽。这个框架涉及记忆、知识库、上下文、护栏、审批、钩子、沙箱、自主性、反思、规划、缓存、联网等大量参数,好处是开箱可用,代价是很难判断某个具体行为由哪个参数决定。分层图缓解了这个问题,但没有消除它。项目有 50 多个开放 issue,对 9,000 Star 的项目不算多,但说明仍在快速迭代,接口稳定性需要团队自行评估。
其四,还有一个框架作者没有展开、但值得所有使用者记住的事实:PraisonAI 自身曾出现过严重安全漏洞。2026 年 7 月披露的 CVE-2026-61447 评分在 CVSS 3.1 与 4.0 两套体系下都达到满分 10.0,问题出在代码执行环节,攻击者可通过构造内容让模型生成读取环境变量并外传的代码,进而窃取 API 密钥与云凭据。同批次还包含任意文件写入、参数未校验的 SQL 注入等缺陷。这恰好说明:把工具放进沙箱不是可选项,而是使用这类框架的前提条件。
其五,关于具体版本号与长期维护承诺,公开材料未给出语义化版本信息。目前官方及行业暂未披露更多细节,后续将持续跟进迭代动态。
怎么用这套分层
把上面的内容收敛成三条可执行的建议。
先把五层表当成调试清单用起来。这一步不需要引入任何框架,只要在团队内部约定:Agent 出问题时,先判断属于哪一类症状,再去看对应那层。多数「它就是不听话」的工单,会在这一步被拆成可处理的具体问题。
再明确执行边界。哪些工具可以出本机、哪些数据不能出本机、推理过程本身能不能出本机,这三个问题要在选型之前回答。如果答案是「代码不能出本机」,那么把工具推到远端沙箱的方案就不适用,需要往反方向选。
最后评估取舍。作者给出的判断标准比较中肯:如果团队更怕「自己写太多」,这类高集成度框架是合适的;如果更怕「不知道行为从哪来」,那么一个更薄、每行都在自己控制之下的循环可能更合适。这两者没有优劣,只有匹配与否。