1. 从 Token 到决策:Jev 到底在解决什么问题
第一次看到“Jev:当 AI 不再生成 Token,而是直接做决策”这个标题,我脑子里蹦出来的第一个画面是:过去两年我们跟大模型打交道,本质上都在做一件事——猜下一个 Token。你问它“今天天气怎么样”,它一个字一个字往外蹦;你让它写代码,它也是一行一行往外吐。整个过程里,模型是个“文本生成器”,决策权始终在人手里:它给建议,你来拍板。
Jev 想干的事情不太一样。它把“生成 Token”这个动作往后放,把“做决策”提到前面来。换句话说,模型不再只是输出一段看起来合理的文字,而是直接给出一个可执行的动作、一个明确的选择、一个带状态的判断。这个转变听起来只是措辞上的差别,但落到工程实现上,是两套完全不同的架构。
我拿一个实际场景来说明。假设你有一个客服工单系统,用户提交了一条“我的订单三天没发货,我要退款”。传统 LLM 方案是:把工单内容塞进 prompt,让模型生成一段回复文本,比如“非常抱歉给您带来不便,我帮您查询一下……”。这段文本再交给人工或者规则引擎去判断下一步。而 Jev 这类决策型 Agent 的思路是:模型直接输出一个结构化决策,比如{"action": "query_order", "order_id": "12345", "next_step": "check_logistics"},系统拿到这个决策直接执行,不需要再经过“文本→解析→判断”的中间层。
这个差别为什么重要?因为Token 生成是有成本的,而且成本不低。你让模型生成 500 个 Token 的客套话,这 500 个 Token 里可能只有 20 个 Token 是有用的决策信息,剩下 480 个都是“语言润滑剂”。Jev 的核心主张就是把这层润滑剂砍掉,让模型直接输出决策信号。对于高频调用的 Agent 场景,这个优化带来的延迟下降和成本下降是实打实的。
那 Jev 适合谁?我觉得三类人最应该关注:一是正在做 Agent 开发的工程师,你们肯定被“模型输出格式不稳定”折磨过;二是做 LLM 应用落地的产品和技术负责人,你们关心的是怎么把 Token 成本压下来;三是对 AI 决策机制好奇的开发者,想搞清楚“不生成 Token 的模型”到底怎么工作。下面我按自己的理解,把这个事情拆开讲。
2. 核心机制拆解:Jev 是怎么绕过 Token 生成的
2.1 传统 LLM 的 Token 生成链路回顾
要理解 Jev 的改动,得先看清楚传统 LLM 在 Agent 场景里是怎么跑的。我画不了图,就用文字描述这条链路:
用户输入 → Prompt 拼接 → 模型前向计算 → 输出概率分布 → 采样得到 Token → 重复直到结束符 → 得到完整文本 → 后处理解析 → 提取决策 → 执行动作。
这条链路里,最耗时的环节是“重复直到结束符”。每生成一个 Token,模型都要做一次完整的前向计算。生成 200 个 Token 就是 200 次前向计算。虽然现在有 KV Cache 优化,但延迟依然跟输出长度成正比。更麻烦的是,Agent 场景往往需要多轮决策,每一轮都要走一遍这个链路,延迟叠加起来很可观。
还有一个隐藏问题:Token 生成是概率性的。模型输出“我建议您先查询订单状态”和“建议先查订单”是两个不同的 Token 序列,但语义几乎一样。你的后处理解析器得同时兼容这两种写法,否则就会解析失败。这就是为什么很多 Agent 项目里,Prompt 里要写一大堆“请严格按照 JSON 格式输出”,但模型还是时不时给你加个“好的,以下是 JSON:”。
2.2 Jev 的决策输出机制
Jev 的思路是:既然 Agent 最终只需要一个决策,那为什么还要让模型把决策“翻译”成自然语言再解析回来?直接在模型输出层做约束,让模型输出一个决策向量或者决策 ID 不就行了。
我理解的具体做法是这样的:模型在预训练或者微调阶段,除了学习 Token 预测,还学习一个“决策头”。这个决策头不输出词表上的概率分布,而是输出一个动作空间上的概率分布。动作空间是预先定义好的,比如[查询订单, 发起退款, 转人工, 结束会话]。模型看完输入后,直接在这个动作空间上做分类,选出概率最高的动作。
这跟传统 LLM 的区别在于:传统 LLM 的输出空间是词表,几万到几十万个 Token;Jev 的决策输出空间是动作集合,可能只有几十到几百个动作。输出空间小了,计算量自然就小了。而且输出是结构化的,不需要后处理解析,直接就能用。
我打个比方。传统 LLM 像是一个翻译官,你把中文需求给它,它先翻译成英文,你再找人把英文翻译回中文执行。Jev 像是一个直接听懂中文的助理,你说什么它直接做,不需要中间翻译环节。翻译环节少了,出错概率就低了,速度也快了。
2.3 决策空间的设计与约束
这里有个关键问题:决策空间怎么定?如果动作集合太小,模型能做的事情就有限;如果动作集合太大,又退化成 Token 生成了。
我看了下 Jev 相关的讨论,常见的做法是分层决策空间。第一层是粗粒度动作,比如“查询类”“修改类”“交互类”“结束类”。第二层是细粒度参数,比如查询类下面有“查订单”“查物流”“查账户”。模型先选粗粒度动作,再选细粒度参数。这样每一层的输出空间都可控,组合起来又能覆盖足够多的场景。
这种分层设计还有个好处:可以针对每一层单独做约束。比如查询类动作不允许修改数据,修改类动作必须带确认参数。这些约束可以在解码阶段直接屏蔽掉不合法的动作,而不是等模型输出文本后再用规则去拦。这就从“事后检查”变成了“事前约束”,可靠性高了一个档次。
注意:决策空间的设计不是一劳永逸的。业务变化了,动作集合要跟着变。所以 Jev 这类方案通常需要配套一个动作注册机制,让开发者能动态增删动作,而不是每次改动作都要重新训练模型。
3. 实操落地:怎么在现有项目里接入 Jev 思路
3.1 环境准备与依赖梳理
假设你现在有一个基于 LLM 的 Agent 项目,想试试 Jev 这种决策型方案。我的建议是不要一上来就推翻现有架构,而是先做一个“决策层替换”的试点。
你需要准备的东西不多:一个能跑推理的模型服务(可以是本地部署的,也可以是 API 调用的),一个动作注册表(用 JSON 或者 YAML 定义都行),一个决策执行器(根据模型输出的动作 ID 调用对应的业务函数)。如果你用的是 Python,我习惯用 Pydantic 来定义动作 schema,这样类型检查和序列化都省事了。
from pydantic import BaseModel from enum import Enum class ActionType(str, Enum): QUERY_ORDER = "query_order" QUERY_LOGISTICS = "query_logistics" INITIATE_REFUND = "initiate_refund" TRANSFER_HUMAN = "transfer_human" END_SESSION = "end_session" class Decision(BaseModel): action: ActionType order_id: str | None = None reason: str | None = None这个Decision模型就是 Jev 思路的落地形式。模型不需要生成一段话,只需要填这个结构。填完之后,你的执行器直接match decision.action就能分发。
3.2 动作注册表的定义与维护
动作注册表是 Jev 方案的核心配置文件。我一般会把它设计成三层结构:动作 ID、动作描述、参数 schema。动作描述是给模型看的,参数 schema 是给执行器用的。
actions: - id: query_order description: "根据订单号查询订单状态和基本信息" params: - name: order_id type: string required: true description: "订单编号,通常是数字或字母组合" - id: initiate_refund description: "对指定订单发起退款流程" params: - name: order_id type: string required: true - name: reason type: string required: false description: "退款原因,用于记录"维护这个表的时候有个经验:动作描述要写得像给新人看的操作手册,不要写得太抽象。比如“查询订单”不如“根据订单号查询订单状态和基本信息”来得清楚。模型对描述的理解越准确,选错动作的概率就越低。
3.3 决策解码与执行流程
接入 Jev 之后,你的 Agent 主循环会变成这样:
- 接收用户输入,拼接上下文。
- 调用模型,模型输出一个决策 ID 和参数。
- 校验参数是否完整、是否合法。
- 执行对应动作,拿到执行结果。
- 把执行结果作为新的上下文,进入下一轮决策。
- 直到模型输出
end_session或者达到最大轮次。
这个循环里,第 3 步的校验很关键。我踩过的坑是:模型有时候会输出一个不存在的动作 ID,或者参数类型不对。所以校验层要严格,不合法就直接打回让模型重新决策,而不是硬着头皮执行。
def execute_decision(decision: Decision, registry: dict): if decision.action not in registry: raise ValueError(f"未知动作: {decision.action}") action_def = registry[decision.action] for param in action_def["params"]: if param["required"] and not getattr(decision, param["name"], None): raise ValueError(f"缺少必填参数: {param['name']}") return registry[decision.action]["handler"](decision)这段代码看起来简单,但它是整个决策链路的守门员。守门员不靠谱,后面全乱套。
3.4 与传统 Token 方案的混合使用
完全抛弃 Token 生成也不现实。有些场景需要模型解释决策理由,或者需要生成一段面向用户的自然语言回复。我的做法是混合使用:决策走 Jev 通道,回复生成走传统 Token 通道。
比如用户问“为什么我的订单还没发货”,模型先输出决策query_logistics,执行器查到物流信息后,再把物流信息喂给模型,让模型生成一段自然语言解释。这样决策是结构化的,回复是自然的,两边的好处都占了。
提示:混合模式下,要控制好两个通道的调用顺序。先决策后生成,不要反过来。反过来会让模型先编一段话,再根据话去猜决策,那就本末倒置了。
4. 常见问题与排查技巧实录
4.1 模型选错动作怎么办
这是最常见的问题。模型选错动作,通常有三个原因:动作描述有歧义、上下文信息不足、模型本身能力不够。
排查顺序我一般是这样的:先看动作描述,把容易混淆的动作描述拿出来对比,看是不是描述太接近了。比如“查询订单”和“查询物流”,如果描述都写“查询相关信息”,模型肯定懵。把描述改清楚,大部分选错问题都能解决。
如果描述没问题,再看上下文。模型做决策需要足够的信息,如果用户说“帮我处理一下”,模型根本不知道处理什么。这时候要么让模型先输出一个“澄清”动作,要么在 Prompt 里补充更多上下文。
最后才考虑换模型。动作选择本质是个分类任务,分类任务对模型规模的要求没有生成任务那么高。一个小模型如果微调得当,在固定动作空间上的表现可能比大模型还好。
4.2 参数提取不完整怎么处理
模型选了正确的动作,但参数没填全,比如选了query_order但没给order_id。这种情况我一般分两步处理:先尝试从上下文里补全,补不全再让模型重新决策。
从上下文补全的逻辑可以写得很简单:如果用户上一句提到了订单号,就用正则提取出来填进去。如果上下文里没有,就返回一个“需要补充信息”的状态,让模型生成一个追问动作。
def fill_missing_params(decision, context): if decision.action == "query_order" and not decision.order_id: match = re.search(r"\b\d{6,}\b", context) if match: decision.order_id = match.group() return decision这个正则不一定通用,但思路是通用的:能自动补的就自动补,不能自动补的就追问,不要硬猜。硬猜的后果是执行了一个错误的动作,比不执行还糟糕。
4.3 决策循环陷入死胡同怎么跳出
Agent 决策循环有个经典问题:模型反复选同一个动作,或者两个动作来回跳。比如先查订单,发现没发货,又查订单,又发现没发货,无限循环。
我的解法是加一个状态指纹机制。每执行一个动作,就把动作 ID 和关键参数拼成一个字符串,存到一个集合里。如果下一轮决策生成的指纹已经在集合里,就强制中断循环,转人工或者返回兜底回复。
visited = set() def step(decision): fingerprint = f"{decision.action}:{decision.order_id}" if fingerprint in visited: return fallback_response() visited.add(fingerprint) return execute_decision(decision)这个机制简单但有效。我实测下来,加了状态指纹之后,死循环的概率从大概百分之几降到了几乎为零。
4.4 常见问题速查表
| 问题现象 | 可能原因 | 排查方向 | 解决建议 |
|---|---|---|---|
| 模型输出未知动作 ID | 动作注册表未同步 | 检查注册表版本 | 重新加载注册表,增加兜底动作 |
| 参数类型不匹配 | 模型输出格式漂移 | 检查 schema 定义 | 在解码层加类型强制转换 |
| 决策延迟高 | 动作空间过大 | 统计动作分布 | 分层决策,先粗后细 |
| 多轮对话后决策质量下降 | 上下文过长 | 检查上下文窗口 | 做上下文摘要,只保留关键信息 |
| 同一动作重复执行 | 缺少状态跟踪 | 检查循环控制逻辑 | 引入状态指纹机制 |
这张表是我在实际项目里慢慢攒出来的,基本上覆盖了八成以上的常见问题。遇到新问题的时候,先往表里对,对不上再单独排查。
5. 决策型 Agent 的边界与我的个人体会
Jev 这种“不生成 Token 直接做决策”的思路,听起来很美好,但也不是万能药。我自己的体会是,它最适合动作空间有限、决策频率高、对延迟敏感的场景。比如客服工单路由、游戏 NPC 行为选择、自动化运维的故障响应。这些场景里,动作就那么几十个,模型不需要发挥创造力,只需要选对动作。
反过来,如果场景需要大量自然语言生成,比如写文章、做翻译、生成代码,那 Token 生成还是绕不开的。你不可能让模型直接输出一个“写文章”的决策 ID,然后指望执行器把文章写出来。执行器没那个能力。
还有一个边界是动作空间的维护成本。动作越多,注册表越复杂,模型选错的概率也越高。我见过一个项目,动作空间膨胀到三百多个,模型选动作的准确率直接掉到六成以下。后来砍到八十个,准确率回到九成。所以动作空间不是越大越好,该合并的合并,该拆分的拆分,保持在一个模型能 hold 住的范围内。
最后分享一个我在实际接入时的小技巧:先用传统 Token 方案跑一遍全流程,把模型实际输出的决策文本收集起来,做聚类分析。你会发现,虽然模型每次输出的文本不一样,但语义上其实就那几类。这几类就是你动作空间的雏形。用真实数据反推动作空间,比拍脑袋定动作要靠谱得多。
这个思路后续还可以扩展。比如把决策日志存下来,定期做动作分布的漂移检测。如果某个动作的调用频率突然暴涨,可能是业务变了,也可能是模型出问题了。早发现早处理,比等用户投诉再排查要主动得多。