# Dotprompt 字段完整参考手册

本文档整理了 `.prompt` 文件 YAML frontmatter 中所有可用字段的完整定义，基于源码 `typing.py`、`parse.py`、`picoschema.py` 等模块。

---

## 文件结构

一个 `.prompt` 文件由两部分组成：

```
---
<YAML frontmatter — 所有字段定义在此>
---
<Handlebars 模板正文>
```

---

## 顶层字段一览

| 字段 | 类型 | 必填 | 说明 |
|------|------|------|------|
| `name` | `string` | 否 | Prompt 名称标识 |
| `variant` | `string` | 否 | Prompt 变体标识（用于 A/B 测试等） |
| `version` | `string` | 否 | 版本号或哈希 |
| `description` | `string` | 否 | Prompt 用途的人类可读描述 |
| `adapter` | `string \| AdapterConfig` | 否 | LLM 适配器配置 |
| `config` | `object` | 否 | 模型特定的配置参数（含 `model` 字段） |
| `input` | `PromptInputConfig` | 否 | 输入变量配置 |
| `output` | `PromptOutputConfig` | 否 | 输出格式与结构配置 |
| `tools` | `list[string]` | 否 | 可用工具的名称列表 |
| `toolDefs` | `list[ToolDefinition]` | 否 | 内联工具定义列表 |
| `runtime` | `RuntimeConfig` | 否 | 运行时执行参数（批处理等） |
| `ext` | `object` | 否 | 扩展字段（命名空间嵌套） |
| `metadata` | `object` | 否 | 任意附加元数据 |
> **命名空间扩展**：frontmatter 中带 `.` 的 key（如 `foo.bar: value`）会被自动转换为嵌套对象，存入 `ext` 字段（`{ "foo": { "bar": "value" } }`）。

---

## 详细字段说明

### `name`

```yaml
name: my-prompt
```

Prompt 的基础名称标识。可用于 PromptStore 中的加载和检索。

---

### `variant`

```yaml
variant: concise
```

指定 prompt 的变体，适用于同一 prompt 的不同版本（如简洁版 vs 详细版）。

---

### `version`

```yaml
version: abc123
```

Prompt 内容的特定版本哈希或标识符。

---

### `description`

```yaml
description: 从用户输入的文本中提取结构化信息
```

对 prompt 用途的人类可读描述。

---

### ~~`model`~~（已移除）

顶层 `model` 字段已被**完全移除**。请使用 `config.model` 指定模型名称，`adapter` 指定适配器/提供商。

```yaml
# ✅ 正确写法
adapter: openai
config:
  model: gpt-4o

# ❌ 以下写法不再支持
# model: gpt-4o
```
---

### `adapter`

适配器有两种写法：

**简写形式** — 仅指定适配器名称：

```yaml
adapter: openai
```

**完整形式** — 包含自定义端点配置（`AdapterConfig`）：

```yaml
adapter:
  name: openai
  base_url: https://api.deepseek.com
  api_key: sk-...    # 建议优先使用环境变量
```

#### `AdapterConfig` 字段

| 字段 | 类型 | 必填 | 说明 |
|------|------|------|------|
| `name` | `string` | 是 | 适配器名称（`openai`、`anthropic`、`google`） |
| `base_url` | `string` | 否 | 自定义 API 端点 URL（用于第三方兼容服务） |
| `api_key` | `string` | 否 | API 密钥（建议使用环境变量替代） |

#### 支持的适配器

| 适配器 | 环境变量 | 默认 Base URL |
|--------|----------|--------------|
| `openai` | `OPENAI_API_KEY` | OpenAI 官方 API |
| `anthropic` | `ANTHROPIC_API_KEY` | Anthropic 官方 API |
| `google` | `GOOGLE_API_KEY` | Google Gemini API |

所有适配器均支持通过 `base_url` 或环境变量（`OPENAI_BASE_URL` / `ANTHROPIC_BASE_URL` / `GOOGLE_BASE_URL`）配置第三方兼容端点（如 DeepSeek、vLLM、Ollama）。

