从 OpenClaw 到 Android:Harness Engineering 是怎么让 Agent 变得可用的

作者:陆业聪日期:2026/3/24

最近看到一张图,把 Agent 工程的演化路线列了出来:ReAct(2023初)→ Plan & Execute(2023末)→ Multi-Agent(2024)→ Context Engineering(2025)→ Harness Engineering(2025+)。配了一句话:

"名词换了五六轮,核心问题从未改变。Agent 工程师的核心能力:在不确定性上构建确定性。"

这句话我反复想了一下,觉得说到点子上了。这篇文章不打算再讲 Harness Engineering 的定义,而是从一个具体系统——OpenClaw——出发,拆解它的 Harness 是怎么搭的,然后讨论同样的工程思路怎么落到 Android 上。

一、先说"不确定性"到底是什么

做过 Agent 开发的人都知道,模型本身不是问题,问题是它在工程环境里会失控。常见的失控姿势:

• 工具调用结果格式不对,模型不知道怎么继续

• 上下文太长,模型开始"幻忆"——把没发生的事情当成已经发生的

• 多步任务中途某一步失败,没有重试逻辑,整条链路断掉

• 用户输入包含注入攻击,模型不加甄别地执行了奇怪的指令

这些都是"不确定性"的具体形态。Harness Engineering 要解决的问题,不是让模型变聪明,而是给模型套上一个工程框架,让它在这些不确定性里仍然能产出可预期的行为

2024年,Anthropic 的研究团队发表过一篇关于 Agent 可靠性的内部报告(Building Effective Agents,2024),里面有个观察我觉得很有价值:

"Most agent failures don't come from the model being wrong. They come from the scaffolding being wrong — bad tool descriptions, missing error handling, or context that doesn't give the model what it needs to act."

说白了:Agent 出问题,80% 是脚手架的问题,不是模型的问题。这也是为什么 Harness Engineering 这个词会出现——专门描述"围绕模型的那层工程壳"。

二、OpenClaw 的 Harness 长什么样

这个系列的前三篇已经拆解了 OpenClaw 的运行机制、执行循环和上下文管理。今天从 Harness Engineering 的视角重新看一遍,你会发现 OpenClaw 其实是一个教科书级的 Harness 实现。

2.1 工具描述即协议

OpenClaw 的工具定义走 JSON Schema,每个工具有明确的 descriptionparametersrequired 字段。这不是给开发者看的注释,这是给模型看的行为规范。

Anthropic 的工程师在 2025 年的一次播客(Latent Space,2025年3月期)里提到过一个细节:他们在内部评估里发现,工具描述写得好不好,对任务完成率的影响超过了模型版本的差异。从 Claude 3 Haiku 换到 Claude 3.5 Sonnet,任务成功率提升 15%;把工具描述从一句话扩展为带示例的完整说明,任务成功率提升 22%。

OpenClaw 的工具定义有几个值得注意的设计:

工具名语义化memory_search 而不是 search_db,模型不需要推断用途

参数说明包含使用场景:不只是"query: string",而是"语义搜索 MEMORY.md + memory/*.md,在回答关于过往工作、决策、日期等问题前必须调用"

互斥关系明确:哪些工具不能同时用、哪些有先后顺序,在描述里写清楚

这是 Harness Engineering 的第一条原则:工具描述是人机协议,不是注释

2.2 执行循环的确定性保障

OpenClaw 的执行循环有几个硬性约束,不允许模型绕过:

• 工具调用有超时限制,超时后返回结构化错误而不是裸异常

• 工具输出超过阈值时自动截断,并注入摘要说明("输出已截断,原始长度 X 字符,以下为前 2000 字")

• 危险操作(删除、发送、外部写入)有独立确认步骤,不能在单轮对话里直接执行

这些约束不是靠 System Prompt 里写"请小心操作"来实现的,是代码层面的硬约束。关键认知:凡是你希望模型"一定"做到的事,就不要靠提示词,要靠代码

2.3 记忆分层的工程价值

前一篇讲过 OpenClaw 的三级记忆(日记→MEMORY.md→按需检索),从 Harness 视角看,这个设计解决的是上下文的可预期性问题

没有分层记忆的 Agent,上下文窗口里塞什么是随机的——用户聊了多久,上下文就有多长,模型表现会随着对话长度非线性衰退。有了分层记忆,每次对话开始时注入的内容是固定结构的(今天的日记 + MEMORY.md 核心摘要),模型进入任务时的"初始状态"是可控的,不随对话历史漂移。

这是 Harness Engineering 的第二条原则:让模型的初始状态可重现,而不是随机的

三、Harness Engineering 的本质:在运行时建立边界

