芥末
发布于 2026-04-13 / 0 阅读
0
0

从 Prompt、Context 到 Harness:OpenClaw Agent 架构设计拆解

OpenClaw 值得关注的地方,不在于它把一个聊天机器人包装成了更有个性的个人助理,而在于它把近几年 AI Agent 领域的一批关键工程实践组合到了一起:动态提示词、文件化人格与配置、技能渐进加载、上下文压缩、长期记忆、工具调用、Hook 钩子、安全沙箱和人在环路控制。

这些能力单独看并不神秘,真正有意思的是它们如何被组织成一个可长期运行的 Agent 系统。一个成熟的 Agent 不是只靠一段 System Prompt 工作,而是要同时回答三个问题:

  1. Prompt Engineering(提示词工程):如何把角色、规则、工具和任务要求清晰地告诉模型?
  2. Context Engineering(上下文工程):如何让模型在有限窗口里看到最需要的信息?
  3. Harness Engineering(驾驭工程 / 脚手架工程):如何用外部机制约束模型,让它安全、可控、可恢复地执行任务?

三者的关系可以用一张图概括:

Prompt、Context 与 Harness 的关系

Prompt 决定模型“应该怎么想、怎么说、怎么行动”,Context 决定模型“能看到哪些信息”,Harness 则决定模型“在什么边界内行动”。Prompt 和 Context 主要发生在模型输入侧,Harness 更偏系统侧,它通过工具权限、Hook、沙箱、审批、测试和状态机等机制,把 Agent 从“会回答问题”推进到“能可靠执行任务”。

flowchart TB
    U[用户 / 外部事件] --> H[Harness: Hook、沙箱、审批、测试]
    H --> P[Prompt Builder: 动态组装系统提示词]
    P --> C[Context Manager: 历史、技能、记忆、工具结果]
    C --> M[LLM 大语言模型]
    M --> T[Tools 工具调用]
    T --> H
    H --> C
    M --> R[回复 / 行动结果]

Prompt Engineering:从固定提示词到动态组装系统

在早期应用里,System Prompt 往往是一段手写文本,例如“你是一个有帮助的助手”。这种方式适合简单问答,但不适合长期运行的 Agent。Agent 需要知道自己的身份、工具能力、安全边界、工作目录、当前渠道、可用技能、记忆读取规则、消息发送方式、沙箱状态等信息。把所有内容硬编码成一个巨大字符串,会带来三个问题:

  • 指令难维护,改一处可能影响很多场景;
  • 所有场景都加载全量提示词,浪费上下文窗口;
  • 工具、技能、用户信息不断变化,固定提示词跟不上运行时状态。

OpenClaw 的做法是把 System Prompt 当成一个运行时构建产物。最终传给模型的仍然是一段完整系统提示词,但它不是提前写死的,而是由多个模块按条件拼接出来。

三种 PromptMode:不同任务加载不同提示词

OpenClaw 把提示词加载分成三种模式:

模式适用场景加载内容
full主 Agent 与用户直接对话身份、工具、安全规则、技能、记忆、消息系统、工作区、运行时信息等完整模块
minimal子 Agent 执行独立任务保留工具、工作区、运行时信息等必要模块,去掉主会话相关内容
none极简内部场景基本只保留身份标识和运行时必要信息

这种区分的原因很直接:上下文窗口是有限资源。主 Agent 需要完整人格、记忆和消息规则;子 Agent 只需要完成被分配的任务,不应该背负过多历史和个性化配置;极简任务甚至不需要完整系统设定。

一个简化后的构建逻辑可以写成这样:

type PromptMode = "full" | "minimal" | "none";

function buildAgentSystemPrompt(ctx: RuntimeContext) {
  const parts: string[] = [];

  // 永远存在:身份和运行时信息
  parts.push("You are OpenClaw, a personal AI assistant.");

  if (ctx.mode !== "none") {
    parts.push(renderAvailableTools(ctx.tools));
    parts.push(renderWorkspace(ctx.workspace));
    parts.push(renderRuntime(ctx.runtime));
  }

  if (ctx.mode === "full") {
    parts.push(renderToolCallStyle());
    parts.push(renderSafetyGuidelines());
    parts.push(renderCliCommands());
    parts.push(renderSkills(ctx.skills));
    parts.push(renderMemoryRecall(ctx.memory));
    parts.push(renderMessaging(ctx.channels));
    parts.push(renderHeartbeats(ctx.heartbeat));
    parts.push(renderSilentMode());
  }

  parts.push(renderMarkdownProjectContext(ctx.workspaceFiles));

  return parts.filter(Boolean).join("\n\n");
}

