判断型Agent Skill:用类型安全契约锁死大模型输出

发布时间:2026/10/22 14:06:49

判断型Agent Skill:用类型安全契约锁死大模型输出 从“大模型会写”到“大模型会判”这中间的工程化距离比大多数人想象的要远。最近我在一个某跨平台系统里做了一个判断型Agent Skill全程没有让它生成任何长文本只输出结构化的判断结果用TypeSafe契约把输出牢牢锁死。做下来最直观的感受就是当你不再需要模型“写作文”而是只让它“填表格”的时候整个系统的稳定性、可观测性和成本控制都会变得完全不一样。这篇文章就针对这个模拟项目X的实际落地过程聊清楚三件事为什么判断型任务不应该走生成式路线、TypeSafe Agent Skill的设计思路是什么、以及真实接入时那些文档里不会写的坑。1. 项目定位与需求拆解1.1 为什么“只做判断”的任务不该让模型“生成文本”判断型任务在业务里太常见了一条用户反馈进来到底属于“投诉”还是“咨询”一篇社区帖子该“推荐”还是“隐藏”一张工单该路由给“技术团队”还是“财务团队”这些任务的共同点是输出空间有限答案不是从几十个字里选一个就是从几个固定标签里挑一个。这类任务如果直接用生成式模型去回答天然存在三个问题。第一是成本浪费。模型生成“这是一个咨询类问题用户主要想了解退款流程……”这种句式可能消耗几百个token但业务方真正关心的只是末尾那个“咨询”标签。为了一个单词付了作文的钱。第二是延迟不可控。生成式模式需要逐token解码输出越长耗时越长。放在实时链路里每多一秒都可能直接影响用户体验。第三是解析可靠性问题。就算你告诉模型“只输出JSON”模型偶尔也会给出意料之外的字段名、多余的注释、甚至一段自然语言解释。而判断型业务最忌讳的就是“不可解析”——下游系统没法用。所以“不生成文本只做精准判断”不是一种技术风格的偏好而是这类业务场景的硬约束。判断类任务的本质是分类、决策、路由输入一个上下文输出一个有限集合内的元素这跟“生成一段话”是完全不同的技术路线。1.2 需求指标的量化定义与成功标准项目一开始为了避免各方对“精准”的理解不一致我们把成功标准拆成了可量化的指标指标目标值说明判断准确率不低于95%以人工复核结果为基准单次调用P95延迟小于2秒从请求发出到拿到结构化结果解析失败率小于1%返回结果无法通过Schema校验的比例单次调用成本控制在较小模型档位输出token数限制在100以内判断可解释性每条理由不超过30字让人工审核能快速理解判断依据这组指标后面几乎贯穿了所有技术决策。比如“输出token数限制在100以内”这条直接决定了Skill的输出Schema要设计得足够精简“解析失败率小于1%”这条则逼着我们引入运行时校验、重试和兜底策略。1.3 边界梳理明确“不做什么”比“做什么”更重要这个项目里最容易失控的地方不是判断本身而是判断之外的生成冲动。模型天生话多你让它判断一条投诉是否成立它总想顺便给你解释一下投诉背景、分析一下用户情绪、再给点改进建议。所以项目从一开始就划了一条清清楚楚的边界线Skill只输出三个字段——decision判断结论、confidence置信度、reason短理由。除此之外一个字都不准多出。另外边界还包括对“不确定”的处理。我们专门设计了一个unknown逃逸类型当模型对输入内容把握不足时允许它输出unknown而不是强行在有限分类里挑一个。这个设计在后面解决很多误判问题时起到了关键作用。2. 方案选型与TypeSafe设计思路2.1 选型对比从规则引擎到TypeSafe Skill判断型任务的实现方案其实不少项目组把候选方案都摆到桌面上对比过方案优点缺点关键词规则引擎零模型成本、响应快、可解释性强规则维护成本高、召回率低、语义泛化差传统文本分类模型精度较高、推理快需要大量标注数据训练、新类别扩展困难通用LLM直接生成文本回答上手快、无需训练输出不可控、解析困难、成本延迟都高LLM JSON模式输出输出半结构化、比纯文本好解析缺少业务级类型校验错误字段名没法拦截TypeSafe Agent Skill结构化输出 运行时校验 可重试兜底需要一定的工程改造量最终选择TypeSafe Agent Skill核心原因是它把“LLM的泛化能力”和“工程上对稳定性的要求”做了最好的结合。规则引擎的问题是太脆换一种说法就漏判传统分类模型的问题是太死新增一个类别就要重新训练而纯LLM方案的问题是太飘输出质量完全靠运气。2.2 类型安全到底在解决什么问题很多人在第一次听说“TypeSafe Agent Skill”时会把它等同于“让模型输出JSON”。这个理解不够完整。JSON模式解决的只是“格式”问题而类型安全解决的是“契约”问题。打个比方JSON模式像是要求对方把答案写在纸上但没告诉对方纸上必须有哪些栏目、每个栏目填什么格式类型安全则是先把表格的栏目标好——这栏只能填“投诉/咨询/建议/其他”这栏必须是0到1之间的数字这栏最多30个字——然后才让模型往里面填。在TypeScript生态里这个“表格”就是用Schema来定义的。工程上既可以用Zod声明运行时校验规则也可以从Schema推导出静态类型让编辑器在编译期就帮你检查字段拼写错误。两端都锁死之后模型输出哪怕稍有偏离也能在第一时间被拦截而不是带着脏数据继续往下游传。2.3 Skill的输入输出契约设计这个Skill的核心契约我们花了一下午反复推敲最终定下来的版本很克制输入侧只需要三样东西待判断的文本内容、所属业务场景、以及该用户的最近交互次数。输出侧则严格遵守判断型设计的“极简原则”一个枚举类型的决策、一个置信度、一句不超过30字的理由。这里有个关键的设计决策为什么要把“业务场景”作为输入字段因为同一句话在不同场景下判断结论可能完全不同。比如“我的订单怎么还没到”这句话放在order场景是要查物流放在complaint场景可能就是投诉物流慢。把场景作为显式输入等于提前帮模型限定了解读范围判断准确率会显著提升。输出契约里为什么要有confidence因为下游系统需要根据置信度决定动作高置信度直接自动处理低置信度转人工复核。没有这个字段你就只能靠猜决定什么时候信任模型。3. 接入实操与工程落地3.1 用Zod定义判断契约编译期和运行时双双锁死项目使用TypeScript作为主语言Schema选型直接用Zod。选择Zod的理由很朴素既能做运行时校验又能顺便推导出TypeScript类型一份定义同时干两件事。import { z } from zod; // 输入契约判断任务需要什么上下文 const JudgmentInputSchema z.object({ content: z.string().min(1).max(2000), scene: z.enum([order, comment, ticket, complain]), recentInteractionCount: z.number().int().min(0).max(100).default(0), }); // 输出契约模型只能填这些字段 const JudgmentResultSchema z.object({ decision: z.enum([approve, reject, review, unknown]), reason: z.string().max(30), confidence: z.number().min(0).max(1), }); export type JudgmentInput z.infertypeof JudgmentInputSchema; export type JudgmentResult z.infertypeof JudgmentResultSchema;注意这里decision的枚举值只设了四个approve、reject、review、unknown。这是刻意控制的分类粒度越粗模型判断越稳定。等线上数据积累到一定量级再考虑细分也不迟。3.2 Skill注册与调用链路实现在Agent框架里Skill被定义为可复用的能力单元。这个判断Skill的Handler实现思路如下const judgeSkill skillRegistry.register(content_judge, { inputSchema: JudgmentInputSchema, outputSchema: JudgmentResultSchema, async handler(input: JudgmentInput): PromiseJudgmentResult { // 第一层输入校验防止脏数据进入模型 const parsedInput JudgmentInputSchema.parse(input); // 第二层调用模型强制JSON模式输出 const response await llm.complete({ prompt: buildJudgePrompt(parsedInput), temperature: 0, maxTokens: 100, jsonMode: true, }); // 第三层解析并执行运行时校验 const raw JSON.parse(response.text); // 第四层失败自动修复与重试 for (let attempt 0; attempt 2; attempt) { try { return JudgmentResultSchema.parse(raw); } catch (err) { if (attempt 1) { const repairPrompt buildRepairPrompt(raw, err.message); const retry await llm.complete({ prompt: repairPrompt, temperature: 0, maxTokens: 100, jsonMode: true }); return JudgmentResultSchema.parse(JSON.parse(retry.text)); } // 二次失败直接落入unknown兜底绝不阻塞业务 return { decision: unknown, reason: 模型输出多次校验失败, confidence: 0 }; } } }, });这段链路里有几个不容忽视的细节。超时控制必须放在Handler外层模型接口P95在2秒以下超时就直接走兜底避免拖垮链路。maxTokens限制在100既是成本约束也是对模型的“物理提示”——别啰嗦。温度固定为0排除随机采样带来的无谓波动。重试次数上限设为2次不给无限重试的机会防止一次故障演变成成本风暴。3.3 Prompt工程怎么让模型只填表不废话同样的Schema不同的Prompt写法效果天差地别。这个项目踩了几次坑之后总结出一套稳定可复用的Prompt结构。系统提示词部分要达成三个目标明确任务边界、限制输出形式、提供判断锚点。const buildJudgePrompt (input: JudgmentInput): string { return 你是一个严谨的内容判断引擎。你不生成分析文章你只判断。 输入内容${input.content} 业务场景${input.scene} 用户近期交互次数${input.recentInteractionCount} 判断规则 - 输出JSON对象只包含三个字段decision、reason、confidence - decision只能是以下四个值之一approve、reject、review、unknown - reason是一句不超过30个字的判断理由 - confidence是0到1之间的数字表示你对判断的把握程度 - 当内容明显超出判断范围或信息不足时输出unknown 输出示例 {decision: approve, reason: 内容合规无明显违规, confidence: 0.95} ; };这里最后那个输出示例非常重要。不带示例的Prompt模型很容易在格式上自由发挥带了一个明确示例之后模型会把示例当作格式模板来模仿结构化输出成功率大大提高。实操中还有一个细节值得分享示例里的decision值不要全部堆在一个类目上。尽量覆盖所有枚举值至少在示例中把approve、reject、review、unknown各出现一次。这样模型对每个类别的边界会有一个更均衡的感知不会出现“只学到了一两种判断”的情况。3.4 在线监控、灰度放量与人工兜底Skill上线不是锁死就算完事还需要一套完整的监控和护栏机制。核心监控指标包括这五个指标监控方式告警阈值判断准确率抽样人工复核比对低于93%告警P95延迟全量请求日志统计大于2秒告警解析失败率Schema校验失败次数统计大于1%告警置信度分布全量输出置信度可视化低置信占比过高告警成本消耗按token用量统计单日成本超预算告警灰度放量的策略很简单先在内部测试集上跑一遍离线评估准确率达标后再切1%线上流量观察两三天逐步放大到5%、20%、50%、100%。每一步放量之前都会人工抽看最近样本确认没有出现系统性偏差。人工兜底机制围绕confidence展开。线上规则是置信度大于等于0.95的结果直接自动处理0.8到0.95之间进入半自动确认流程低于0.8则进入人工复核队列。unknown结果则一律由人工处理。这套机制保证了模型拿不准的时候系统不会自作主张。4. 常见问题与排查技巧实录4.1 同一条输入判断结果不稳定这个坑几乎是所有上线过Agent判断类服务的团队都会遇到的。明明temperature设成了0为什么同一条输入在不同时间调用结果还是不一样实际排查中主要找三个原因。第一是模型版本变动平台经常默默升级模型你的判断逻辑可能被新版本“带偏”。第二是上游文本的隐形变化比如同一句话前后多了空格、特殊字符。第三是输入长度截断行为不同。解法是三层保障模型版本锁定到固定快照至少在主要链路上不要自动跟随最新版每次发版前用固定回归集跑一遍全量比对回归集至少包含1000条典型样本和200条边界样本输入文本做标准化预处理去除不可见字符干扰。4.2 Schema校验失败引发的“重试风暴”上线初期我们遇到过一种连锁故障模型偶尔返回的JSON不符合Schema触发重试重试仍然失败继续触发下一次重试在模型响应较慢的高峰期积压任务把并发通道直接打满。排查下来是重试策略设计得不严谨。无脑重试完全是负优化失败的时候模型大概率还是会失败只会白白增加成本和延迟。修正后的策略有几个关键点。重试次数硬性封顶为2次。第一次失败后把校验错误信息拼进Prompt让模型知道“你上次的回复缺了decision字段请补全后重新输出”这是有效的“错误反馈重试”。第二次失败就不再纠缠直接返回unknown兜底结果保证主流程不被阻断。4.3 模型自报置信度与真实准确率不匹配运营同学很快发现一个奇怪现象模型对几乎每条判断都给出0.98以上的置信度但人工复核下来真实准确率只有92%。如果完全相信模型的自信兜底机制就等于虚设。这里需要理解一个底层事实大模型输出的置信度本质上是对其自身token概率分布的某种映射并不等同于真实世界里的概率统计。它“自信”不代表它“正确”。校正思路是把模型置信度当作一维特征而不是最终答案。做法很简单线上跑了几天之后抽取每个置信度区间内的样本做人工复核统计得到一条“模型置信度—真实准确率”的对照校准表。然后将这条校准表映射成业务层的真实置信度阈值。简单说模型说0.98不可信但结合校准表后0.98意味着真实准确率可能在93%这时候要不要自动处理业务方可以重新拍板。4.4 延迟与成本优化从3秒压到1秒以内的实操最初版本上线时P95延迟超过3秒单次调用的model档位也偏高成本对不住收益。优化的路径很直接从四个方向层层收口第一模型档位降级。判断任务复杂度远低于生成任务换成一个更小、更快的模型来跑实测准确率只降了不到2个百分点但延迟直接砍半。这个实验告诉我们判断类任务往往是被大材小用了。第二输入裁剪。原始输入最长允许2000字但很多内容有效信息集中在前500字于是做成按场景动态截断大幅减少输入token。第三增加相似度缓存。对完全相同的输入直接命中缓存返回结果省掉一次模型调用。判断型任务高度适合这个优化因为同样的投诉文本、同样的工单内容可能在短时间内反复出现。第四并发控制。控制同时打向模型的并发数量防止模型端超时连锁。整套优化做完P95延迟降到接近1秒单次成本下降超过一半。缓存键的设计这里提一个小细节缓存键里一定要包含schema版本号和模型版本号否则Schema升级之后旧缓存结果可能直接污染新链路。最后再分享一个我在项目收尾后特别有感的体会判断型Agent的工程难度不在“让模型会判断”而在“让模型只能判断”。TypeSafe Skill的核心价值不是把输出限定在一个JSON结构里而是逼你在一开始就把业务边界、输出契约、失败兜底全部想清楚。你永远没办法让大模型百分百稳定但你可以通过契约设计让每一次不稳定都被拦截在业务主流程之外不造成伤害。如果你也在做类似的判断型Skill接入我建议从最小的Schema开始四个枚举值、一句短理由、一个置信度先用起来再根据真实数据逐步放宽。契约收得越紧工程上能做的事就越多这句话在Agent领域里至少目前还是成立的。
延伸阅读