如果把 Agent 系统想象成一个工厂,模型是工人,Harness 是工厂的布局、流水线、操作规程和安全装置。工人技术再好,没有好的工厂设计,产出质量就不稳定。

Harness Engineering 做的事,就是把那些"我们希望模型表现好的边界条件",从提示词里挪到运行时代码里。用一个对比来说明:

诉求靠提示词(不稳定)靠 Harness(可靠)
不执行危险操作System Prompt 写"谨慎操作"危险工具调用前代码层拦截确认
上下文不超限写"如果上下文太长请总结"注入前自动计算 token,超限截断
工具调用不超时无法靠提示词解决执行层超时中断,返回结构化错误
记忆准确可靠写"记住用户偏好"外置文件存储,启动时结构化注入

这张表说明一个问题:很多工程师在 Agent 开发早期,把大量精力放在调 System Prompt 上,想靠语言说服模型表现好。Harness Engineering 的核心转变是——把"说服"变成"约束"

2025 年 Vercel 的 AI SDK 团队做过一个反直觉的实验:给 Agent 提供 20 个工具 vs. 只提供 3 个工具,在同样的任务集上评估完成率。结论是:工具越少,任务完成率越高——3 个工具的 Agent 比 20 个工具的版本高出约 34%。原因很简单:工具多了,模型在选择上消耗了太多"注意力",反而在执行上犯错。这是 Harness 设计的第三条原则**:给模型最小化、最精确的能力集**。

四、Android 上的 Harness Engineering

说完原理,说实践。Android 上搭 Agent Harness,和服务端有什么不一样?

最大的不同是资源约束。服务端的 Harness 可以用相对奢侈的方式处理上下文(反正显存够),Android 端必须在以下几个硬约束里工作:

• 内存:4-8GB 系统 RAM,留给应用的通常只有 300-500MB

• 推理延迟:本地模型冷启动 2-5 秒,云端 API 网络延迟 200-800ms

• 电池:一次 Agent 任务如果涉及多轮 LLM 调用,耗电量相当于流畅打游戏的 2-3 倍

这意味着 Android 上的 Harness 必须更激进地裁剪。

4.1 工具集的极简设计

Android Agent 的工具集建议遵循 Vercel 实验的结论:不超过 5 个核心工具,每个工具的语义边界清晰不重叠。以一个"智能日程助手"场景为例:

1data class AgentTool(
2    val name: String,
3    val description: String,
4    val parameters: JsonSchema
5)
6
7// 只暴露 4 个工具,职责不重叠
8val CALENDAR_AGENT_TOOLS = listOf(
9    AgentTool(
10        name = "read_schedule",
11        description = "查询指定日期范围内的日程。调用前必须确认用户已授权日历权限。返回 JSON 数组,每条包含 title/startTime/endTime/location。",
12        parameters = readScheduleSchema
13    ),
14    AgentTool(
15        name = "create_event",
16        description = "创建新日程。危险操作,必须在展示预览并获得用户明确确认后才能调用。不得在同一轮对话中连续调用超过 3 次。",
17        parameters = createEventSchema
18    ),
19    AgentTool(
20        name = "get_current_time",
21        description = "获取当前系统时间,用于理解'今天''明天''下周'等相对时间表达。每次需要时间上下文时调用,不要缓存结果超过 60 秒。",
22        parameters = emptySchema
23    ),
24    AgentTool(
25        name = "ask_user",
26        description = "当信息不足以完成任务时,向用户提问。优先用于:时间模糊('下午'具体几点)、地点缺失、参与者不明确。每次对话最多调用 2 次,避免来回追问。",
27        parameters = askUserSchema
28    )
29)
30

注意工具描述里的细节:限制条件写在描述里("不得连续调用超过 3 次"、"每次对话最多调用 2 次")。这些是给模型的行为约束,但更重要的是——代码层面也要校验,描述里的说明只是让模型理解意图,真正的约束在执行层实现。

4.2 本地记忆的实用方案

Android 上的记忆不需要向量数据库,用 Room 就够了。关键是分层:

