Agent Skills(智能体技能)¶
概述¶
Agent Skills 是 PersonAgent 的能力组织方式。PersonAgent 是一个轻量的 ReAct 编排器,其能力
由**可插拔的 Skill 流水线**提供。它解决的问题不只是“如何写插件”,而是如何把社会科学中的行为机制拆
成可以检查的仿真环节:一个人看到了什么,如何解释这个情境,形成了什么意图,采取了什么行动,又把哪些
经历带到后续决策中。
Skill 遵循 metadata-first、selected-only 模型:
选择阶段:LLM 只看到 Skill 目录(
name+description),据此决定激活哪些。执行阶段:只有被 LLM 选中的 Skill 才会被加载、读取、执行(惰性加载)。
好处是提示词体积可控(未选中的 Skill 不进上下文),且 Skill 可独立演进、热加载。一个 Skill 是一个
自包含目录,至少含一个 SKILL.md,包含 YAML frontmatter 和行为文档;可选地含
scripts/ 可执行脚本和 references/ 参考资料。
备注
本页描述的是 Ray 重构后 的技能子系统。旧的内置 observation / cognition / plan /
memory 四技能已被移除;技能基础设施(registry / runtime)从 agent/skills/ 下沉到
agentsociety2.agent.base;Skill 脚本默认在 agent 进程内经 entrypoint 执行,而不再是
每步 fork 子进程。当前唯一内置技能是 内置技能:daily-guidance。最权威的工程说明见源码
agentsociety2/agent/skills/README.md。
设计目标¶
按需加载:降低每步不必要的上下文占用与执行开销。
可解释选择:选择依据来自 catalog 中的简短描述,便于调试和复盘。
热更新友好:支持运行时扫描、激活/停用与重载(自定义 skill 放进
custom/skills/即被发现)。文件约定解耦:技能通过 workspace 文件交换状态,而不是互相直接调用。
进程内执行:脚本默认走
entrypoint,复用热解释器,毫秒级、完全并发安全。
Skill 目录结构¶
内置技能位于 agentsociety2/agent/skills/,自定义技能位于工作区 custom/skills/,环境模块技能
由环境提供。SkillRegistry 按目录扫描,用 namespace@name 作为稳定 skill_id。
# 内置技能(命名空间 built-in)
agentsociety2/agent/skills/
└── daily-guidance/
├── SKILL.md # frontmatter(name/description/script/hooks)+ 行为说明
├── scripts/
│ └── daily_guidance.py
└── references/
# 自定义技能(命名空间 custom,热加载)
{workspace}/custom/skills/
└── my-skill/
├── SKILL.md
└── scripts/
└── my_skill.py
# 环境模块技能(命名空间 env)
{env_module}/skills/
└── weather-query/
└── SKILL.md
扫描规则:每个子目录必须含 SKILL.md,否则跳过;以 . 或 _ 开头的目录被忽略;同名(同
skill_id)先到先得。agent 启动时通过 default_activated_skill_ids 配置默认激活哪些 skill。
SKILL.md 格式¶
每个 skill 目录必须含 SKILL.md,头部用 YAML frontmatter 描述元数据:
---
name: daily-guidance
description: 强制使用:凡是时间尺度在小时及以下的日常行为模拟,必须使用本 Skill ...
script: scripts/daily_guidance.py
hooks:
pre_step: scripts/daily_guidance.py
---
# Daily Guidance
(激活后被注入 system prompt 的行为说明……)
frontmatter 字段:
字段 |
说明 |
|---|---|
|
显示名,与命名空间组合成 |
|
目录描述——选择阶段 LLM 唯一可见的文本,决定是否激活。务必精炼、可操作。 |
|
可选,默认脚本相对路径(如 |
|
可选,生命周期 hook 脚本映射,键为 hook 类型( |
备注
frontmatter 之后的 Markdown 正文,是 skill 被 激活后 注入 system prompt 的行为说明。未激活时
不进上下文。激活时支持 $ARGUMENTS / $1 / $2 占位符替换与 !cmd 命令输出注入。
可见性与激活¶
可见(visible):skill 出现在目录里,LLM 能看到、能选择激活。
激活(activated):skill 的
SKILL.md正文被注入 system prompt,其脚本 / hook 可被调用。
LLM 通过下列工具操作 skill:
工具 |
作用 |
|---|---|
|
加载某 skill 的 |
|
从上下文移除某 skill。 |
|
读取 skill 内文件(渐进式披露)。 |
|
执行 skill 脚本。 |
ReAct 主循环每个 step() 开始前会刷新可见 skill 集合;ask 模式(外部问答)下只暴露只读工具子集。
脚本执行模型(进程内 entrypoint)⭐¶
这是当前实现的**核心**。历史上 skill 脚本以子进程方式执行(python script.py <argv>),每个 agent
每步都 fork 一个新解释器,冷启动开销巨大。改版后 skill 脚本默认**在 agent 进程内执行**,分三档优先级:
① entrypoint(argv, ctx) ← 首选:缓存 import 后直接调用,毫秒级,完全并发安全
② 动态包装器(exec) ← 兜底:无 entrypoint 时,以 __name__=="__main__" 就地执行
③ 子进程(python script.py) ← 最后回退:模块无法 import 时
entrypoint 契约(推荐所有 skill 脚本遵循)¶
Skill 脚本可在模块顶层定义一个 entrypoint,runtime 会优先调用它:
def entrypoint(argv: list[str], ctx) -> str:
"""进程内入口。
Args:
argv: 命令行参数(去掉脚本名之后的部分),与子进程方式的 sys.argv[1:] 一致。
ctx: SkillScriptContext,携带本 agent 的运行上下文。
Returns:
str: 脚本原本会打印到 stdout 的文本(通常是 YAML/JSON 结果块)。
"""
要点:
签名兼容:runtime 检测形参数量,
entrypoint(argv)与entrypoint(argv, ctx)都支持, 强烈建议接受 ``ctx``。返回 stdout:不要依赖
print被 capture;直接return结果字符串。异常即失败:
entrypoint抛异常 → 记为失败(exit_code=1)。不要用sys.exit();逻辑 失败在返回文本里写ok: false。幂等加载:runtime 按
(路径, mtime)缓存模块,模块顶层代码只执行一次。
SkillScriptContext¶
进程内执行时上下文通过 ctx 显式传入(定义在 agent/base/runtime.py):
字段 |
说明 |
|---|---|
|
本 agent 的工作区根目录(子进程时代对应环境变量 |
|
本 skill 的包根目录。 |
|
注册 id( |
|
子进程方式本会设置的 env 快照(dict)。 |
并发安全要求(重要)¶
一次模拟里多个 agent 在**同一个进程**内并发跑各自的 skill 脚本。下列进程级状态是**共享**的,绝不能在 entrypoint 里直接读写,否则产生数据竞争:
❌ 禁止 |
✅ 替代方案 |
|---|---|
|
用 |
|
用绝对路径( |
|
在 entrypoint 里 |
模块级可变全局当作“本次调用状态” |
用 |
动态包装器¶
无 entrypoint 的脚本由动态包装器就地执行:以 __name__ == "__main__" 在全新命名空间 exec
脚本源码——语义等价子进程,但复用热解释器、无 fork。由于临时设置 os.environ / os.chdir /
捕获 stdout 这些进程级状态,动态包装器由一把全局锁 串行 执行。因此推荐所有热路径脚本提供
entrypoint,享受完全并发。
内置技能:daily-guidance¶
当前唯一内置技能是 daily-guidance``(``built-in@daily-guidance),面向**时间尺度在小时及以下**的
日常行为模拟。它让 agent 先形成一天的完整 Story(state/daily_guidance/YYYY-MM-DD/story.yaml),
再按 Story 指导每个仿真步的行为:
用 ``plan --json`` 提交一天的安排:脚本校验后写入 story.yaml。
执行状态由时钟推导:
completed_segments/current_segment_id是(segments, 当前仿真时间)的函数,由脚本在读取时计算。``pre_step`` hook 每步注入当前 segment:含
activity和location_policy,agent 据此移动与 回答问卷。内含 needs-decay 模型与 story revision 能力,用于评估和修正每日安排。
daily-mobility 等实验默认激活该 skill。它也是“进程内 entrypoint + pre_step hook 注入”的参考实现
(见 agent/skills/daily-guidance/scripts/daily_guidance.py)。
旧的 observation / cognition / plan / memory 四技能已被移除;这些认知/行为能力现在通过
自定义 skill + workspace 状态文件 + ask_env 组合实现。
生命周期 Hook(pre_step / post_step)¶
在 SKILL.md 的 hooks: 里声明,每个仿真步自动触发:
pre_step:agent.step()开头、ReAct 循环之前运行。典型用途:根据仿真时钟推导当前状态, 注入到首轮上下文。post_step:ReAct 循环之后运行。典型用途:记录实际行为、收尾。
hook 以 --args-json 形式接收 payload(含 hook_type / tick / time / agent_id /
step_count)。改版后,pre_step 的输出渲染为**专用的 <skill_hooks> XML 分块**,出现在
ReAct 首条 user 消息中——而不是被塞进通用 observation dump(那容易被 LLM 忽略)。例如:
<skill_hooks>
<skill_hook skill="built-in@daily-guidance" hook="pre_step" ok="true">
active_segment:
activity: sleep
location_policy: home_aoi
</skill_hooks>
这样 agent 不必再花一轮观察去“重新发现”状态。
环境类 Skill(env: 前缀)¶
以 env: 开头的 skill_id 会被 execute_skill_script 重定向到 ask_env``(走环境路由
``RouterBase),而非执行脚本。用于把“查询/操作仿真环境”包装成 skill 暴露给 LLM。这类 skill 不需要
entrypoint。
SkillRegistry API¶
SkillRegistry 是技能的发现中心(位于 agentsociety2.agent.base.skill_registry)。在大规模仿真下
它是共享只读单例(不再每 agent 复制)。
方法 |
说明 |
|---|---|
|
扫描内置技能。 |
|
扫描自定义技能。 |
|
扫描环境模块提供的技能。 |
|
返回所有 |
|
按 id / 名称查询。 |
|
读取 |
|
返回声明了某 hook 的技能。 |
|
复制一份 registry(一般无需调用)。 |
SkillDescriptor 是每个 skill 的元数据(skill_id / name / description / script /
hooks / 来源路径等)。激活、脚本执行与 hook 调度由 AgentSkillRuntime``(见 :doc:`/api/skills`)
负责,``AgentBase 持有其实例 self.skill_runtime。
自定义 Skill 最小示例¶
目录:
{workspace}/custom/skills/hello-skill/
├── SKILL.md
└── scripts/
└── hello_skill.py
SKILL.md:
---
name: hello-skill
description: Add a short greeting into the step log when greeting is relevant
script: scripts/hello_skill.py
---
# Hello Skill
Write a greeting to the workspace.
scripts/hello_skill.py``(``entrypoint + CLI 共用派发):
import contextvars
import json
from pathlib import Path
from typing import Any
_WORKSPACE_ROOT: contextvars.ContextVar[Path | None] = contextvars.ContextVar(
"hello_workspace_root", default=None
)
def entrypoint(argv: list[str], ctx: Any) -> str:
root = Path(str(getattr(ctx, "workspace_root"))).resolve()
_WORKSPACE_ROOT.set(root)
(root / "hello.txt").write_text("hello-skill: greeted", encoding="utf-8")
return json.dumps({"ok": True, "summary": "greeted"}, ensure_ascii=False)
if __name__ == "__main__":
# 子进程回退路径仍可用
raise SystemExit(0 if entrypoint([], type("C", (), {"workspace_root": "."})()) else 1)
放进 custom/skills/ 即被热加载;激活后主 LLM 会在合适上下文选择它执行。
编写 Skill 的检查清单¶
内置目录放在
agent/skills/<name>/;自定义目录放在工作区custom/skills/<name>/。有
SKILL.md:frontmatter 含name、精炼可操作的description、可选script/hooks。若有脚本:提供
def entrypoint(argv, ctx) -> str并接受ctx;工作区根取自ctx.workspace_root;结果用return返回;用contextvars承载调用状态;CLI 派发与entrypoint共用同一函数。若声明
pre_stephook,输出要自包含、可直接作为 agent 指引(会被包进<skill_hooks>)。参考资料放
references/,SKILL.md里点名引用,按需被读取。
参考¶
使用智能体 -
PersonAgent使用说明架构与可扩展性 - Ray 执行模型与
ServiceProxySkills 模块 -
SkillRegistry/AgentSkillRuntimeAPI源码
agentsociety2/agent/skills/README.md- 技能子系统最权威说明ReAct: Yao et al. (2022), https://arxiv.org/abs/2210.03629