这个伪代码表达的是一种架构思想:System Prompt 不是一段文本,而是一组可组合模块。每个模块有明确职责,并且受模式、工具可用性、配置文件、运行环境共同控制。

System Prompt 的模块分层

OpenClaw 的系统提示词模块很多,但可以归为几类:

模块类型代表内容作用
身份与行为准则身份标识、安全准则、回复风格定义 Agent 是谁、能做什么、不能做什么
工具与执行规则工具清单、工具调用风格、命令说明告诉模型可以调用哪些工具,以及何时调用
技能系统Skills 列表、SKILL.md 读取规则支持按需加载专业能力
工作区上下文Workspace、项目 Markdown 文件、文档链接让模型理解当前工作目录和项目约束
记忆系统Memory Recall、MEMORY.md、每日记忆支持跨会话连续性
通信系统Reply Tags、Messaging、群聊回复、TTS支持多渠道交互
运行控制Silent Mode、Heartbeats、Runtime支持后台任务、心跳任务和环境感知
安全与权限沙箱、授权发送者、外部动作限制限制越权访问和敏感数据泄露

模块化之后,提示词不再是“越长越保险”,而是变成“按场景加载最小必要信息”。

flowchart LR
    A[运行时配置] --> B[Prompt Builder]
    C[工具列表] --> B
    D[Workspace 文件] --> B
    E[Skills 元数据] --> B
    F[Memory 配置] --> B
    G[Channel 信息] --> B
    B --> H[完整 System Prompt]
    H --> I[LLM]

Markdown 驱动:把人格、规则和环境从代码里解耦

OpenClaw 很多关键信息不是写在代码里,而是放在工作区根目录的 Markdown 文件中。Markdown 的好处是:

  • 对人友好,用户和开发者都能直接阅读和编辑;
  • 比纯文本更适合表达结构,例如标题、列表、强调;
  • 能被文件系统、Shell、Git、搜索工具自然管理;
  • 可以作为 Agent 的长期配置和可演化文档。

常见文件可以这样理解:

文件角色主要内容加载方式
AGENTS.md总纲工作区规则、启动流程、记忆策略、红线、安全边界启动或构建 Prompt 时注入
SOUL.md人格性格、语气、价值倾向、行为边界存在时注入,并要求 Agent 体现对应风格
IDENTITY.md身份卡名字、类型、标志性 Emoji、头像等作为外在身份信息
USER.md用户档案称呼、时区、偏好、项目背景用于个性化服务
TOOLS.md本地工具笔记摄像头名、SSH 别名、TTS 偏好、设备名称等与通用 Skill 分离,避免泄露环境信息
HEARTBEAT.md心跳任务周期性检查、提醒、维护任务心跳触发时读取
BOOTSTRAP.md首次启动脚本初始化身份、用户信息、初始人格首次启动后删除
BOOT.md启动任务每次启动时要执行的短指令可配合 Hook 使用
MEMORY.md长期记忆高价值、长期稳定的事实和偏好主会话中加载或检索

这里有一个重要的分离原则:共享能力和本地环境要分开。例如某个 TTS Skill 可以是通用的,但“默认音箱叫 Kitchen HomePod”“某台服务器 SSH 别名是 home-server”属于本地隐私配置,应该写进 TOOLS.md,不能混进可分享的 Skill 包。

提示词措辞:短、准、可执行

提示词不是越长越好。很多系统提示词会把同一个约束解释好几遍,结果既浪费 token,又让模型抓不住重点。OpenClaw 的提示词风格更接近操作手册:短句、强约束、少废话。

啰嗦写法更适合 Agent 的写法
在群聊中,你需要根据上下文判断是否有必要回复,不应该频繁参与,否则可能干扰用户交流。Humans don't respond to every message. Neither should you. Quality > quantity.
如果你对某个操作是否安全存在不确定性,建议你先询问用户。When in doubt, ask.
如果用户要求你记住某件事,你应该把它存储到文件中,因为会话结束后你无法保证记住。No mental notes. Write it to a file.