1// 三层记忆结构:对应 OpenClaw 的日记/MEMORY.md/检索
2class AgentMemoryManager(
3    private val db: AgentDatabase
4) {
5    // 层一:会话记忆(当次对话,存 SharedPreferences,关 app 清除)
6    private val sessionMemory = mutableListOf()
7
8    // 层二:用户画像(持久化,Room,每次启动注入到 System Prompt)
9    suspend fun getUserProfile(): String {
10        val prefs = db.profileDao().getLatest() ?: return ""
11        // 只返回最近 30 天内更新的 profile,避免过期信息污染上下文
12        val cutoff = System.currentTimeMillis() - 30L * 24 * 3600 * 1000
13        return if (prefs.updatedAt > cutoff) prefs.summary else ""
14    }
15
16    // 层三:历史事件检索(关键词匹配,不用向量,够用)
17    suspend fun searchHistory(query: String, limit: Int = 5): List {
18        return db.historyDao().search(query, limit)
19    }
20
21    // 构建注入上下文:固定结构,每次启动相同
22    suspend fun buildContextBlock(): String {
23        val profile = getUserProfile()
24        return buildString {
25            if (profile.isNotEmpty()) {
26                appendLine("## 用户偏好")
27                appendLine(profile)
28                appendLine()
29            }
30            appendLine("## 当前时间")
31            appendLine(SimpleDateFormat("yyyy-MM-dd HH:mm EEEE", Locale.CHINESE).format(Date()))
32        }
33    }
34}
35

这个结构的关键是 buildContextBlock() 返回的内容是结构固定的——每次 Agent 启动,注入的上下文形状是一样的,模型知道从哪里找什么信息,不需要靠推断。

4.3 执行层的确定性保障

Android 端的 Agent 执行层,有几个必须处理的边界情况:

1class AgentExecutor(
2    private val llmClient: LLMClient,
3    private val toolRegistry: ToolRegistry
4) {
5    private val MAX_TURNS = 8        // 硬限制轮数,防止无限循环
6    private val TOOL_TIMEOUT_MS = 5_000L  // 工具调用超时
7
8    suspend fun run(userInput: String, context: String): AgentResult {
9        val messages = mutableListOf(
10            Message("system", buildSystemPrompt(context)),
11            Message("user", userInput)
12        )
13
14        repeat(MAX_TURNS) { turn ->
15            val response = llmClient.complete(messages, tools = toolRegistry.getTools())
16
17            // 没有工具调用,说明任务完成
18            if (response.toolCalls.isEmpty()) {
19                return AgentResult.Success(response.content, turns = turn + 1)
20            }
21
22            // 执行工具调用,有超时保护
23            val toolResults = response.toolCalls.map { call ->
24                try {
25                    val result = withTimeout(TOOL_TIMEOUT_MS) {
26                        toolRegistry.execute(call.name, call.arguments)
27                    }
28                    ToolResult(call.id, result, isError = false)
29                } catch (e: TimeoutCancellationException) {
30                    // 超时返回结构化错误,不是裸异常
31                    ToolResult(call.id, "工具调用超时(${TOOL_TIMEOUT_MS}ms),请重试或换一种方式", isError = true)
32                } catch (e: Exception) {
33                    ToolResult(call.id, "工具执行失败:${e.message}", isError = true)
34                }
35            }
36
37            messages += Message("assistant", toolCalls = response.toolCalls)
38            messages += Message("tool", toolResults = toolResults)
39        }
40
41        // 达到最大轮数,保底返回
42        return AgentResult.Interrupted("任务超出最大执行步数,已停止")
43    }
44}
45

这段代码里有几个关键的 Harness 细节:

MAX_TURNS = 8:硬限制轮数,永远不会无限循环,即使模型卡住了

• 工具超时返回结构化错误文本而非抛异常:模型能理解这个信息,知道要换策略

• 达到上限后保底返回而非崩溃:用户看到的是"任务超出步数已停止",不是 ANR

五、Android 上 Agent 的实际应用形态

讲完工程,讲场景。Android 上 Agent 目前最有落地价值的方向,我个人的判断是三类:

5.1 系统级 Accessibility Agent

用 AccessibilityService 让 Agent 能"看"屏幕、"点"界面。这是 Google 自己也在探索的方向(Android AI Core + AccessibilityService),本质上是给模型一个操控手机 UI 的工具集。

这个方向的 Harness 设计难点在于:UI 树是动态的,工具描述写的是语义操作("点击确认按钮"),但执行时需要实时解析 AccessibilityNodeInfo 找到对应节点。Harness 层要做的就是把"语义指令 → 节点定位 → 执行 → 结果验证"这条链路封装好,错误时给模型可操作的反馈。

5.2 端侧对话增强(RAG-lite)

不做完整 Agent 循环,只做一件事:让本地 LLM(Gemma 2B / Phi-3 mini)在回答时能访问用户的本地数据(笔记、联系人、日历)。这是 Harness 最轻量的形态——单次检索注入,不需要多轮工具调用。

Google 的 MediaPipe LLM Inference API 在 2025 年底支持了 RAG 扩展接口,可以在推理时注入额外的文本片段,而不需要把所有内容都加载进上下文窗口。这是端侧 Agent 非常值得用的基础能力。