更多相关文章

2026/10/22 14:06:49

大模型幻觉防御指南:防御性提示与事实校验的落地实践

前几天我在调一个文档问答机器人,用户问了一句“这个系统支持的最大并发数是多少”,模型给了一串看起来很专业的数字和参数。我翻了一下原始需求文档,里面根本没写过这个指标——那串数字是模型自己编的。 这正是大模型最常见也最难防的问题…

2026/10/22 14:01:46

C++算法模板库实战指南:线段树、FFT与图论模板的封装与避坑

简介:一套面向竞赛编程的算法模板库,适合算法竞赛选手、考研与面试准备者,以及需要在复杂场景下快速实现高效算法的开发者。库内按专题系统组织,覆盖基础算法、数学算法、数据结构与图论四大板块:基础部分包含双指针、…

2026/10/22 14:01:46

文档型数据库安全认证实战:从账号密码到角色权限与内部认证

1. 为什么数据库认证不是“可选项”而是“必答题”很多刚接触文档型数据库的朋友,第一次把服务跑起来的时候,往往只关心一件事:能不能连上、能不能读写。默认配置下,本地起一个实例,端口一开,客户端一连&am…

2026/10/22 15:22:43

三端分离:SSM+Android+Vue养老院管理系统源码实战拆解

简介:基于Java SSM、Vue和Android的养老院管理系统源码包,适合毕业设计、课程实训、全栈开发练习或养老机构信息化改造参考。项目以Spring容器管理事务,SpringMVC处理请求分发,MyBatis简化数据持久化,Vue构建响应式后台…