**适配器自动推断**：如果未显式指定 `adapter`，系统会尝试从 `config.model` 的名称自动推断适配器。

---

### `config`

模型特定的配置参数，以字典形式传递给 LLM API。

```yaml
config:
  model: gpt-4o
  temperature: 0.7
  max_tokens: 1024
  top_p: 0.9
  top_k: 40
  stop_sequences:
    - "\n\n"
```

`config` 内容取决于所使用的适配器，下表列出各适配器实际支持的字段：

#### 各适配器支持的 `config` 字段

| 字段 | 类型 | OpenAI | Anthropic | Google | 说明 |
|------|------|:------:|:---------:|:------:|------|
| `model` | `string` | ✅ | ✅ | ✅ | **必填**。LLM 模型名称 |
| `temperature` | `number` | ✅ | ✅ | ✅ | 生成温度 |
| `topP` / `top_p` | `number` | ✅ | ✅ | ✅ | 核采样参数 |
| `maxTokens` / `max_tokens` | `integer` | ✅ | ✅ (默认 4096) | ✅ | 最大输出 token 数 |
| `stop` / `stopSequences` | `list[string]` | ✅ | ✅ | ✅ | 停止生成的序列 |
| `frequencyPenalty` / `frequency_penalty` | `number` | ✅ | ❌ | ❌ | 频率惩罚 |
| `presencePenalty` / `presence_penalty` | `number` | ✅ | ❌ | ❌ | 存在惩罚 |
| `seed` | `integer` | ✅ | ❌ | ❌ | 随机种子（可复现性） |

> `config` 是一个开放字典，可以传入任何适配器支持的参数。字段名支持 camelCase 和 snake_case 两种风格。

#### 模型名称优先级（从高到低）

1. 运行时 `options.config['model']` 覆盖
2. Frontmatter `config.model`
3. `Dotprompt` 实例的 `default_model`
---

### `input`

定义 prompt 的输入数据。不再使用 schema，而是直接提供数据值或文件引用。

```yaml
# 方式1：内联数据
input:
  topic: "AI"
  count: 5

# 方式2：文件引用
input: "data.json"

# 方式3：批处理模式（列表）
input:
  - {id: 1, name: "Alice"}
  - {id: 2, name: "Bob"}

# 方式4：JSONL 文件（批处理）
input: "batch.jsonl"
```

#### `input` 字段类型

类型：`dict | list[dict] | string | list[string] | None`

- **内联 dict**：直接提供数据值
- **list[dict]**：批处理模式（多条记录）
- **string**：文件路径（`.json`, `.yaml`, `.jsonl`），相对于 .prompt 文件
- **list[string]**：多个输入文件（批处理模式）

**注意**：
- 输入 schema 会从数据结构自动推断，无需显式定义
- 文件路径相对于 .prompt 文件解析
- 路径遍历攻击会被拒绝（如 `../../etc/passwd`）
- 批处理模式从输入结构自动检测

---

### `output`

定义 prompt 的输出格式与结构配置。

```yaml
output:
  format: json
  schema:
    name?: string, 人物全名
    age?: number, 年龄
    occupation?: string, 职业
```

#### `PromptOutputConfig` 字段

| 字段 | 类型 | 说明 |
|------|------|------|
| `format` | `"json" \| "text" \| "image"` | 期望的输出格式 |
| `schema` | `Schema` | 输出结构的 schema 定义（支持 Picoschema 或 JSON Schema） |
| `save_path` | `string` | 图片输出保存路径（**当 `format` 为 `image` 时必填**） |

#### 输出格式说明

- **`json`** — 模型返回 JSON，可通过 `schema` 约束结构
- **`text`** — 纯文本输出（默认）
- **`image`** — 图片生成输出（目前仅 Google 适配器支持）

#### 图片输出示例

```yaml
output:
  format: image
  save_path: output/cat.png
```

> - `save_path` 在 `format: image` 时**必填**，否则会在解析时抛出 `ValidationError`
> - `save_path` 会校验路径遍历攻击（如 `../../etc/passwd`），仅允许当前工作目录内的路径
> - 父目录不存在时会自动创建