5.3 意图路由 Agent

这个我觉得是当前最容易落地的方向:用一个轻量分类器(或小模型)理解用户的自然语言输入,然后路由到现有的功能模块。不需要模型真的"做"什么,只需要它"判断"应该做什么。

Harness 在这里的价值是定义清晰的意图类型和路由规则,让分类器的输出是枚举值而不是自由文本,执行层完全确定。论文 *"Chain of Thought Prompting Elicits Reasoning in Large Language Models"(Wei et al., 2022)*里有一个被忽视的结论:对于分类任务,给模型提供有限的选项集比让它自由生成答案,准确率高 15-20%。这正是意图路由 Harness 的设计依据。

六、一个可以现在就开始的 checklist

Harness Engineering 听起来很重,但起步不需要重构一切。如果你现在手上有一个 Android + AI 的项目,可以用这个 checklist 检查当前状态:

📌 📋 Android Agent Harness 自检清单 ☐ 工具数量是否控制在 5 个以内? ☐ 每个工具的描述是否包含"何时调用"和"限制条件"? ☐ 执行层是否有最大轮数硬限制? ☐ 工具调用是否有超时处理,且返回结构化错误而非裸异常? ☐ 危险操作(写入、删除、发送)是否有代码层的二次确认? ☐ 注入到 System Prompt 的上下文是否结构固定、不随对话漂移? ☐ 是否有任务中断后的保底 fallback,避免 ANR 或白屏?

这七条,每条都不难实现,但缺了任何一条,Agent 在真实用户手里都可能以你想不到的方式崩掉。

最后说两句

我最近和几个做 Android + AI 的朋友聊,发现大家踩的坑惊人地相似:花了很多时间调 prompt,结果发现根本问题是工具设计太随意;或者模型调用链跑通了,但 production 环境里一旦网络抖动就 crash,因为没有超时和 fallback。

这些都是 Harness 的问题,不是模型的问题。OpenClaw 给了我一个很好的参照:一个真正可用的 AI 助手,不是因为模型多聪明,而是因为围绕它的工程壳足够扎实。

Android 上的 Agent 还在早期,但 Harness Engineering 的方法论已经成熟了。这轮技术演进,最先吃到红利的,应该是那些把工程基础打好的人。


从 OpenClaw 到 Android:Harness Engineering 是怎么让 Agent 变得可用的》 是转载文章,点击查看原文


相关推荐


基于 AST 与 Proxy沙箱 的局部代码热验证
July_lly2026/3/16

