简介:大模型是概率模型而非确定性函数,直接用于生产会带来Token浪费与执行路径不可控两大痛点。本文提出“给河修渠”的工程思路:把流程顺序、数据格式、API调用与状态管理从模型推理中剥离,交由确定性程序接管,让Agent只做嵌入精密轨道中的决策引擎。读者将获得一套可复用的Skill分层设计方法、Schema约束手段与校验重试机制,从而把随机输出收敛为可预期结果。
先说结论:目标是把 Agent 当成一个算法来使用——给定输入,得到指定格式的输出。中间的推理过程不关心,但结果必须是确定、可预期的。
这个诉求听起来平平无奇,但与大语言模型的本质存在根本张力。LLM 是概率模型,不是函数。每一次调用都相当于在概率空间中采样:你能约束采样大致落在某个区域,却无法精确控制落点。在演示环境里这种柔性是优点,在生产环境里却会演化为两类真实痛点。
痛点一:Token 即成本,试错即浪费。 面对模糊需求,Agent 会反复揣摩、多轮试探、走到一半发现方向不对再折返,每一步都在消耗 Token。以”创建权限集”这类操作举例:若让 Agent 自行摸索流程,可能需要五轮对话才能做对;若有人替它把路径铺好,一轮即可完成。成本差距是数量级的。
痛点二:路径不确定,每次执行像开盲盒。 同一段提示词,换模型、换上下文顺序,输出可能截然不同。用户今天走通了,明天换个说法就翻车。这种不确定性在演示中可容忍,在生产中是灾难。
核心思路可以概括为一句话:不改变河的本性,但给它修好渠。 当 Agent 出错时,不急于归因于模型能力不足,而应先审视执行环境缺少了哪些关键因素。让 Agent 保留它最擅长的事——理解自然语言、做判断、组织表达;把所有确定性的事——流程顺序、数据格式、接口调用、状态管理——全部从它脑中取出,交给一个它触碰不到的确定性程序。
角色由此转变:Agent 不再是”什么都要自己想”的自由意志体,而是嵌入精密轨道中的决策引擎——输入是用户自然语言,输出是结构化参数,推理归它,推理之外的一切归轨道。
工程化的第一步是分层。把整个系统切成若干职责单一的层,让不确定性只存在于必要的那一层。
第一层:意图理解层。 由模型负责,把用户自然语言映射为结构化意图,例如识别出”用户想创建一个权限集,作用对象是某类资源,授权范围是只读”。这一层必须允许模糊,因为自然语言本身就是模糊的。
第二层:参数抽取层。 仍然由模型负责,但输出必须受 Schema 强约束,字段名、类型、枚举值全部预先定义。模型的任务从”自由发挥”收敛为”填空”。
第三层:流程编排层。 由确定性程序负责。步骤顺序、条件分支、依赖关系全部硬编码或用配置描述,模型无权改变执行次序。
第四层:执行与状态层。 由确定性程序负责接口调用、幂等控制、事务边界、重试与补偿。模型不接触凭证,也不感知状态机。
这样分层的收益是:模糊性被隔离在第一、二层,越往后越确定。第三、四层完全不依赖模型,可以像普通后端服务一样被测试、被监控、被回归。
Schema 是让概率模型逼近函数的关键手段。它至少发挥三重作用:约束输出形态、缩小采样空间、提供校验依据。
一个典型的工具调用参数 Schema 可以长这样:
{"name": "create_permission_set","parameters": {"type": "object","required": ["resource_type", "scope", "principal"],"properties": {"resource_type": { "type": "string", "enum": ["storage", "queue", "compute"] },"scope": { "type": "string", "enum": ["read_only", "read_write"] },"principal": { "type": "string", "pattern": "^[a-z0-9_-]{3,32}$" }},"additionalProperties": false}}
要点有四。其一,能枚举的字段一律用 enum,避免模型自造词。其二,禁止额外属性,防止模型”贴心地”多塞字段。其三,用正则与长度约束兜住明显非法值。其四,必填项明确列出,缺失即拒绝,而不是让模型猜。
Schema 之外还需一层语义校验:类型合法不代表业务合法,例如只读权限作用于某类资源可能业务上不允许。这类规则放在确定性程序中判断,失败时返回结构化错误码,而不是抛一句自然语言报错让模型自行消化。
即便有 Schema,模型仍会偶发输出不合规结果。工程上必须假设”一定会错”,并设计好错误处理路径。
推荐的做法是”校验—反馈—有限重试”闭环:确定性程序校验输出,失败时把结构化错误信息(哪个字段、什么原因、期望形态)回传给模型,要求其仅修正该字段后重试,重试次数设上限(通常两到三次)。超过上限则降级为向用户澄清或走人工兜底。
这个闭环有三个设计要点。第一,反馈必须结构化,避免把冗长的自然语言错误描述塞回上下文,反而增加噪声。第二,重试只允许修正局部字段,不允许推翻整体计划,防止模型借重试之名重新规划流程。第三,每次重试都要记录日志,便于事后统计哪类字段最容易出错,进而优化 Schema 或补充示例。
另一个常被忽视的点是幂等。重试意味着同一操作可能被执行多次,因此执行层必须为每个写操作设计幂等键,确保重复调用不产生副作用。这属于确定性程序的职责,不能寄望于模型自觉。
回到最初的判断:Agent 出错时,先问执行环境缺了什么。实践中常见缺失项有以下几类。
缺少流程知识。 模型不知道某类操作必须先申请资源再授权,于是顺序颠倒。解法是把流程固化为编排配置,模型只负责填参数。
缺少状态可见性。 模型不知道上一步是否成功,于是重复提交或跳过步骤。解法是由编排层维护状态机,把当前状态作为只读上下文注入,而非让模型自行推断。
缺少失败语义。 接口报错返回一段文本,模型理解偏差导致后续动作全错。解法是统一错误码体系,并在提示中附带错误码到处置建议的映射表。
缺少边界约束。 模型可能生成超出权限范围的操作。解法是在执行层做权限校验,模型无凭证,越权请求在轨道上直接被拦截。
这四类补齐之后,模型的职责被压缩到”理解与选择”,其余全部由轨道接管。系统整体表现随之从”随机可用”变为”稳定可预期”。
工程化不能只靠感觉,需要指标。建议至少跟踪四项:一次成功率(首轮即通过校验的比例)、平均重试次数、Token 消耗分布、人工兜底率。一次成功率上升、重试次数下降,说明 Schema 与流程设计在收敛;若某类字段长期高频出错,则应补充枚举或示例,而非反复调整提示词措辞。
迭代顺序也有讲究:优先修 Schema 与流程,其次补错误语义,最后才考虑换更大模型。多数”模型不够强”的抱怨,实际根源在环境缺失。
把 Agent 当算法用,本质是一次职责重划分:模型负责它擅长的模糊理解与判断,确定性程序负责它擅长的精确执行与状态管理。Schema 收敛输出空间,校验重试闭环兜住偶发错误,编排与执行层补齐流程、状态、失败语义与边界约束,度量指标则让工程化程度可观测、可迭代。
河还是那条河,但渠修好之后,水流的方向与落点就变得可预期了。