短提示词不是省略约束,而是把约束压缩成模型容易遵循的指令。对于 Agent 系统来说,token 应该优先留给任务上下文、工具结果和必要记忆,而不是消耗在重复解释上。

Context Engineering:在有限窗口里管理技能、历史和记忆

Prompt 解决“规则是什么”,Context 解决“模型现在应该看什么”。Agent 运行时间越长,上下文越容易膨胀,主要来源包括:

  • System Prompt 本身;
  • 多轮对话历史;
  • 工具调用输入与输出;
  • Skill 文档;
  • 项目文件内容;
  • 记忆召回片段。

如果所有内容都塞进上下文,会出现成本上升、延迟增加、关键信息被淹没等问题。更麻烦的是 Lost in the Middle 现象:模型对上下文开头和结尾更敏感,中间位置的信息容易被忽略。OpenClaw 用三类机制处理这个问题:Skills 渐进披露、对话压缩与工具结果修剪、双层记忆系统。

Skills:让能力无限扩展,但上下文按需加载

Agent Skills 的核心思想是渐进式披露(Progressive Disclosure)。系统不把所有技能说明一次性塞给模型,而是先给模型看技能名称和简短描述。只有当某个技能明显适用时,模型才读取对应的 SKILL.md

flowchart TD
    A[收到任务] --> B[扫描 available_skills 的名称和描述]
    B --> C{是否有明确匹配的 Skill?}
    C -- 无 --> D[不读取 SKILL.md]
    C -- 一个 --> E[读取对应 SKILL.md]
    C -- 多个 --> F[选择最具体的一个]
    E --> G[按 Skill 指令执行任务]
    F --> G
    D --> H[使用基础工具处理]

这种设计解决了两个问题:

  1. 能力扩展问题:Agent 可以通过 Skill 包获得 PPT 生成、语音合成、特定云服务运维等新能力。
  2. 上下文爆炸问题:日常运行只加载技能目录,不加载所有技能细节。

Skill 机制也带来安全风险。因为 Skill 包可能包含脚本、依赖和工具调用逻辑,恶意 Skill 理论上可以植入后门、窃取环境变量或执行危险命令。能力市场和插件机制必须配套来源校验、签名、权限声明、沙箱执行和人工确认,不能把第三方 Skill 当成普通文档处理。

上下文压缩:把早期历史变成高密度摘要

长会话中最容易膨胀的是历史消息。OpenClaw 的压缩策略可以理解为:保留最近几轮完整对话,把更早的历史压缩成摘要。这类似开卷考试只能带十页纸,最近必考内容原样保留,早期内容整理成重点笔记。

压缩有两种触发方式:

触发方式说明
手动触发用户执行 /compact,也可以要求特别保留某些信息
自动触发系统监控 token 用量,超过水位线后自动压缩旧历史

自动触发通常遵循这样的判断:

当前 token 用量 > 上下文窗口大小 - 预留缓冲区

例如上下文窗口为 200,000 token,系统预留 20,000 token 给后续交互和工具结果,当当前用量超过 180,000 token,就触发压缩。

压缩过程可以用图表示:

上下文压缩流程示意

图中的关键点是:最近消息保持原样,因为它们最可能影响当前任务;旧消息不会直接删除,而是先切块、摘要,再把摘要作为历史背景继续保留。这样既释放了上下文空间,又尽量保存任务连续性。

OpenClaw 的压缩逻辑包含几个工程细节:

机制作用
自适应分块按 token 数把旧消息切成多个 chunk,避免单次摘要输入过大
分阶段摘要先对每个 chunk 摘要,再合并成最终摘要
兜底策略摘要失败时排除超大消息重试,再失败则返回默认空历史
工具结果预处理摘要前移除工具输出里过长的 details 字段
超时保护压缩任务有最长执行时间,避免主流程被卡住
写锁压缩会话文件时防止并发写入导致数据损坏
标识符严格保留UUID、哈希、文件名、实例 ID 等不透明标识符必须原样保留
压缩模型可配置可以用成本更低的模型专门做摘要

