去年我在做一个内部知识库问答项目时,第一次被 Claude Skills 这套技能机制吸引。当时的痛点很典型:模型本身能力够强,但面对几十个工具、几百条规则时,要么把上下文窗口直接撑爆,要么在无关技能上反复横跳。Claude Skills 通过 SKILL.md 声明技能、available_skills 注册清单、渐进式加载按需读取,再加上最少惊讶原则约束技能行为,把这个问题拆成了一个能落地的模块化方案。
我花了几周时间把项目里的工具改造成这种结构之后,上下文占用大概下降了三分之一,误调用也明显变少。这篇文章把我对这套机制的理解、改造过程和踩过的坑完整讲一遍,适合正在搭智能体,或者深度使用 Claude 做自动化任务的开发者和产品同学。如果你只是想了解 AI 应用工程化落地的方式,也能从中看到一类值得参考的设计思路。
1. 三层上下文架构:为什么不是一层到底
1.1 把“全部文档”硬塞进上下文的后果
很多人第一次接触技能系统时,下意识会想:把所有工具说明、规则、示例一次性写进系统提示词里,不是最省事吗?我一开始也是这么干的,结果很快就发现两个问题。
第一是上下文浪费。每个技能的完整说明动辄几百上千字,几十个技能加起来就是几万字。模型每次请求都要把这一大堆内容重新读一遍,真正和当前任务相关的可能只有一两句话,其余全是噪声。这就好比食堂给你一个固定大小的托盘,你为了备用把几十个菜全装上,结果主食都放不下了。
第二是决策质量下降。上下文越长,模型越容易在无关信息上产生注意力偏移。有时候它会记住某个技能里一个不重要的细节,反而把用户真实意图忽略了。我实测过一个场景:系统里挂了二十个数据分析相关的技能,结果模型经常为了“用哪个技能”纠结半天,甚至把完全不相干的技能拉出来用。
Claude Skills 解决这个问题的思路,不是把所有文档塞进去,而是把上下文拆成三层,让模型按需读取。这三层分别是:最底层的基础上下文、中间层的可用技能目录、最顶层的技能详细内容。每一层都有完全不同的职责和加载时机。
1.2 三层各自的职责
第一层是基础上下文,也就是系统提示和启动时加载的全局信息。这一层的内容是“无论用户问什么,模型都得知道的底线”。比如它是谁、它的回答风格、它必须遵守的安全约束、它对用户身份的基本认知,以及一份对技能系统本身的简要说明。
第二层是 available_skills,它是一份动态生成的技能清单。这一层不需要包含任何技能的具体操作细节,只需要列出“当前有哪些技能可用,每个技能是干什么的,用一句话怎么概括”。模型看到这份清单,就知道自己手里有哪些牌,但具体怎么出牌,还要看第三层。
第三层才是技能的完整说明,也就是 SKILL.md 的实际内容。这一层只有在模型判断“当前任务确实需要这个技能”时,才会被加载进上下文。加载后,技能里的指令、步骤、示例、限制条件才真正对模型生效。
这三层的关系,我习惯用一个比喻来理解:基础上下文是你的职业身份和岗位职责,available_skills 是你办公桌上贴着的一张工具列表,SKILL.md 则是抽屉里对应工具的使用说明书。你不会把全部工具说明书都摊在桌面上,而是先看工具列表,确定要用的那一把,再打开抽屉去读说明书。
1.3 层级之间的协作逻辑
这三层不是简单的叠加关系,而是一个按需触发的过程。用户发起请求后,模型先基于第一层基础上下文理解任务,随后查看第二层 available_skills,判断哪些技能可能相关。如果判断某个技能相关,系统就把第三层对应的 SKILL.md 加载进来,模型再基于完整指令去执行。
这套机制最重要的特点,是“触发权”交给模型,但“控制权”留在系统里。模型可以自主判断当前该看哪份说明书,但能不能看到说明书、看到哪一份,由系统的渐进式加载逻辑决定。这种分工既保住了灵活性,又避免模型被海量信息淹没。
我在实际项目中体会最深的一点是:这种三层结构不只是为了省钱省空间,它本质上是在模仿人处理复杂任务的路径。人不会打开电脑就把所有软件的用户手册读一遍,而是先看任务是什么,再想该用什么工具,最后才去查工具的用法。Claude Skills 把这套路径工程化了,让模型的行为更接近一个有经验的工作者。
2. SKILL.md:技能的核心文件,一份小而准的说明书
2.1 SKILL.md 里到底该写什么
SKILL.md 是每个技能的灵魂文件,它决定了一个技能在模型眼中“是什么”和“怎么做”。我第一次写 SKILL.md 时踩过一个很典型的坑:把技能文档写得像产品需求说明书,又长又细,以为这样模型执行起来就更准,结果反而更糟。
原因在于 SKILL.md 的核心定位不是“完整手册”,而是“可被渐进式加载的紧凑指令”。它需要让模型在加载后能快速抓住要点,而不是在一堆背景描述里找重点。我后来总结出一个经验:SKILL.md 只写四类内容:技能的身份信息、技能的触发条件、技能的执行步骤、技能的边界和输出格式。
身份信息对应文件名和简短描述,让模型在 available_skills 清单里一眼就能判断是否相关。触发条件要写清楚“什么场景下用这个技能”“什么场景下不要用”,这一步能有效减少误调用。执行步骤是核心,要按顺序写清楚模型该做什么,而且要写“怎么做”,而不是只写“做什么”。边界和输出格式则是容易被忽略的部分,技能在什么情况下会失败、失败后应该怎么反馈、输出结果必须长成什么样,这些信息对保证结果稳定性非常重要。
我见过的很多失败案例,问题都出在“边界”没写。有次我接一个第三方接口,技能文档里只写了正常返回的情况,没写接口超时怎么办。结果模型在接口宕机时编造了一个看似合理的返回结果,用户差点把这个假数据拿去用。后来我在 SKILL.md 里明确写了:接口无响应时,不要猜测数据,直接返回错误信息并提示稍后重试,这个问题才算解决。
2.2 字段设计的原则与取舍
由于 SKILL.md 本质是 Markdown 文件,它在格式上比较自由,但我在实践中会刻意保持一套固定的结构,方便模型理解和维护。我的 SKILL.md 一般包含头部元信息区和正文指令区两块。
头部元信息区我用 YAML frontmatter 格式,写上技能名称、描述和必要的标签。这里有几个取舍要说明一下。技能名称我会用下划线风格,和代码变量风格保持一致,避免空格带来的识别歧义。描述字段是我花时间最多的部分,因为它决定了模型在扫描 available_skills 时,会不会把这个技能关联到当前任务上。描述太宽泛,比如“处理数据”,会导致模型在所有涉及数据的场景都尝试加载它;描述太具体,比如“把 CSV 文件中的第二列数值求和”,又会让模型在其他需要类似能力但场景描述不完全匹配的时候漏掉它。
我的经验是描述里至少要包含三个要素:技能作用的对象、技能执行的动作、技能产出的结果。比如“读取本地 CSV 文件,按指定列做聚合统计,返回 Markdown 格式的汇总表格”。这句话虽然长一点,但信息量很足,模型扫描时不需要重新理解。
正文指令区我会分成几个带小标题的段落:任务目标、执行步骤、约束条件、输出格式、失败处理。每个段落不要写废话。执行步骤尽量用有序列表,让模型能按编号推进,而不是一口气读完一大段话。约束条件里我会写死“不允许修改原始文件”之类的红线,这些说明对模型行为的影响比想象中大得多。
2.3 一个能直接抄的 SKILL.md 示例
这里分享一个我在项目里实际用的精简版 SKILL.md,功能是查询某个内部 API 接口的数据并生成日报摘要。你可以直接参考这个结构。
--- name: fetch_api_daily_summary description: 调用内部数据接口获取当天的业务数据,生成一份包含核心指标的日报摘要。适合用户在每天早上询问业务进展时使用。 metadata: version: 1.2.0 framework: skill tags: [日报, 数据, api] --- # 任务目标 用户要求查看某天的业务概况时,调用内部数据接口获取数据,并生成简洁的日报摘要。 # 执行步骤 1. 确认用户指定的日期,缺省时使用当前日期。 2. 调用接口 GET /api/daily/summary,按日期拼接查询参数。 3. 从返回的 JSON 中提取总营收、订单量、客单价三个字段。 4. 用以下格式输出摘要:日期、总营收、订单量、客单价、与昨日对比的增减百分比。 5. 输出完成后,提示数据更新时间。 # 约束条件 - 不要修改接口返回的原始数据。 - 日期格式统一为 YYYY-MM-DD。 - 接口响应时间超过 5 秒时,直接终止本次调用。 # 输出格式 用 Markdown 表格输出核心指标,表格上方加一句总结性描述。 # 失败处理 - 接口返回空数据时,返回“当天暂无数据”,不要补造数值。 - 接口超时或报错时,返回“数据服务暂时不可用”,并建议用户稍后重试。 - 不要尝试多次调用同一个失败接口。这个示例看着简单,但它把“什么时候做、按什么顺序做、遇到问题怎么办”都说清楚了。尤其那个“接口超时时不要编造数据”,是我用一次实际事故换来的教训。好的 SKILL.md 不会让模型变成全能专家,但会让模型在可控范围内稳定输出。
3. available_skills:让智能体知道“自己会什么”
3.1 为什么需要一份显式的可用技能清单
有了 SKILL.md,为什么还要多一层 available_skills?这其实是很多人的疑问。我的理解是:模型默认并不知道自己挂载了哪些技能,它只知道系统里有一套技能机制。如果没有一份显式的清单,模型只能靠猜,或者靠用户提示去触发技能,这会带来两个明显问题。
一是技能发现效率低。模型知道有技能可用,但不知道具体有哪些,于是每次都要在对话中试探,或者要求用户提供更多信息。这非常消耗轮次,用户体验会很差。二是存在“暗技能”问题。某个技能明明已经挂载,但因为没有任何地方提到它,模型始终不知道它的存在,这个技能就变成了一堆永远不会被加载的代码。
available_skills 解决的就是“技能发现”问题。它把当前所有可用技能压缩成一份轻量清单,注入到模型能稳定看到的位置,相当于告诉模型:“这是你现在拥有的全部工具,请根据任务自行选用。”有了这份清单,模型可以主动提出“我可以用日报生成技能来帮你完成这件事”,而不是一脸茫然地反问“你想让我做什么”。
3.2 available_skills 的构建与注入过程
在我的项目里,available_skills 并不是手工维护的,而是由系统启动时自动扫描技能目录,读取每个技能的 SKILL.md 头部元信息,然后动态生成。这样每当我新增或删除一个技能,只需要添加或移除对应的 SKILL.md 文件,清单会自动更新,不会出现漏登记的问题。
生成后的清单格式我习惯保持极简,每一条只包含技能名和一句描述。示例长这样:
<available_skills> <skill name="fetch_api_daily_summary" description="调用内部数据接口获取当天业务数据,生成日报摘要" /> <skill name="weekly_report_builder" description="整合一周业务数据,生成周报文档" /> <skill name="data_chart_generator" description="根据表格数据生成柱状图或折线图" /> <skill name="sql_query_helper" description="将自然语言问题转换为 SQL 查询语句" /> </available_skills>你会注意到描述和 SKILL.md 里的 description 字段基本一致。这是有意为之,因为模型在 available_skills 层看到的描述,就是它决定是否读取完整 SKILL.md 的依据。如果这两处文本不一致,或者清单里的描述被截断,模型就可能做出错误判断。
注入位置也有讲究。available_skills 必须放在基础上下文里一个非常明确、固定的区块中,不要和其他内容混在一起。我最早是把技能清单放在一大段系统提示的末尾,结果模型经常忽略它。后来我把它放在独立区块,并用明显的标签包裹,模型识别率明显提升。
3.3 目录与完整技能:一碗汤的浓度问题
我有一个很朴素的判断标准:如果 available_skills 里的描述都要超过 50 个字,说明你的技能拆分有问题。清单应该像餐厅菜单,每道菜一行字就能说清楚。如果一道菜需要三行字描述,大概率是这道菜本身设计得太复杂,应该拆成多个技能,而不是靠描述来解释。
这里涉及到一个技能粒度的问题。我在项目里见过有人把“数据获取、数据清洗、数据分析、可视化、日报生成”全塞进一个技能里,导致描述字段怎么写都不够准确,模型总是误判。后来我把这一个超级技能拆成五个独立技能,每个技能的 SKILL.md 都变得短小精悍,available_skills 的清单也清爽了,模型的选择准确率反而提高了。
技能清单还有一个隐性作用:它相当于给模型画了一个能力边界。模型看到清单后,会知道哪些事它能干、哪些事它不能干。当用户提出清单范围之外的需求时,模型可以主动说明“我目前没有这个能力”,而不是硬扛着去完成任务。这种边界感对降低幻觉、减少错误操作非常有价值。在工作中有一份清晰的边界,比什么都敢接但什么都做不好要重要得多。
4. 渐进式加载:从目录到全文的分层读取
4.1 渐进式加载的两大收益
渐进式加载是这套机制里最不显眼但最值钱的部分。简单说,它的流程是:模型先只看到 available_skills 清单,当它判断某个技能有用时,系统才把对应的 SKILL.md 全文加载进来。
这里最大的收益,是控制了上下文的使用效率。我粗略算过一笔账,在挂载 20 个技能的情况下,如果所有 SKILL.md 全文都常驻上下文,仅技能部分就要吃掉大约 1.5 万到 2 万 token。而在渐进式加载模式下,一次对话通常只会加载两到三个真正用到的技能,技能部分可能只占两三千 token。省下来的空间可以留给多轮对话内容和用户数据,对复杂任务来说,这点空间有时候直接决定了任务能不能完成。
第二大收益是减少干扰。模型每多读一份不相干的说明书,产生错误联想的风险就高一分。渐进式加载保证模型每次只需要关注当前任务真正需要的技能,而不是被无关内容分散注意力。我在实际使用中明显感受到,改成渐进式加载后,模型“用错技能”或者说“硬套技能”的次数大大下降。
4.2 标准的三步加载流程
我实践中总结出来的渐进式加载流程,大致可以分成三步。第一步是模型读取基础上下文,理解用户的请求,看到 available_skills 清单。第二步是模型根据用户请求和清单描述,做一轮“技能相关性筛选”,这一步是模型自主完成的,它会在内心评估哪个技能最匹配。第三步是系统接收到模型的选中信号后,把对应 SKILL.md 的完整内容追加到上下文中,然后模型开始正式执行。
这里有一个细节值得展开:第三步的触发方式在不同实现里可能不一样。有些场景下,模型会先输出一个类似“我要使用 fetch_api_daily_summary 技能”的中间信号,系统捕捉到后再加载。有些更聪明的实现,会在模型生成每个回复前,由系统预先计算需要注入哪些技能。无论哪种方式,核心逻辑都是一样的:触发不能靠运气,必须有一个明确的加载信号。
为了让这个信号更准确,我会在基础上下文里给模型一段简洁的说明,大意是:当你确定某个技能能帮助用户完成当前任务时,请先声明使用该技能,再执行操作。这段说明看起来简单,但能让模型养成“先确认工具再动手”的习惯,也大大减少了瞎猜的情况。
4.3 什么情况下会漏加载或误加载
渐进式加载不是万能的,我遇到过不少漏加载和误加载的情况,这里挑两类最常见的讲讲。第一类是“描述歧义导致的误加载”。当 available_skills 里两个技能的描述有重叠时,模型经常分不清该加载哪个。比如我有两个技能,一个叫“日报生成”,描述是“根据业务数据生成日报”;另一个叫“周报合并”,描述是“合并一周的日报数据”。用户说“帮我看看这周每天的情况”,模型就懵了,要么先加载了日报生成,发现不对再切换,要么干脆两个都加载,浪费上下文。
解决这类问题,我建议从源头入手:技能拆分时就要保证职责边界清晰,描述用词不要互相包含。日报生成就管单日数据,周报合并就管跨日汇总,两者的差异尽量体现在描述关键词上,比如“单日”和“区间”,让模型能一眼区分。
第二类是“用户需求表述过于隐晦导致漏加载”。有时候用户不会直接说“用日报技能”,而是说“今天生意怎么样”。如果 available_skills 的描述里没有“生意”这种口语化表达,模型可能不会联想到日报技能。我的解决办法是在 SKILL.md 的触发条件里写清楚这个技能能回答哪些类型的问题,包括口语表达,甚至在必要的时候在描述里加上一两个同义词。这会稍微增加描述长度,但比漏加载要划算得多。
5. 最少惊讶原则:技能设计里最容易翻车的地方
5.1 最少惊讶原则到底是什么
最少惊讶原则(Principle of Least Surprise)不是 Claude Skills 独有的概念,软件设计领域早就用它了。它的核心含义是:一个组件的行为应该让使用者感到符合直觉,尽量不出现“超出预期”的反常表现。放到技能系统里,就是说技能的执行方式和输出结果,必须让用户和模型都能预料到。
为什么这个原则在技能设计里尤其重要?因为技能的“使用者”有两个:一个是最终用户,一个是模型本身。用户期望一个叫“发送邮件”的技能就是发送邮件,而不是连带着做了一堆额外操作;模型期望一个技能按照它文档里写好的步骤执行,而不是中途冒出意料之外的规则。
我一开始对这套原则理解得很浅,觉得只要技能能跑出正确结果就行,后来被一个真实场景教育了一次。我开发过一个“会议记录整理”技能,它除了整理会议纪要,还会自动把纪要发给所有参会人。从功能上这确实是一体的,但用户用的时候吓一跳:明明只想让自己看看纪要,结果全员都收到了邮件。这个“意外”彻底破坏了用户对技能的信任,从此我对“技能到底做了什么”抱持了极大的敬畏。
5.2 在读取、执行、输出三个环节如何落地
把最少惊讶原则落到实际操作中,我总结出三个环节的检查点。首先是最初的技能触发环节,模型扫描 available_skills 时,通过名称和描述来判断这个技能是否匹配需求。如果一个技能的名字叫“数据分析”,但实际功能只是统计文本长度,这就是名不副实。技能命名和描述必须忠实反映真实能力,让模型和用户在看到名字的第一眼就知道它是什么。
其次是执行过程环节。技能在执行时应严格按照 SKILL.md 里的步骤推进,不要擅自增加文档里没有说明的操作。比如文档里没写“记录日志”,技能就不应该额外在系统里写入日志。尤其是那些带有外部副作用的操作,比如发邮件、写文件、调接口,必须提前在文档里写明,并且尽量放在执行步骤的靠后位置,给模型留出充分的前置判断时间。
最后是输出环节。输出格式需要保持稳定,不要这次返 JSON,下次返 Markdown,第三次又变成纯文本。稳定的输出格式不仅方便用户阅读,也让模型拿到技能结果后能顺畅地继续后续处理。技能在失败时也一样,失败提示要明确,不要返回一个看似正常但实际没数据的空壳结果。宁可说“我做不到”,也不要让用户拿到一个看起来没问题、实际无效的结果。
5.3 一个反例和改造过程
我拿自己做过的“邮件助手”技能完整演示一遍改造过程。最初的 SKILL.md 里,我把“发送邮件”直接写成“根据用户意图撰写并发送邮件”,没有细分发件人、收件范围,也没有说明默认抄送规则。结果有一次用户只是说“帮我起草一封请假邮件”,技能直接给用户主管发了出去。用户那条消息后面跟了一串问号,我才意识到出大事了。
我重新设计了 SKILL.md,第一步先让用户确认收件人,第二步撰写邮件内容并展示给用户,第三步等待用户明确回复“发送”后才真正发出。同时我在描述里写清楚:该技能默认不会自动发送,必须经过用户确认。改造之后,这个技能的触发率没变,但用户的信任明显回来了。
这个例子说明,最少惊讶原则不是限制技能的效率,而是给技能加入必要的确认节点和边界意识。一个能自动干很多事的技能,如果让用户失去了掌控感,它的价值就会大打折扣。技能不是越“聪明”越好,而是越“可预期”越好。让用户猜得到每次都发生什么、不突然做多余的事,比追求自动化和效率更重要,长期来看这套标准的复利效应非常明显。
6. 实操里踩过的坑与排查技巧
6.1 高频问题速查表
把我在项目中反复遇到并解决的问题整理成一张速查表,方便你快速定位。这些问题很多不是功能逻辑错了,而是技能架构层面的细节没做到位。
| 现象 | 可能原因 | 解决思路 |
|---|---|---|
| 模型完全不调用任何技能 | available_skills 清单丢失或未注入 | 检查基础上下文里清单区块是否存在,技能目录路径是否正确 |
| 模型老是用错技能 | 技能描述相互重叠,边界不清晰 | 精简描述,明确区分各技能适用场景,必要时拆细粒度 |
| 某个技能从未被触发 | 描述与用户日常表达差距太大 | 扩充触发条件,加入口语化同义词和常见问题形式 |
| 技能加载后执行结果不稳定 | SKILL.md 步骤写得模糊,没有明确顺序 | 将执行步骤改为有序列表,补充失败处理 |
| 技能无故编造数据 | 失败处理缺失,模型只能用错觉补全 | 在 SKILL.md 写清失败返回策略,禁止猜测 |
| 上下文大量被技能占用 | 渐进式加载失效,全部 SKILL.md 被常驻 | 检查加载触发机制,确认每次只注入选中的技能 |
| 用户对技能操作感到意外 | 技能做了文档之外的事,违反最少惊讶原则 | 重新审视 SKILL.md 的约束条件,移除隐藏副作用 |
这张表的后两列,其实正是在强调本文反复提到的那套原则:描述要准、边界要清、流程要显式、失败要兜底。
6.2 我的标准调试流程
调试技能系统时,我会遵循一套固定流程,而不是出了问题再随手改动。第一步是复现,我会用一个最小化的请求去触发目标技能,同时开启日志,记录模型当前看到了什么内容。这一步能快速确定问题出现在哪一层:是 available_skills 清单层、SKILL.md 内容层,还是加载触发逻辑层。
第二步是看 available_skills 是否按预期生成。我会直接要求模型“列出你当前可用的技能清单”,通过它的回答和实际清单做对比,确认模型看到的内容和系统生成的内容是否一致。这一步能发现清单漏项、描述截断、注入位置不当等问题。
第三步是单独测试 SKILL.md。我会临时写一个直接调用该技能核心逻辑的简化请求,不经过完整的技能选择流程,看技能本身的输出是否正确。如果单独测试正常,那问题大概率出在“技能选择”环节;如果单独测试就不对,那直接回去改 SKILL.md。
最后一步是回归验证。改完 SKILL.md 或清单之后,我会把之前失败过的所有请求重跑一遍,而不是只测当前这一个。因为技能之间经常互相影响,新改的内容可能解决了 A 问题,却让 B 问题重新冒出来。这一步虽然费时间,但能避免“修一个 bug 带出另一个 bug”的恶性循环。
6.3 几个让技能更稳的经验笔记
这里分享几条我在多轮迭代后沉淀下来的经验,不一定写在哪里文档里,但非常值得参考。第一条是关于 SKILL.md 的版本记录,我一定在元数据里带上 version 字段,每次有改动都递增一个版本号。因为模型行为对技能内容很敏感,如果某个输出风格变化了,我可以通过版本号快速判断是哪次改动引起的,而不是面对一堆历史文档无从下手。
第二条是保持技能描述和 SKILL.md 内的第一段内容一致。模型的注意力并不是均匀分布的,它对一段内容开头部分的敏感度远高于结尾。如果描述说“这个技能能生成日报”,但 SKILL.md 里第一段却在讲接口参数,模型就可能产生错觉。所以每次我改描述时,都会顺手检查 SKILL.md 开头是否同步更新。
第三条是不要吝惜在 SKILL.md 里写“不要做什么”。我见过很多 SKILL.md 只写“要做什么”,很少写“不做什么”。但其实,明确排除一些行为比列一堆正向要求更能约束模型。比如“不要修改原始数据”“不要自动发送”“不要猜测缺失字段”,这些负向指令能直接堵住那些容易出事的操作路径。这就像教新手开车,告诉他“别踩油门”可能比“请缓慢起步”更容易记住。
第三条延伸到技术之外,我的感受是:Claude Skills 本质上是一套帮模型“收心”的框架。模型的能力一直在膨胀,上下文窗口也越来越大,但不能因此就让模型随意使用能力。真正决定一个智能体靠不靠谱的,不是它挂载了多少技能,而是它能不能在正确的时机,加载正确的技能,然后用最少惊讶的方式完成任务。
我希望这篇拆解能帮你少走一点弯路。若你正在设计自己的技能系统,不管最终套用什么框架,“分层上下文、显式清单、渐进加载、稳定行为”这四个关键词都值得先刻在脑子里。我就是按照这个顺序一点点把项目盘活的,从最初的混乱到现在大体稳当,过程中最大的体会是:技能系统的工程价值,从来不在于塞给模型多少功能,而在于让它只关注当下这件事,别乱想、别乱动、别骗人。