@dpml/core
Version:
DPML Core: Implementations of base compiler, and provide a simple framework for domain developers.
707 lines (564 loc) • 18.5 kB
Markdown
DPML (Deepractice Prompt Markup Language) 是一种专为AI提示词工程设计的声明式标记语言,作为人类意图和AI处理之间的标准化中间表示。DPML Core 包提供了解析、验证、转换和执行DPML文档的核心功能,使开发者能够为特定领域创建自定义的DPML编译器。
DPML 基于"意图交互模式"设计,在这一模式中:
- **人类**是终极的创新载体,专注于高层次意图表达,关注"做什么"而非"怎么做"
- **AI**是抽象与具象的桥梁,将人类意图转换为结构化指令
- **计算机**是终极的效率载体,精确高速地执行任务
作为中间表示语言,DPML通过声明式标记语法,降低了技术门槛,提高了开发效率,支持各行业创建自己的领域特定语言(DSL)。
DPML Core 框架由以下核心组件构成:

- **Schema** - 定义领域特定DPML文档的结构和约束
- **解析器** - 将DPML文本解析为内存中的文档对象模型(DOM)
- **处理器** - 验证文档是否符合Schema并处理引用
- **转换器** - 将DPML文档转换为特定目标格式或数据结构
- **编译器** - 封装上述组件的统一入口点,负责调度整个处理流程
- **CLI系统** - 提供命令行界面功能,用于与DPML文档交互
```bash
npm install @dpml/core
```
```typescript
import { createDomainDPML } from '@dpml/core';
// 1. 定义领域Schema
const mySchema = {
// Schema定义(见后文详细说明)
};
// 2. 创建转换器
const myTransformer = {
name: 'myTransformer',
transform: (input, context) => {
// 转换逻辑
return { result: 'transformed data' };
}
};
// 3. 定义CLI命令配置
const commandsConfig = {
includeStandard: true, // 包含标准命令(validate、parse)
actions: [
{
name: 'process',
description: '处理DPML文档',
args: [
{
name: 'filePath',
description: '文件路径',
required: true
}
],
options: [
{
flags: '-o, --output <format>',
description: '输出格式',
defaultValue: 'json'
}
],
action: async (actionContext, filePath, options) => {
// 命令实现逻辑
console.log(`处理文件: ${filePath}, 输出格式: ${options.output}`);
}
}
]
};
// 4. 创建领域编译器
const myDPML = createDomainDPML<ResultType>({
domain: 'my-domain',
description: '我的DPML领域',
schema: mySchema,
transformers: [myTransformer],
commands: commandsConfig // 添加命令配置
});
// 5. 使用编译器处理DPML文档
async function processDPML() {
const dpmlContent = '<my-element>DPML content</my-element>';
const result = await myDPML.compiler.compile(dpmlContent);
console.log(result);
}
// 6. CLI入口点(在bin.ts文件中)
async function main() {
await myDPML.cli.execute();
}
processDPML();
```
安装全局或本地DPML CLI后,可以使用命令行工具:
```bash
dpml my-domain validate path/to/document.xml
dpml my-domain custom-command path/to/document.xml --option value
```
Schema是DPML的核心组成部分,它定义了领域特定DPML文档的结构和约束规则。
```typescript
// 文档级别的结构定义
interface DocumentSchema {
root: ElementSchema | TypeReference; // 根元素定义
types?: Array<ElementSchema>; // 可复用类型定义
globalAttributes?: Array<AttributeSchema>; // 全局属性定义
namespaces?: Record<string, string>; // 命名空间定义
}
// 元素结构定义
interface ElementSchema {
element: string; // 元素标签名
attributes?: Array<AttributeSchema>; // 属性定义
children?: ChildrenSchema; // 子元素定义
content?: ContentSchema; // 内容模型定义
}
// 类型引用
interface TypeReference {
$ref: string; // 引用的类型名称
}
```
```typescript
import { Schema, DocumentSchema } from '@dpml/core';
// 定义工作流领域的Schema
const workflowSchema: DocumentSchema = {
// 根元素定义
root: {
element: 'workflow',
attributes: [
{ name: 'name', required: true },
{ name: 'version' }
],
children: {
elements: [
{ $ref: 'step' }, // 引用预定义类型
{ $ref: 'transition' }
]
}
},
// 可复用类型定义
types: [
{
element: 'step',
attributes: [
{ name: 'id', required: true },
{ name: 'type', enum: ['start', 'process', 'end'], required: true }
],
content: { type: 'text', required: true }
},
{
element: 'transition',
attributes: [
{ name: 'from', required: true },
{ name: 'to', required: true },
{ name: 'condition' }
]
}
]
};
```
转换器负责将处理后的DPML文档转换为领域特定的对象结构。DPML Core提供多种方式创建和使用转换器。
所有转换器必须实现`Transformer<TInput, TOutput>`接口:
```typescript
interface Transformer<TInput, TOutput> {
// 转换器名称,用于标识和调试
name: string;
// 转换方法
transform(input: TInput, context: TransformContext): TOutput;
}
```
```typescript
import { createTransformerDefiner } from '@dpml/core';
// 获取转换器定义器
const definer = createTransformerDefiner();
// 创建结构映射转换器
const workflowTransformer = definer.defineStructuralMapper<unknown, Workflow>(
'workflowTransformer', // 转换器名称
[
{
selector: "workflow", // 元素选择器
targetPath: "", // 目标路径
transform: (value) => ({
name: value.attributes.get("name") || "",
version: value.attributes.get("version"),
steps: []
})
},
{
selector: "workflow > step",
targetPath: "steps[]", // 数组路径表示法
transform: (value) => ({
id: value.attributes.get("id") || "",
type: value.attributes.get("type") || "process",
description: value.content || ""
})
}
]
);
```
DPML Core提供多种内置转换器类型,满足不同需求:
| 转换器类型 | 方法 | 描述 |
|------------|------|------|
| 结构映射转换器 | `defineStructuralMapper` | 将DPML节点映射到目标对象结构,支持选择器和路径映射 |
| 模板转换器 | `defineTemplateTransformer` | 使用模板生成文本输出,如生成代码或文档 |
| 聚合转换器 | `defineAggregator` | 收集、分组和处理符合条件的节点 |
| 关系处理转换器 | `defineRelationProcessor` | 处理节点间的关系,如构建引用关系图 |
| 语义提取转换器 | `defineSemanticExtractor` | 提取领域特定语义信息 |
| 结果收集转换器 | `defineResultCollector` | 收集多个转换器的结果 |
**模板转换器示例**:
```typescript
// 创建模板转换器
const promptTemplateTransformer = definer.defineTemplateTransformer<{userName: string}>(
'promptTemplateTransformer',
"你好,{{userName}}!欢迎使用DPML。",
// 可选的预处理函数
(input) => ({
userName: input.userName.toUpperCase()
})
);
// 使用模板转换器
const result = promptTemplateTransformer.transform({userName: "张三"}, context);
// 输出: "你好,张三!欢迎使用DPML。"
```
**聚合转换器示例**:
```typescript
// 创建聚合转换器
const stepsCollectorTransformer = definer.defineAggregator<unknown, {steps: any[]}>(
'stepsCollectorTransformer',
{
selector: "workflow > step",
groupBy: "type", // 可选,按类型分组
sortBy: "id" // 可选,按ID排序
}
);
// 结果示例:收集所有步骤到数组
// {
// steps: [
// {id: "step1", type: "start", ...},
// {id: "step2", type: "process", ...},
// {id: "step5", type: "end", ...}
// ]
// }
```
DPML使用简单直观的选择器语法来定位元素:
| 选择器类型 | 语法 | 描述 | 示例 |
|------------|------|------|------|
| 标签选择器 | `tagName` | 选择所有指定标签的元素 | `workflow` |
| 属性选择器 | `tagName[attr]` | 选择具有特定属性的元素 | `step[type]` |
| 属性值选择器 | `tagName[attr="value"]` | 选择属性等于特定值的元素 | `step[type="process"]` |
| 直接子元素选择器 | `parent > child` | 选择作为直接子元素的元素 | `workflow > step` |
转换器按注册顺序执行,后注册的转换器可以访问前面转换器的结果:
```typescript
// 定义转换器序列,顺序很重要
const transformers = [
// 1. 基础转换器:创建核心结构(必须首先执行)
workflowBaseTransformer,
// 2. 内容填充转换器:添加详细信息
stepsTransformer,
// 3. 关系处理转换器:处理元素间引用
transitionsTransformer
];
```
编译器是DPML的核心组件,它协调Schema验证、文档解析和转换过程。
```typescript
import { createDomainDPML } from '@dpml/core';
// 创建领域编译器
const workflowDPML = createDomainDPML<Workflow>({
// 领域标识符
domain: 'workflow',
// 领域描述
description: '工作流处理领域',
// Schema定义
schema: workflowSchema,
// 转换器数组
transformers: [workflowTransformer],
// 命令配置
commands: commandsConfig,
// 编译选项
options: {
strictMode: true,
errorHandling: 'throw'
}
});
```
```typescript
async function processWorkflow(dpmlContent: string): Promise<void> {
try {
// 编译DPML为领域对象
const workflow = await workflowDPML.compiler.compile(dpmlContent);
// 使用领域对象...
console.log(`工作流名称: ${workflow.name}`);
console.log(`步骤数量: ${workflow.steps.length}`);
} catch (error) {
console.error('编译失败:', error.message);
}
}
```
编译器支持三种错误处理策略:
- **'throw'** (默认):遇到错误时立即抛出异常
- **'warn'**:记录警告但继续执行
- **'silent'**:忽略错误,静默继续执行
```typescript
// 设置错误处理策略
const workflowDPML = createDomainDPML<Workflow>({
// 其他配置...
options: {
errorHandling: 'warn' // 'throw' | 'warn' | 'silent'
}
});
```
可以通过`extend`方法动态扩展现有编译器:
```typescript
// 添加新的转换器
workflowDPML.compiler.extend({
transformers: [newTransformer]
});
// 更新编译选项
workflowDPML.compiler.extend({
options: {
strictMode: false
}
});
```
DPML Core提供了完整的CLI框架,允许领域包开发者快速创建自定义命令行工具。
CLI系统由以下组件组成:
1. **命令定义**:描述命令名称、参数、选项和行为
2. **命令注册**:将命令添加到领域DPML实例
3. **命令执行器**:处理命令行参数并调用相应命令
4. **执行上下文**:提供命令执行期间所需的工具和状态