前言 在真实开发中系统中,我们常常会做/需要做一些代码运行或者检测工作。但是全量的代码运行消耗的时间是漫长的。那么我们有没有办法能够只处理我们修改的部分呢?答案是肯定的。 下面将验证介绍一种结合 AST (抽象语法树) 与 沙箱技术 的方案,局部代码热验证。 具体重服务mock代码会放在文章末尾 整体 -> 局部 我们切换一个方向:过去我们总是使用整体运行完拿到export的内容。在一些情况下,不论是 build 构建还是 dev 开发,我们通常都是全量编译打包一次。当然我们可以让他执行两次(比


GPT-5.4 API 上线了,在openClaw龙虾中试试
程序员陆通2026/3/7

突破性的前沿模型,现已全面开放 OpenAI 最新发布的 GPT-5.4 模型现已正式上线 WellAPI 平台!作为 OpenAI 迄今为止最强大的通用模型,GPT-5.4 在推理能力、编程水平和专业文档处理方面实现了质的飞跃,专为复杂专业工作场景打造 。 GPT-5.4 核心特性解析 1. 原生计算机操作能力 GPT-5.4 是 OpenAI 首个具备原生计算机使用能力的通用模型,这标志着 AI 代理(Agent)技术的重大突破。模型能够直接与计算机系统交互,为开发者和智能代理应用开辟了全新


实测UU远程云电脑:堪称游戏党专属“性能王”,游戏全程流畅,好用到出圈
啊阿狸不会拉杆2026/2/27

前言:本地设备性能拉胯,想畅玩《崩坏星穹铁道》《CSGO2》《鸣潮》《原神》?不用花大价钱组装高配电脑,UU远程云电脑直接帮你解决痛点!作为网易旗下主打游戏场景的云电脑工具,它凭借三款不同显卡机型、低延迟优化,稳居云电脑排行榜前列,堪称游戏党专属“性能王”,实测四款热门游戏全程流畅,好用到出圈。         UU远程云电脑核心优势的是精准适配游戏需求,目前推出三款显卡机型——GTX 1660S(入门款)、RTX 3660(主流款)、RTX 4070Ti/5070(旗舰款),按需选择灵活


IoT 平台可编程化:基于 Pydantic Monty 构建工业级智能自动化链路
Lupino2026/2/19

在万物互联的下半场,设备间的简单联动已无法支撑复杂的工业与商业场景。为了打破“配置化逻辑”的瓶颈,我们正式集成了 Pydantic Monty 运行时环境。这一演进赋予了开发者直接在云端编写 Python 脚本的能力,实现了从“被动连接”到“确定性逻辑自主”的跨越。 1. 核心底座:为什么是 Pydantic Monty? 我们选择了由 Pydantic 团队推出的 Monty 作为脚本引擎。它不仅是 Python 的子集,更是为高性能嵌入式场景量身定制的方案: 轻量级沙箱:相比庞大的标准 P


细说日常 Vibe coding 的十宗罪
mCell2026/2/10

同步至个人站点:细说我日常 AI coding 碰到的十个问题 这一年大量 vibe coding,经典翻车现场真的不少。有些是模型习惯问题,有些是 Agent 工具链缺陷,还有些属于“工程现实 vs 最佳实践”的冲突。下面这十个算是我最常遇到、也最容易让人 当场没绷住 的。 1. hardcode:类型系统被你当摆设 是的,很多 TS / Golang 项目,vibe coding 一顿猛改之后,总会冒出一堆 hardcode。 比如判断任务状态: 你会看到它写:taskResult.st


在 Arch Linux 中安装 **Xorg 服务器**
i建模2026/2/1

在 Arch Linux 中安装 Xorg 服务器(即 xorg-server)及相关组件的步骤如下: 一、核心安装命令 1. 安装 Xorg 服务器 sudo pacman -S xorg-server 此命令会安装 Xorg 的核心服务包,包含 X11 协议的实现和基础组件。 2. 安装显卡驱动(必选) 根据显卡类型选择驱动: Intel 集成显卡:sudo pacman -S xf86-video-intel AMD 显卡:sudo pacman -S xf86-video-amdg


Rust 所有权与借用:从堆栈开始建立心智模型
mCell2026/1/23

本文写作时,极大的借鉴了《The Rust Programming Language》(俗称“Rust 圣经”)中相关章节的内容和结构,在此表示感谢。 写 Rust 的第一道坎,不是语法,也不是宏,而是“我明明只是把变量传给你用一下,怎么它就不属于我了?” 这类困惑通常并不奇怪,因为我们习惯了别的语言那套“内存默认有人兜底”的模型,比如 Javascript、Golang 的自动垃圾回收机制。Rust 恰恰相反:它要求你把内存这件事想清楚,然后把规则写进类型系统,交给编译器在编译期强制执行——


WebSocket 在 Spring Boot 中的实战解析:实时通信的技术利器
苏渡苇2026/1/15

WebSocket 在 Spring Boot 中的实战解析:实时通信的技术利器 一、引言:为什么我们需要 WebSocket? 在传统的 Web 应用中,客户端(浏览器)与服务器之间的通信是 请求-响应 模式:客户端发起请求,服务器处理后返回结果。这种模式适用于大多数场景,但在需要 实时双向通信 的场景下(如聊天室、股票行情、在线协作、游戏等),频繁轮询(Polling)或长轮询(Long Polling)会带来高延迟、高开销的问题。 WebSocket 协议应运而生——它提供了一种全双工、低


小迪安全第二十六天
江边鸟2192026/1/6

写好这些配置好相应的数据库内容 发现不足套用模板使用模板框架 <!DOCTYPE html> <html> <head>    <meta charset="UTF-8">    <!-- 页面标题(动态变量) -->    <title>{page_title}</title>    <style>        /* 全局样式 */        body {            font-family: Arial, sans-serif;  /* 设置默认字体


激活函数有什么用?有哪些常用的激活函数?
aicoting2025/12/29

在深度学习中,激活函数(Activation Function)是神经网络的灵魂。它不仅赋予网络非线性能力,还决定了训练的稳定性和模型性能。那么,激活函数到底是什么?为什么我们非用不可?有哪些经典函数?又该如何选择?本文带你全面解析。 所有相关源码示例、流程图、面试八股、模型配置与知识库构建技巧,我也将持续更新在Github:AIHub,欢迎关注收藏! 阅读本文时,请带着这三个问题思考: 什么是激活函数,为什么需要激活函数? 经典的激活函数有哪些? 怎么选择激活函数? 1. 什么是激活函数,

首页编辑器站点地图

本站内容在 CC BY-SA 4.0 协议下发布

Copyright © 2026 XYZ博客