---

### `tools`

可用工具的名称列表。这些名称会在渲染时通过 `ToolResolver` 或静态 `tools` 映射解析为 `ToolDefinition`。

```yaml
tools:
  - search_web
  - calculate
```

---

### `toolDefs`

直接在 frontmatter 中内联定义工具。

```yaml
toolDefs:
  - name: search_web
    description: 在网络上搜索信息
    inputSchema:
      type: object
      properties:
        query:
          type: string
          description: 搜索关键词
      required:
        - query
    outputSchema:
      type: object
      properties:
        results:
          type: array
```

#### `ToolDefinition` 字段

| 字段 | 类型 | 必填 | 说明 |
|------|------|------|------|
| `name` | `string` | 是 | 工具唯一标识 |
| `description` | `string` | 否 | 工具用途描述 |
| `inputSchema` | `Schema` | 是 | 输入参数的 JSON Schema |
| `outputSchema` | `Schema` | 否 | 输出结构的 JSON Schema |

---

### `runtime`

控制 CLI 批处理执行的运行时参数。

```yaml
runtime:
  max_workers: 10
  output_dir: ./results
  jsonl: true
```

#### `RuntimeConfig` 字段

| 字段 | 类型 | 默认值 | 说明 |
|------|------|--------|------|
| `max_workers` | `integer` | `5` | 批处理并发 worker 数 |
| `output_dir` | `string` | `null` | 批处理输出文件目录 |
| `jsonl` | `boolean` | `false` | 是否以 JSONL 格式输出 |

---

### `ext`

扩展字段，用于自定义命名空间数据。通过带 `.` 的 key 自动生成嵌套结构。

```yaml
# frontmatter 中：
myapp.feature: enabled
myapp.version: 2

# 解析后的 ext 结构：
# {
#   "myapp": {
#     "feature": "enabled",
#     "version": 2
#   }
# }
```

---

### `metadata`

任意附加元数据字典。`HasMetadata` 基类允许 `extra='allow'`，因此可以包含任意字段。

```yaml
metadata:
  author: team-ai
  tags:
    - extraction
    - nlp
```

---

## Schema 定义格式

`input.schema` 和 `output.schema` 支持两种格式：

### 1. Picoschema（推荐）

Picoschema 是一种紧凑的、YAML 优化的 schema 定义格式，会编译为 JSON Schema。

#### 基本类型

| 类型 | 说明 |
|------|------|
| `string` | 字符串 |
| `number` | 数字（浮点） |
| `integer` | 整数 |
| `boolean` | 布尔值 |
| `null` | 空值 |
| `any` | 任意类型 |

#### 语法特性

**可选字段** — 字段名后加 `?`：

```yaml
schema:
  name?: string
```

**内联描述** — 类型后加逗号和描述：

```yaml
schema:
  name: string, 用户的全名
  age?: integer, 用户的年龄
```

**数组类型** — 使用 `(array)` 标注：

```yaml
schema:
  tags(array): string
  scores(array): number
```

**嵌套对象** — 使用 `(object)` 标注或直接嵌套：

```yaml
schema:
  address(object):
    street: string
    city: string
    zip?: string
```

等价的直接嵌套写法：

```yaml
schema:
  address:
    street: string
    city: string
    zip?: string
```

**枚举** — 使用 `(enum)` 标注：

```yaml
schema:
  status(enum):
    - PENDING
    - APPROVED
    - REJECTED
```

**通配符** — `(*)` 允许额外属性：

```yaml
schema:
  name: string
  (*): any
```

**命名引用** — 引用已注册的 schema：

```yaml
schema:
  user: UserProfile    # 通过 SchemaResolver 解析
```

#### 完整 Picoschema 示例

```yaml
input:
  schema:
    user(object):
      name: string, 用户全名
      age?: integer, 年龄
      email: string, 电子邮件
      tags(array): string
      role(enum):
        - admin
        - user
        - guest
      address?(object):
        city: string
        country: string
```

### 2. JSON Schema

直接使用标准 JSON Schema 格式：

