Jev框架提出用Dot-and-Index路径和上下文隔离解决生产环境LLM的上下文腐烂、提示注入等问题,构建可靠的子100ms决策循环。
如果你正在构建生产级 AI 系统,你很可能遇到了一堵令人沮丧的墙。你的提示词经过精心设计,检索增强生成(RAG)管道运行正常,但面对复杂的、多租户数据载荷时,模型仍然会产生幻觉、偏离主题,或给出严重校准不足的回答。
问题不在于你的提示词。问题在于你的状态架构。
在早期的教程中,向 AI 模型传入单个客户消息或简短的交易字符串可以无缝工作。但生产系统处理的不是单句话,而是包含订单、用户、历史消息、策略、功能开关和潜在工作流状态的大规模 JSON 投影。
如果你把状态当作一个被动的"输入载荷"而不是一个严格的、可遍历的 API 契约,你就是在让应用程序面临上下文腐化、提示词注入和统计稀释的风险。
理论基础:状态即 API 契约
要使用 Jev 构建可靠的、亚 100 毫秒决策循环,你需要理解 System One 架构的基本不对称性:状态是共享的,但问题是隔离的。
当你向 Jev 提交请求时,你传递一个单一的状态对象以及一组独立的问题。每个问题并行地针对相同的状态进行评估。没有一个问题能看到另一个问题的答案。状态是信息流动的唯一通道。
正因为如此,状态不是一个中性的容器。它是每一种判断行走的领域。
DOM 和文件系统类比
把状态对象想象成前端开发中的文档对象模型(DOM)。你不会通过将页面的原始文本倾倒到一个黑箱中来与网页交互;你通过使用 CSS 选择器的结构化、可寻址树来与它交互。
Jev 状态的工作原理完全相同。当你写一个针对 ticket.messages[0].text 的问题时,你是在写一个选择器。你在通过命名键和数字索引遍历来描述一个结构化对象的绝对路径。
类似地,想象一个文件系统路径如 /var/log/nginx/access.log。层次结构编码了语义和访问模型。像 order.charges[0].status 这样的路径会迫使模型的注意力聚焦。它告诉读者——在任何一字节的推理发生之前——这个查询是关于一笔扣款,是列表中的第一笔扣款,我们问的是它的状态,而不是时间戳或金额。
路径特异性与推理成本成反比。路径越完整地指定其目标,模型需要猜测的就越少,其概率分布就越集中在正确答案周围。
这里演示的概念和代码直接来自我的电子书 Jev: The Definitive Guide to System One AI。另请查看 9 卷合集:TypeScript AI & Agentic Engineer Masterclass
浅层状态与模式设计原则
设计状态模式时,必须平衡三个相互竞争的优先级:路径清晰度、更新局部性和上下文隔离。
保持路径浅层:像 workflow.stages[2].steps[5].outputs.results[0].data.amount 这样深层嵌套的结构会迫使模型维持过多的认知参考框架。这增加了遍历成本,降低了置信度分数,并扩大了概率分布。目标是最多三到四层深度。
为不可变更新而设计:在实时应用中,状态持续变化。如果你在原地变更状态对象,diff 变得不可能,迫使你不必要地重新运行昂贵的查询。通过使用结构共享实现不可变更新,只有状态树的修改分支被替换。这使状态 diff 变得微不足道,并让你的缓存层决定哪些问题族实际需要重新评估。
强制严格隔离:Jev 容易受到提示词注入和对抗性内容的影响,如果恶意文本与可信的系统逻辑混合在同一个命名空间中。隔离必须在模型运行之前、在状态模式层面强制执行。在良好作用域的状态中,未被引用的内容充当中性的背景上下文,而不是污染活跃目标。
生产级 Jev 系统解剖
让我们看一个完整的端到端 TypeScript 程序,它将这些理论基础付诸实践。这个账单分诊示例处理嵌套的 JSON 状态,在单个并行请求中评估三种原始类型(noul、choice 和 score),并完全在代码中组合最终的业务逻辑。
// src/lib/triage.ts
import { TypeSafeClient, choice, noul, score } from "@typesafe-ai/sdk";
/**
* One per-process client. Reads `TYPESAFE_API_KEY` from the environment
* and defaults to `jev-latest`. Reuse this object across requests so
* the connection pool and retry policy stay warm.
*/
const client = new TypeSafeClient();
/**
* The `state` is the single blob of evidence the model reads to answer
* every question. Paths *inside* this object are the addressing surface
* that the questions point at, using backticked dot-and-index
* expressions such as `ticket.messages[0].text`.
*/
const state = {
ticket: {
id: "T-1042",
messages: [
{
from: "customer",
text: "I was charged twice for order A-104. Please refund the duplicate.",
},
{
from: "support",
text: "We are checking the charges.",
},
],
},
order: {
id: "A-104",
charges: [
{ amount_usd: 49, status: "captured" },
{ amount_usd: 49, status: "captured" },
],
},
refund_policy: "Duplicate charges are eligible for a refund.",
};
/**
* Every question is defined statically. The keys (`refund_requested`,
* `department`, etc.) are what the answers are keyed by in the response.
*/
const questions = {
refund_requested: noul(
"Does `ticket.messages[0].text` request a refund?",
),
duplicate_charge: noul(
"Do `order.charges[0].amount_usd` and `order.charges[1].amount_usd` match?",
),
policy_supports_refund: noul(
"Given `refund_policy`, does it support the request in `ticket.messages[0].text`?",
),
department: choice("Which team should handle `ticket.messages[0].text`?", {
billing: "Payment or subscription issues",
technical: "Bugs or integration problems",
sales: "Pricing or account questions",
}),
frustration: score(
"How frustrated is the customer in `ticket.messages[0].text`?",
[
"Calm and factual",
"Frustrated but civil",
"Very angry, strong language",
],
),
};
/**
* Orchestrates one triage pass in a single systemOne call.
*/
export async function triage(): Promise<void> {
const result = await client.systemOne({ state, questions });
const refund = result.answers.refund_requested.noul;
const duplicate = result.answers.duplicate_charge.noul;
const policy = result.answers.policy_supports_refund.noul;
const department = result.answers.department.choice;
const frustration = result.answers.frustration.score;
// Compose independent judgments into a deterministic business rule in code.
const shouldAutoRefund =
refund >= 0.8 && duplicate >= 0.8 && policy >= 0.8;
console.log({
department,
frustration,
shouldAutoRefund,
probabilities: result.answers.department.probabilities,
confidence: result.answers.department.confidence,
});
}
triage().catch(console.error);
逐行解析程序
在模块级别构造一次 TypeSafeClient() 而不是在处理函数内部构造是至关重要的。重用客户端实例可以保持你的 TLS 设置、重试书签和 keep-alive 连接池处于热状态,防止热请求路径中的延迟峰值。
注意问题指令如何用反引号包裹路径:`ticket.messages[0].text`。这不是单纯的格式;而是对模型的形式指令。它指示 Jev 将该标记视为结构坐标而非通用文本。省略反引号会导致路径解析不一致,以及当周围文本恰好匹配模式中的关键字时出现脆弱行为。
noul:返回一个介于 0 和 1 之间的校准浮点数,表示封闭的二元概率。
choice:返回一个与你标准键匹配的类型化联合类型,以及完整的概率分布和置信度指标。这允许你检查候选答案并将模糊情况路由到人工审核队列。
score:评估有序的标准列表并返回概率加权的平均分数,捕捉细微差别和梯度,而不是强制严格的二元类别。
注意决策逻辑的位置:完全在 TypeScript 代码中(refund >= 0.8 && duplicate >= 0.8 && policy >= 0.8)。模型的工作仅限于在精确坐标上评估归一化证据。你的代码负责将这些校准后的输出应用于业务阈值。
当扩展到处理数万个请求的多租户架构时,简单的 JSON 载荷已经不够。你需要物理检索隔离、路径渲染工具以及请求级状态管理。
下面是一个高级架构,利用 Node 的 AsyncLocalStorage 来保证并发租户操作永远不会交叉污染,同时整合了 Pinecone 向量搜索与 Jev 状态投影的服务器动作。
File 1 — 状态形状与选择器(lib/jev/state-shape.ts)
export type PathSeg = string | number;
export type StatePath = readonly PathSeg[];
export function renderPath(path: StatePath): string {
return path.reduce(
(acc, seg) =>
typeof seg === "number"
? acc[{acc}[acc[{acc}[{seg}] : acc ? acc.{acc}.acc. {seg} : seg),
"",
);
}
export const cite = (path: StatePath): string => \${renderPath(path)}``;
export function getAt(root: unknown, path: StatePath): unknown {
let node: unknown = root;
for (const seg of path) {
if (node === null || node === undefined) return undefined;
node = (node as Record)[seg];
}
return node;
}
export function setAt<T>(root: T, path: StatePath, value: unknown): T {
if (path.length === 0) return value as T;
const [head, ...rest] = path;
if (Array.isArray(root)) {
const copy = root.slice();
copy[head as number] = setAt(copy[head as number], rest, value);
return copy as unknown as T;
}
const base = (root ?? {}) as Record<string, unknown>;
return { ...base, [head]: setAt(base[head], rest, value) } as T;
}
export interface Candidate {
rank: number;
id: string;
similarity: number;
ageDays: number;
sourceType: "policy" | "contract" | "kb" | "forum";
title: string;
passage: string;
}
export interface ShapedState {
fastPath: {
entitlements: {
plan: "free" | "pro" | "enterprise";
allowsAutoReply: boolean;
};
routing: {
autoReplyFloor: number;
escalateBelow: number;
injectionCeiling: number;
};
};
task: {
question: string;
locale: string;
channel: "email" | "chat" | "api";
};
evidence: {
index: string;
namespace: string;
topK: number;
candidates: Candidate[];
};
derived: {
candidateCount: number;
maxSimilarity: number;
totalPassageChars: number;
hasPolicySource: boolean;
};
}
export function project(state: ShapedState): Record<string, unknown> {
return {
task: state.task,
evidence: state.evidence,
derived: state.derived,
};
}
File 2 — 请求级隔离(lib/jev/scope.ts)
import { AsyncLocalStorage } from "node:async_hooks";
import { setAt, getAt, type ShapedState, type StatePath } from "./state-shape";
export const vectorNamespace = (tenantId: string): string => `tenant:${tenantId}`;
export interface ScopeHandle {
readonly tenantId: string;
readonly requestId: string;
readonly state: ShapedState;
commit(path: StatePath, value: unknown): void;
at<T>(path: StatePath): T;
}
const storage = new AsyncLocalStorage<string, ScopeHandle>();
export function withScope<T>(
init: {
tenantId: string;
requestId: string;
fastPath: ShapedState["fastPath"];
},
fn: (scope: ScopeHandle) => Promise<T>,
): Promise<T> {
let state: ShapedState = {
fastPath: init.fastPath,
task: { question: "", locale: "en", channel: "api" },
evidence: { index: "", namespace: vectorNamespace(init.tenantId), topK: 0, candidates: [] },
derived: { candidateCount: 0, maxSimilarity: 0, totalPassageChars: 0, hasPolicySource: false },
} as ShapedState;
const handle: ScopeHandle = {
tenantId: init.tenantId,
requestId: init.requestId,
get state() { return state; },
commit(path, value) {
state = setAt(state, path, value);
},
at<T>(path: StatePath) {
return getAt(state, path) as T;
},
};
return storage.run(handle, () => fn(handle));
}
export function currentScope(): ScopeHandle {
const scope = storage.getStore();
if (!scope) throw new Error("No Jev scope open: call withScope() at the request boundary.");
return scope;
}
File 3 — 服务器动作(app/actions/answer-from-evidence.ts)
"use server";
import { Pinecone } from "@pinecone-database/pinecone";
import { choice, noul, score, RateLimitError, TypeSafeClient } from "@typesafe-ai/sdk";
import { passagePath, project, type Candidate } from "@/lib/jev/state-shape";
import { vectorNamespace, withScope } from "@/lib/jev/scope";
const JEV_MODEL = "jev-1.13.0";
const TOP_K = 12;
const INJECTION_SCAN_K = 6;
const jev = new TypeSafeClient({
apiKey: process.env.TYPESAFE_API_KEY!,
defaultModel: JEV_MODEL,
timeout: 4_000,
});
const pinecone = new Pinecone({ apiKey: process.env.PINECONE_API_KEY! });
const index = pinecone.index(process.env.PINECONE_INDEX!);
export async function answerFromEvidence(input: {
tenantId: string;
requestId: string;
question: string;
locale: string;
channel: "email" | "chat" | "api";
plan: "free" | "pro" | "enterprise";
}) {
return withScope(
{
tenantId: input.tenantId,
requestId: input.requestId,
fastPath: {
entitlements: {
plan: input.plan,
allowsAutoReply: input.plan !== "free",
},
routing: {
autoReplyFloor: 0.85,
escalateBelow: 0.55,
injectionCeiling: 0.7,
},
},
},
async (scope) => {
// 1. 在租户的物理命名空间中检索
const vector = [0.1]; // Mock embedding vector
const { matches } = await index
.namespace(vectorNamespace(scope.tenantId))
.query({ vector, topK: TOP_K, includeMetadata: true });
// 2. 塑形并预计算标量,使 Jev 从不做算术运算
const now = Date.now();
const candidates: Candidate[] = matches.map((m, i) => ({
rank: i + 1,
id: String(m.id),
similarity: Number((m.score ?? 0).toFixed(4)),
ageDays: 2,
sourceType: "kb",
title: "Sample Doc",
passage: String(m.metadata?.text ?? "").slice(0, 1_200),
}));
scope.commit(["task"], { question: input.question, locale: input.locale, channel: input.channel });
scope.commit(["evidence"], { index: "idx", namespace: vectorNamespace(scope.tenantId), topK: TOP_K, candidates });
// 3. 构建针对精确路径的问题
const core = {
best_passage: choice(
`Which passage in \`evidence.candidates\` states the answer to \`task.question\`?`,
{ ...Object.fromEntries(candidates.map((c) => [c.id, null])), none: "No matching passage." }
),
evidence_sufficient: noul(
`Do the passages in \`evidence.candidates\` contain everything needed to answer \`task.question\`?`
),
};
const questions = { ...core };
// 4. 执行单一并行调用
const result = await jev.systemOne({
state: project(scope.state),
questions,
model: JEV_MODEL,
});
return {
success: true,
answers: result.answers,
};
},
);
}
忘记反引号:写路径时如 ticket.messages[0].text 不加反引号,会迫使模型猜测你是在写代码还是自然语言,导致置信度大幅下降。始终用反引号包裹路径。
在循环中提问或请求:永远不要在单独的问题或不同票据的循环内调用 systemOne。将问题批量放入单一状态载荷,使用 Promise.all() 展开票据请求。
将数学运算委托给模型:Jev 是一个推理引擎,不是计算器。不要让模型计数数组项、比较日期或求账单总额。在 TypeScript 代码中预计算这些值,作为标量字段传入状态。
租户隔离失败:依赖查询过滤字符串({ tenantId: currentTenant })会使数据库暴露于人为错误。使用物理存储命名空间(如 Pinecone 命名空间)和 AsyncLocalStorage 在基础设施层面强制执行隔离。
状态塑形本质上是 API 设计。当你将 Jev 状态对象视为结构化、可寻址的契约而非混乱的字符串转储时,一切都改变了。
通过保持路径扁平、在代码中预计算标量、强制请求级隔离,以及将问题指向精确坐标路径,你将 LLM 输出从概率赌博转化为可靠的高性能工程原语。正确构建你的地形,模型每次都会给出清晰、校准的答案。