摘要时要保留的信息通常包括:

  • 当前活跃任务;
  • 已经做出的重要决策;
  • 待办事项;
  • 对用户做出的承诺;
  • 文件路径、实例 ID、哈希值、UUID 等不透明标识符;
  • 工具调用导致的关键结果。

标识符尤其重要。模型如果把 i-abc123 摘成“某个 ECS 实例”,后续工具调用就无法继续执行;如果把哈希值或文件名改写,排查问题会变得非常困难。

工具结果修剪:长输出保留头尾,中间截断

工具调用结果是上下文消耗大户。读取一个大文件、返回一个复杂 JSON、打印一段长日志,都可能瞬间占用数万 token。压缩适合处理历史对话,但工具结果往往需要更快、更低成本的处理方式,于是 OpenClaw 使用规则化修剪。

典型策略是保留开头和结尾,截断中间

工具结果修剪示意

这张图表达的是一种实用经验:错误堆栈、异常名称、命令输出摘要通常在开头;最终失败原因、退出码、最后几行日志常在结尾;中间大量重复日志可以截断。对于 JSON 或 XML,头部往往包含结构定义和关键字段,也比中间重复数组更有价值。

压缩和修剪的区别很明显:

特性压缩 Compaction修剪 Pruning
核心操作调用模型生成摘要,替换旧消息用规则裁剪工具结果或旧片段
信息保留方式语义保留,细节可能被概括被截断部分直接丢失
成本需要额外 LLM 调用规则处理,成本低
适合场景长对话历史太多工具输出过长、日志过大、JSON 过大
风险摘要遗漏或改写细节中间关键信息可能被截掉

实际系统里两者通常配合使用:先用修剪控制单次工具结果,再用压缩管理长周期会话历史。

KV Cache 不是无限上下文的解药

很多模型服务支持 KV Cache 或 Prefix Caching。当前缀上下文相同,服务端可以复用缓存,加快推理并降低部分成本。但缓存通常有时间窗口,例如几分钟到十几分钟。窗口过期后,长上下文仍然会重新计费,并且推理延迟会明显增加。

所以,即使模型支持超长上下文和缓存,Agent 仍然需要主动压缩和修剪。长上下文不是免费的,延迟也是用户体验的一部分。

Memory:长期记忆和每日笔记分层管理

对 Agent 来说,记忆不是把所有聊天记录永久塞进提示词,而是要区分“长期稳定事实”和“可检索日常细节”。

OpenClaw 采用双层记忆:

层级文件内容访问方式
长期记忆MEMORY.md高价值、稳定、需要长期保留的事实和偏好主会话中注入或按需读取
每日笔记memory/YYYY-MM-DD.md某天发生的细节、过程日志、临时上下文通过搜索和行号读取

可以用这个结构理解:

flowchart TB
    A[当前会话] --> B{是否有值得记住的信息?}
    B -- 用户明确要求记住 --> C[写入 MEMORY.md 或每日笔记]
    B -- 会话结束 / 压缩触发 --> D[Memory Flush 提炼关键信息]
    D --> E[长期事实写入 MEMORY.md]
    D --> F[过程细节追加到 memory/YYYY-MM-DD.md]

    G[用户询问过去事项] --> H[memory_search]
    H --> I[BM25 文本匹配]
    H --> J[Embedding 向量召回]
    I --> K[候选片段]
    J --> K
    K --> L[memory_get 精确读取原文件行号]

MEMORY.md 适合存放不应频繁变化的内容,例如:

  • 用户常用技术栈;
  • 当前长期项目名称和目标;
  • 明确表达过的工作偏好;
  • 需要长期遵守的沟通边界;
  • 关键账号或环境的非敏感说明。

每日笔记适合记录当天上下文,例如:

  • 今天讨论了某个 API 的重构;
  • 某次排障尝试过哪些命令;
  • 某个临时 TODO;
  • 一段任务过程日志。

两层记忆的差异可以整理成表:

特性MEMORY.md 长期记忆memory/日期.md 每日笔记
文件数量一个每天一个
写入方式整理后编辑追加为主
内容类型稳定事实、长期偏好、高价值结论日常过程、细节、临时上下文
注入方式主会话中可被注入,通常有行数限制不全量注入,通过检索访问
时间衰减不衰减检索权重随时间降低
适合记录用户偏好、长期项目、重要原则今天聊过什么、做过什么尝试

