@dosco:ax 框架是一系列想法,有些是我自己的,很多来自他人,整合成一个 JS/TS 库,使得……
摘要
Ax 是一个 JS/TS 库,为 LLM 使用提供高层抽象(签名、智能体、工作流、优化器)。现在引入了 axIR,可以编译成 Python、Java、C++ 和 Go,将相同的编程模型带到多种语言中。
查看缓存全文
缓存时间: 2026/06/05 09:12
ax 框架是一套理念——其中一些是我自己的,许多来自他人——它们被整合成一个 js/ts 库,使得使用 LLM 变得简单且高效。但 ax 运行在比编程语言更高的抽象层级上;我一直坚信这一点,只是当初开始构建时 js/ts 更有趣。如今,代码应优先面向机器,其次才是人,因此我引入了 axIR——一种内部表示形式,它作为构成 ax 的诸多理念的更好基底。简而言之,ax 现在可以被编译成你选择的语言。首先,我们支持 C++、Java、JS/TS 和 Python。很快我们还将支持 Rust 和 Go。当我脱离 JS 环境时,总希望能像使用 ax 一样轻松地调用某些功能,现在我可以了——所有 ax 的功能,包括签名、LLM 抽象、带运行时的智能体、流程、GEPA 优化器,现在都随处可用。https://github.com/ax-llm/ax
ax-llm/ax
来源:https://github.com/ax-llm/ax
Ax — 适用于 TypeScript / Python / Java / C++ / Go 等的 DSPy
一套统一的编程模型,用于在 TypeScript、Python、Java、C++ 和 Go 中使用 LLM 进行构建。
Ax 以 TypeScript 优先,目前以 @ax-llm/ax 形式发布。相同的签名、提供者映射、智能体、流程、运行时约定和优化器也被编译成经过验证的 Python、Java、C++ 和 Go 库。Rust 是计划中的后端目标,而非独立的产品分支。
NPM (https://www.npmjs.com/package/@ax-llm/ax)
Discord (https://discord.gg/DSHg3dU7dW)
Twitter (https://twitter.com/dosco)
什么是 Ax
- 签名:用于类型化的结构化生成——支持字符串 DSL、流畅的
f()构建器或任意 Standard Schema v1 验证器(Zod、Valibot、ArkType)。 - 提供者抽象:支持 OpenAI 兼容端点、OpenAI Responses、Anthropic、Gemini、Grok/xAI、Mistral、Cohere、Reka、DeepSeek、Azure OpenAI、音频以及实时事件流。
- 智能体:具有运行时执行、上下文预算、检查点、操作日志回放、发现、记忆、技能和委派功能。
- 流程:类型化的程序图,支持分支、循环、反馈、缓存行为、并行执行以及
.returns(...)投影。 - 优化器:包括 GEPA、少样本引导(bootstrapping)、可移植的优化器产物以及评估/应用流程。
- 单一语义核心:编译为 TypeScript、Python、Java、C++ 和 Go 的库形态,使得相同的 Ax 程序模型能够在不同的运行时栈之间迁移。
语言矩阵
| 生态系统 | 包 / 导入 | 状态 |
|---|---|---|
| TypeScript / JavaScript | @ax-llm/ax import { ai, ax, agent, flow } from "@ax-llm/ax" | 已发布的 npm 包 |
| Python | axllm from axllm import ai, ax, agent, flow | 仓库中已生成并验证;准备上传至 PyPI |
| Java | dev.axllm:ax import dev.axllm.ax.* | 仓库中已生成并验证;准备上传至 Maven Central |
| C++ | axllm::axllm #include <axllm/axllm> | 仓库中已生成并验证;准备通过 CMake/GitHub Release 发布 |
| Go | github.com/ax-llm/ax/go import ax "github.com/ax-llm/ax/go" | 仓库中已生成并包含一致性检查,以及可选的 runtime/goja JavaScript 参与者运行时 |
| Rust | 待定 | 未来的生成后端 |
flowchart LR
S["Signature (string, f, Standard Schema)"] --> G["AxGen typed generation"]
G --> P["Provider descriptors / AI clients"]
G --> A["AxAgent"]
G --> F["AxFlow"]
G --> O["GEPA / optimizer artifacts"]
C["Shared Ax semantics"] --> TS["TypeScript"]
C --> PY["Python"]
C --> JV["Java"]
C --> CP["C++"]
C --> GO["Go"]
30 秒快速上手
TypeScript 包是源实现,也是当前已发布的包:
import { ai, ax } from "@ax-llm/ax";
const llm = ai({
name: "openai",
apiKey: process.env.OPENAI_APIKEY
});
const classify = ax(
'review:string -> sentiment:class "positive, negative, neutral"',
);
const { sentiment } = await classify.forward(llm, {
review: "This product is amazing!",
});
// sentiment: "positive" — 类型为字面量联合类型
无需提示工程。将 name: "openai" 切换为 "anthropic"、"google-gemini"、"mistral"、"deepseek"、"grok" 等——相同的签名,相同的代码。
每种语言中的相同理念
生成的 Python、Java、C++ 和 Go 库以原生包的形式公开相同的高层 Ax 概念。仓库构建脚本会在本地构建生成的包,并运行示例,无需你记忆编译器命令:
npm run example -- python signature_schema.py
npm run example -- java SignatureSchemaExample.java
npm run example -- cpp signature_schema.cpp
npm run example -- go signature_schema.go
可运行的示例请参见 src/examples/README.md,包/发布形态参见 docs/RELEASE.md,语言无关的 Ax 编译器工作原理参见 docs/COMPILER.md。
提供者原生速度
Ax 设计为在保持与直接调用提供者相同的延迟类别的同时,增加类型化输出、验证、重试、工具、追踪和记忆。热路径刻意保持轻量:渲染签名、调用提供者、解析结果、返回类型化值。
流式是默认行为,因为它能让 Ax 在模型完成之前做有用的工作:解析陆续到达的字段、执行流式断言、提前失败、取消正在进行的流、并开始修正,而无需在已经知道无效的输出上消耗 token。当你只想要最终对象时,forward() 仍然能提供一个;当你想要增量输出时,streamingForward() 可以直接暴露流。
仓库包含一个流式基准测试,用于检查你自己的提供者和模型的开销:
AX_STREAM_BENCH_PROVIDER=anthropic AX_STREAM_BENCH_MODEL=claude-sonnet-4-5-20250929 AX_STREAM_BENCH_RUNS=2 AX_STREAM_BENCH_WARMUP_RUNS=0 npm run tsx src/examples/streaming-latency.ts
AX_STREAM_BENCH_PROVIDER=google-gemini AX_STREAM_BENCH_MODEL=gemini-2.5-flash AX_STREAM_BENCH_RUNS=2 AX_STREAM_BENCH_WARMUP_RUNS=0 npm run tsx src/examples/streaming-latency.ts
最近在 Claude Haiku/Sonnet 和 Gemini Flash/Flash Lite 上运行的结果显示,提供者排队和模型生成主导了总延迟;AxGen 保持接近原始 ai.chat() 路径,同时提供了结构化输出的控制循环,而直接 SDK 调用则将此交给应用程序代码。
示例
结构化提取
const extract = ax(`
customerEmail:string, currentDate:datetime
->
priority:class "high, normal, low",
sentiment:class "positive, negative, neutral",
ticketNumber?:number,
nextSteps:string[],
estimatedResponseTime:string
`);
const result = await extract.forward(llm, {
customerEmail: "Order #12345 hasn't arrived. Need this resolved immediately!",
currentDate: new Date(),
});
使用 f() 构建嵌套对象
import { ax, f } from "@ax-llm/ax";
const productExtractor = f()
.input("productPage", f.string())
.output("product", f.object({
name: f.string(),
price: f.number(),
specs: f.object({
dimensions: f.object({
width: f.number(),
height: f.number()
}),
materials: f.array(f.string()),
}),
reviews: f.array(f.object({
rating: f.number(),
comment: f.string()
})),
}))
.build();
const gen = ax(productExtractor);
const { product } = await gen.forward(llm, { productPage: "..." });
// product.specs.dimensions.width 是端到端类型化的
Standard Schema v1 (Zod / Valibot / ArkType)
任何 Standard Schema v1 验证器都可以在 f.* 接受的任何位置使用——字段级别、整个对象级别,或 fn() 工具上。同样的重试管道,同样的类型推断,无需适配器。
import { z } from "zod";
import { ax, f, fn } from "@ax-llm/ax";
// (1) 逐字段 zod —— 可以与 f.* 字段自由混合
const reviewSentiment = ax(
f()
.input("productName", z.string().describe("Reviewed product"))
.input("reviewText", z.string().min(10))
.output("sentiment", z.enum(["positive", "neutral", "negative"]))
.output("score", z.number().min(1).max(10))
.output("keyPoints", z.array(z.string()))
.build(),
);
// (2) 整个对象 zod —— 声明一次,分解为有序字段
const productSummary = ax(
f()
.input(z.object({ productName: z.string(), buyerProfile: z.string() }))
.output(z.object({
headline: z.string(),
pros: z.array(z.string()),
cons: z.array(z.string()),
recommendation: z.enum(["buy", "wait", "skip"]),
}))
.build(),
);
// (3) 在 fn() 上使用整个对象 zod —— 类型化工具定义
const lookupProduct = fn("lookupProduct")
.description("Look up a product by name")
.arg(z.object({ productName: z.string().min(1), includeSpecs: z.boolean().optional() }))
.returns(z.object({ price: z.number(), inStock: z.boolean(), rating: z.number().min(1).max(5) }))
.handler(async ({ productName }) => ({
price: 79.99, inStock: true, rating: 4.3
}))
.build();
.min()、.max()、.email()、.url()、.regex() 会馈送给正常的重试管道;.refine()、.transform() 和 .superRefine() 在解析时对完整字段值执行,同时适用于流式和非流式。
缓存断点和内部推理字段使用配套选项:{ cache: true }、{ internal: true }。多模态输入(image、audio、file)仍然使用 f.*。
可运行示例:src/examples/standard-schema.ts。
工具 (ReAct)
const assistant = ax("question:string -> answer:string", {
functions: [
{ name: "getCurrentWeather", func: weatherAPI },
{ name: "searchNews", func: newsAPI },
],
});
const { answer } = await assistant.forward(llm, {
question: "What's the weather in Tokyo and any news about it?",
});
多模态
const analyze = ax(`
image:image, question:string
->
description:string,
mainColors:string[],
category:class "electronics, clothing, food, other",
estimatedPrice:string
`);
音频
批量语音 API 由 AI 服务暴露:ai.transcribe({ audio }) 将音频转为文本,ai.speak({ text }) 将文本转为音频产物。签名中的音频输出是编排好的产物:模型为 speech:audio 编写文本,然后 Ax 在解析后合成它。
const say = ax("question:string -> speech:audio, summary:string");
const res = await say.forward(llm, {
question: "Greet the team."
}, {
speech: { speak: { voice: "alloy", format: "mp3" } },
});
console.log(res.speech.data); // base64 编码的音频
console.log(res.speech.transcript); // 生成的脚本
智能体在规划器/执行器/响应器阶段之前转写 :audio 输入,因此工具和记忆接收的是稳定的文本,而非 base64 负载。原生的对话音频仍然可以通过 .chat() 使用。
OpenAI 支持基于请求的音频聊天(gpt-audio、gpt-audio-mini)以及实时语音/转录模型(gpt-realtime-2、gpt-realtime-whisper)。Gemini 原生音频在相同的 .chat() 形态下使用 Live API;Grok Voice 使用实时语音端点。
import WebSocket from "ws";
import {
ai,
axAIOpenAIRealtimeDefaultConfig,
axAIOpenAIRealtimeTranscriptionDefaultConfig,
} from "@ax-llm/ax";
const voice = ai({
name: "openai",
apiKey: process.env.OPENAI_APIKEY!,
config: axAIOpenAIRealtimeDefaultConfig(), // gpt-realtime-2
});
const stream = await voice.chat(
{ chatPrompt: [{ role: "user", content: "Say hello out loud." }] },
{ stream: true, webSocket: WebSocket }
);
for await (const chunk of stream) {
const audio = chunk.results[0]?.audio;
if (audio?.isDelta) {
// base64 pcm16 音频字节
process.stdout.write(".");
}
}
const transcriber = ai({
name: "openai",
apiKey: process.env.OPENAI_APIKEY!,
config: axAIOpenAIRealtimeTranscriptionDefaultConfig(), // gpt-realtime-whisper
});
可运行示例:src/examples/audio-chat.ts 实时流式传输音频,保存 WAV 文件,并在有本地播放器时播放。src/examples/audio-batch-and-agent.ts 在 src/examples/output/ 下写入生成的 MP3 产物并立即播放。
AxAgent
AxAgent 是一个三阶段管道,它将签名转化为一个长期运行的、使用工具的参与者。每次 forward() 调用执行:蒸馏器(Distiller) → 执行器(Executor) → 响应器(Responder)。
flowchart LR
IN["inputs"] --> D["Distiller"]
D --> E["Executor (RLM loop)"]
E --> RT["AxJSRuntime sandbox"]
E --> FN["functions / child agents"]
E --> M["recall - memories"]
E --> SK["consult - skills"]
E --> RES["Responder"]
RES --> OUT["typed output"]
import { agent, AxJSRuntime } from "@ax-llm/ax";
const analyzer = agent(
"context:string, query:string -> answer:string, evidence:string[]",
{
agentIdentity: {
name: "documentAnalyzer",
description: "Analyze long documents with iterative code + sub-queries",
},
contextFields: ["context"],
runtime: new AxJSRuntime(),
maxTurns: 20,
maxRuntimeChars: 2_000,
contextPolicy: { preset: "checkpointed", budget: "balanced" },
executorOptions: { model: "gpt-4o-mini" },
},
);
const result = await analyzer.forward(llm, {
context: veryLongDocument,
query: "What are the main arguments and supporting evidence?",
});
递归运行时(RLM) 将长上下文保持在根提示之外:执行器在持久的沙箱会话中运行 JS,通过 llmQuery(...) 子调用缩小上下文范围,并使用检查点回放,使较早的回合折叠为摘要,而不是无限制地增长提示。
可运行示例:src/examples/rlm-agent-controlled.ts、src/examples/rlm-discovery.ts。
上下文映射、记忆、技能、沙箱运行时
agent(...) 上的四个正交选项。根据任务需要选择启用。
上下文映射(Context map) —— 一个小的持久化定位缓存,用于在相同长上下文上重复提问。配置后,Ax 会将其展示给蒸馏器,并在每次成功完成的运行后更新它。默认情况下,映射会持续演化;设置 infiniteEvolve: false 和映射对象上的 evolveSteps 进行有限预热,然后重用冻结的映射。使用 onUpdate 将新的快照保存到你的应用存储状态的任何地方。
import { agent, AxAgentContextMap } from "@ax-llm/ax";
const map = new AxAgentContextMap(savedSnapshot, {
maxChars: 4000,
infiniteEvolve: false,
evolveSteps: 10,
});
const analyzer = agent("context:string, query:string -> answer:string", {
contextFields: ["context"],
contextMap: {
map,
onUpdate: ({ map }) => saveSnapshot(map.snapshot()),
},
});
记忆(Memories) —— 向量 / BM25 / KV 查找,参与者通过 await recall([...]) 控制。结果会出现在 inputs.memories 上供下一轮使用。生命周期为一次 .forward() 调用;要跨调用持久化,需在外部保存。
const myAgent = agent("task:string -> plan:string", {
onMemoriesSearch: async (searches, alreadyLoaded) => {
const skip = new Set(alreadyLoaded.map((m) => m.id));
return (await myVectorDB.searchBatch(searches, { topK: 3 }))
.filter((m) => !skip.has(m.id));
},
onUsedMemories: (results) => console.log("[memories]", results.map((r) => r.id)),
});
技能(Skills) —— 指南 / 运行手册主体,参与者通过 await consult([...]) 按需拉取。加载的技能会在执行器系统提示中显示为“已加载技能”,并在 .forward() 调用间持久化。
const myAgent = agent("task:string -> plan:string", {
onSkillsSearch: async (searches) =>
mySkillStore.searchBatch(searches, { topK: 2 }),
// 或者静态预加载——无需 consult():
skills: [
{ name: "release-checklist", content: "1. Bump version\n2. ..." },
],
});
沙箱 JS 运行时(Sandboxed JS runtime) —— AxJSRuntime 是默认运行时;默认开启强化,并可跨 Node、Bun(smol: true 工作线程)、Deno 和浏览器移植。能力通过权限选择启用。
import { AxJSRuntime, AxJSRuntimePermission } from "@ax-llm/ax";
const runtime = new AxJSRuntime({
permissions: [AxJSRuntimePermission.NETWORK], // 仅授予 fetch 权限
});
默认设置:import() 被阻止,内置对象被冻结,ShadowRealm 被锁定,工作线程 IPC 被锁定,并且在 Node 20+ 上,操作系统权限模型会自动作为第二道防线启用。仅在任务需要时添加 FILESYSTEM、STORAGE、CHILD_PROCESS 等。
安全模型:该运行时是针对 LLM 生成的代码的纵深防御,而不是协
相似文章
@dosco:使用 perplexity、parallel、Google、X 搜索等,用 DSPy+RLM(ax-agent)在 5 分钟内构建此功能 http://axllm.…
Ax 是一个开源 TypeScript 库,实现了 DSPy 风格的类型化签名和代理框架,用于以最少的提示词构建可靠的 AI 应用。它支持多个 LLM 提供商,并包含代理、流程、RAG 和自优化管道等功能。
@dosco: PEEK 即将登陆 ax-agent https://github.com/ax-llm/ax
PEEK 功能即将登陆 ax-agent,这是一个用于自动生成提示词和构建 AI 智能体的 TypeScript 库,支持多种提供商。
Axol
Axol 是一款旨在自动化物理工作的机器人,为自动化提供强大的解决方案。
@tom_doerr: 在隔离的 git worktrees 中编排 AI 代理 https://github.com/txtx/axel-app
Axel 是一款 macOS 应用,配有 Rust CLI,可在隔离的 git worktrees 和 tmux panes 中编排 AI 代理,为多代理工作流提供任务管理界面。
@almond_robotics: 宣布推出 Axol:一款专为物理AI团队设计的双臂机器人。美国制造。Axol 为构建者而生…
Almond Robotics 宣布推出 Axol,一款专为物理AI团队设计的双臂机器人,在美国制造,强调实际应用和开放性。