```yaml
input:
  schema:
    type: object
    properties:
      name:
        type: string
        description: 用户全名
      age:
        type: integer
        description: 年龄
    required:
      - name
```

> 系统会自动检测：如果 schema 对象包含顶层 `type` 字段且值为合法 JSON Schema 类型，则视为 JSON Schema；否则视为 Picoschema。

---

## 模板正文

模板正文使用 [Handlebars](https://handlebarsjs.com) 语法，并扩展了以下 GenAI 专用 helper：

### 内置 Helper

| Helper | 用法 | 说明 |
|--------|------|------|
| `{{role "system"}}` | `{{role "system"}}` | 标记消息角色切换（`user`、`model`、`system`、`tool`） |
| `{{history}}` | `{{history}}` | 插入历史消息占位符 |
| `{{media url=... contentType=...}}` | `{{media url=imageUrl contentType="image/png"}}` | 插入媒体内容（图片、音频等） |
| `{{section "name"}}` | `{{section "summary"}}` | 标记内容分区 |
| `{{json value}}` | `{{json myObject indent=2}}` | 将值序列化为 JSON 字符串 |
| `{{#ifEquals a b}}...{{/ifEquals}}` | 条件块 | 两值相等时渲染内容 |
| `{{#unlessEquals a b}}...{{/unlessEquals}}` | 条件块 | 两值不等时渲染内容 |

### 消息角色

| 角色 | 说明 |
|------|------|
| `user` | 用户消息（默认角色） |
| `model` | 模型/AI 助手消息 |
| `system` | 系统指令消息 |
| `tool` | 工具调用结果消息 |

### Partial 引用

```handlebars
{{> partial_name}}
```

Partial 通过 `PartialResolver` 或 `PromptStore` 解析，支持递归引用（带循环检测）。

---

## 完整示例

### 文本提取

```handlebars
---
name: extract-person
description: 从文本中提取人物信息
adapter: openai
config:
  model: gpt-4o
  temperature: 0
input:
  schema:
    text: string, 待提取的原始文本
output:
  format: json
  schema:
    name?: string, 人物全名
    age?: number, 年龄
    occupation?: string, 职业
---
{{role "system"}}
你是一个信息提取助手。从给定文本中提取人物信息，如果某项信息不存在则省略该字段。

{{role "user"}}
请从以下文本中提取人物信息：

{{text}}
```

### 带历史记录的多轮对话

```handlebars
---
adapter: anthropic
config:
  model: claude-sonnet-4-20250514
  max_tokens: 2048
input:
  schema:
    question: string
---
{{role "system"}}
你是一个知识渊博的助手。

{{history}}

{{role "user"}}
{{question}}
```

### 图片生成

```handlebars
---
adapter: google
config:
  model: gemini-2.0-flash-exp
output:
  format: image
  save_path: output/result.png
input:
  schema:
    style: string, 绘画风格
    subject: string, 绘画主题
---
Draw a {{style}} illustration of {{subject}}.
```

### 第三方兼容服务（DeepSeek）

```handlebars
---
adapter:
  name: openai
  base_url: https://api.deepseek.com
config:
  model: deepseek-chat
  temperature: 0.7
input:
  schema:
    topic: string
---
请详细介绍 {{topic}}。
```

### 批处理配置

```handlebars
---
adapter: openai
config:
  model: gpt-4o-mini
runtime:
  max_workers: 20
  output_dir: ./batch-results
  jsonl: true
input:
  schema:
    text: string
output:
  format: json
  schema:
    summary: string
    sentiment(enum):
      - positive
      - negative
      - neutral
---
Summarize the following text and determine its sentiment:

{{text}}
```

---

## 保留关键字

以下字段名在 frontmatter 中被保留，不会进入 `ext` 命名空间扩展：

```
adapter, config, description, ext, input, name, output, raw, runtime, toolDefs, tools, variant, version
```

其他非保留的、不带 `.` 的 key 会被忽略（不进入 `ext`）。带 `.` 的 key 自动转为命名空间嵌套存入 `ext`。