记忆检索不能只靠关键词,也不能只靠向量。OpenClaw 使用类似“双路召回”的思路:BM25 负责精确词匹配,Embedding 负责语义相似度,两者结合后再读取原始文件的具体行号。这样既能找到“ECS 实例 ID”这种精确对象,也能找到“上次那个部署问题”这种语义模糊的回忆。

每日笔记还有时间衰减。一个简单的衰减公式是:

衰减系数 = e^(-λ × 天数)

λ = ln(2) / 半衰期天数
默认半衰期:30 天

当半衰期为 30 天时:

时间衰减系数含义
1 天前约 0.977几乎不变
7 天前约 0.851略微降低
30 天前0.5权重减半
60 天前0.25权重剩四分之一
90 天前0.125权重剩八分之一

这不是删除旧记忆,而是在检索排序时降低旧日常细节的优先级。长期记忆不衰减,每日笔记逐渐淡出,能让 Agent 更关注近期和高价值信息。

Harness Engineering:把 Agent 放进可控运行环境

Prompt 和 Context 都发生在模型输入层面,但 Agent 真正执行任务时,还会调用工具、读写文件、执行命令、发送消息、访问网络。如果只依赖模型“自觉遵守规则”,系统很容易出问题。

Harness Engineering 关注的是模型外部的工程约束。它不只是提示模型“请小心”,而是用系统机制让危险操作被拦截、错误结果被反馈、任务流程能恢复、人类随时能接管。

可以把三类工程这样区分:

工程类型解决的问题主要手段
Prompt Engineering模型应该遵守什么规则系统提示词、角色设定、行为准则
Context Engineering模型应该看到什么信息检索、压缩、修剪、记忆、技能加载
Harness Engineering模型如何被约束地行动Hook、沙箱、权限、审批、测试、状态机、评估

没有 Harness 的 Agent 常见问题包括:

  • 写完代码就停止,不运行测试;
  • 工具调用失败后在同一个错误上反复尝试;
  • 删除文件、发送消息、调用外部 API 时没有确认;
  • 遇到不确定参数仍然强行执行;
  • 被 Prompt Injection 诱导泄露本地文件或密钥;
  • 后台任务没有可观测性,出错后难以恢复。

Harness 的核心目标不是剥夺模型规划能力,而是给它装上外部约束。模型仍然可以决定下一步做什么,但必须在工具权限、执行规则、校验逻辑和人工审批范围内行动。

Workflow 和 Harness 的区别

Workflow 和 Harness 都能提升可控性,但主导权不同。

Workflow 与 Harness 的差异

图中的差异可以归纳为:Workflow 更像预先写好的流程图,大模型只是流程里的一个节点;Harness 更像一套运行边界和反馈机制,Agent 仍然有自主规划空间,但行动会被校验、约束和纠偏。

维度WorkflowHarness
主导权人写好的流程主导Agent 自主规划,系统外部约束
执行路径固定步骤较多动态路径较多
适合任务规则明确、分支有限、结果格式稳定长周期、开放式、多工具、多轮迭代任务
优点确定性高、易调试、速度快灵活性高、能处理未知分支、能自我修复
缺点遇到未知情况容易断裂工程复杂度更高,需要监控和护栏
模型角色流程节点规划者和执行者

企业系统里不需要二选一。稳定业务流程可以用 Workflow,开放式复杂任务可以用 Harness,关键节点再用 Workflow 固化。例如“创建云资源”可以由 Agent 收集信息和排查错误,但真正下单前必须进入固定审批流程。

Hook:在 Agent 生命周期插入校验和纠偏

OpenClaw 的 Hook 系统是典型 Harness 能力。Hook 允许开发者在 Agent 运行关键节点插入自定义逻辑,例如构建 Prompt 前注入上下文、工具调用前校验参数、工具调用后处理结果。

