// 检验自己用的小 Jev 客户端(任务书 12 第四部分第 6 条):不经 src/jev,也不改它。 // 请求格式参照 src/jev/jev.ts 和 RivalBits research-wiki/参考-Jev使用指南.md 第二部分: // POST {model, state, questions},回答里 answers.<问题名>.noul 是 0 到 1 的概率。 // 检验的问题都没有校准过阈值,一律以概率大于 0.5 判"是",原始概率照存(任务书 12 第 5.2 节)。 const ENDPOINT = "https://api.typesafe.ai/v1/systemone"; /** 检验用的 Jev 模型名,和研究配置的 models.jev 同一个。 */ export const JEV_MODEL = "jev-latest"; export const THRESHOLD = 0.5; export const THRESHOLD_NOTE = "阈值未校准:一律以概率大于 0.5 判\"是\""; /** 一条是非题,写法照 src/jev/questions.ts:问题、关注点、判"是"判"否"的说明和反例。 */ export interface Noul { type: "noul"; instructions: { question: string; focus: string }; criteria: { true: { what: string; examples: string[] }; false: { what: string; not_for: string; examples: string[] }; }; } export interface Answer { question: string; probability: number; yes: boolean; requestId: string; } /** 调不通时重试前等多久:只重试连不上、超时、429 和 5xx(原因在我们控制之外),一共最多 4 次。 */ const RETRY_WAITS_MS = [2_000, 10_000, 30_000]; /** 就一份材料问几问,一次请求。 */ export async function ask(state: Record, questions: Record): Promise { const key = process.env["TYPESAFE_API_KEY"]; if (key === undefined || key.trim() === "") throw new Error("环境变量 TYPESAFE_API_KEY 没有设置"); const body = JSON.stringify({ model: JEV_MODEL, state, questions }); const failures: string[] = []; for (let attempt = 0; attempt <= RETRY_WAITS_MS.length; attempt++) { if (attempt > 0) await new Promise((ok) => setTimeout(ok, RETRY_WAITS_MS[attempt - 1])); let response: Response; let text: string; try { response = await fetch(ENDPOINT, { method: "POST", headers: { "content-type": "application/json", authorization: `Bearer ${key}` }, body, signal: AbortSignal.timeout(60_000), }); text = await response.text(); } catch (error) { failures.push((error as Error).message); continue; } const requestId = response.headers.get("x-typesafe-request-id") ?? "无"; if (!response.ok) { const what = `HTTP ${response.status}(request-id: ${requestId}):${text.slice(0, 300)}`; if (response.status !== 429 && response.status < 500) throw new Error(`Jev 拒绝了请求:${what}`); failures.push(what); continue; } const answers = (JSON.parse(text) as { answers?: Record }).answers; return Object.keys(questions).map((question) => { const probability = answers?.[question]?.noul; if (typeof probability !== "number" || !(probability >= 0 && probability <= 1)) { throw new Error(`Jev 的回答里问题 ${question} 没有 0 到 1 之间的概率(request-id: ${requestId}):${text.slice(0, 300)}`); } return { question, probability, yes: probability > THRESHOLD, requestId }; }); } throw new Error(`Jev 调不通,发了 ${failures.length} 次:${failures.join(";")}`); }