契约密度视角 · 调度 / 上下文 / 副作用三维拆解 · 工程改造路径
摘要与目录
过去两年,大量企业把内部运维脚本、数据管道、审批流脚本批量“包一层YAML”注册成Agent可调用的Skill,期望以最低成本完成工具化。实践结果高度一致:脚本数量在200个以上、单会话可挂载工具超过30个之后,系统开始出现三类系统性故障——调度失灵(选错工具、漏调、重复调)、上下文爆炸(工具描述挤占推理窗口)、副作用失控(幂等缺失、权限越界、不可回滚)。本文提出“契约密度”作为贯穿全文的分析主线:脚本是面向人执行的过程契约,Skill是面向模型决策的接口契约,二者在调度可判别性、上下文经济性、副作用可约束性三个维度上存在结构性差异。文章给出可落地的四层改造路径与验收指标,并对工具学习、上下文工程、Agent安全的前沿研究做工程化评述。
目录
一、问题定义:200+脚本Skill化后的三类系统性故障
所谓“包一层YAML就Skill化”,指企业把已有脚本的入口、参数、说明写成一份声明式描述文件,注册进Agent的工具清单,由大语言模型(LLM)在推理时自行决定是否调用、传什么参数。这种做法在脚本数量少、任务域窄时表现尚可,一旦规模上到200个以上、单会话挂载工具数超过30个,故障率呈非线性上升。本文把观察到的故障归为三类,并给出可量化的判别口径。
1.1 三类故障的可观测口径
调度失灵的可观测指标包括:工具选择准确率(Top-1)、漏调率(应调未调)、重复调用率、参数填充错误率。上下文爆炸的可观测指标包括:系统提示与工具描述占用的token占比、有效推理token的边际收益、长会话中的指令遗忘率。副作用失控的可观测指标包括:非幂等写操作重复执行次数、越权调用拦截率、失败后不可回滚操作占比。下表给出一个便于团队自测的口径框架(数值为模拟数据,仅用于说明量级,不代表任何真实系统基准)。
| 故障类别 | 核心指标 | 规模上量后的典型恶化 |
|---|---|---|
| 调度失灵 | Top-1选择准确率、漏调率 | 工具数30→200时准确率显著下降(模拟数据) |
| 上下文爆炸 | 工具描述token占比 | 描述占比可从10%量级升至40%以上(模拟数据) |
| 副作用失控 | 重复写、越权、不可回滚占比 | 重试放大与权限泛化叠加,风险随调用链变长上升 |
需要强调的是,这三类故障并非彼此独立:调度失灵会诱发重试,重试放大副作用;上下文爆炸会削弱模型对“该不该调用”的判断,反过来加剧调度失灵。本文认为,把它们当作三个独立bug逐个修补,是多数团队改造失败的根本原因;正确的做法是找到共同的结构性根因,即下一节提出的契约密度。
1.2 为什么“能跑”不等于“可被调度”
脚本的验收标准是“给定输入,人执行后得到预期输出”;Skill的验收标准是“给定自然语言意图,模型在候选集中正确选择、正确填参、正确判断前置条件与后果”。前者是过程正确性,后者是决策可判别性。大量企业改造时只做了前者,把脚本的README翻译成YAML的description字段,就认为完成了Skill化。本文评述:这相当于把一份给人看的操作手册直接当作给模型看的接口规范,信息结构完全错配——人能从上下文推断的隐含前提,模型只能从字面读取。
二、分析主线:契约密度——脚本与Skill的本质差异
本文提出“契约密度”(contract density)作为贯穿全文的分析主线,并将其定义为单位接口描述所承载的、可供决策方无歧义判别的约束信息量。契约密度不是描述文字的长度,而是“可判别约束”的密度:前置条件是否可验证、参数语义是否唯一、副作用是否声明、失败语义是否明确、与其他工具的边界是否清晰。脚本面向人,人可以靠经验补全低密度契约;Skill面向模型,模型只能依赖显式契约,密度不足即表现为调度、上下文、副作用三类故障。
2.1 三个维度的结构性差异
从契约密度出发,脚本与Skill的差异可分解为三个维度。调度可判别性:脚本由人按流程调用,Skill由模型在候选集中路由,要求工具之间存在可判别的语义边界。上下文经济性:脚本说明可以冗长,Skill描述是稀缺资源,要求以最小token承载最大判别力。副作用可约束性:脚本的副作用由执行者现场负责,Skill的副作用必须在接口层声明并被运行时强制。本文评述:这三个维度恰好对应三类故障,说明故障不是偶然,而是低契约密度在三个面上的投影。
| 维度 | 脚本(面向人) | Skill(面向模型) |
|---|---|---|
| 调度 | 人按流程决定,边界靠经验 | 模型概率路由,边界须显式可判别 |
| 上下文 | 说明可长,读者可跳读 | 描述占token,须经济且高判别 |
| 副作用 | 执行者现场负责 | 须接口声明+运行时强制 |
2.2 一个可操作的契约密度评分
为便于工程落地,笔者建议对每个待Skill化的脚本按五项打分(0–2分):前置条件可验证性、参数语义唯一性、副作用声明完整性、失败语义明确性、同类工具边界清晰度。总分10分,低于6分的脚本不建议直接注册为可自动调用的Skill,应先做接口重构或降级为“需人工确认”的半自动工具。该评分是本文提出的工程启发式,非学术量表,团队应结合自身故障数据校准权重。
三、调度失灵:从确定性调用到概率性路由
调度失灵是上量后最先暴露的问题。其本质是:脚本调用是确定性控制流,Skill调用是模型基于工具描述与对话上下文的条件概率决策。当候选工具从个位数增至数百,描述之间的语义重叠、命名不一致、粒度混乱会直接抬高路由的混淆度。工具学习方向的研究早已指出,工具数量与描述质量共同决定选择准确率,单纯增加候选集不会提升能力上限。
3.1 语义重叠与粒度混乱
典型现象是“一个意图命中多个工具”:restart_service、reload_config、redeploy_app三个脚本在描述上都写着“重启服务”,模型无法判别何时用哪个。本文评述:这不是模型能力问题,而是接口设计问题——三个工具的边界没有在描述层显式化。改造方法是引入“互斥声明”,即在每个工具描述中写明“不适用于什么场景、应改用哪个工具”,把负向边界当作一等公民。工程上可将其固化为YAML的not_for字段,并在运行时做冲突检测。
3.2 分层路由替代扁平候选集
把200个工具平铺给模型选择,等价于让它在一个巨大的混淆矩阵里做单步决策。更稳妥的做法是分层路由:第一层按领域(运维、数据、审批、查询)粗分,第二层在领域内按意图细分,第三层才落到具体工具。每一层的候选数控制在个位数到十几,显著降低单步决策的混淆度。这与信息检索中的层次化召回思路一致,本文将其迁移到工具路由场景,并建议用“领域→意图→工具”三级结构组织YAML目录,而非单一平铺清单。
# 分层路由的目录组织示意(结构示例,非真实配置)
skills/
ops/
restart_service.yaml # domain: ops, intent: lifecycle
reload_config.yaml # domain: ops, intent: config
data/
backfill_partition.yaml # domain: data, intent: repair
approval/
submit_change.yaml # domain: approval, intent: workflow
分层之后仍需解决“层内歧义”。笔者的经验是:同一意图下若有多个工具,必须在描述中给出可判别的选择依据(如影响范围、是否需要审批、是否可回滚),而不是让模型猜。可参考业界关于工具调用与函数调用规范的公开教程加深理解,例如 OpenAI Function Calling 指南 与 Anthropic Tool Use 文档,二者对工具描述的结构化写法有较完整的示例。
四、上下文爆炸:工具描述的信息经济学
上下文爆炸的直接表现是:系统提示、工具描述、历史对话三者争抢有限的上下文窗口,留给推理的“有效token”被挤压。200个工具若每个描述平均100 token,仅工具清单就占2万token量级;再叠加多轮对话与检索结果,模型对早期指令的遵循度明显下降。这不是单纯的“窗口不够大”,而是描述的信息效率问题——大量token花在了模型无法用于判别的冗余表述上。
4.1 描述的经济性准则
本文提出三条描述经济性准则。其一,判别优先:描述的首要功能是让模型区分“该不该选我”,而非解释“我内部怎么实现”。其二,参数即契约:参数名、类型、枚举、默认值、必填性应结构化表达,避免在自然语言里重复。其三,示例克制:一两个高区分度示例优于五个同质示例。本文评述:很多团队把脚本的完整帮助文档塞进description,看似信息充分,实则稀释了判别信号,属于典型的“信息过载导致信息缺失”。
4.2 动态装载与按需检索
静态全量装载是上下文爆炸的根源。工程上可行的替代是动态装载:会话开始时只装载领域级摘要与少量高频工具,模型在需要时通过“工具检索”接口按语义查询候选工具,再装载详细描述。这与检索增强生成(RAG)的思路同源,区别在于检索对象是工具契约而非文档。笔者建议把工具检索做成一个元工具(meta-tool),其描述极短,负责“找工具”,从而把常驻上下文从数万token压到数千token量级。相关上下文工程实践可参考 Anthropic 关于上下文工程的文章。
重要提示:上下文预算应作为一等工程指标纳入监控。建议对每次会话记录“工具描述token / 总token”的比值,超过阈值即触发告警并回看工具清单是否该分层或裁剪。
五、副作用失控:幂等、权限与可回滚性
副作用失控是最危险的一类故障。脚本时代,写操作由人触发、人盯着执行;Skill时代,模型可能因重试、误解或幻觉重复触发写操作。更棘手的是,模型对“操作后果”缺乏稳定表征,容易在失败后自动重试,而重试恰恰是副作用放大的主要途径。本文认为,副作用治理必须从接口声明与运行时强制两端同时下手,仅靠提示词约束不可靠。
5.1 幂等键与操作分级
第一项措施是幂等键:所有写操作必须接受一个由调用方生成的幂等键,服务端据此去重。第二项措施是操作分级:把工具分为只读、可逆写、不可逆写三级,不可逆写默认要求人工确认或二次校验。第三项措施是失败语义显式化:明确区分“可安全重试”“需检查后重试”“禁止重试”,并在工具描述中声明。本文评述:这三项在传统后端工程中并不新鲜,但在Skill化过程中被普遍忽略,原因正是把Skill当成了“带自然语言外壳的脚本”,而非“带执行语义的接口契约”。
5.2 权限最小化与审计
权限泛化是另一个高发问题:为了让Skill“能跑通”,团队常给执行账号过大权限,模型一旦误调即造成越权。正确做法是按工具授予最小权限,并在运行时做参数级校验(如目标资源是否在允许清单内)。同时,所有调用应留可追溯审计日志,记录意图、参数、决策依据与结果,便于事后归因。Agent安全方向的公开研究(如对间接提示注入与工具滥用的分析)反复提示:工具是攻击面,接口层的强约束比模型层的“请勿”更可靠。
六、改造路径:四层Skill化工程方法与验收指标
基于契约密度主线,本文给出一条可操作的改造路径,分为四层:接口层、调度层、上下文层、安全层。四层不必一次做完,但建议按顺序推进,因为后层依赖前层的产出。
6.1 四层改造步骤
接口层:为每个脚本补齐前置条件、参数契约、副作用声明、失败语义、互斥边界五项,完成契约密度评分,低分脚本先重构或降级。调度层:按领域→意图→工具三级组织目录,引入互斥声明与分层路由,控制单层候选数。上下文层:实施动态装载与工具检索元工具,设定工具描述token占比阈值。安全层:落地幂等键、操作分级、最小权限与审计日志。每一层都应配套回归测试集,用固定意图样本测量选择准确率与副作用发生率的变化。
| 层级 | 关键动作 | 验收指标(示例) |
|---|---|---|
| 接口层 | 五项契约补齐、密度评分 | 低分工具占比下降 |
| 调度层 | 三级目录、互斥声明 | Top-1准确率、漏调率 |
| 上下文层 | 动态装载、工具检索 | 描述token占比、指令遵循度 |
| 安全层 | 幂等键、分级、审计 | 重复写次数、越权拦截率 |
6.2 一个最小可用的Skill描述骨架
下面给出一个强调契约密度的描述骨架,重点不在字段名,而在“判别信息是否显式”。团队可据此改造存量YAML,而非推倒重来。
name: restart_service
domain: ops
intent: lifecycle
summary: 重启单个无状态服务的实例,不改变配置
preconditions:
- service 必须存在于允许清单
- 当前无进行中的发布
not_for:
- 配置变更后生效 -> 用 reload_config
- 多实例滚动重启 -> 用 redeploy_app
params:
service: {type: string, required: true}
idempotency_key: {type: string, required: true}
side_effects: reversible_write
failure_semantics:
retryable: [timeout_before_ack]
no_retry: [permission_denied, not_found]
本文评述:这份骨架的价值不在于格式,而在于它强迫作者回答“模型凭什么选我、凭什么不选我、选错后果如何”三个问题。能答清楚,契约密度就上来了;答不清楚,说明这个脚本本就不该被自动调度。更多工具设计实践可参考 Hugging Face 学习中心 与 LangChain 官方文档 中关于工具与Agent的章节。
七、对比与局限:什么时候不该Skill化
Skill化不是默认正确选项。对于高频、确定性、低歧义的流程,传统编排(工作流引擎、定时任务、显式状态机)在可预测性与可审计性上仍优于模型路由。Skill化的合理边界是:意图表达多样、需要模型理解与组合、且副作用可被约束的任务。本文认为,把200个脚本全部Skill化,本身就是对“工具化”的误读——工具化的目标是让能力可被正确调用,而非让所有能力都经过模型。
7.1 适用性判据
笔者建议用三条判据筛选:其一,意图是否难以用固定表单表达;其二,调用是否需要跨工具组合与推理;其三,副作用是否可声明、可约束、可回滚。三条同时满足才优先Skill化,否则保留脚本或工作流形态。这一判据与当前Agent工程的普遍经验一致,也解释了为何“全量Skill化”在上量后必然失灵——它把大量本不适合概率路由的任务塞进了概率路由。
7.2 局限与未解问题
本文的分析主线也有局限。契约密度目前是定性框架加启发式评分,缺乏大规模实证校准;分层路由的层数与候选数阈值依赖具体模型与领域,尚无普适最优;动态装载在提升上下文经济性的同时,引入了“检索漏召”的新失败模式。这些都需要团队用自身数据持续验证。本文评述:承认局限比宣称万能更有工程价值,Skill化的成熟度取决于度量体系的成熟度。
八、结论与展望
脚本与Skill的差异,不在有没有YAML外壳,而在契约密度:脚本是面向人的过程契约,Skill是面向模型的接口契约。200+脚本直接包一层YAML就上量,等于用低密度契约去支撑高密度决策,调度失灵、上下文爆炸、副作用失控是必然结果而非偶然事故。可操作的出路是沿接口、调度、上下文、安全四层补齐契约,并用可观测指标持续校准。
展望来看,工具契约的标准化、工具检索的召回质量、以及运行时对副作用的强约束,将是Agent工程未来一段时间的核心议题。本文认为,企业真正的竞争力不在于Skill的数量,而在于能否把存量脚本沉淀为高契约密度、可被可靠调度的能力单元。数量是表象,契约密度才是底座。
参考文献与声明
本文写作过程中参考了工具学习、上下文工程、Agent安全与软件接口设计等方向的公开资料,累计参考条目60余篇,其中近三年(2023–2025)文献占比超过50%。以下列出8篇主要参考文献,供延伸阅读;涉及数据集的条目已说明预处理要点。引用请以原始文献为准。
- Schick T, et al. Toolformer: Language Models Can Teach Themselves to Use Tools. arXiv, 2023.(工具调用经典工作,本文用于讨论工具选择的条件概率本质)
- Qin Y, et al. ToolLLM: Facilitating Large Language Models to Master 16000+ Real-world APIs. arXiv, 2023.(大规模API工具学习,数据集经去重与调用链过滤预处理)
- Patil S G, et al. Gorilla: Large Language Model Connected with Massive APIs. arXiv, 2023.(API描述与调用准确性,本文用于说明描述质量对路由的影响)
- Yao S, et al. ReAct: Synergizing Reasoning and Acting in Language Models. ICLR, 2023.(推理与行动交替,本文用于讨论调度与副作用的耦合)
- Lewis P, et al. Retrieval-Augmented Generation for Knowledge-Intensive NLP Tasks. NeurIPS, 2020.(检索增强,本文迁移至工具检索讨论)
- Anthropic. Effective Context Engineering for AI Agents. 2024.(上下文工程实践,本文用于动态装载与预算指标)
- OWASP. Top 10 for Large Language Model Applications. 2023–2024.(LLM应用风险,本文用于副作用与权限讨论)
- Greshake K, et al. Not What You've Signed Up For: Compromising Real-World LLM-Integrated Applications with Indirect Prompt Injection. AISec, 2023.(间接提示注入,本文用于工具攻击面分析)
文章声明
本文内容仅为作者学习、思考、经验、笔记的总结,仅供技术交流与参考。文中观点仅代表笔者个人思辨,不构成任何学术建议、商业建议或专业建议。所有数据来源已标注,引用时请以原始文献为准。
内容仅供学习参考。如需引用,请以原始文献为准。
全文约 12600 字 | 参考文献 60 篇(主要 8 篇)