Hook 名称触发时机典型用途
before_prompt_build构建提示词之前注入业务上下文、用户权限、环境状态
before_tool_call执行工具之前参数校验、权限检查、危险命令拦截
after_tool_call工具执行之后结果清洗、错误分类、追加诊断信息
before_compaction上下文压缩之前标记必须保留的信息
after_compaction上下文压缩之后检查摘要是否遗漏关键标识符
message_received收到消息时消息预处理、渠道鉴权、敏感信息识别
message_sending发送消息前防泄露检查、格式转换、人工审批

一个云服务运维 Agent 很容易混淆不同资源 ID。例如 ECS 实例 ID 可能以 i- 开头,某些轻量应用服务器 ID 可能是 32 位字母数字组合。如果没有工具调用前校验,模型传错参数后只能等 API 报错,再由模型尝试修复,容易浪费轮次甚至进入循环。

可以在 before_tool_call 中做参数拦截:

type HookResult =
  | { action: "continue" }
  | { action: "reject"; message: string };

export async function beforeToolCall(event: {
  toolName: string;
  args: Record<string, unknown>;
}): Promise<HookResult> {
  if (event.toolName === "ecs.rebootInstance") {
    const instanceId = String(event.args.instanceId ?? "");

    if (!/^i-[a-zA-Z0-9]+$/.test(instanceId)) {
      return {
        action: "reject",
        message:
          "instanceId 格式不符合 ECS 实例 ID 规则。ECS 实例 ID 应以 i- 开头,请重新确认资源类型和参数。",
      };
    }
  }

  return { action: "continue" };
}

这类校验不应该完全依赖 Prompt,因为模型可能忘记规则,也可能被复杂上下文干扰。Hook 的优势是强制执行:只要工具调用经过这个入口,就一定会被校验。

AI Coding 场景:从“写完即止”变成“写完必测”

Harness 在代码生成任务里非常有价值。裸 Agent 常见行为是:生成代码、解释修改、宣布完成。但代码是否能运行、测试是否通过、Lint 是否报错,都不一定检查。

一个更可靠的执行链路应该这样设计:

flowchart TD
    A[生成或修改代码] --> B[自动运行格式化 / Lint]
    B --> C{是否通过?}
    C -- 否 --> D[把错误日志反馈给模型]
    D --> A
    C -- 是 --> E[运行单元测试]
    E --> F{是否通过?}
    F -- 否 --> G[反馈失败用例和堆栈]
    G --> A
    F -- 是 --> H[生成变更摘要]
    H --> I[等待用户验收或提交]

这条链路里,模型仍然负责修代码,但是否进入下一步不由模型自己宣布,而由外部测试结果决定。这样可以明显减少“看起来完成,实际不能运行”的交付。

安全沙箱:把权限边界做在系统层

OpenClaw 的能力扩展到本地文件、命令执行和网络访问后,安全边界就不能只写在提示词里。一个更稳妥的 Agent 运行环境至少需要三层沙箱:

层级控制对象典型策略
文件系统沙箱读写路径限制在 Workspace 内,禁止访问系统根目录和敏感目录
命令执行沙箱Shell 命令白名单、黑名单、Ask 模式、危险命令拦截、只读命令豁免
网络访问沙箱外部连接域名白名单、出站流量控制、防止敏感数据外传

底层还需要操作系统最小权限原则兜底:Agent 进程不应该拥有超过任务所需的权限,插件和工具最好独立进程运行,避免一个工具被攻破后直接获得整个系统控制权。

安全护栏要覆盖几类风险:

  • Prompt Injection:外部网页或文件诱导模型忽略系统规则;
  • 越权调用:模型调用未授权工具或访问不该访问的资源;
  • 敏感泄露:API Key、密码、私有文件被发到外部渠道;
  • 破坏性修改:删除文件、覆盖配置、执行危险命令;
  • 供应链风险:第三方 Skill 包含恶意脚本或依赖。

关键原则是:安全规则能放在系统层,就不要只放在提示词里。提示词是软约束,沙箱、权限和审批才是硬边界。

人在环路:高风险动作必须能暂停和接管

Agent 越接近真实业务,越需要人在环路(Human-in-the-Loop)。外部发送消息、删除文件、修改生产配置、购买资源、执行高成本操作,都应该进入确认流程。

一个简单的审批策略可以这样设计:

