本指南介绍如何将 DPML 集成到各种应用场景中,包括与 AI 工具、构建系统和生产环境的集成。
DPML 可以集成到多种场景:
- AI 应用:生成 LLM prompt 配置
- 构建工具:预编译 DPML 文档
- 服务端应用:动态处理 prompt 模板
- CLI 工具:命令行 prompt 处理
将 DPML 文档转换为 OpenAI Chat Completion API 格式:
import { createDPML, defineSchema, defineTransformer } from 'dpml';
import OpenAI from 'openai';
// 定义 prompt schema
const promptSchema = defineSchema({
element: 'prompt',
attributes: [
{ name: 'model', type: 'string' },
{ name: 'temperature', type: 'string' },
],
children: {
elements: [
{ element: 'system' },
{ element: 'user' },
{ element: 'assistant' },
],
},
});
// OpenAI 格式转换器
interface OpenAIConfig {
model: string;
temperature: number;
messages: Array<{
role: 'system' | 'user' | 'assistant';
content: string;
}>;
}
const openAITransformer = defineTransformer<any, OpenAIConfig>({
name: 'openai-transformer',
transform: (input) => {
const rootNode = input.document.rootNode;
const messages: OpenAIConfig['messages'] = [];
for (const child of rootNode.children) {
if (['system', 'user', 'assistant'].includes(child.tagName)) {
messages.push({
role: child.tagName as 'system' | 'user' | 'assistant',
content: child.content.trim(),
});
}
}
return {
model: rootNode.attributes.get('model') || 'gpt-4',
temperature: parseFloat(rootNode.attributes.get('temperature') || '0.7'),
messages,
};
},
});
// 创建 DPML 实例
const dpml = createDPML({
schema: promptSchema,
transformers: [openAITransformer],
});
// 使用示例
async function chat(promptContent: string, userMessage: string) {
const config = await dpml.compile<OpenAIConfig>(promptContent);
// 添加用户消息
config.messages.push({ role: 'user', content: userMessage });
const openai = new OpenAI();
const response = await openai.chat.completions.create(config);
return response.choices[0].message.content;
}
// DPML 文档
const prompt = `
<prompt model="gpt-4" temperature="0.7">
<system>You are a helpful coding assistant.</system>
</prompt>
`;
const response = await chat(prompt, 'How do I write a hello world in Python?');为 Claude API 生成配置:
import Anthropic from '@anthropic-ai/sdk';
interface ClaudeConfig {
model: string;
max_tokens: number;
system: string;
messages: Array<{
role: 'user' | 'assistant';
content: string;
}>;
}
const claudeTransformer = defineTransformer<any, ClaudeConfig>({
name: 'claude-transformer',
transform: (input) => {
const rootNode = input.document.rootNode;
let systemPrompt = '';
const messages: ClaudeConfig['messages'] = [];
for (const child of rootNode.children) {
if (child.tagName === 'system') {
systemPrompt = child.content.trim();
} else if (['user', 'assistant'].includes(child.tagName)) {
messages.push({
role: child.tagName as 'user' | 'assistant',
content: child.content.trim(),
});
}
}
return {
model: rootNode.attributes.get('model') || 'claude-3-opus-20240229',
max_tokens: parseInt(rootNode.attributes.get('max-tokens') || '4096'),
system: systemPrompt,
messages,
};
},
});
async function askClaude(promptContent: string, userMessage: string) {
const dpml = createDPML({
schema: promptSchema,
transformers: [claudeTransformer],
});
const config = await dpml.compile<ClaudeConfig>(promptContent);
config.messages.push({ role: 'user', content: userMessage });
const anthropic = new Anthropic();
const response = await anthropic.messages.create(config);
return response.content[0].text;
}利用 DPML 内置的 resource 功能引用外部资源:
import { createDPML, defineSchema } from 'dpml';
import type { ResourceResult } from 'dpml';
const schema = defineSchema({
element: 'prompt',
});
const dpml = createDPML({ schema, transformers: [] });
// 编译包含资源引用的文档
const result = await dpml.compile<ResourceResult>(`
<prompt>
<system>You are a helpful assistant.</system>
<resource src="arp:text:file://./prompts/coding-rules.md"/>
<resource src="arp:text:file://./prompts/style-guide.md"/>
</prompt>
`);
// 处理资源引用
for (const resource of result.resources) {
console.log(`Resource: ${resource.src}`);
console.log(`Protocol: ${resource.protocol}`); // 'arp' 或 'rxl'
// 根据协议加载资源内容
if (resource.protocol === 'arp') {
// 使用 ARP 协议加载
// const content = await loadArpResource(resource.src);
} else if (resource.protocol === 'rxl') {
// 使用 ResourceX 加载
// const content = await registry.resolve(resource.src);
}
}创建 Vite 插件处理 .dpml 文件:
// vite-plugin-dpml.ts
import { createDPML, defineSchema, defineTransformer } from 'dpml';
import type { Plugin } from 'vite';
export function dpmlPlugin(options: { schema: any }): Plugin {
const dpml = createDPML({
schema: options.schema,
transformers: [
defineTransformer({
name: 'json-exporter',
transform: (input) => ({
document: input.document,
isValid: input.isValid,
}),
}),
],
});
return {
name: 'vite-plugin-dpml',
transform(code, id) {
if (!id.endsWith('.dpml')) {
return null;
}
// 同步验证
const validation = dpml.validate(code);
if (!validation.isValid) {
throw new Error(
`DPML validation failed in ${id}: ${validation.errors.map(e => e.message).join(', ')}`
);
}
// 返回 JavaScript 模块
return {
code: `export default ${JSON.stringify(dpml.parse(code))}`,
map: null,
};
},
};
}
// vite.config.ts
import { defineConfig } from 'vite';
import { dpmlPlugin } from './vite-plugin-dpml';
import { defineSchema } from 'dpml';
export default defineConfig({
plugins: [
dpmlPlugin({
schema: defineSchema({ element: 'prompt' }),
}),
],
});// esbuild-plugin-dpml.ts
import { createDPML, defineSchema } from 'dpml';
import type { Plugin } from 'esbuild';
import fs from 'fs';
export function dpmlPlugin(options: { schema: any }): Plugin {
const dpml = createDPML({
schema: options.schema,
transformers: [],
});
return {
name: 'dpml',
setup(build) {
build.onLoad({ filter: /\.dpml$/ }, async (args) => {
const content = await fs.promises.readFile(args.path, 'utf8');
const validation = dpml.validate(content);
if (!validation.isValid) {
return {
errors: validation.errors.map(e => ({
text: e.message,
location: e.location ? {
file: args.path,
line: e.location.startLine,
column: e.location.startColumn,
} : undefined,
})),
};
}
const document = dpml.parse(content);
return {
contents: `export default ${JSON.stringify(document)}`,
loader: 'js',
};
});
},
};
}创建构建脚本预编译所有 DPML 文件:
// scripts/build-prompts.ts
import { createDPML, defineSchema, defineTransformer } from 'dpml';
import { glob } from 'glob';
import fs from 'fs/promises';
import path from 'path';
const schema = defineSchema({
element: 'prompt',
attributes: [
{ name: 'id', required: true },
{ name: 'version', type: 'string' },
],
});
const dpml = createDPML({
schema,
transformers: [
defineTransformer({
name: 'prompt-extractor',
transform: (input) => {
const root = input.document.rootNode;
return {
id: root.attributes.get('id'),
version: root.attributes.get('version') || '1.0.0',
content: root.content.trim(),
children: root.children.map(c => ({
tag: c.tagName,
content: c.content.trim(),
})),
};
},
}),
],
});
async function buildPrompts() {
const files = await glob('src/prompts/**/*.dpml');
const prompts: Record<string, any> = {};
for (const file of files) {
const content = await fs.readFile(file, 'utf8');
try {
const result = await dpml.compile(content);
prompts[result.id] = result;
console.log(`Compiled: ${file} -> ${result.id}`);
} catch (error) {
console.error(`Failed to compile ${file}:`, error.message);
process.exit(1);
}
}
// 输出为 JSON
await fs.writeFile(
'dist/prompts.json',
JSON.stringify(prompts, null, 2)
);
// 输出为 TypeScript
await fs.writeFile(
'dist/prompts.ts',
`export const prompts = ${JSON.stringify(prompts, null, 2)} as const;`
);
console.log(`Built ${Object.keys(prompts).length} prompts`);
}
buildPrompts();避免重复编译相同的文档:
import { createDPML, defineSchema } from 'dpml';
import crypto from 'crypto';
class DPMLCache {
private cache = new Map<string, any>();
private dpml: ReturnType<typeof createDPML>;
constructor(schema: any, transformers: any[]) {
this.dpml = createDPML({ schema, transformers });
}
private hash(content: string): string {
return crypto.createHash('md5').update(content).digest('hex');
}
async compile<T>(content: string): Promise<T> {
const key = this.hash(content);
if (this.cache.has(key)) {
return this.cache.get(key) as T;
}
const result = await this.dpml.compile<T>(content);
this.cache.set(key, result);
return result;
}
clearCache(): void {
this.cache.clear();
}
}
// 使用
const dpmlCache = new DPMLCache(schema, transformers);
// 相同内容只编译一次
const result1 = await dpmlCache.compile(promptContent);
const result2 = await dpmlCache.compile(promptContent); // 从缓存返回在生产环境中监控编译错误:
import { createDPML, defineSchema } from 'dpml';
interface CompileError {
timestamp: Date;
content: string;
errors: string[];
stack?: string;
}
class MonitoredDPML {
private dpml: ReturnType<typeof createDPML>;
private errors: CompileError[] = [];
private onError?: (error: CompileError) => void;
constructor(
schema: any,
transformers: any[],
options?: { onError?: (error: CompileError) => void }
) {
this.dpml = createDPML({ schema, transformers });
this.onError = options?.onError;
}
async compile<T>(content: string): Promise<T | null> {
try {
// 先验证
const validation = this.dpml.validate(content);
if (!validation.isValid) {
const error: CompileError = {
timestamp: new Date(),
content: content.substring(0, 500), // 截断
errors: validation.errors.map(e => e.message),
};
this.errors.push(error);
this.onError?.(error);
return null;
}
return await this.dpml.compile<T>(content);
} catch (err) {
const error: CompileError = {
timestamp: new Date(),
content: content.substring(0, 500),
errors: [err instanceof Error ? err.message : 'Unknown error'],
stack: err instanceof Error ? err.stack : undefined,
};
this.errors.push(error);
this.onError?.(error);
return null;
}
}
getRecentErrors(count = 10): CompileError[] {
return this.errors.slice(-count);
}
}
// 使用
const dpml = new MonitoredDPML(schema, transformers, {
onError: (error) => {
// 发送到监控系统
console.error('DPML compile error:', error);
// metrics.increment('dpml.compile.error');
// logger.error('DPML compile error', error);
},
});// 1. 使用单例 DPML 实例
const dpmlInstance = createDPML({ schema, transformers });
// 不要在每次调用时创建新实例
// 错误:const dpml = createDPML(...); await dpml.compile(content);
// 2. 批量处理
async function compileAll(contents: string[]): Promise<any[]> {
return Promise.all(contents.map(c => dpmlInstance.compile(c)));
}
// 3. 预热
async function warmup() {
// 预编译常用模板
const commonTemplates = ['template1.dpml', 'template2.dpml'];
for (const template of commonTemplates) {
await dpmlInstance.compile(await loadTemplate(template));
}
}创建类型安全的 prompt 管理 API:
// types.ts
export interface PromptTemplate {
id: string;
version: string;
content: string;
metadata: {
author?: string;
description?: string;
tags?: string[];
};
}
export interface CompiledPrompt {
messages: Array<{ role: string; content: string }>;
config: {
model: string;
temperature: number;
};
}
// prompt-service.ts
import { createDPML, defineSchema, defineTransformer } from 'dpml';
export class PromptService {
private dpml: ReturnType<typeof createDPML>;
private templates = new Map<string, PromptTemplate>();
constructor() {
const schema = defineSchema({
element: 'prompt',
attributes: [
{ name: 'id', required: true },
{ name: 'model', type: 'string' },
{ name: 'temperature', type: 'string' },
],
});
const transformer = defineTransformer<any, CompiledPrompt>({
name: 'prompt-compiler',
transform: (input) => {
const root = input.document.rootNode;
return {
messages: root.children
.filter(c => ['system', 'user', 'assistant'].includes(c.tagName))
.map(c => ({
role: c.tagName,
content: c.content.trim(),
})),
config: {
model: root.attributes.get('model') || 'gpt-4',
temperature: parseFloat(root.attributes.get('temperature') || '0.7'),
},
};
},
});
this.dpml = createDPML({ schema, transformers: [transformer] });
}
async registerTemplate(template: PromptTemplate): Promise<void> {
// 验证模板
const validation = this.dpml.validate(template.content);
if (!validation.isValid) {
throw new Error(`Invalid template: ${validation.errors.map(e => e.message).join(', ')}`);
}
this.templates.set(template.id, template);
}
async getPrompt(id: string, variables?: Record<string, string>): Promise<CompiledPrompt> {
const template = this.templates.get(id);
if (!template) {
throw new Error(`Template not found: ${id}`);
}
let content = template.content;
// 变量替换
if (variables) {
for (const [key, value] of Object.entries(variables)) {
content = content.replace(new RegExp(`{{${key}}}`, 'g'), value);
}
}
return this.dpml.compile<CompiledPrompt>(content);
}
listTemplates(): PromptTemplate[] {
return Array.from(this.templates.values());
}
}
// 使用
const promptService = new PromptService();
await promptService.registerTemplate({
id: 'coding-assistant',
version: '1.0.0',
content: `
<prompt id="coding-assistant" model="gpt-4" temperature="0.3">
<system>You are an expert {{language}} programmer.</system>
</prompt>
`,
metadata: {
author: 'team',
description: 'Coding assistant prompt',
tags: ['coding', 'assistant'],
},
});
const prompt = await promptService.getPrompt('coding-assistant', {
language: 'TypeScript',
});import { describe, it, expect } from 'vitest';
import { createDPML, defineSchema, defineTransformer } from 'dpml';
describe('DPML Integration', () => {
const schema = defineSchema({
element: 'prompt',
attributes: [{ name: 'role', required: true }],
});
const transformer = defineTransformer({
name: 'test-transformer',
transform: (input) => ({
role: input.document.rootNode.attributes.get('role'),
content: input.document.rootNode.content.trim(),
}),
});
const dpml = createDPML({ schema, transformers: [transformer] });
it('should compile valid document', async () => {
const result = await dpml.compile(`
<prompt role="assistant">Hello World</prompt>
`);
expect(result.role).toBe('assistant');
expect(result.content).toBe('Hello World');
});
it('should validate required attribute', () => {
const validation = dpml.validate(`<prompt>Hello</prompt>`);
expect(validation.isValid).toBe(false);
expect(validation.errors.length).toBeGreaterThan(0);
});
it('should parse nested elements', () => {
const doc = dpml.parse(`
<prompt role="user">
<context>Background info</context>
</prompt>
`);
expect(doc.rootNode.children.length).toBe(1);
expect(doc.rootNode.children[0].tagName).toBe('context');
});
});- 单例模式:复用 DPML 实例,避免重复创建
- 缓存结果:缓存编译结果,避免重复编译
- 错误处理:优雅处理编译错误,提供有用的错误信息
- 类型安全:使用 TypeScript 类型确保类型安全
- 监控日志:在生产环境中监控编译错误
- 预编译:在构建时预编译静态模板
- 测试覆盖:为 DPML 集成编写测试用例