命令使用以下结构定义:
```typescript
// 领域命令配置
const commandsConfig: DomainCommandsConfig = {
// 是否包含标准命令(如validate和parse)
includeStandard: true,
// 自定义领域命令
actions: [
{
// 命令名称(使用kebab-case格式)
name: 'execute',
// 命令描述(显示在帮助信息中)
description: '执行工作流',
// 位置参数定义
args: [
{
name: 'filePath', // 参数名称
description: '文件路径', // 参数描述
required: true // 是否必需
}
],
// 选项参数定义
options: [
{
flags: '-o, --output <format>', // 选项标志
description: '输出格式', // 选项描述
defaultValue: 'json', // 默认值
choices: ['json', 'xml', 'yaml'] // 可选值
}
],
// 命令处理函数 - 当命令被执行时调用
action: async (domainActionContext, filePath, options) => {
// 命令实现...
}
}
]
};
```
`domainActionContext`对象是命令处理函数的第一个参数,提供重要的环境信息和工具:
```typescript
/**
* 命令执行上下文(DomainActionContext)
*/
interface DomainActionContext {
/**
* 获取当前领域编译器实例
*/
getCompiler<T = unknown>(): DomainCompiler<T>;
/**
* 获取领域标识符
*/
getDomain(): string;
/**
* 获取领域描述
*/
getDescription(): string;
/**
* 获取编译选项
*/
getOptions(): Required<CompileOptions>;
}
```
使用示例:
```typescript
action: async (domainActionContext, filePath, options) => {
try {
// 读取文件
const content = await readFile(filePath, 'utf-8');
// 使用编译器解析DPML
const workflow = await domainActionContext.getCompiler().compile(content);
console.log(`执行工作流: ${workflow.name}`);
console.log(`输出格式: ${options.output}`);
// 实际执行逻辑...
} catch (error) {
console.error('执行失败:', error.message);
}
}
```
当用户在命令行输入DPML命令时,执行流程如下:
1. `bin.js`脚本被Node.js执行
2. 脚本调用`domainDPML.cli.execute()`
3. CLI系统解析命令行参数,确定要执行的命令
4. 创建domainActionContext对象,包含编译器和环境信息
5. 调用匹配命令的action函数,传入domainActionContext、参数和选项
6. 命令处理函数执行业务逻辑
**1. 定义命令配置**
```typescript
// config/cli.ts
import { readFile } from 'fs/promises';
import type { DomainCommandsConfig } from '@dpml/core';
export const commandsConfig: DomainCommandsConfig = {
includeStandard: true,
actions: [
{
name: 'execute',
description: '执行工作流',
args: [
{
name: 'filePath',
description: '工作流文件路径',
required: true
}
],
options: [
{
flags: '-o, --output <format>',
description: '输出格式',
defaultValue: 'json'
}
],
action: async (domainActionContext, filePath, options) => {
try {
// 读取文件
const content = await readFile(filePath, 'utf-8');
// 使用编译器解析DPML
const workflow = await domainActionContext.getCompiler().compile(content);
console.log(`执行工作流: ${workflow.name}`);
console.log(`输出格式: ${options.output}`);
// 实际执行逻辑...
} catch (error) {
console.error('执行失败:', error.message);
}
}
}
]
};
```
**2. 创建领域DPML实例**
```typescript
// index.ts
import { createDomainDPML } from '@dpml/core';
import { workflowSchema } from './config/schema';
import { transformers } from './config/transformers';
import { commandsConfig } from './config/cli';
import type { Workflow } from './types';
// 创建领域DPML实例
export const workflowDPML = createDomainDPML<Workflow>({
domain: 'workflow',
description: '工作流处理领域',
schema: workflowSchema,
transformers,
commands: commandsConfig
});
// 导出编译器
export const compiler = workflowDPML.compiler;
```
**3. CLI入口点**
```typescript
// bin.ts
import { workflowDPML } from './index';
async function main() {
try {
// 执行CLI命令
await workflowDPML.cli.execute();
} catch (error) {
console.error('CLI执行错误:', error.message);
process.exit(1);
}
}
main();
```
**4. 最终用户使用方式**
```bash
npm install -g my-workflow-tool
dpml workflow execute path/to/workflow.xml --output yaml
dpml workflow --help
dpml workflow execute --help
```
- 将Schema定义、转换器和命令配置分别放在独立模块中
- 使用桶文件(index.ts)统一导出
- 保持每个组件职责单一
- 遵循单一职责原则,一个转换器只负责一种转换
- 使用有意义的名称标识转换器
- 仔细规划转换器执行顺序
- 使用选择器精确定位目标元素
- 提供清晰的错误信息
- 在合适的环境中选择合适的错误处理策略
- 使用日志系统记录关键信息
- 提供清晰、一致的命令名称和选项
- 添加详细的帮助信息
- 处理各种边缘情况和错误
- 提供用户友好的反馈
领域包项目结构示例:
```
my-dpml-domain/
├── src/
│ ├── api/
│ │ └── index.ts
│ │
│ ├── core/
│ │
│ ├── types/
│ │
│ ├── config/
│ │ ├── schema.ts
│ │ ├── transformers.ts
│ │ ├── cli.ts
│ │ └── index.ts
│ │
│ ├── bin.ts
│ └── index.ts
│
├── examples/
│
├── package.json
└── README.md
```
```bash
npm install @dpml/core
```