操作类型默认策略
读取 Workspace 内文件允许
整理本地笔记、生成草稿允许
执行只读命令,如 lscatgit status允许或低风险提示
修改文件根据目录和文件类型决定是否确认
删除文件必须确认,优先使用可恢复删除
发送邮件、群消息、公开发布必须确认
调用生产 API、购买资源、重启实例必须确认或走审批流
访问未知域名默认拒绝或确认

人在环路不是为了让用户每一步都点确认,而是把确认集中到真正有外部影响或不可逆的动作上。低风险内部动作放开,高风险外部动作收紧,Agent 才既能工作,又不会失控。

心跳和启动任务:把周期性行为变成规定动作

HEARTBEAT.mdBOOT.md 体现了另一类 Harness:系统主动触发的规定动作。

  • BOOT.md 适合放启动时要执行的短任务,例如检查工作区状态、读取必要配置、恢复后台任务。
  • HEARTBEAT.md 适合放周期性任务,例如检查日历、整理记忆、查看项目状态、执行轻量巡检。

心跳机制要控制频率和范围,否则会变成 token 消耗黑洞。一个合理的心跳文件应该短小,只放当前确实需要周期检查的事项,并记录上次检查时间,避免每次唤醒都重复做同样的事。

把 OpenClaw 的设计迁移到自己的 Agent 系统

OpenClaw 的个人助理形态不一定适合直接搬进企业生产环境。企业场景通常有更严格的数据边界、权限模型、审计要求、响应时延和稳定性指标。真正可迁移的是设计方法。

可以从四张清单开始设计自己的 Agent。

1. Prompt 模块清单

模块是否需要设计建议
身份与目标必需一句话说明 Agent 角色和目标
行为准则必需写成短规则,避免长篇解释
工具清单必需工具名、用途、参数要求要准确
安全边界必需外部动作、敏感数据、破坏性操作要明确
工作区信息按需注入当前目录、项目规则、文档入口
用户偏好按需只注入和任务相关的信息
技能说明按需先注入名称和描述,再按需读取详情
运行时信息必需渠道、模型、系统时间、权限状态等

2. Context 预算清单

上下文来源管理方式
System Prompt模块化、按模式加载
历史对话最近保留,旧历史压缩
工具结果长输出修剪,必要时让模型按行读取
项目文件不全量注入,通过检索或明确文件读取
Skills渐进式披露
长期记忆精简高价值内容,避免流水账
每日记忆切片、索引、检索、时间衰减

3. Memory 写入规则

情况写入位置
用户明确说“记住”优先写长期记忆或指定文件
长期偏好、稳定事实MEMORY.md
当天任务过程memory/YYYY-MM-DD.md
工具使用经验TOOLS.md 或对应 Skill 文档
失败教训和项目规则AGENTS.md 或项目规则文件
敏感信息默认不写,除非用户明确要求且存储位置安全

4. Harness 约束清单

风险点外部约束
参数错误before_tool_call 校验
工具失败循环最大重试次数、错误分类、切换策略
代码不可运行强制测试、Lint、构建检查
删除或覆盖文件人工确认、可恢复删除
外部消息发送发送前审批
访问敏感目录文件系统沙箱
访问未知网站网络白名单
第三方插件风险签名、来源校验、权限声明、沙箱执行
记忆泄露群聊不加载私人长期记忆,回复前做敏感检查

可落地的结论

OpenClaw 的价值不是某一个炫目的功能,而是一组工程取舍:

  • System Prompt 要模块化、动态组装,不要写成不可维护的大段文本;
  • Markdown 文件适合作为 Agent 的人格、规则、环境和记忆载体;
  • Skills 要按需披露,能力可以扩展,但上下文不能无限膨胀;
  • 长会话必须有压缩,长工具结果必须有修剪;
  • 记忆要分层,长期事实和每日细节不能混在一起;
  • Harness 要做成系统级约束,不能只靠模型自觉;
  • 高风险动作必须有人在环路;
  • 企业落地时,优先迁移方法论,而不是复制个人助理形态。

一个好用的 Agent 系统,本质上是在“模型能力”和“工程约束”之间找平衡。Prompt 让模型理解任务,Context 让模型拿到信息,Harness 让模型在安全边界内行动。三者组合起来,Agent 才能从一次性问答工具,变成能够长周期执行复杂任务的工程系统。


评论