内容
# 合成核心
[](https://github.com/Abick91/synthcore/tags)
[](LICENSE)
[](package.json)
[](package.json)
**基于库学习和归纳编程合成的JavaScript/TypeScript工具,无需大型语言模型(LLM)或图形处理器(GPU)。**
提供输入-输出示例,`synthcore` 返回一个**已验证的函数**(或 `{ok:false}`)。它永远不会凭空捏造:它只返回一个通过所有示例的程序。零边际成本,确定性,可审计,离线。
```ts
import { synthesize } from "synthcore";
const r = await synthesize([
{ input: '{"email":"a@b.com"}', output: "a@b.com" },
{ input: '{"email":"c@d.com"}', output: "c@d.com" },
{ input: '{"email":"e@f.com"}', output: "e@f.com" },
]);
if (r.ok) {
console.log(r.recipe); // "get(parseJSON(arg0),\"email\")" ← 真实的配方,已验证
console.log(r.code); // 一个独立的 `solve` 函数,通过 3 个示例
}
```
`r` 是 `{ ok:true, code, recipe, size, entry, ast }` 或 `{ ok:false, reason }`。`code` 是一个可以直接运行的 JavaScript 函数;`recipe` 是其可读形式;`ast` 是 recipe 的树状结构(由 `learn()` 消费);`reason` ∈ `"bad_input" | "not_found" | "unverified"`。
## 它解决了什么 / 它不能解决什么
有界领域特定语言(DSL)上的枚举搜索:它在**小型的可组合转换**上表现出色,适用于数字、字符串、数组和 JSON。它不是通用的代码生成。
| ✅ 今日解决问题(在 demo/tests 中验证) | ❌ 今日超出范围 |
|---|---|
| 标量算术 — `double` → `add(arg0,arg0)` | 大型程序 / 应用逻辑(它不会编写应用程序) |
| 字符串 — `reverse` → `rev(arg0)`,`UPPERCASE` → `upper(arg0)` | 过滤 / 去重:`filter`/`unique` 组合子缺失 |
| JSON 解析 — `JSON 字段` → `get(parseJSON(arg0),"email")` | 任意递归(例如斐波那契数列)/ 深度结构 |
| 列表缩减 — `sum` → `sum(arg0)`,`average` → `idiv(sum(arg0),len(arg0))` | 具有深递归或回溯的算法 |
| 列表 — `sort` → `sort(arg0)`,`max` → `max(arg0)`,`map`/`zipWith` | 依赖外部状态或 I/O 的转换 |
| 日期/数字/正则表达式通过 **可选** 的 `std` 包 — `year` → `year(arg0)`,`"$1,234.50"` → `num(arg0)` | 大型多步骤程序(枚举预算) |
对于右侧,路径是**种子化基元**(`extraPrims`,例如由 LLM 提出)或提高搜索预算 — 这不是一道墙,而是一道会移动的前沿。
## 用例
Synthcore 在您拥有**小型、可重复转换**的**示例**,并且需要**保证正确、廉价且离线**时表现出色 — 而不是一个可能仍需要测试的似是而非的猜测:
- **大规模数据清理 / ETL.** 标准化一个杂乱的列(`"$1,234.50"` → `1234.5`),然后在**零每次调用成本**、离线(无数据离开您的机器)情况下,将其应用于数百万行。[编译为 Python](#多语言输出-编译为-python) 以适用于您的管道。
- **终结您将要搜索的正则表达式.** 通过示例而不是模式提取字段(`"ERR-404: not found"` → `"404"`)。您描述的是**什么**,而不是**如何**。
- **模式映射 / API 粘合剂.** 将“他们的有效载荷 → 您的有效载荷”的示例转换为已验证的提取器;提交它,在 CI 中运行它,循环中没有外部 API。
- **从数据中恢复精确的公式.** 已验证的符号回归(`½mv²`,`pH`)用于单位转换、定价规则和离散律 — 精确的,而不是近似的。
- **用于代理的已验证工具.** 通过 [MCP](#从代理-mcp-使用),LLM 可以为 Synthcore 调用一个**保证**转换,而不是凭空捏造一个。
## 工作原理
- **自顶向下类型搜索**,基于组合子的 DSL(n 元应用、`map`、`fold`、`zipWith`、常量),具有**观测等价性剪枝**(按输出向量去重)→ 指数级剪枝使其变得可行。
- **确定性验证**,在**强化**的子进程中(无 `env`、内存上限、临时 `cwd`、超时硬杀),只有通过所有示例的代码才会被返回。
- **库学习**(wake/sleep,DreamCoder/LILO 风格):挖掘循环的子程序,将它们概括为**抽象**,按压缩(MDL)排名并重用 → 以相同的预算解决更深层次的问题。
- **可选的 LLM 混合**:当纯合成失败时,LLM 提出一个**新的基元**(`extraPrims`);引擎验证它,如果它解锁了解决方案,则免费重新组合它。LLM 引入了罕见的、昂贵的位;引擎确定性地重新组合并在 $0。
## API
```ts
synthesize(examples, opts?) → Promise<{ ok:true, code, recipe, size, entry, ast } | { ok:false, reason }>
```
- `examples`:`{ input, output }` | `{ in, out }` | `{ args:[...], expect }` 的列表。数组 `input` 是一个**列表**参数(不是变参)。至少推荐 **3–5** 个示例。
- `opts`:`{ entry?, tools?, rounds?, maxEvals?, extraPrims?, std?, verify? }`。
### 丰富的类型(可选):日期,文本中的数字,正则表达式
标准基元不在基本 DSL 中 — 它们扩大搜索并增加过拟合风险 — 因此它们通过 `{ std: true }`(或传递 `extraPrims: stdPrims`)启用:
```ts
await synthesize([{ input: "2024-03-15", output: 2024 }, /* … */], { std: true }); // → year(arg0)
await synthesize([{ input: "$1,234.50", output: 1234.5 }, /* … */], { std: true }); // → num(arg0)
```
`stdPrims` = `datePrims`(`year`/`month`/`day`/`weekday`,UTC)+ `numberPrims`(`num`/`digits`)+ `regexPrims`(`regexExtract`/`regexMatch`)。
### 科学领域包(可选):物理和化学定律
物理和化学定律作为可注入的基元(`physicsPrims`、`chemPrims` 或两者通过 `sciencePrims`)提供。给出数据,它恢复**精确**的定律 — 已验证的符号回归,如 PySR/Eureqa,但具有精确保证而不是最小化误差:
```ts
import { synthesize, physicsPrims, chemPrims } from "synthcore";
await synthesize([{ args: [2, 3], expect: 9 }, { args: [4, 5], expect: 50 }, /* … */],
{ extraPrims: physicsPrims }); // → kinetic(arg0,arg1) (½·m·v²)
await synthesize([{ input: 0.01, output: 2 }, { input: 0.001, output: 3 }, /* … */],
{ extraPrims: chemPrims }); // → pH(arg0) (-log₁₀[H⁺])
```
诚实的前沿:对于**噪声**实验数据,使用 PySR(它最小化误差);对于**精确**转换(离散律、单位转换、恒等式),Synthcore 胜出(精确验证)。注意引擎只在轮次中组合 arity-1/2 基元,因此 arity-3 定律(例如 `idealGasP` = `nRT/V`)仅在任务本身具有该 arity 时合成。
### 多语言输出:编译为 Python
引擎合成了一个与语言无关的 AST(`Recipe`);`synthesize` 将其降低为 JavaScript,而 `emitPython` 将相同的已验证 AST 降低为独立的 Python — 无需额外搜索,只需一个输出阶段:
```ts
import { synthesize, emitPython } from "synthcore";
const r = await synthesize([{ input: [1, 2, 3], output: 6 }, { input: [10, 20], output: 30 }]);
if (r.ok) emitPython(r.ast); // → "def solve(*a):\n return sum(a[0])"
```
传递与 `synthesize` 相同的 `tools`/`extraPrims`/`std`。只有我们维护的基础 DSL 和包(`std`,领域)可以编译;学习到的抽象或任意注入的 `extraPrim`(原始 JavaScript)抛出一个明确的错误,而不是发出不正确的代码。
### 学习一个随使用而增长的库
`learn()` 从已经找到的解决方案中挖掘可重用的抽象(DreamCoder/LILO,MDL 排名)。将它们作为 `tools` 传回,引擎以相同的预算解决更深层次的问题。`serializeLibrary` / `loadLibrary` 在会话之间持久化它们(纯 JSON):
```ts
const r1 = await synthesize(examplesA);
const r2 = await synthesize(examplesB);
const lib = await learn([r1, r2]); // 挖掘已验证的抽象
const r3 = await synthesize(examplesC, { tools: lib.tools }); // 重用已学习的内容
const json = serializeLibrary(lib.tools); // 持久化
const tools = loadLibrary(json); // 在另一个会话中恢复
```
### LLM-种子混合
当纯合成失败时,LLM 提出一个**基元**(`extraPrims`);引擎验证它并免费重新组合它。完整的复制粘贴示例:[`examples/hybrid-llm-seeding.ts`](examples/hybrid-llm-seeding.ts)。
**高级表面**(组合、独立验证):`solveBySynthesis`、`learnAbstractions`、`grade`(验证器)、`buildOps`、`configureSearch`,以及类型 `Tool` / `Recipe` / `Op` / `Abstraction`。
## 从代理(MCP)使用
[`synthcore-mcp`](mcp/) 是一个 [Model Context Protocol](https://modelcontextprotocol.io) 服务器,公开 `synthesize` 作为工具,以便代理(Claude Desktop, Cursor, …)可以获得一个**确定性、已验证、$0** 数据转换,而不是凭空捏造一个。LLM 进行推理;Synthcore 保证。
```bash
cd mcp && npm install && npm start # 带有单个 `synthesize` 工具的标准输入/输出服务器
```
然后将您的客户端指向它,并使用示例调用 `synthesize`(支持可选的 `bundle`s 和 `language: "python"`)。[`mcp/README.md`](mcp/README.md) 中有适用于 Claude Desktop / Cursor 的完整线路。
## 限制(阅读它们 — 诚实的销售避免炒作)
- **它不是通用代码生成。** 枚举搜索仅达到有界 DSL 中的**小**程序;它不编写应用程序,也不根据自然语言规范进行推理。
- **它补充 LLM,而不是取代它。** 模型是混合模型(LLM 提出稀有基元;Synthcore 免费重新组合并验证),而不是直接竞争。
- **示例少时可能会过拟合。** 它返回一些通过您提供的示例的程序;示例少时可能是巧合。真实案例:对于“电子邮件域”,3 个示例引擎找到 `max(split(capitalize(arg0),"@"))` — 它通过偶然(域赢得词法顺序),而不是因为它“理解”电子邮件。提供 **≥3–5** 个示例和边缘情况,以便解决方案真正泛化。
- **有界 DSL.** 日期、正则表达式、文本中的数字和科学包(物理/化学)存在但**可选**(`{ std: true }` 或 `extraPrims`),因为每个基元都扩大搜索。`filter`/`unique` 组合子仍然缺失,没有递归,因此过滤、去重或斐波那契数列返回 `not_found`。这是当前的 DSL 前沿(通过种子基元移动),不是隐藏用例。
- **转译基于模板,而不是完整的编译器。** `emitPython` 涵盖基础 DSL 和我们维护的包。学习到的抽象和任意注入的基元(原始 JavaScript)不会被转译 — 它抛出错误,而不是发出无法保证的代码。
- **特定领域,而不是大众市场。** 受众是开发者/工具,而不是终端消费者。
## 定位
- **对比 Microsoft PROSE / FlashFill** (成熟的 PBE):Synthcore 添加了**库学习 + 深度组合**,并且是**可嵌入的、开源的 TypeScript** (PROSE 是 C#/封闭的,并且以字符串/表格为中心)。
- **对比 DreamCoder / LILO** (学术的,Python + GPU):Synthcore 是一个 TypeScript 项目,**无需 GPU 即可在笔记本电脑上运行**。
- **对比 LLM 代码生成** (Copilot/Cursor):**确定性、已验证、$0、离线、可审计** — 堆栈的另一半。
## 用法
```bash
npm install synthcore # 在您的项目中
```
仓库开发:
```bash
npm install # 仅开发依赖(TypeScript、tsx、@types/node)
npm run demo # 解决 8/8 示例任务,已验证,$0
npm run bench # 诚实的基准测试:13/15 任务,~150 毫秒/任务,已解决,$0
npm test # 契约套件(node:test)
npm run typecheck # tsc --noEmit
npm run build # 编译库到 dist/(JavaScript + 类型)以发布
```
需要 Node ≥ 22。纯 ESM,无运行时依赖。
## 许可证
[MIT](LICENSE).