本文档介绍 DPML 的 Schema 系统,用于定义和验证文档结构。
Schema 是用于定义 DPML 文档结构的规则集合。它描述了:
- 哪些元素是合法的
- 元素可以有哪些属性
- 元素可以包含什么内容
- 元素之间的层级关系
通过 Schema,可以验证 DPML 文档是否符合预期的结构。
DPML 支持两种 Schema 类型:
定义完整文档的结构,包含根元素和可复用的类型定义。
interface DocumentSchema {
// 根元素定义(必需)
root: ElementSchema | TypeReference | string;
// 可复用的类型定义
types?: ElementSchema[];
// 全局属性(适用于所有元素)
globalAttributes?: AttributeSchema[];
// 命名空间声明
namespaces?: string[];
}定义单个元素的结构。
interface ElementSchema {
// 元素名称(必需)
element: string;
// 属性定义
attributes?: AttributeSchema[];
// 内容模型
content?: ContentSchema;
// 子元素定义
children?: ChildrenSchema;
}定义一个简单的 prompt 元素:
import { processSchema } from '@dpml/core';
const schema = {
root: {
element: 'prompt',
attributes: [
{ name: 'role', required: true },
{ name: 'type', enum: ['text', 'markdown'] }
],
content: { type: 'text', required: true }
}
};
const processedSchema = processSchema(schema);
console.log(processedSchema.isValid); // true对应的合法 DPML 文档:
<prompt role="system" type="markdown">
你是一个专业的编程助手。
</prompt>定义一个包含多个元素的 Agent 结构:
const agentSchema = {
root: {
element: 'agent',
children: {
elements: [
{ $ref: 'llm' },
{ $ref: 'prompt' },
{ $ref: 'tools' }
]
}
},
types: [
{
element: 'llm',
attributes: [
{ name: 'model', required: true },
{ name: 'temperature', type: 'number' },
{ name: 'max-tokens', type: 'number' }
]
},
{
element: 'prompt',
attributes: [
{ name: 'type', enum: ['text', 'markdown'] }
],
content: { type: 'text', required: true }
},
{
element: 'tools',
children: {
elements: [
{
element: 'tool',
attributes: [{ name: 'name', required: true }]
}
]
}
}
]
};对应的合法 DPML 文档:
<agent>
<llm model="gpt-4" temperature="0.7"/>
<prompt type="markdown">
# 角色
你是一个专业的编程助手。
</prompt>
<tools>
<tool name="search"/>
<tool name="code-execute"/>
</tools>
</agent>使用 AttributeSchema 定义元素的属性:
interface AttributeSchema {
// 属性名称(必需)
name: string;
// 属性值类型
type?: string; // 'string' | 'number' | 'boolean'
// 是否必需
required?: boolean; // 默认 false
// 枚举值列表
enum?: string[];
// 正则表达式模式
pattern?: string;
// 默认值
default?: string;
}const attributes = [
// 必需属性
{ name: 'model', required: true },
// 带类型的属性
{ name: 'temperature', type: 'number' },
// 枚举属性
{ name: 'type', enum: ['text', 'markdown', 'json'] },
// 带模式的属性
{ name: 'id', pattern: '^[a-z][a-z0-9-]*$' },
// 带默认值的属性
{ name: 'enabled', type: 'boolean', default: 'true' }
];使用 ContentSchema 定义元素的内容模型:
interface ContentSchema {
// 内容类型
type: 'text' | 'mixed';
// 是否必需
required?: boolean; // 默认 false
// 内容模式
pattern?: string;
}- text: 纯文本内容,不允许子元素
- mixed: 混合内容,允许文本和子元素混合
// 纯文本内容
{
element: 'prompt',
content: { type: 'text', required: true }
}
// 混合内容
{
element: 'description',
content: { type: 'mixed' }
}使用 ChildrenSchema 定义元素可以包含的子元素:
interface ChildrenSchema {
// 允许的子元素列表
elements: (ElementSchema | TypeReference)[];
// 顺序是否重要
orderImportant?: boolean; // 默认 false
// 子元素数量限制
min?: number;
max?: number;
}// 内联定义子元素
{
element: 'tools',
children: {
elements: [
{
element: 'tool',
attributes: [{ name: 'name', required: true }]
}
]
}
}
// 通过引用定义子元素
{
element: 'agent',
children: {
elements: [
{ $ref: 'llm' },
{ $ref: 'prompt' }
],
orderImportant: true
}
}使用 TypeReference 引用在 types 中定义的类型:
interface TypeReference {
$ref: string; // 引用的类型名称
}const schema = {
root: {
element: 'workflow',
children: {
elements: [
{ $ref: 'step' } // 引用 types 中的 step
]
}
},
types: [
{
element: 'step',
attributes: [
{ name: 'id', required: true },
{ name: 'name', required: true }
],
children: {
elements: [
{ $ref: 'step' } // 递归引用自身
]
}
}
]
};使用 processSchema 函数处理和验证 Schema:
import { processSchema } from '@dpml/core';
const schema = {
root: { element: 'prompt' }
};
const result = processSchema(schema);
console.log(result.isValid); // true 或 false
console.log(result.schema); // 原始 schema
console.log(result.errors); // 错误列表(如果无效)interface ProcessedSchema<T extends object> {
// 原始 Schema
schema: T;
// 是否有效
isValid: boolean;
// 错误列表
errors?: SchemaError[];
}
interface SchemaError {
// 错误消息
message: string;
// 错误代码
code: string;
// 错误路径
path: string;
}Schema 验证器会检查以下规则:
| 规则 | 描述 |
|---|---|
element 必需 |
必须提供元素名称 |
element 类型 |
必须是字符串 |
attributes 类型 |
如果存在,必须是数组 |
content.type 必需 |
如果定义了 content,type 是必需的 |
children.elements 必需 |
如果定义了 children,elements 是必需的 |
| 规则 | 描述 |
|---|---|
root 必需 |
必须定义根元素 |
root 类型 |
必须是 ElementSchema、TypeReference 或字符串 |
types 类型 |
如果存在,必须是数组 |
globalAttributes 类型 |
如果存在,必须是数组 |
| 规则 | 描述 |
|---|---|
name 必需 |
必须提供属性名称 |
name 类型 |
必须是字符串 |
enum 类型 |
如果存在,必须是字符串数组 |
| 代码 | 描述 |
|---|---|
INVALID_SCHEMA |
无效的 Schema 对象 |
INVALID_SCHEMA_TYPE |
无效的 Schema 类型 |
MISSING_ELEMENT |
缺少 element 字段 |
MISSING_ROOT |
缺少 root 字段 |
MISSING_ATTRIBUTE_NAME |
缺少属性名称 |
MISSING_CONTENT_TYPE |
缺少 content.type 字段 |
MISSING_CHILDREN_ELEMENTS |
缺少 children.elements 字段 |
INVALID_ATTRIBUTES_TYPE |
attributes 不是数组 |
INVALID_REF_TYPE |
$ref 不是字符串 |
将重复使用的元素定义为 types:
const schema = {
root: { element: 'workflow', children: { elements: [{ $ref: 'task' }] } },
types: [
{ element: 'task', /* ... */ }
]
};只将真正必需的属性标记为 required: true:
{
element: 'llm',
attributes: [
{ name: 'model', required: true }, // 必需
{ name: 'temperature' }, // 可选
]
}对于有限的选项,使用 enum:
{
name: 'type',
enum: ['text', 'markdown', 'json']
}为可选属性提供合理的默认值:
{
name: 'temperature',
type: 'number',
default: '0.7'
}