Day 18 / 共 20 天 · 第 4 周 前端/安全/生态
微代理 microagents 与 Skills
不改一行代码,就能"教" Agent 你的项目规范、领域知识、常用流程。这就是微代理(在 V1 里演进成 skills)。今天读它的真实机制。
📍 第 4 周 前端与生态 · 你在这里
Day16 前端展示→Day17 安全权限→Day18 微代理Skills→Day19 企业版→Day20 构建收官
L01
为什么要"教" Agent
默认 Agent 很通用,但你的项目有特殊规矩:用什么测试框架、代码风格、部署流程、内部术语……你希望 Agent 一上来就知道这些,而不是每次都在提示里重复交代。微代理/skills 就是"把项目知识固化下来,自动喂给 Agent"。
类比:给新员工的"入职手册 + 便签"
新来的通用 Agent 像个能力很强但不了解你项目的外包程序员。你不想每次都口头交代"我们用 pytest、提交前要跑 lint、数据库叫 xxx"。skills 就是贴在他工位上的便签和入职手册——遇到相关任务自动翻出来看。这样 Agent 表现得像"懂你项目的老员工",而你没改任何代码,只写了几个知识文件。
🤔 如果没有这层会出什么事故?没有 skills,通用 Agent 每次都像"第一天来的临时工":这次它用了
unittest,你纠正"我们用 pytest";下次换个会话,它又用 unittest——同一个坑反复踩,你反复交代。项目术语、部署禁忌它一概不知,可能把测试库当生产库操作。💡 本质:skills = 把项目知识固化成文件,自动喂给 Agent就像生活中给新员工的"岗位速查手册":老员工不会每天口头教新人"我们食堂几点开、报销找谁、代码提交前要跑 lint",而是发一本手册,遇到相关事翻一下。skills 就是这本手册——写一次,此后每个会话的 Agent 一上岗就"懂规矩",不用你反复叮嘱。写 skill = 把口头交代沉淀成可复用、可分享的文件。
L02
microagent → skill 的演进
经典 OpenHands 里这个概念叫 microagents(微代理)。V1 里演进/统一成了 skills,但保留了向后兼容——看 skills_router.py:34 这行就懂:
GLOBAL_SKILLS_DIR = Path(openhands.__file__).parent.parent / 'skills'
USER_SKILLS_DIR = Path.home() / '.openhands' / 'microagents' # ★ 仍叫 microagents(兼容)
读法:用户级 skill 目录仍然是
~/.openhands/microagents——保留旧名字,让老用户的微代理继续能用。这是 Day 10 见过的"向后兼容"哲学的又一例:概念升级了,但不破坏老配置。所以你看文档说 microagents、代码里说 skills,指的是同一件事。L03
skill 长什么样
一个 skill 通常就是一个 Markdown 文件,带元数据头(frontmatter)+ 知识正文:
---
name: our-testing-convention
triggers: ["test", "测试", "pytest"] # 触发词(可选)
---
# 我们项目的测试规范
- 用 pytest,测试放在 tests/ 目录
- 提交前必须跑 `make test` 且全绿
- mock 外部 API,不要真实网络请求
读法:元数据头声明 skill 的名字和"触发词",正文是要注入给 Agent 的知识(自然语言)。有触发词的 skill 是"按需激活"——用户消息里出现触发词才注入(省 token);没触发词的可以是"常驻知识"。
SkillInfo 结构在 skills_router.py:38。为什么是 Markdown + 自然语言?
因为 skill 的受众是 LLM——它读自然语言最在行。你不用写代码,就用大白话把"我的项目该怎么搞"写清楚,Agent 就懂了。这是"提示词工程"的产品化:把有效的提示沉淀成可复用、可分享的文件。写 skill 本质是在写"给 AI 的说明书"。
L04
五个来源合并
skills 可以来自多个层级,Agent 启动时全部加载合并(app_conversation_service_base.py:110 的 load_and_merge_all_skills 调 agent-server 的 /api/skills):
| 来源 | 范围 | 例 |
|---|---|---|
| Public(公共) | 来自 OpenHands/skills GitHub 仓库 | 通用最佳实践 |
| User(用户) | ~/.openhands/microagents | 你个人的偏好 |
| Org(组织) | 团队/公司级 | 公司编码规范 |
| Repo(仓库) | 项目里的 .openhands/skills/ | 本项目的特殊约定 |
| Sandbox(沙箱) | 沙箱环境内置 | 环境相关 |
多来源合并的意义:知识分层管理——公共的大家共享、组织的团队统一、仓库的随项目走、个人的自己定制。就像"国家法律 + 公司制度 + 部门规定 + 个人习惯"层层叠加。Repo 级 skill(放项目
.openhands/skills/)尤其实用——把 Agent 知识随代码一起版本管理,团队共享,Agent 一 clone 项目就懂规矩。L05
触发式 vs 常驻
两种 skill:
- 触发式(有 triggers):用户消息里出现触发词才注入。比如只在提到"部署"时才把部署流程知识加进来。
- 常驻式(无 triggers / knowledge 类):始终在上下文里,比如项目总体说明。
为什么要区分?还是 token 经济学
如果把所有知识都常驻在上下文里,会占大量 token(贵 + 挤占对话空间)。触发式让"部署知识只在聊部署时出现、数据库知识只在聊数据库时出现"——按需加载,省 token。这和 Day 03 的历史压缩、Day 14 的成本控制一脉相承:上下文空间是稀缺资源,要精打细算地用。回忆 Day 03 的 MessageEvent 有个
activated_microagents 字段——记录"这轮激活了哪些微代理",就是触发式在起作用的证据。👶💬 对话体:为什么不把所有手册都常驻,图省事?
👶 小白:把所有 skill 都塞进上下文,Agent 啥都懂,不香吗?
👨🏫 老师:上下文空间是有限且花钱的(token)。全塞进去既贵,又挤占对话空间,还可能把无关知识混进来干扰判断。
👶 小白:那怎么办?
👨🏫 老师:给手册贴触发词——聊到"部署"才翻出部署那一页。就像速查手册分章节,用到哪章翻哪章,而不是把整本书全背下来。
👨🏫 老师:上下文空间是有限且花钱的(token)。全塞进去既贵,又挤占对话空间,还可能把无关知识混进来干扰判断。
👶 小白:那怎么办?
👨🏫 老师:给手册贴触发词——聊到"部署"才翻出部署那一页。就像速查手册分章节,用到哪章翻哪章,而不是把整本书全背下来。
📝 举个例子你有一个 skill:
triggers:["部署","deploy"],正文写着"部署前必须先跑 make test"。你发消息"帮我部署到预发环境"→ 命中触发词 部署 → 这条 skill 被注入上下文、activated_microagents 记上它 → Agent 于是知道"先跑测试再部署"。若你只是聊"改个 typo",这条 skill 不会加载,省下 token。图:触发词命中才注入对应 skill——按需加载,精打细算用上下文
L06
.openhands 目录:项目的"Agent 配置"
回忆 Day 07:会话启动时会处理项目里的 .openhands/ 目录(app_conversation_service_base.py:66 注释列出)。它是"随项目走的 Agent 配置":
.openhands/setup.sh:项目环境准备脚本(装依赖等).openhands/skills/:仓库级 skills(本课重点).openhands/pre-commit.sh:git 提交前钩子PLAN.md:规划型 Agent(Day 11)的计划文件
把 Agent 配置放进代码仓库意味着:团队共享同一套 Agent 行为、随版本演进、code review 时也能审查"我们怎么配 Agent"。"Agent 配置即代码"(Agent-config-as-code)——和"基础设施即代码"同理,让 AI 协作可复现、可协同、可审计。这是 OpenHands 用于团队的关键设计。
L07
加载源码
本仓的 skills 加载逻辑(app_conversation_service_base.py:102):
async def load_and_merge_all_skills(self, ...):
# 调用 agent-server 的 /api/skills 端点,加载并合并所有来源的 skill
# agent-server 负责:public(GitHub repo)/ user / org / repo / sandbox
return await load_skills_from_agent_server(...)
读法:又是"薄代理"模式(Day 07)——app_server 不自己实现 skill 合并逻辑,而是调沙箱里 agent-server 的
/api/skills,由它统一处理五个来源。还有一个 skills_router.py 提供"浏览可用 skills、marketplace 预览"等 UI 支持接口。skill 的具体类型 Skill 来自 openhands.sdk.skills(外部包)。L08
今日小结 + 动手
🧠 今天你应该能回答
- 为什么要"教" Agent?microagents/skills 解决什么?
- microagent 和 skill 的关系?(演进 + 向后兼容)
- 一个 skill 长什么样?为什么用 Markdown+自然语言?
- 五个来源分别是?触发式 vs 常驻为什么要区分?
- .openhands 目录里有什么?"Agent 配置即代码"什么意思?
✋ 动手
grep -n 'GLOBAL_SKILLS_DIR\|USER_SKILLS_DIR\|microagents\|class SkillInfo' openhands/app_server/user/skills_router.py
grep -n 'def load_and_merge_all_skills\|\.openhands\|setup.sh\|skills' openhands/app_server/app_conversation/app_conversation_service_base.py | head
grep -rn 'activated_microagents' frontend/src/types/v1/
明天预告 · Day 19:enterprise 企业版扩展——本仓
enterprise/ 目录一览:多租户、鉴权(Keycloak)、计费、Git 平台集成、会话分享。看 OpenHands 如何从"单机工具"扩展成"企业级 SaaS"。