2026/10/22 15:22:43

Win32滚动条消息机制详解:从通知码到SCROLLINFO实战

接手过一个纯Win32写的文本查看器项目,数据量从几千行涨到几万行之后,滚动区域开始变得卡顿,滑块也拖不利索。排查到最后,问题全出在滚动条消息的处理上——要么是通知码理解有偏差,要么是SCROLLINFO结构体参数没对齐。…

2026/10/22 15:22:43

计算机网络物理层复习:从考点地图到高频题型解题全攻略

如果你正在为计算机网络物理层这一章的复习发愁,觉得公式多、概念碎、题目一做就错,那这篇专门为你准备的解题复习篇应该能帮上忙。 物理层是计算机网络的“最底层”,也是最容易被轻视的一章。很多人把它当背诵内容来复习,结果一…

2026/10/22 15:22:43

Harness不是工具而是系统确定性治理方法论

1. “Harness”不是新热词,而是被误读的工程基建名词最近在多个技术社区和协作平台里,频繁看到有人把“Harness”当作某个新兴工具、框架甚至网络梗来讨论。比如在某次跨团队需求评审会上,有同事直接问:“这个功能能不能用Harness…

2026/10/22 15:12:16

手写UTF-8编解码器:从编码规则到边界测试的完整实现

UTF-8编码这块,说实话是个典型的“看着简单、写起来全是坑”的活儿。网上能搜到一大堆实现,真到自己动手,要处理非法序列、边界码点、代理区的时候,才知道水有多深。我这次在某个内部项目里需要处理一批用户昵称数据,要…

