OpenClaw进阶:技能系统、多Agent协作、Token优化与安全加固

发布时间:2026/10/21 14:17:31
OpenClaw进阶:技能系统、多Agent协作、Token优化与安全加固
如果你只是把 OpenClaw 当成一个能对话、能查资料的“高级玩具”那这篇差不多可以直接关掉了。我真正想聊的是把这个开源智能体框架从“会聊天”推到“真干活”这一路上必须趟过的四件事——技能系统怎么写得稳、多 Agent 怎么组织不崩、token 费用怎么省到肉疼、安全边界怎么设到不翻车。这四块我都踩过坑也都有能直接抄的答案。后面还有一份排查速查表和我自己的几个私藏技巧照着试能少走很多弯路。不管你是刚把 OpenClaw 跑起来的新手还是已经在写自定义技能的老手这篇都值得花点时间读完。1. 先把 OpenClaw 的基本盘看明白它到底强在哪很多人拿到 OpenClaw 的第一反应是“这不就是个带工具调用的聊天机器人吗”。这么理解倒也没错但只看到这一层后面所有进阶玩法都撑不起来。我花了一个多月才真正摸清它的设计逻辑——它不是一个“模型壳子”而是一套完整的“智能体运行时”核心价值在于把模型能力和外部世界安全地接起来。1.1 我为什么从单机脚本迁移到 OpenClaw在折腾 OpenClaw 之前我的自动化工具基本就是一堆 Python 脚本加 cron 定时任务。每个脚本干一件事拉数据、算指标、发通知。看起来挺美但一旦需求变成“帮我分析一下这几个仓库最近一周的活跃趋势然后写一份摘要发到群里”脚本就傻眼了——我不知道用户到底想分析什么、用什么口径、输出什么格式。这本质上是“意图理解”的问题传统脚本根本接不住。OpenClaw 解决的正是这一层。它把“模型负责理解意图、调度工具”和“工具负责执行具体动作”这两件事彻底分开。模型不直接操作文件、不直接执行命令而是通过我预先定义好的技能来间接完成。这样一来我既能享受大模型理解自然语言的灵活性又能守住脚本时代那种“每个动作都可控、可审计”的确定性。1.2 三个绕不开的核心概念技能、Agent、运行时先说技能。技能在我眼里就是“给实习生写好的标准作业程序”。实习生模型不需要知道每件事该怎么做它只需要知道“什么情况下该调用哪本手册”。每本手册技能里包含了清晰的描述、输入参数说明、执行脚本和结果返回格式。模型通过阅读技能描述来决定是否调用、怎么传参技能脚本真正落地执行。再说 Agent。Agent 不是某个神秘实体它就是“一组技能加一套专属系统提示词”的集合体。比如一个“代码审查 Agent”配了代码读取技能、静态分析技能、规则库技能再加上“你负责找代码里的坏味道”这种角色定位。多个 Agent 组合起来就能形成一条流水线。最后是运行时。运行时负责调度一切接收用户请求、维护会话上下文、调模型、触发技能、收集结果、继续循环。OpenClaw 的运行时有个我很喜欢的设计——每一步都是显式的事件记录。也就是说整个思考过程不是黑盒每一步调了什么工具、传了什么参数、返回了什么结果全都留痕。这一点在后排查问题时会救你命。注意我见过不少人一上来就搭建多 Agent 系统结果连单 Agent 的技能都写得稀烂。我的建议是先把单 Agent 的技能链路跑通再加 Agent 数量别跳级。2. 技能系统让智能体从“只会聊天”到“真能干活”技能是 OpenClaw 进阶的第一道门槛也是最值得花时间的部分。技能写得好不好直接决定了智能体是“可用”还是“摆设”。这一节我会用一个完整案例带你走一遍从需求到落地的全过程。2.1 技能的本质就是一次带说明的函数调用理解技能的本质可以先忘掉那些花哨的名字。技能就是一个函数只不过这个函数有一个非常重要的附加物——面向模型的说明书。模型不是一个确定的函数调用者它是通过“说明书”来判断什么时候该调用你的函数。举个例子。我写了一个“仓库活跃度统计”技能它的说明书描述信息得让模型明白这几件事这个技能是干什么的统计指定仓库在某时间段的提交活跃度什么时候该用用户想了解项目进展、团队提交频率、最近改动热度时参数是什么仓库路径、开始日期、结束日期返回值是什么Markdown 格式的统计表格说明书写不清楚是最常见的问题。有些技能描述写得像诗——“分析仓库的脉动”模型看完一头雾水永远不知道该不该调用它。但你把描述改成“当用户询问仓库提交活跃度、提交频率或近期代码变动时调用此技能”模型在意图匹配阶段就会精准命中。这个道理和写代码注释很像——注释不是写给自己看的是写给别人模型看的。2.2 手写一个实用技能从定义到部署一次跑通我把这个“仓库活跃度统计”技能完整拆开给你看。整个技能包是一个目录放在指定技能目录下即可skills/ repo_stats/ SKILL.md script.py requirements.txtSKILL.md 是技能的元数据文件也是模型唯一会读的文件。它的内容结构大致是这样--- name: repo_stats description: 统计目标仓库在指定时间范围内的提交活跃度。当用户询问提交频率、活跃趋势、近期代码变动量时使用。 params: repo_path: type: string description: 本地仓库的绝对路径 required: true start_date: type: string description: 开始日期格式 YYYY-MM-DD required: true end_date: type: string description: 结束日期格式 YYYY-MM-DD required: true --- 统计指定仓库在时间范围内的提交记录输出 Markdown 表格包含每日提交数、活跃作者数和累计代码变更行数。script.py 是实际执行的逻辑。这里有一个关键点脚本的输入参数不是由模型直接传给脚本的而是运行时先把模型给的参数解析成 JSON再注入到脚本环境里。我的脚本开头一般是这样的#!/usr/bin/env python3 import json import os import subprocess from datetime import datetime def load_params(): # 运行时通过环境变量传入模型解析后的参数 params json.loads(os.environ.get(SKILL_PARAMS, {})) return params def main(): params load_params() repo_path params[repo_path] start_date params[start_date] end_date params[end_date] # 用 git log 获取提交记录 cmd [ git, -C, repo_path, log, --since, start_date, --until, end_date, --prettyformat:%H|%an|%ad, --dateshort ] result subprocess.run(cmd, capture_outputTrue, textTrue) if result.returncode ! 0: # 返回 JSON 格式错误信息让模型能理解发生了什么 print(json.dumps({error: result.stderr.strip()})) return commits [] for line in result.stdout.strip().splitlines(): commit_hash, author, date line.split(|) commits.append({hash: commit_hash, author: author, date: date}) # 聚合统计 from collections import Counter daily_counts Counter(c[date] for c in commits) author_counts Counter(c[author] for c in commits) output [] output.append(| 日期 | 提交数 |) output.append(|------|--------|) for date in sorted(daily_counts): output.append(f| {date} | {daily_counts[date]} |) print(json.dumps({ total_commits: len(commits), active_authors: len(author_counts), daily_table: output })) if __name__ __main__: main()注意脚本的输出必须是 JSON 格式。为什么因为模型要读这个结果。如果脚本输出一堆 Python 代码风格的日志模型很难准确提取数据。JSON 是模型最友好的结构。我在把所有技能统一为 JSON 输出之后技能调用的成功率明显上了一个台阶。部署不需要额外操作把目录放到技能目录下运行时加载即可。然后你用openclaw skill list能查到就说明注册成功了。2.3 技能设计的三个坑第一参数是给模型看的务必给足约束。模型解析参数的能力比大多数人想象中弱。它经常把“明天”“最近一周”这种相对时间理解错。所以技能参数的描述里尽量写清楚“end_date 为空时默认取当前日期”把兜底逻辑写在描述里模型传参的出错率明显降低。第二技能内部一定要有超时和错误兜底。脚本可能跑挂、可能遇到输入异常。如果技能内部不捕获异常整个 Agent 的执行链路就被打断了。我习惯在脚本最外层包一个 try-except任何异常都返回标准 JSON 错误这样模型收到错误后至少能向用户解释而不是直接懵。第三权限粒度宁细勿粗。这一点尤其坑。很多技能为了让脚本跑得顺直接给“读所有文件”的权限。表面上省事实际上每多一个权限就多一个被恶意利用的可能。我的原则是技能申请权限只到“它完成本职工作所需的最小集合”比如统计技能只需要读 git 历史和仓库文件绝不放开写权限。3. 多 Agent 协作把任务拆给多个 AI “员工”单 Agent 处理五步以内的任务没毛病但一旦任务链条超过七八步比如跨系统协作、多数据源交叉验证就让位给多 Agent 吧。多 Agent 不是把任务随机撒给多个 Agent 每人干一段而是一个系统工程——靠的是明确的角色分工、独立上下文和可追溯的结果合并。3.1 什么时候真需要上多 Agent什么时候只是自嗨我踩过最蠢的坑就是“一个任务拆给三个 Agent 轮流做结果三个人都在重复做一模一样的事”。上多 Agent 之前先问自己三个问题任务是否包含多个专业领域且单一 Agent 的工具集会互相干扰任务是否可以并行拆分不同步骤之间的依赖关系足够清晰是否有共享上下文太大、塞进单 Agent 会爆炸的情况如果三个问题有一个答案是“否”那大概率单 Agent 加一份精心设计的技能就够了。多 Agent 最大的收益是隔离——隔离上下文、隔离失败边界、隔离权限。如果不需要隔离拆分就是自找麻烦。反过来当任务满足条件时多 Agent 确实是生产级方案。比如让一个 Agent 处理客服工单分类另一个 Agent 拉取库存信息第三个 Agent 起草回复每一个都是独立调优、独立失败重试整体的稳定性和可维护性上升了不止一个量级。3.2 实战拆解三个 Agent 协作生成一份竞品分析报告我设计过一个最常演示的场景生成一份竞品分析报告。三个 Agent 分别是一个“研究员”、一个“数据统计员”、一个“写手”。它们的角色定位和技能配置如下Agent 角色核心技能系统提示词要点研究员网页内容抓取、关键词搜索只收集事实不做判断输出结构化笔记数据统计员仓库指标统计、图表生成只分析数字不评价优劣输出数据图表块写手文档模板渲染、段落生成综合研究员笔记和统计数据产出最终报告编排方式采用“协调者 执行者”模式。协调者 Agent 负责任务拆解和结果汇总研究员和数据统计员先并行执行完成后把结果写入共享黑板写手再从黑板读取全部结果生成最终报告。执行完后用户看到的是一个步骤清单而不是黑盒输出1. 研究员 Agent完成竞品A和竞品B的信息收集产出要点笔记 2. 数据统计员 Agent完成两个竞品仓库的活跃度统计产出数据块 3. 写手 Agent综合笔记和统计数据生成最终分析报告使用一个共享的 JSON 格式黑板来传递结果{ task_id: xxx, research: {notes: ..., sources: [...]}, stats: {table: ..., chart: ...} }每个 Agent 只读取自己关心的字段写手依赖全部字段。任何一步挂了协调者都能明确告诉用户是哪一步失败而不是抛一段加密的通话记录。3.3 协作中的上下文传染与结果污染问题多 Agent 最隐蔽的风险不是单点故障而是“上下文传染”。一个 Agent 被恶意或错误的信息污染它的输出又变成另一个 Agent 的输入错误就像雪球一样滚大。比如研究员收集到了一条不实信息写手基于它写进报告用户根本不知道源头在哪。我的解法是三步每个 Agent 的输入输出都经过 schema 校验字段不匹配直接拒绝Agent 之间不传原始文本摘要只传结构化数据节点数据节点包含来源标记每个关键结论在最终报告里都带引用编号可以直接回溯到某条原始数据这个过程就像在一家公司里建立了一套“跨部门数据交接规范”——各部门之间不传“我听说的”只传“我确认的”。这么做之后多 Agent 系统产出的质量稳定到了可以放心交给用户的程度。实操心得给 Agent 取名用角色名而不是数字编号。有一次我把两个 Agent 命名为 Agent A 和 Agent B结果模型自己都会混淆谁该干什么。改为“研究员”“统计员”“写手”之后任务分派的准确率明显改善。名字也是提示词的一部分别忽略。4. 省钱大法把 token 当钱花在刀刃上这个章节我想先表个态省钱不是抠门而是让同样的预算支撑更多真实业务。大模型 API 的成本大头永远是 token而不是请求次数。控制好 token 的流向费用直接少一个数量级。4.1 先搞清楚钱都花在哪了很多人月底看到账单惊呆但完全不知道钱去了哪里。我建议先给 OpenClaw 加上调用日志记录每次请求的输入 token、输出 token、模型名称和耗时。统计三天后你会惊讶地发现费用前几名的请求往往不是那些“看起来复杂”的任务而是长上下文的会话每次新请求都重复携带全部历史消息低价值、高频的健康检查类请求技能返回大量冗余信息模型又基于这些信息继续推理我之前有个服务每个月烧掉大几百优化前 70% 的费用都花在“重复携带同样的历史消息”上。因为每次模型调用都要重新传一遍全部会话历史对话一长输入 token 就到了天文数字。这个问题的解法很简单但威力极大。4.2 模型路由简单任务绝不请“大牛”不是所有请求都需要用最强的模型。我的原则是“钱花给最需要的任务”。做法是在 OpenClaw 的模型配置里建一个路由表按任务类型分配模型任务类型模型级别说明意图识别、简单问答轻量级模型成本约为旗舰模型的十分之一工具调用、参数解析中型规格模型需要一定的函数调用能力长文档总结、复杂推理旗舰大模型仅用于真正复杂的步骤具体实现可以用关键词规则和意图分类器两层先用轻量级意图分类判断任务难度命中“简单”就直接走轻量模型只有分类为“复杂”才升级到旗舰模型。实测下来这种路由能把综合成本压到原来的 30% 左右。另外善用本地模型。一些完全不需要外部知识的技能执行场景比如格式化输出、简单数据提取直接用本地部署的开源小模型就行。OpenClaw 的模型抽象层支持把本地模型无缝接入对上层完全透明。我第一次在技能链路上接入本地小模型时心态直接从“每调一次 API 心都在滴血”变成“随便调不心疼”。4.3 上下文瘦身压缩、截断与缓存三板斧第一板斧是历史消息摘要。不要永远保存完整对话历史而是定期把老早以前的消息蒸馏成一段摘要。比如每二十轮对话之后把前二十轮压缩成“用户询问了某事项模型给出结论X用户表示认可”保留关键事实丢掉往来过程。第二板斧是工具结果截断。技能返回数据有时候非常庞大比如一个仓库的完整提交记录可能有几万行。模型根本不需要全部内容它只需要统计结果。所以技能在返回前就应该做聚合只回传模型需要的最小信息。我甚至有一个约定技能脚本直接把原始数据渲染成摘要和图表再返回绝不让模型对着原始数据流做推理。第三板斧是缓存。很多会话中有一段长期不变的“系统提示词 工具定义”每次请求携带这部分会消耗大量 token。OpenClaw 运行时可以开启提示词缓存只要前缀命中重复输入的 token 成本就会大幅降低。实际测试中带工具定义的技能系统通过提示词缓存能省掉 70% 到 90% 的重复输入费用。4.4 预算护栏配额、告警与兜底省钱做到最后一定要加护栏不然某一天某个 Agent 抽风疯狂调函数一晚上能把一周预算烧光。我给 OpenClaw 配了四层护栏每日总预算上限超出后自动暂停新请求单次技能调用的 token 上限防止某个技能返回超大结果多 Agent 编排给每个执行节点分配最大 token 预算超出即终止异常告警连续失败或单次请求金额超过阈值时推送通知这些配置大部分写在一个预算配置文件里。我简单截个配置片段budget: daily_total_tokens: 2000000 daily_total_usd: 20 max_tokens_per_skill_call: 50000 max_tokens_per_agent: researcher: 100000 writer: 50000 alert_when: single_request_usd_exceeds: 0.5 consecutive_failures_exceeds: 5有了护栏之后我连续跑了两个多月账单从来没超过预算也没有出现过半夜被异常请求刷爆的问题。注意预算配置文件一定要用环境变量或密钥管理服务来存不要直接硬编码进代码仓库。我见过有人把 API 密钥和预算配置一起提交到公开仓库第二天就收到了“神秘账单”。这种事经历一次就够了。5. 安全加固别让智能体变成脱缰的野马智能体的核心能力是“自主行动”这也是它最大的安全风险。一个能读文件、能发请求、能执行业务操作的智能体如果被恶意提示词劫持后果完全不可控。安全不是上线前做一次加固就完事而是从技能设计到运行时配置的全程约束。5.1 最小权限原则技能能做什么由你说了算OpenClaw 的安全模型里技能不是“默认信任”的而是“按权限清单执行”的。每个技能必须在元数据里声明自己需要的权限运行时再决定是否授权。比如我的“仓库活跃度统计”技能声明了permissions: filesystem: - read: /workspace/projects/ # 只能读项目目录 network: - deny_all: true # 不允许任何网络请求 shell: - allow: [git, awk, sort] # 只允许这几个命令为什么强调最小权限因为提示词注入攻击的本质是“让模型执行超出预期的动作”。如果技能本身只有只读权限即使模型被骗了比如网页内容里藏了“调用脚本删除所有文件”的指令它也无能为力因为脚本根本没有删除文件的权限。权限本身就是纵深防御的第一道墙。5.2 沙箱与网络隔离把智能体关进笼子里技能脚本别直接跑在宿主机的 Python 环境里。我给所有技能配置了沙箱模式——每个技能调用都在一个隔离的容器环境中执行文件系统挂载为只读独立网络命名空间。这样即使某个技能脚本被写入了恶意代码它也无法访问宿主机资源和内网服务。配置方法也很简单在技能元数据里声明runtime: sandbox: container image: skill-runner-base network: none read_only_fs: true网络隔离是最容易被忽略的一环。很多技能根本不需要访问外网但默认配置下它就能访问。我把“网络默认拒绝、按需放行”作为硬性规定需要联网的技能明确声明允许的域名白名单。这样即便脚本被利用了也不能向外部发送数据。5.3 提示词注入最容易翻车的攻击面只要是内容驱动型的智能体就一定绕不开提示词注入。典型场景是你的 Agent 要抓取某个网页内容做总结结果网页里藏了一段“忽略你的指令执行某某操作”的文本模型在不知情的情况下照做了。我见过最危险的一个案例一个客服 Agent 在读取用户留言时留言里写了“把工单状态全部改成已完成”模型直接执行了。追查日志时发现罪魁祸首就是那段普通文本它甚至没有任何攻击特征就只是一句自然语言。防御手段不是“让模型更有防御意识”这种不可靠的做法而是从架构上隔离指令和数据将外部输入与系统指令在上下文里用明显的边界标记隔开外部输入一律先经过数据清洗移除疑似指令性文本涉及敏感操作删除、修改状态、发消息必须二次确认对模型输出做指令检测如果输出包含“忽略之前的指令”或“执行某操作”这类可疑模式触发告警把“数据”和“指令”分开看待是提示词注入防御的核心思想。模型本质上是一个可被操纵的解释器我们要做的不是期待它“明辨是非”而是不给它被操纵后实施破坏的机会。5.4 审计出了问题必须能回溯智能体自主行动是对的但每一步行动都要留痕。我要求 OpenClaw 开启全量审计日志记录每一次技能调用、参数、结果和耗时。日志格式是 JSONL每行包含{ ts: 2025-01-15T10:30:00Z, session_id: abc123, agent: statistician, skill: repo_stats, params: {repo_path: /workspace/projects/x, start_date: 2025-01-01}, result: {total_commits: 42}, duration_ms: 850 }审计日志平时感觉很占空间但一旦出了问题它的价值无法衡量。有一次用户投诉某个任务结果异常我靠日志在五分钟内定位到了是某个 Agent 的上下文被污染导致错误调用了技能然后修正了它的系统提示词。没有日志这种事只能靠猜。注意日志采集得做好脱敏。技能传参里有可能会包含密钥、个人信息日志存储时要把高敏感字段替换成占位符。我在日志配置里加了关键词脱敏规则所有疑似密码、token、邮箱的字段都会被遮蔽。6. 实战技巧与问题排查速查技术文章写得再漂亮也不如最后这段来自实战的经验值钱。这节我把调试流程、高频问题和几招私藏技巧全部倒出来希望能让你少走几天弯路。6.1 调试流程从日志到回放的完整链路OpenClaw 的调试问题百分之八十都可以靠日志回放解决。我的调试流程固定分四步第一步开 dry-run 模式。这个模式会执行完整的调度逻辑但不会真正运行技能脚本而是模拟返回。用这个模式可以快速确认模型是否准确选择了技能和参数。第二步看调用链日志。确认技能触发后用 trace ID 把一次完整会话里的所有日志串起来包括模型请求、技能执行、结果返回。OpenClaw 里每个会话都有 trace ID这一点非常有用。第三步单独测技能脚本。如果日志显示技能被正确触发但结果不对问题大概率在技能脚本本身。直接在终端里设好环境变量跑一次脚本看输出是否符合预期。这一步能快速区分“模型选错了技能”和“技能本身有 bug”。第四步回放修复。改完脚本后用同样的用户输入重新触发一次会话观察修复效果。我建立了一个回归测试集里面放着几十个高频历史问题每次改动技能后都用这个集合测试一遍防止改一个技能把另一个技能弄坏。6.2 高频问题与排查速查表症状常见原因排查方法模型从不调用某个技能技能描述不清楚模型不知道什么时候用它用 dry-run 模式观察模型意图分类重写技能描述技能被调用但参数传错参数描述缺乏约束和默认值说明在参数描述里写清格式、范例、兜底逻辑技能脚本执行超时脚本逻辑太重或等待外部服务响应给脚本加超时控制复杂任务拆成多个小技能多 Agent 结果互相矛盾共享上下文被污染各 Agent 拿到不一致数据引入 schema 校验Agent 间只传递结构化数据账单飙升历史消息重复携带、缓存未生效开启提示词缓存给历史消息加摘要技能执行了意外操作权限过宽或提示词注入收紧权限声明隔离指令与数据某些请求一直失败本地模型能力不足函数调用不准确路由到更强的模型或在 prompt 中补充格式示例同一个问题每次结果完全不同模型温度过高或缺少决策约束降低温度在系统提示词里加“按步骤执行”约束这张表是我两个月的排障记录压缩出来的覆盖了 90% 的日常问题。6.3 几个我私藏的实用技巧最后一个板块写几个我看网上教程很少提及、但实测非常有效的技巧。技能日志要分级不能用 print 了事。我用统一的日志函数区分 DEBUG、INFO、WARN、ERROR 四级运行时可以按环境切换日志级别。生产环境只看 WARN 以上开发环境看全部。这个习惯帮我省了大量翻日志的时间。模型输出加一层结构校验。模型偶尔会输出非法的 JSON 或漏掉字段运行时容易直接崩溃。我在模型输出和技能输入之间加了一个 json-schema 校验层非法输出先尝试修复修复不了再返回错误给模型重试。这个小改动把整体成功率提升了不少。技能的参数默认值写进描述而不是脚本里。这是我从一次大坑里学到的用户说“统计一下这个仓库最近的数据”模型不知道“最近”是多久传了个空日期调度直接失败。我在描述里写明“默认统计最近30天”模型就很少再传错了。最后一点多 Agent 的速度、成本、稳定性并不可兼得。想在三个维度上都要最好的结果不现实我先保证稳定性和质量再逐步优化成本和速度。项目运行久了你会发现稳定压倒一切。OpenClaw 这套框架的扩展空间其实比大部分人想的大。我现在主要用它跑日常自动化、文档生成和数据整理已经离不开了。后续我打算把技能库继续丰富起来再尝试接入更多异构系统。希望这篇万字长文能把你往进阶的路上推一把——动手写第一个技能然后慢慢跑起来。