web.rest.aiDecision 是纯 aardio 的 AI 结构化决策客户端,目前实现 OpenRouter 的 POST /api/alpha/decisions 协议。
web.rest.aiChat 面向生成式聊天;web.rest.aiDecision 面向结构化判定、分类和评分。两者按能力命名,本库不继承聊天协议。inception/mercury-decide,优先面向中文任务。 微软说明其由 Qwen3.5-9B 后训练而来;中文质量仍应以自己的业务样本评估,不能仅凭基础模型推断所有任务的准确率。~typesafe/jev-latest)仅作为兼容选择。按现有使用反馈,Jev 中文支持较差,不推荐用于中文任务;本库不自动回退到 Jev。~/lib/web/rest/aiDecision.aardio。~/docs/library/web/rest/aiDecision/index.md;alpha,应保留原始响应并按服务端实际支持的字段使用,不保证未来版本不变。import web.rest.aiDecision;
var client = web.rest.aiDecision({
// 省略 key 时读取环境变量 AI_DECISION_API_KEY。
// 也可以指定 key = "你的 OpenRouter API Key",不要分发真实密钥。
model = "inception/mercury-decide";
});
if(!#client.config.key){
print("请先设置环境变量 AI_DECISION_API_KEY,或在客户端配置中填写自己的 key。");
return;
}
var questions = {
department = ["choice", "这条工单应由哪个团队处理?", {
["财务"] = "付款、发票和退款问题";
["技术"] = "软件故障、服务中断和系统集成问题";
["销售"] = "价格咨询、套餐升级和购买意向";
["其他"] = "不属于以上类别或信息不足";
}];
urgent = ["noul", "这条工单是否需要立即处理?"];
severity = ["score", "当前问题对业务造成的影响有多严重?", [
"轻微影响,主要功能正常",
"部分功能受影响,业务仍可继续",
"核心业务完全中断,无法继续工作"
]];
};
var result,err,errCode = client.evaluate({
state = {
message = "生产系统从今天早上起完全无法登录,所有员工都无法开展工作,请立即修复!";
};
questions = questions;
});
if(!result){
print("请求失败:",err,errCode);
return;
}
print("实际模型:",result.model);
print("负责团队:",result.answers.department.choice);
print("需要立即处理的概率:",result.answers.urgent.noul);
print("业务影响评分(0~2):",result.answers.severity.score);
print("输入、输出用量:",result.usage.input_tokens,result.usage.output_tokens);
后面的代码片段沿用这里的 client。协议字段、类型名与程序标识符保留原样,待判断内容、问题说明、选项和输出提示均使用中文。
questions 是按问题 ID 命名的表,每项可使用以下两种数据形式,并允许混用:
[type, instructions, criteria]。noul 通常只需前两项;choice 的第 3 项为选项到说明的映射表,score 的第 3 项为从低到高的等级数组。{type="noul";instructions="是否紧急?"}。需要自解释字段名或额外协议字段时优先使用。例如,同一请求中可以混用:
var questions = {
urgent = ["noul", "这条工单是否需要立即处理?"];
department = {
type = "choice";
instructions = "这条工单应由哪个团队处理?";
criteria = {
["财务"] = "付款、发票和退款问题";
["技术"] = "软件故障、服务中断和系统集成问题";
["销售"] = "价格咨询、套餐升级和购买意向";
["其他"] = "不属于以上类别或信息不足";
};
};
outage = {type="noul";instructions="当前核心业务是否完全中断?";criteria={
["true"] = "无法继续开展核心业务";
["false"] = "核心业务仍然可以继续";
}};
};
声明只是数据,不会请求模型。 evaluate(包括其别名)调用 buildPayload 时,才将问题的纯数组 [] 转换为接口要求的对象。不要把数组简写直接传给底层 post。
仅转换 questions 的直接成员;不转换 state 中的数组、choice 选项说明或 score 等级数组。不修改调用者的声明,原生问题对象中的扩展字段会保留。数组简写必须有 2~3 项且前两项为字符串,否则 buildPayload / evaluate 返回 null,err,不会发送请求;其他协议约束由服务端检查。
noul.criteria 可省略;指定时使用字符串键 "true" 与 "false",不要改为中文键或布尔键。它们的说明可以是中文。需要结构化 instructions 或服务支持的扩展字段时,使用原生问题对象;数组简写仍要求前两项为字符串。
(state, questions[, model])var result = client.evaluate(
"同一订单扣了两次款,请退回重复扣款。",
{
refund = ["noul", "客户是否要求退回款项?"];
team = ["choice", "这条工单应由哪个团队处理?", {
["财务"] = "付款和退款问题";
["客服"] = "一般使用咨询或其他问题";
}];
}
);
var result = client.evaluate({
state = "这笔付款是正常消费,不需要退款,只想补开发票。";
model = "inception/mercury-decide";
questions = {
refund = {type="noul";instructions="客户是否要求退回款项?"};
};
session_id = "中文工单演示";
});
完整请求表保留 state、显式指定的 model 和其他扩展字段;省略 model 时补充客户端默认值。questions 同样支持原生对象和数组简写,发送前统一为对象形式。
var client = web.rest.aiDecision({
// key = "你的 OpenRouter API Key";
url = "https://openrouter.ai/api/alpha/decisions";
model = "inception/mercury-decide";
extraHeaders = {
["HTTP-Referer"] = "https://example.com";
};
});
key 字段则改用环境变量 AI_DECISION_API_KEYurl 字段则改用环境变量 AI_DECISION_API_URL 或者 https://openrouter.ai/api/alpha/decisionsmodel 字段则改用环境变量 AI_DECISION_API_MODEL;两者都未指定时,OpenRouter 端点默认使用 inception/mercury-decide。自定义服务不会自动注入这个模型 ID,应显式指定该服务支持的模型。model → 调用参数 model → 客户端配置。客户端配置的优先级:构造参数 → 环境变量 → OpenRouter 默认值。url 是完整端点,不是基础地址。本库不会自动拼接 /api/v1 或 /chat/completions,也不会因模型名称变化自动切换协议。extraHeaders、extraParameters、extraUrlParameters、proxy、proxyBypass、httpFlags 等 web.rest 配置。客户端不把决策答案转换成文本,也不按厂商重新包装,返回值保持 OpenRouter 原始结构:
result.answers[id].typeresult.answers[id].noul,回答“是”的概率,范围为 0 到 1;0 是合法结果,接近 0.5 表示不确定,不是“中等严重”。choice 是选中的选项键,可直接是中文;probabilities 是各选项概率,confidence 描述分布集中程度,不代表保证正确。score 是概率加权的位置,可能为小数,不是统一的 0~1 概率,也不是 aardio 数组下标。 OpenRouter 上的决策模型遵循相同的评分结构。legend 将 "0"、"1" 等字符串键映射回等级说明;probabilities 同样按字符串键读取。不能用小数 score 直接索引数组。probabilities、confidence、legend 标为可选字段,跨模型使用时应先检查它们是否存在,不能因为某次响应包含这些字段就假定永远存在。result.model 为实际服务该请求的模型版本;result.provider 是可选的服务商标识。result.usage.input_tokens 与 result.usage.output_tokens 为用量,result.usage.cost 为可选的美元费用。不同模型的分词器及用量统计可能不同,不按固定输出 token 数判断协议兼容性。也可以使用:
var answer = client.answer(result,"department");
var probability = client.noulValue(result,"urgent");
读取答案时,缺失问题或类型不符应进入错误处理/人工复核,不要当作“否”或安全放行。特别注意 aardio 中 0 是假值,判断数值是否缺失应使用 ===null,不要使用 if(!probability)。
model / state / questions 请求结构,三类问题仍是 noul / choice / score。切换这两个模型不需要修改问题协议,不能把 OpenRouter 的协议与厂商直连接口混为一谈。provider、session_id、trace、user 等字段;原生问题对象与响应中的扩展字段也会保留。透传字段不等于服务端一定支持,实际能力由目标模型和端点决定。state 可为字符串、对象或数组;只提供判断所需上下文。问题之间相互独立,同一请求中的问题不能读取彼此的答案;有依赖关系时应分成多次调用。GET https://openrouter.ai/api/v1/models?output_modalities=decisions 查询当前可用模型,而不是依靠固定厂商清单。选择模型还要核对上下文、输入模态、费用和业务效果。url 就能通用。choice / noul / score 已做少量真实接口验证;这验证了调用链与返回结构,并不构成中文能力的全面评测。模型更新或切换后,应使用包含明确正反例、否定句、模糊与无关输入的业务数据重新评估阈值。~typesafe/jev-latest 仅供兼容旧配置;它是可能随版本变化的别名,且中文支持较差。生产使用应记录响应中的实际 model,若服务提供可调用的固定版本,则可固定版本并验证业务效果。null,err[,errCode];数组简写错误属于本地错误,不产生新的 HTTP 请求,lastStatusCode 可能仍保留上次请求状态。不要将它误认为本次本地错误的 HTTP 状态。