2026/10/22 11:29:28

金融AI落地指南:从调研报告到技术选型与工程实践

简介:这份PDF报告聚焦2025年金融服务业中国AI现状与趋势,面向金融科技从业者、AI战略规划人员及关注行业数字化转型的研究者,帮助读者把握生成式AI在银行、支付、交易等场景中的落地路径与投资方向。资源包内含1个PDF文件,大小约1…

2026/10/22 0:01:49

电商智能运营体系从0到1:架构设计、落地步骤与避坑指南

前两年我们团队接了一个电商平台的运营中台项目,目标很直白:把过去靠运营拍脑袋做的选品、定价、发券、推活动这些事,逐步用数据算法和自动化流程代替。项目名字内部就叫“电商智能运营体系”。最近有不少朋友问我当时是怎么设计的、踩过哪些…

2026/10/22 0:01:49

若依框架AI代码生成不稳定?用Agent Skill三层结构+五步法搞定

最近一段时间,我一直想把后台管理系统里那些机械重复的增删改查代码交给AI去写。框架用的是若依,按理说这类业务代码模式非常固定,应该是AI最擅长的事情。可真试下来却不是那么回事——你让AI生成一个用户管理模块,它给出的Contro…

还想了解更多?直接咨询顾问

免费诊断 + 免费方案 + 透明报价。

全国咨询热线400-8866-253
免费获取方案
☎咨询二维码 ☎ ↑