做智能体这两年,我踩过最深的坑,就是给 Agent 无脑堆 Skills。一开始装五六个,感觉什么都能干;装到二十多个,开始偶尔犯傻;装到五六十个,连文献检索这种基础操作都会给你选错工具。项目群里隔三差五就有人问:AI 怎么越装越笨了?这不是玄学,是系统结构问题。今天拿科研场景开刀,把"Skill 越多越笨"背后的机制一次说清楚,再看看 SchoAI 这类新一代编排框架,是怎么把"技能堆砌"真正变成"能力组织"的。这篇东西适合正在搭科研智能体、或者手上 Agent 技能已经多到失控的朋友,不管你是用现成框架还是自己写编排逻辑,里面这套思路都能直接参考。
1. 为什么 Skill 越装越多,智能体反而越用越笨
先说结论:智能体变笨,不是大模型本身退化了,而是你给它的"环境"越来越糟糕。Skill 的本质是一段带触发条件和调用方式的工具描述,它要占用上下文、要参与路由决策、要跟其他 Skill 抢注意力。这三个环节任何一个被撑爆,整体表现就会肉眼可见地下降。
1.1 上下文窗口不是无限仓库,而是带轮子的小工作台
很多人把上下文窗口理解成仓库,觉得 128K tokens 很大,装几百个 Skill 没问题。这个类比是错的。上下文窗口更像一张工作台——你随时要在这张台子上写东西、翻资料、操作工具,台子上堆的东西越多,你能铺开的图纸就越少。
我自己的实测数据:一个科研 Skill 的元数据、工具 schema、触发条件、示例参数,折算下来平均要吃掉 400 到 600 tokens。装 60 个科研 Skill,光系统提示词里的技能描述就是 3 万 tokens 左右。听着还行?但问题在于,这 3 万 tokens 是每轮对话都要重复计费的固定开销,不管这轮任务用不用得上,它们都牢牢占着窗口,挤占真正用于推理和输出的空间。
更麻烦的是注意力稀释。Transformer 的注意力机制在超长上下文里会出现"迷失中间"现象,模型对窗口开头和结尾的内容敏感,对中间大段技能描述容易忽略。我做个很简单的实验:上下文里塞 60 个 Skill,然后问模型"你有哪些跟文献去重相关的技能",它经常把"文献管理"和"数据清洗"里带 deduplication 字段的描述搞混。技能越多,这种混淆越频繁,因为每个 Skill 的描述都在争夺那一点注意力配额。
1.2 技能路由在候选集爆炸时开始"看走眼"
Skill 的调用通常靠路由——要么是模型直接读全部描述做选择,要么是嵌入向量检索找最相近的几条。两种方式都有同一个命门:候选集越大,准确率越低。
直接让模型做全量选择时,60 个 Skill 意味着每次调用都要做一次 60 选 1 的判断题。模型在这件事上的表现很像考试时面对一道"以下哪个工具最适合查 PubMed 综述"的多选题——选项越多,它越容易把"看起来都沾边"的项混在一起。我在一个 40 个科研 Skill 的项目里统计过,路由准确率从 8 个技能时的 96% 一路掉到了 71%,近四分之一的调用选错了工具。
嵌入向量检索也没好到哪去。思路是靠语义相似度召回 Top-K 再交给模型,但科研领域的技能描述高度相似:"生成论文摘要"和"润色论文摘要"、"提取文献关键数据"和"抽取实验结论"——这些描述的向量距离非常近,Top-K 里全是长得差不多的"兄弟技能"。阈值调紧了,正确技能被过滤掉;阈值调松了,噪声全进来了,模型的二次判断压力反而更大。
1.3 工具描述挤占了大模型真正用来思考的空间
还有一个容易被忽略的点:工具 schema 的格式开销。OpenAI 风格的 function calling、Anthropic 的 tool use,每一个工具的 JSON Schema 都要带参数名、类型、描述、枚举值、必填项。这部分 token 不参与语义理解,纯粹是格式负担。
更糟的是,模型为了保证调用格式正确,会在生成工具调用前反复"检查格式",把本该用于推理的 token 预算花在了格式合规上。我抓过日志,一个包含 50 个 Skill 的智能体,单次工具调用的平均推理 token 比 10 个 Skill 时高了 38%,但任务完成率反而低了 12%。钱花多了,活干砸了,典型的边际递减。
| 指标 | 5 个 Skill | 20 个 Skill | 60 个 Skill |
|---|---|---|---|
| 技能描述占用上下文 | ~3k tokens | ~12k tokens | ~35k tokens |
| 路由准确率 | ~98% | ~90% | ~70% |
| 工具调用平均延迟 | 1.2s | 2.1s | 3.8s |
| 简单任务完成率 | 100% | 92% | 78% |
上面这张表是我在多个项目里取的中位数,不同模型会浮动,但趋势是一致的:Skill 数量和性能不是线性关系,而是过了一个拐点之后断崖式下跌。
1.4 功能重叠的 Skill 互相打架,还很难发现
最后一个坑藏得最深:Skill 之间的隐性冲突。你装一个"文献综述撰写",又装一个"论文引言生成",单看都合理,但它们的触发条件高度重叠。模型在处理写作任务时可能先调综述工具生成一段,又调引言工具改一遍,两个工具基于不同的 prompt 模板和格式要求,输出风格互相打架,最后生成的内容四不像。
这种冲突在测试时很难发现,因为每个 Skill 单独验收都是通过的,合在一起才会暴露。而且冲突是概率性的——有时模型选 A 有时选 B,日志里看不出报错,就是结果忽好忽坏。Skill 数量越多,这种两两冲突的组合数按平方级增长,到四五十个技能时,冲突几乎不可避免。
2. SchoAI 换个思路:不追求"装得多",而追求"组得好"
既然问题出在"所有技能同时挤在上下文里",那解法就很明确了:别让不用的技能占地方。SchoAI 的核心思路,就是把传统智能体那种"平铺式技能库"改造成"分层组织、按需加载、流程编排"的结构。这个思路本身不复杂,难的是执行得足够细腻。
2.1 先把科研能力分层:领域底座、技能注册表、工作流编排
SchoAI 把智能体的能力分成了三层,这个分层是所有后续机制的基础。
第一层是领域底座,也就是科研通用能力,包括文献检索、术语理解、学科知识库。这一层是常驻的,但数量被严格控制在 5 到 8 个以内,只保留最高频、最不可能冲突的核心能力。
第二层是技能注册表。注意,注册表不等于加载列表——所有技能都在注册表里有完整定义,但默认不进入上下文,只在被需要时才被拉取。注册表里存的不是工具描述全文,而是精简索引:技能 ID、适用科研阶段、输入输出摘要、依赖关系。这就像图书馆的卡片目录,目录再厚也不占书架空间。
第三层是工作流编排器,负责把科研流程拆成阶段,每个阶段决定加载哪些技能、按什么顺序调用。这正是传统智能体框架几乎不做的事——传统方式只有一层"技能列表",而 SchoAI 多加了一个"什么时候用什么技能"的决策层。
2.2 按需加载:只有当前科研阶段需要的 Skill 才进入上下文
按需加载是 SchoAI 最核心的机制,说穿了就一句话:Skill 是被"召唤"出来的,不是被"陈列"出来的。
科研流程可以拆成几个典型阶段:选题调研、文献综述、实验设计、数据采集、结果分析、论文写作、投稿准备。每个阶段真正用到的技能其实很少。做文献综述时,你需要的是检索、去重、分类、摘要抽取,可能就四五个技能;做实验设计时,你需要的是流程规划、可行性分析、实验记录模板,又是另外四五个。
SchoAI 的做法是:智能体启动时只加载领域底座那 5 到 8 个常驻技能,然后根据当前科研阶段,从注册表里动态加载 3 到 5 个阶段技能。整个上下文里的技能总数始终控制在 10 个左右,而不是 60 个。这就把前文说的注意力稀释、路由混乱、token 浪费三个问题一次性解决了。
实现上,按需加载靠的是"阶段状态机"和"技能入口条件"的配合。每个技能都声明自己适用于哪个科研阶段,工作流推进到新阶段时,上一阶段技能被自动卸载,新阶段技能被加载。模型当前在做的事会被映射到一个阶段状态,而不是让模型自己在 60 个技能里猜。
2.3 工作流编排:把散装 Skill 变成科研流水线
按需加载解决了"上下文干净"的问题,工作流编排解决的是"顺序正确"的问题。传统智能体的技能调用是模型自由发挥的——先调哪个后调哪个全看模型心情。SchoAI 则把科研流程变成了可编排的流水线。
以"写一篇文献综述"为例,工作流可以这样定义:
workflow: literature_review stages: - id: retrieval load_skills: [pubmed_search, semantic_scholar_search, crossref_lookup] output: raw_paper_list - id: screening load_skills: [dedup, relevance_filter, quality_score] input: raw_paper_list output: screened_papers - id: synthesis load_skills: [theme_extraction, argument_mapping, citation_formatter] input: screened_papers output: review_outline - id: writing load_skills: [academic_writing, reference_check] input: review_outline output: final_manuscript每一步的输出是下一步的输入,技能按阶段加载,上一阶段结束立即释放 token 空间。这样做的好处不只是省 token——更重要的是每步的上下文里只存在当前该用的技能,模型不会被"要不要用综述润色工具"这种无关选择干扰。
工作流还允许定义分支和回退。比如筛选阶段发现文献质量普遍不够,可以回退到检索阶段补充关键词再跑一轮。这种"可回退的流程控制"是传统平铺式技能库做不到的,传统方式里模型如果判断错误,往往就在错误的路径上一路走到黑。
2.4 实测对比:同样是 60 个科研 Skill,两种组织的差距有多大
我把自己一个生物信息学科研项目里的 60 个技能,分别用传统平铺方式和 SchoAI 的分层编排方式跑了两组测试,对比结果很有意思。
传统方式下,系统提示词里塞了全部 60 个技能描述,上下文 35k tokens 全是工具定义。第一个问题:模型把"基因富集分析"和"通路注释"两个技能搞混了,跑出来的是错误的富集结果。第二个问题:文献检索阶段,模型试图调用"论文写作"相关技能来整理检索结果,因为那些技能的触发条件写得太宽。
SchoAI 方式下,启动时只加载了 6 个底座技能,进入文献检索阶段后加载了 4 个检索类技能,整个流程的上下文工具开销峰值只有 8k tokens。同类任务,路由准确率回到 95% 以上,平均输出质量评分从 6.2 分涨到 8.5 分,而且错误模式的种类从 7 种降到了 1 种。
我还特意测了一个极端情况:一个技能在注册表里存在但当前阶段没被加载,智能体还会不会用到它?答案是几乎不会。因为阶段的边界把调用范围锁死了,模型的选择空间被大幅收窄。这就是"能力越多越好用"的秘密——不是模型变强了,而是它每次面对的选项变少了,决策质量自然就上去了。
3. 在 SchoAI 上配置科研 Skills 的实操要点
光讲理念没用,得能落地。我把自己在科研项目里配置 Skill 的完整套路整理出来,包括注册表怎么写、上下文预算怎么分、参数怎么调。这套东西你可以直接抄。
3.1 Skill 注册表怎么写:一份可直接套用的元数据模板
注册表的质量决定了按需加载的效果。我实践下来,一个 Skill 的注册信息至少要有下面这些字段:
skill_id: pubmed_search name: PubMed 文献检索 domains: [biomedical, life_science] applicable_stages: [retrieval, screening] description_short: 按关键词检索 PubMed 文献,返回标题、摘要、PMID input_summary: search_query: str, max_results: int, date_range: str output_summary: papers: list[dict] conflict_group: literature_search_group entry_condition: 当前任务涉及文献获取或引文补充 priority: high几个关键点的设计原因:
description_short 要短但要准。这段文字是注册表索引的核心,也是路由匹配的主要依据。不要写长段落,用"动词 + 对象 + 输出"的句式,比如"按关键词检索 PubMed 文献,返回标题摘要"。短描述在向量匹配和模型阅读理解两方面都更不容易出错。
conflict_group 是防冲突的关键字段。我在第 1.4 节说过,功能重叠的 Skill 会互相干扰。用 conflict_group 把相似的技能归组,同组内只允许加载一个,由工作流根据当前阶段决定加载哪个。比如"文献综述生成"和"引言生成"归到 writing_group,综述阶段加载前者,论文开头写作阶段加载后者,永远不同时出现。
entry_condition 要写成可判断的条件,不是模糊描述。不要写"当用户需要帮助时"这种废话,要写"当前任务涉及文献获取或引文补充"这种可被工作流状态机硬判断的条件。条件越明确,按需加载的决策就越稳定。
3.2 三级上下文预算:让每个环节都知道自己能花多少 token
按需加载解决了"该加载谁"的问题,上下文预算解决的是"加载后用多少"的问题。我把 Token 预算分成三级,每一级都有硬上限:
第一级是全局系统预算,占总上下文窗口的 40%。这里面包含人格设定、领域底座技能、全局安全规则。这一级是雷打不动的,不管跑什么任务都要保底。
第二级是工作流预算,占 35%。这一级分配给当前阶段的技能描述、工作流状态、阶段间传递的结构化数据。按需加载进来的技能,它们的 token 开销就从这一级里出。
第三级是任务预算,占 25%。这一级留给当前任务的原始输入、中间推理、输出草稿。可以用下面的公式估算:
全局预算 = 窗口大小 × 0.4
阶段技能可用空间 = 窗口大小 × 0.35 - 已固定的工作流状态 token
如果阶段技能描述总长超出可用空间,触发"精简加载":只加载描述最精简的 Top-N 个,剩余技能保持注册状态。
这个三级预算的好处是让"技能加载"这件事有边界感。以前遇到的问题是:技能描述越长,留给实际任务的窗口就越小。现在预算一卡,技能描述长度和数量都有了硬约束,不用靠感觉。
3.3 科研场景的调参参考:温度、检索阈值、冲突分组
科研智能体和通用助手在参数上有明显差异,我列几个实测下来比较稳的设置:
| 参数 | 推荐值 | 说明 |
|---|---|---|
| 温度 | 0.2 - 0.4 | 科研输出需要严谨,温度太高容易编造文献 |
| 路由 Top-K | 3 - 5 | K 太大噪声多,K 太小容易漏掉正确技能 |
| 向量匹配阈值 | 0.72 - 0.80 | 低于阈值直接丢弃,不进入模型二次判断 |
| conflict_group 大小 | ≤ 3 | 同组技能超过 3 个,说明粒度太粗,需要拆分阶段 |
| 技能描述 token 上限 | ≤ 80 | 注册表索引描述,超过就精简,正文放加载后再说 |
温度这条我要多说两句。科研智能体最怕幻觉,尤其是文献引用幻觉——模型会生成一篇看起来完全合理但其实根本不存在的参考文献。SchoAI 的做法是在写作阶段强制挂一个"引文校验"技能,每生成一条引用就去 Crossref 或 PubMed 检索验证。温度调低 + 引文校验技能强制加载,双保险下来,幻觉引用率能从 15% 降到 2% 左右。
科研场景还有个容易被忽视的点:实验数据的可复现性。传统智能体跑完数据分析就完了,工具调用参数、中间结果都不留痕。我在工作流里加了一个"实验记录"技能,专门把每个环节的输入输出、参数设置、版本号落盘。跑完一次全流程分析,能直接生成一份可复现的实验报告。这个技能不参与分析,但它是整个科研工作流里性价比最高的技能之一。
4. 踩坑实录:科研智能体 Skill 管理的常见问题与排查
配置做得再细,实际跑起来还是会遇到奇奇怪怪的问题。我把自己在科研智能体项目里踩过的坑、排查的思路、最终解决办法都列出来,当个速查表用。
4.1 症状:装完新 Skill,老任务反而失败了
这是最多人遇到的问题,我自己也中过招。给智能体加了一个"实验方案生成"技能之后,原来跑得好好的"文献去重"任务开始频繁报错,模型每次都去调用新技能而不是去重技能。
排查思路是这样的:先看新技能是不是跟旧技能在同一个 conflict_group 下。如果是,说明触发条件撞了。再看新技能的 entry_condition 是不是写得太宽——"当任务涉及数据处理"这种跨度极大的条件,会把大量无关任务吸引过来。最后用消融法验证:把新技能临时禁掉,跑一遍老任务,如果恢复正常,基本锁定就是新技能干扰。
解决方法是三选一:改窄 entry_condition;把新技能移到更精确的 applicable_stages;或者给两个技能加同一个 conflict_group,让工作流决定谁上场。记住一个原则:新技能上线,必须先跑一遍原有任务的回归测试,不能只测新技能本身。
4.2 症状:智能体在几个 Skill 之间来回打转
我遇到过一次特别典型的循环:模型在"数据清洗"和"格式转换"两个技能之间反复调用,第一次清洗完转成格式 A,第二次又清洗一遍转回格式 B,来回三次,结果反而把数据搞乱了。
排查后发现,根因是两个技能的输入输出 schema 里都宣称"接受任意格式数据、输出标准格式",彼此都觉得自己应该处理当前数据,于是进入了"我洗了你再转、你转了我再洗"的死循环。
解决办法是在工作流里加有向无环约束:明确数据清洗必须发生在格式转换之前,并且在流程状态机里记录"数据清洗已完成"这个状态,后续技能看到状态标记就不会再触发清洗。更通用的做法是给每个技能加post_condition字段,声明"调用完成后应该满足什么状态",工作流每次决策前先检查状态,能极大减少这种循环震荡。
4.3 症状:结果质量下降但日志看不出报错
这个最折磨人——没有报错、没有超时、工具调用全部成功,但生成的研究方案就是比以前差。我排查过很多次之后发现,常见真凶有两个。
第一个是上下文碎片化。按需加载技能时,如果上一阶段的技能描述没有完全释放,或者阶段间传递的数据格式不统一,上下文里会堆积大量"半成品"信息,干扰模型判断。检查方法是打印每一轮的上下文组成,看技能描述占比是否超过了 35% 的预算线。
第二个是技能描述被悄悄截断。有些模型对超长 system prompt 会自动截断,注册表里写的 80 token 描述可能实际只生效了前 40 token,后半段的关键约束全丢了。解决方法是建一个简单的提示词健康检查脚本,定期把实际发送给模型的完整 system prompt dump 出来人工检查,比对注册表定义和实际内容是否一致。
4.4 排查工具清单与自检流程
排查不要靠猜,要建立一套可重复的流程。我的自检顺序是这样的:
第一步,看路由日志。确认每个技能调用是怎么被选中的——是向量检索命中的还是模型直接判断的,命中分数是多少,低于 0.7 的直接标记为低置信调用。
第二步,看上下文预算报表。统计每个环节的技能描述 token、工作流状态 token、任务数据 token 的占比,任何一项超过额定预算都会引起隐性退化。
第三步,做最小复现。把失败任务抽出来,只保留当前阶段需要的技能,其余全部禁用,看问题是否消失。这个消融实验是定位问题的最快路径。
第四步,对照 4.1 到 4.3 的症状表查原因,锁定方向后修复,最后跑一次全回归。
| 症状 | 可能的根因 | 排查切入点 | 快速修复 |
|---|---|---|---|
| 老任务失败 | 新技能干扰路由 | 检查 conflict_group、entry_condition | 禁新技能做消融验证 |
| 技能调用循环 | schema 互认 + 状态缺失 | 检查工作流状态标记 | 加 post_condition 约束 |
| 质量隐性下降 | 上下文碎片化/描述截断 | dump 实际 system prompt | 精简阶段数据格式 |
| 路由选错技能 | 候选集过大或阈值过低 | 查 Top-K 命中分数 | 调整阈值、缩小候选集 |
| 文献幻觉 | 写作阶段缺少校验 | 抓生成引用的来源字段 | 强制挂载引文校验技能 |
我把这套排查流程固化成了一个脚本工具,每次跑完科研任务自动生成诊断报告,包含路由日志摘要、上下文预算占比、异常调用标记。这样问题复现时不用重新翻聊天记录,看报告就能定位。
我个人在实际操作中最深的一条体会是:智能体的能力上限,不由 Skill 数量决定,而由组织方式决定。SchoAI 这套分层加载和流程编排的思路,本质上是把"给模型更多选择"换成了"给模型更好的选择"。六十个技能平铺在桌上,和一个技能一个坑、按工序上岗,后者才是科研场景该有的样子。
最后再分享一个我后来养成的习惯:每个季度做一次 Skill 清单体检,把注册表里九十天没被加载过的技能标记为"休眠",再从工作流实际痛点反推要不要新增技能。这个习惯帮我砍掉了将近三分之一的冗余技能,智能体的整体表现反而更稳定了。如果你也在被"Skill 越装越多、AI 越用越笨"困扰,建议先从技能注册表和按需加载做起,这一步走对,后面就顺了。