# https://github.com/vostride/id-agent 项目说明书

生成时间：2026-05-19 13:55:34 UTC

## 目录

- [项目介绍](#page-introduction)
- [安装与快速开始](#page-installation)
- [随机 ID 生成](#page-id-generation)
- [确定性 ID 生成](#page-deterministic-ids)
- [解析与验证](#page-parsing-validation)
- [词表设计](#page-wordlist-design)
- [加密模块](#page-crypto-module)
- [Zod 验证架构](#page-schemas-validation)
- [别名系统](#page-alias-system)
- [重复检测](#page-duplicate-detection)

<a id='page-introduction'></a>

## 项目介绍

### 相关页面

相关主题：[安装与快速开始](#page-installation), [随机 ID 生成](#page-id-generation)

<details>
<summary>相关源码文件</summary>

以下源码文件用于生成本页说明：

- [README.md](https://github.com/vostride/id-agent/blob/main/README.md)
- [src/index.ts](https://github.com/vostride/id-agent/blob/main/src/index.ts)
- [src/parse.ts](https://github.com/vostride/id-agent/blob/main/src/parse.ts)
- [src/detect.ts](https://github.com/vostride/id-agent/blob/main/src/detect.ts)
- [src/deterministic.ts](https://github.com/vostride/id-agent/blob/main/src/deterministic.ts)
- [src/wordlist.ts](https://github.com/vostride/id-agent/blob/main/src/wordlist.ts)
- [package.json](https://github.com/vostride/id-agent/blob/main/package.json)
- [scripts/validate-wordlist.ts](https://github.com/vostride/id-agent/blob/main/scripts/validate-wordlist.ts)
- [scripts/build-wordlist.ts](https://github.com/vostride/id-agent/blob/main/scripts/build-wordlist.ts)
</details>

# 项目介绍

## 概述

id-agent 是一个专为 AI Agent 系统设计的**人类可读、令牌高效**的 ID 生成库。该项目由 [vostride](https://github.com/vostride) 开发，采用 MIT 开源许可证，当前版本为 **1.0.3**。

资料来源：[package.json:2-10](https://github.com/vostride/id-agent/blob/main/package.json#L2-L10)

## 核心目标

id-agent 解决了传统 UUID 在 AI Agent 系统中的几个关键痛点：

| 问题 | UUID 方案 | id-agent 方案 |
|------|-----------|---------------|
| 令牌开销 | ~23 个令牌 | 3词约 5 个令牌（节省 78%） |
| 可读性 | 无意义十六进制字符串 | 自然语言单词组合 |
| 碰撞安全 | 120 bits 熵 | 默认 96 bits（安全 300 万亿条目） |
| 人类协作 | 难以口头交流 | 可直接朗读和拼写 |

资料来源：[README.md](https://github.com/vostride/id-agent/blob/main/README.md)

## 技术架构

### 架构概览

```mermaid
graph TD
    A[用户请求] --> B{ID 类型选择}
    B -->|随机 ID| C[crypto.getRandomValues CSPRNG]
    B -->|确定性 ID| D[HMAC-SHA256 Web Crypto API]
    C --> E[映射到 WORDLIST 索引]
    D --> E
    E --> F[formatId 格式化输出]
    F --> G[返回人类可读 ID]
    
    H[验证流程] --> I[parse 解析 ID]
    I --> J[wordlist 词表校验]
    J --> K{词存在?}
    K -->|是| L[返回有效结果]
    K -->|否| M[返回无效原因]
```

### 核心模块

| 模块 | 文件路径 | 职责 |
|------|----------|------|
| 主入口 | `src/index.ts` | 导出公共 API |
| 随机 ID | `src/random.ts` | 基于 CSPRNG 的随机 ID 生成 |
| 确定性 ID | `src/deterministic.ts` | 基于 HMAC-SHA256 的确定型 ID 生成 |
| 解析器 | `src/parse.ts` | 解析和验证 ID 格式 |
| 检测器 | `src/detect.ts` | 检测文本中的重复 ID |
| 词表 | `src/wordlist.ts` | 4096 个精选单词列表 |
| 别名映射 | `src/alias.ts` | 令牌压缩的双向映射 |

资料来源：[src/deterministic.ts:1-1](https://github.com/vostride/id-agent/blob/main/src/deterministic.ts#L1-L1)

## 工作原理

### 熵与安全性

id-agent 使用精心挑选的 **4096 词表**（2^12），每个单词贡献 12 bits 熵。单词选择通过以下流程确保安全性：

```mermaid
graph LR
    A[CSPRNG 随机数] --> B[取前 16 位]
    B --> C[模 4096 取余]
    C --> D[映射到 WORDLIST]
    D --> E[生成单词]
    E --> F[组合为 ID]
```

**碰撞概率计算公式：**

```
P(collision) ≈ n² / (2 × 2^b)

其中 b = 总熵位数
```

| 单词数 | 熵位 | ID 空间 | 50% 碰撞阈值 |
|--------|------|---------|--------------|
| 3 | 36 bits | 6.9 × 10¹⁰ | ~309K 项 |
| 5 | 60 bits | 1.2 × 10¹⁸ | ~13 亿项 |
| **8** | **96 bits** | **7.9 × 10²⁸** | **~300 万亿项** |
| 10 | 120 bits | 2.7 × 10¹⁸ | UUID 级别安全 |

资料来源：[README.md](https://github.com/vostride/id-agent/blob/main/README.md)

### 令牌效率

BPE 分词器（如 GPT-4o 使用的 o200k_base）在自然语言上训练，**短英文单词恰好是单个令牌**：

| 格式 | 令牌数 | 字符数 | 效率 |
|------|--------|--------|------|
| `dc193952-186a-4645` | ~11 tokens | 18 | 低 |
| `storm-delta-stone` | ~4 tokens | 18 | 高 |

词表中的每个单词都经过验证，确保在 o200k_base 分词器上是**恰好 1 个 BPE 令牌**。

资料来源：[README.md](https://github.com/vostride/id-agent/blob/main/README.md)

### 词表构建

词表构建经过多层过滤：

```mermaid
graph TD
    A[o200k_base 词汇表] --> B{长度 3-6 字符}
    B -->|是| C[系统词典验证]
    B -->|否| X[排除]
    C --> D{小写字母?}
    D -->|是| E{无同音词?}
    D -->|否| X
    E -->|是| F{无贬义?}
    E -->|否| X
    F -->|是| G[加入词表]
```

**过滤规则：**

1. **长度筛选**：仅保留 3-6 个字符的单词
2. **词典验证**：确保是有效的英语单词
3. **同音词过滤**：排除会产生歧义的同音词（如 `bare/bear`）
4. **内容过滤**：移除冒犯性词汇

资料来源：[scripts/build-wordlist.ts](https://github.com/vostride/id-agent/blob/main/scripts/build-wordlist.ts)

## API 参考

### 安装

```bash
npm install id-agent
# 或
pnpm add id-agent
```

**环境要求**：Node.js ≥ 18

资料来源：[package.json:32-33](https://github.com/vostride/id-agent/blob/main/package.json#L32-L33)

### `idAgent.generate(opts?)`

生成随机人类可读 ID。

```typescript
import { idAgent } from 'id-agent'

const id = idAgent.generate()
// => "storm-delta-stone"

const prefixed = idAgent.generate({ prefix: 'task', words: 5 })
// => "task_snow-ocean-frost-finch-grove"
```

**参数选项：**

| 参数 | 类型 | 默认值 | 描述 |
|------|------|--------|------|
| `prefix` | `string` | `undefined` | 类型前缀（小写字母数字） |
| `words` | `number` | `8` | 单词数量（1-16），控制熵位 |

### `idAgent.from(input, opts?)`

基于 HMAC-SHA256 生成确定性 ID，相同输入永远产生相同 ID。

```typescript
const id = await idAgent.from('user@example.com')
// 相同输入产生相同 ID

const namespaced = await idAgent.from('user@example.com', {
  namespace: 'my-app',
  prefix: 'user',
  words: 5,
})
```

**参数选项：**

| 参数 | 类型 | 默认值 | 描述 |
|------|------|--------|------|
| `prefix` | `string` | `undefined` | 类型前缀 |
| `words` | `number` | `8` | 单词数量（1-16） |
| `namespace` | `string` | `'id-agent'` | HMAC 密钥，用于域隔离 |

资料来源：[src/deterministic.ts](https://github.com/vostride/id-agent/blob/main/src/deterministic.ts)

### `parse(id)`

解析任意 id-agent ID 为其组成部分。

```typescript
import { parse } from 'id-agent'

parse('task_storm-delta-stone')
// => {
//   prefix: 'task',
//   words: ['storm', 'delta', 'stone'],
//   wordCount: 3,
//   bits: 36,
//   raw: 'task_storm-delta-stone',
//   format: 'readable'
// }
```

### `validate(id)`

验证字符串是否为合法的 id-agent ID。

```typescript
import { validate } from 'id-agent'

validate('storm-delta-stone')
// => { valid: true, prefix: undefined, wordCount: 3 }

validate('task_jump-notaword')
// => { valid: false, reason: 'unknown words: notaword' }

validate('INVALID')
// => { valid: false, reason: 'contains uppercase characters' }
```

资料来源：[src/parse.ts](https://github.com/vostride/id-agent/blob/main/src/parse.ts)

### `detectDuplicates(opts)`

扫描文本中的重复 ID。

```typescript
import { detectDuplicates } from 'id-agent'

const dupes = detectDuplicates({
  pattern: /[a-z]+(?:-[a-z]+)+/,
  text: 'Found storm-delta-stone in file A and storm-delta-stone in file B',
})
// => [{ id: 'storm-delta-stone', count: 2 }]
```

**参数选项：**

| 参数 | 类型 | 描述 |
|------|------|------|
| `pattern` | `RegExp` | 匹配 ID 的正则表达式 |
| `text` | `string \| string[]` | 要扫描的文本 |

资料来源：[src/detect.ts](https://github.com/vostride/id-agent/blob/main/src/detect.ts)

### `createAliasMap(opts)`

创建用于 LLM 上下文令牌压缩的双向别名映射。

```typescript
import { createAliasMap } from 'id-agent'

const aliases = createAliasMap({ words: 3 })

// 设置长 UUID 并获取短别名
aliases.set('8cdda07b-85d2-459c-8a2a-83c8f9245dbe')
// => "storm-delta-stone"

// 替换文本中的所有 UUID
const shortened = aliases.replace(text, {
  pattern: /[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}/gi
})

// 恢复原始 UUID
const restored = aliases.restore(shortened)
```

### `WORDLIST`

直接访问 4096 词表（只读数组）。

```typescript
import { WORDLIST } from 'id-agent'

WORDLIST.length          // => 4096
Object.isFrozen(WORDLIST) // => true
```

资料来源：[README.md](https://github.com/vostride/id-agent/blob/main/README.md)

## 应用场景

| 场景 | 推荐配置 | 熵位 | 说明 |
|------|----------|------|------|
| 开发/测试 | `words: 3` | 36 bits | 快速原型，便于一目了然 |
| 生产 SaaS | `words: 5` | 60 bits | 节省 65% 令牌，安全到 10 亿项 |
| 高并发/分布式 | `words: 8`（默认） | 96 bits | 默认安全配置，可应对 300 万亿项 |
| UUID 等效 | `words: 10` | 120 bits | 与 UUID v4 碰撞概率相同 |

## 开发命令

| 命令 | 说明 |
|------|------|
| `pnpm build` | 构建生产版本 |
| `pnpm test` | 运行测试 |
| `pnpm lint` | 代码检查 |
| `pnpm validate` | 验证词表质量 |
| `pnpm build:wordlist` | 重新构建词表 |

资料来源：[package.json:37-44](https://github.com/vostride/id-agent/blob/main/package.json#L37-L44)

## 项目依赖

### 生产依赖

| 依赖 | 版本 | 用途 |
|------|------|------|
| `zod` | 4.3.6 | Schema 验证 |

### 开发依赖

| 依赖 | 用途 |
|------|------|
| `vitest` | 单元测试 |
| `tsup` | 构建工具 |
| `js-tiktoken` | 分词器验证 |
| `obscenity` | 词表内容过滤 |
| `dprint` | 代码格式化 |
| `oxlint` | 代码检查 |

资料来源：[package.json:17-28](https://github.com/vostride/id-agent/blob/main/package.json#L17-L28)

## 总结

id-agent 是一款专为 AI Agent 工作流优化的 ID 生成工具，通过以下核心优势解决 LLM 上下文中的效率问题：

1. **令牌高效**：默认配置节省约 78% 的令牌开销
2. **人类可读**：基于自然语言单词，便于口头交流和日志追踪
3. **灵活安全**：可配置的熵位满足从开发到生产各级别需求
4. **确定性与随机性兼顾**：支持随机生成和 HMAC 确定性生成两种模式

---

<a id='page-installation'></a>

## 安装与快速开始

### 相关页面

相关主题：[项目介绍](#page-introduction), [随机 ID 生成](#page-id-generation)

<details>
<summary>相关源码文件</summary>

以下源码文件用于生成本页说明：

- [package.json](https://github.com/vostride/id-agent/blob/main/package.json)
- [README.md](https://github.com/vostride/id-agent/blob/main/README.md)
- [src/wordlist.ts](https://github.com/vostride/id-agent/blob/main/src/wordlist.ts)
- [src/parse.ts](https://github.com/vostride/id-agent/blob/main/src/parse.ts)
- [src/deterministic.ts](https://github.com/vostride/id-agent/blob/main/src/deterministic.ts)
</details>

# 安装与快速开始

## 项目概述

`id-agent` 是一个用于 AI 代理系统的人类可读、令牌高效的可识别 ID 生成库。该项目通过将 UUID 或其他长标识符转换为基于单词的短格式，实现高达 78% 的令牌节省效果，同时保持足够的熵值以防止碰撞。

资料来源：[package.json:2-3]()

## 安装前准备

### 系统要求

| 要求 | 最低版本 | 说明 |
|------|---------|------|
| Node.js | >= 18 | 必须支持 Web Crypto API |
| 包管理器 | pnpm 10.6.1 | 推荐使用 pnpm |

资料来源：[package.json:21-22]()

### 核心依赖

| 依赖 | 版本 | 用途 |
|------|------|------|
| zod | 4.3.6 | 参数验证与类型安全 |

资料来源：[package.json:28-30]()

## 安装步骤

### 方式一：使用 pnpm（推荐）

```bash
pnpm add id-agent
```

### 方式二：使用 npm

```bash
npm install id-agent
```

### 方式三：使用 yarn

```bash
yarn add id-agent
```

## 快速开始

### 基础导入与使用

```typescript
import { idAgent } from 'id-agent'

// 生成随机人类可读 ID
const id = await idAgent.generate()
// => "storm-delta-stone-cloud-voice-fruit-north-field"

// 带前缀的 ID
const taskId = await idAgent.generate({ prefix: 'task', words: 5 })
// => "task_storm-delta-stone-cloud-voice-fruit"
```

资料来源：[README.md](https://github.com/vostride/id-agent/blob/main/README.md)

### 确定性 ID 生成

基于输入字符串生成稳定的 ID，适用于用户 ID、文档 ID 等场景：

```typescript
const userId = await idAgent.from('user@example.com')
// 相同输入始终返回相同的 ID

const namespaced = await idAgent.from('user@example.com', {
  namespace: 'my-app',
  prefix: 'user',
  words: 5,
})
```

资料来源：[src/deterministic.ts:1-47]()

### ID 解析与验证

```typescript
import { parse, validate } from 'id-agent'

// 解析 ID 组成
const parsed = parse('task_storm-delta-stone')
// => { prefix: 'task', words: ['storm', 'delta', 'stone'], wordCount: 3, bits: 36 }

// 验证 ID 有效性
const result = validate('storm-delta-stone')
// => { valid: true, prefix: undefined, wordCount: 3 }

const invalid = validate('task_jump-notaword')
// => { valid: false, reason: 'unknown words: notaword' }
```

资料来源：[src/parse.ts]()

## 生成选项配置

| 选项 | 类型 | 默认值 | 取值范围 | 说明 |
|------|------|--------|---------|------|
| `prefix` | `string` | `undefined` | 小写字母数字 | 类型前缀，用于域名分离 |
| `words` | `number` | `8` | 1-16 | 单词数量，控制熵值：words * 12 bits |

资料来源：[README.md](https://github.com/vostride/id-agent/blob/main/README.md)

### 不同场景推荐配置

| 场景 | words | bits | 容量 | 说明 |
|------|-------|------|------|------|
| 快速原型 | 3 | 36 | ~309K | 最小令牌占用 |
| 生产 SaaS | 5 | 60 | ~1.3B | UUID 65% 令牌节省 |
| 高流量/分布式 | 8 | 96 | ~300T | 安全默认值 |

资料来源：[README.md](https://github.com/vostride/id-agent/blob/main/README.md)

## 别名映射与文本替换

在 LLM 上下文中，可以使用别名映射将长 ID 替换为短单词格式：

```typescript
import { createAliasMap } from 'id-agent'

const aliases = createAliasMap({ words: 3 })
aliases.set('8cdda07b-85d2-459c-8a2a-83c8f9245dbe')
// => "storm-delta-stone"

const text = 'Process 8cdda07b-85d2-459c-8a2a-83c8f9245dbe then 6ba7b810-9dad-11d1-80b4-00c04fd430c8'
const shortened = aliases.replace(text, {
  pattern: /[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}/gi
})
// => "Process storm-delta-stone then cloud-train-scope"

const restored = aliases.restore(shortened)
// => 恢复原始 UUID
```

资料来源：[README.md](https://github.com/vostride/id-agent/blob/main/README.md)

## 重复 ID 检测

```typescript
import { detectDuplicates } from 'id-agent'

const dupes = detectDuplicates({
  pattern: /[a-z]+(?:-[a-z]+)+/,
  text: 'Found storm-delta-stone in file A and storm-delta-stone in file B',
})
// => [{ id: 'storm-delta-stone', count: 2 }]
```

## 开发环境搭建

### 克隆项目

```bash
git clone https://github.com/vostride/id-agent.git
cd id-agent
```

### 安装依赖

```bash
pnpm install
```

### 可用脚本命令

| 命令 | 说明 |
|------|------|
| `pnpm build` | 使用 tsup 构建项目 |
| `pnpm test` | 运行 vitest 测试 |
| `pnpm test:watch` | 监听模式运行测试 |
| `pnpm lint` | 使用 oxlint 检查代码 |
| `pnpm format` | 使用 dprint 格式化代码 |
| `pnpm format:check` | 检查代码格式 |
| `pnpm size` | 检查 bundle 大小 |
| `pnpm publint` | 检查包发布配置 |
| `pnpm validate` | 验证单词列表 |

资料来源：[package.json:24-36]()

## 验证安装

安装完成后，可以通过以下方式验证：

```typescript
import { idAgent, WORDLIST } from 'id-agent'

// 验证 WORDLIST 加载
console.log(WORDLIST.length)          // => 4096
console.log(Object.isFrozen(WORDLIST)) // => true

// 生成测试 ID
const testId = await idAgent.generate({ words: 3 })
console.log(testId)                    // => 3 词格式 ID
```

## 下一步

- 查看 [基本概念](/docs/concepts) 了解 ID 格式与熵值计算
- 查看 [API 参考](/docs/api) 获取完整 API 文档
- 查看 [最佳实践](/docs/best-practices) 了解生产环境配置建议

---

<a id='page-id-generation'></a>

## 随机 ID 生成

### 相关页面

相关主题：[确定性 ID 生成](#page-deterministic-ids), [词表设计](#page-wordlist-design), [加密模块](#page-crypto-module)

<details>
<summary>相关源码文件</summary>

以下源码文件用于生成本页说明：

- [src/generate.ts](https://github.com/vostride/id-agent/blob/main/src/generate.ts)
- [src/types.ts](https://github.com/vostride/id-agent/blob/main/src/types.ts)
- [src/schemas.ts](https://github.com/vostride/id-agent/blob/main/src/schemas.ts)
- [src/deterministic.ts](https://github.com/vostride/id-agent/blob/main/src/deterministic.ts)
- [src/parse.ts](https://github.com/vostride/id-agent/blob/main/src/parse.ts)
- [src/alias.ts](https://github.com/vostride/id-agent/blob/main/src/alias.ts)
- [src/wordlist.ts](https://github.com/vostride/id-agent/blob/main/src/wordlist.ts)
- [package.json](https://github.com/vostride/id-agent/blob/main/package.json)
</details>

# 随机 ID 生成

## 概述

随机 ID 生成是 id-agent 项目的核心功能之一。该模块利用加密安全的随机数生成器（CSPRNG）创建人类可读、Token 高效的标识符。与传统的 UUID 相比，随机生成的 ID 由从精心策划的 4096 词表中选取的单词组成，每个单词恰好对应一个 BPE Token，在 LLM 场景下显著降低 Token 消耗。

## 核心设计

### 词表机制

id-agent 维护一个包含 4096 个英语单词的词表，每个单词满足以下条件：

- 长度为 3-6 个字符
- 在 o200k_base 分词器上恰好为 1 个 Token
- 不包含冒犯性词汇
- 排除同音异义词（如 "wait" 和 "weight"）

每个单词提供 log2(4096) = 12 位的熵值，ID 的总熵由单词数量决定：

```
总熵 = 单词数量 × 12 bits
ID空间 = 4096^单词数量 = 2^(单词数量 × 12)
```

资料来源：[README.md](https://github.com/vostride/id-agent/blob/main/README.md)

### 随机数生成

随机 ID 使用 `crypto.getRandomValues()` 作为熵源，这是 Web Crypto API 提供的加密安全随机数生成器。相比 Math.random()，CSPRNG 提供的随机数具有密码学安全性，适用于需要防止预测的攻击场景。

## API 参考

### `idAgent.random(opts?)`

生成一个随机 ID，默认配置为 8 个单词（96 位熵）。

```typescript
import { idAgent } from 'id-agent'

const id = idAgent.random()
// => "storm-delta-stone-cloud-frost-raven-ocean-ember"

const shortId = idAgent.random({ words: 3 })
// => "storm-delta-stone"

const prefixedId = idAgent.random({ prefix: 'user', words: 5 })
// => "user-storm-delta-stone-cloud-frost"
```

#### 参数选项

| 参数 | 类型 | 默认值 | 描述 |
|------|------|--------|------|
| `prefix` | `string` | `undefined` | 类型前缀（小写字母数字组合） |
| `words` | `number` | `8` | 单词数量（范围 1-16），控制熵值 |

参数验证由 Zod Schema 执行，无效输入会抛出描述性错误。

资料来源：[src/schemas.ts](https://github.com/vostride/id-agent/blob/main/src/schemas.ts)

### 类型定义

```typescript
interface IdAgentRandomOptions {
  prefix?: string
  words?: number
}

interface IdAgent {
  random(opts?: IdAgentRandomOptions): string
  from(input: string, opts?: IdAgentFromOptions): Promise<string>
  parse(id: string): ParsedId | null
  validate(id: string): ValidationResult
}
```

资料来源：[src/types.ts](https://github.com/vostride/id-agent/blob/main/src/types.ts)

## 工作流程

```mermaid
graph TD
    A[调用 idAgent.random] --> B{参数验证}
    B -->|通过| C[计算所需单词数]
    B -->|失败| Z[抛出 ZodError]
    C --> D[调用 crypto.getRandomValues]
    D --> E[从 DataView 读取随机字节]
    E --> F[每 2 字节映射到 WORDLIST 索引]
    F --> G{检查重复}
    G -->|无重复| H[收集单词到数组]
    G -->|重复| E
    H --> I{单词数已满足}
    I -->|否| E
    I -->|是| J[拼接单词为字符串]
    J --> K{提供 prefix}
    K -->|是| L[添加前缀: prefix-words]
    K -->|否| M[仅返回 words]
    L --> N[返回完整 ID]
    M --> N
```

## 碰撞概率分析

由于使用固定词表，存在理论碰撞概率。根据生日悖论公式：

```
P(碰撞) ≈ n² / (2 × 2^b)

其中 b = 总位数 = 单词数 × 12
```

### 不同配置的碰撞概率

| 单词数 | 熵值 | ID 空间 | 100 万条时概率 | 10 亿条时概率 | 50% 碰撞点 |
|--------|------|---------|----------------|---------------|------------|
| 3 | 36 位 | 6.9 × 10¹⁰ | 0.00004% | ~43% | ~309K 条 |
| 4 | 48 位 | 2.8 × 10¹⁴ | 1.8 × 10⁻⁶ % | ~100% | ~20M 条 |
| 5 | 60 位 | 1.2 × 10¹⁸ | 4.3 × 10⁻⁸ % | 0.43% | ~1.3B 条 |
| **8** | **96 位** | **7.9 × 10²⁸** | **6.3 × 10⁻¹⁸ %** | **~0%** | **~300T 条** |
| 10 | 120 位 | 1.3 × 10³⁶ | ~0% | 9.4 × 10⁻²⁰ % | ~2.7 × 10¹⁸ 条 |

**默认配置（8 单词，96 位）** 可安全处理超过 300 万亿条 ID 而不产生 50% 碰撞概率。

资料来源：[README.md](https://github.com/vostride/id-agent/blob/main/README.md)

## Token 效率对比

id-agent 的单词型 ID 在 LLM 分词器上远比 UUID 高效。以 o200k_base 分词器为例：

| 格式 | 平均 Token 数 | 熵值 | 相比 UUID 节省 |
|------|---------------|------|----------------|
| UUID v4 | ~23 | 122 位 | -- |
| id-agent (3 单词) | ~5 | 36 位 | **78%** |
| id-agent (5 单词) | ~9 | 60 位 | **61%** |
| id-agent (8 单词) | ~14 | 96 位 | **39%** |

这是因为短英语单词在 BPE 分词器上天然就是单个 Token，而 UUID 的十六进制字符会不可预测地分裂成多个 Token。

资料来源：[README.md](https://github.com/vostride/id-agent/blob/main/README.md)

## 与确定性 ID 的关系

id-agent 提供两种 ID 生成模式：

| 模式 | 熵源 | 可重现性 | 适用场景 |
|------|------|----------|----------|
| **随机** `random()` | `crypto.getRandomValues()` | 否 | 会话 ID、临时标识符 |
| **确定性** `from()` | HMAC-SHA256 | 是 | 用户标识、内容寻址 |

确定性模式使用相同的词表和单词选择逻辑，但通过 HMAC-SHA256 将输入字符串映射到固定的单词序列，确保相同输入始终产生相同输出。

```typescript
// 随机 ID：每次调用生成不同 ID
idAgent.random()   // => "storm-delta-stone..."
idAgent.random()   // => "frost-ocean-ember..."

// 确定性 ID：相同输入产生相同 ID
await idAgent.from('user@example.com')   // => "cloud-train-scope..."
await idAgent.from('user@example.com')   // => "cloud-train-scope..."
```

资料来源：[src/deterministic.ts](https://github.com/vostride/id-agent/blob/main/src/deterministic.ts)

## 使用场景

### 场景一：会话标识符

```typescript
const sessionId = idAgent.random({ words: 4, prefix: 'session' })
// => "session-storm-delta-stone-cloud"
```

### 场景二：任务队列标识符

```typescript
const taskId = idAgent.random({ words: 5, prefix: 'task' })
// => "task-frost-ocean-ember-light-rain"
```

### 场景三：轻量级随机标识符

```typescript
const shortId = idAgent.random({ words: 3 })
// => "stone-cloud-train"
```

## 配置建议

| 应用场景 | 推荐配置 | 熵值 | 说明 |
|----------|----------|------|------|
| 开发/测试 | `words: 3` | 36 位 | 简短易读，用于非关键场景 |
| 生产 SaaS | `words: 5` | 60 位 | 安全到约 10 亿条，节省 65% Token |
| 高容量/分布式 | `words: 8` (默认) | 96 位 | 安全到约 300 万亿条，推荐默认值 |
| UUID 等效 | `words: 10` | 120 位 | 与 UUID v4 碰撞概率相当 |

## 安全性考量

### CSPRNG 的必要性

使用 `crypto.getRandomValues()` 而非 `Math.random()` 是关键安全设计：

- `Math.random()`：伪随机数，可被预测
- `crypto.getRandomValues()`：密码学安全随机数，满足熵要求

### 前缀验证

前缀仅接受小写字母数字组合（`/^[a-z0-9]+$/`），防止格式注入和解析歧义。

```typescript
idAgent.random({ prefix: 'User-ID' })
// => 抛出错误: "prefix must be lowercase alphanumeric only"
```

资料来源：[src/schemas.ts](https://github.com/vostride/id-agent/blob/main/src/schemas.ts)

## 验证与解析

### `validate(id)`

验证 ID 是否合法：

```typescript
import { validate } from 'id-agent'

validate('storm-delta-stone')
// => { valid: true, prefix: undefined, wordCount: 3 }

validate('task_jump-notaword')
// => { valid: false, reason: 'unknown words: notaword' }
```

### `parse(id)`

解析 ID 的组成部分：

```typescript
import { parse } from 'id-agent'

parse('task_storm-delta-stone')
// => {
//   prefix: 'task',
//   words: ['storm', 'delta', 'stone'],
//   wordCount: 3,
//   bits: 36,
//   raw: 'task_storm-delta-stone',
//   format: 'readable'
// }
```

资料来源：[src/parse.ts](https://github.com/vostride/id-agent/blob/main/src/parse.ts)

## 内部实现

### 单词选择算法

核心逻辑位于 `selectRandomWords` 函数，通过以下步骤选择单词：

1. 使用 `DataView.getUint16()` 从随机字节序列中读取 16 位无符号整数
2. 取模 4096 得到词表索引
3. 重复直到收集到所需单词数量
4. 去重确保无重复单词

### 重复检测

如果生成过程中出现重复单词，会重新生成而不是替换。这确保 ID 的实际熵值与理论值一致。

```typescript
// 简化伪代码
do {
  word = WORDLIST[randomUint16() % 4096]
} while (used.has(word) && used.size < 4096)
```

## 总结

随机 ID 生成是 id-agent 项目的基石功能，通过以下设计实现了安全性、可读性和 Token 效率的统一：

- **4096 词表**：每个单词 12 位熵，BPE 友好
- **CSPRNG**：密码学安全的熵源
- **可配置单词数**：根据场景平衡安全性和简洁性
- **可选前缀**：支持类型化 ID 命名空间
- **与确定性模式共存**：覆盖随机和可重现两种场景

---

<a id='page-deterministic-ids'></a>

## 确定性 ID 生成

### 相关页面

相关主题：[随机 ID 生成](#page-id-generation), [加密模块](#page-crypto-module)

<details>
<summary>相关源码文件</summary>

以下源码文件用于生成本页说明：

- [src/deterministic.ts](https://github.com/vostride/id-agent/blob/main/src/deterministic.ts)
- [src/generate.ts](https://github.com/vostride/id-agent/blob/main/src/generate.ts)
- [src/parse.ts](https://github.com/vostride/id-agent/blob/main/src/parse.ts)
- [src/schemas.ts](https://github.com/vostride/id-agent/blob/main/src/schemas.ts)
- [src/types.ts](https://github.com/vostride/id-agent/blob/main/src/types.ts)
- [src/wordlist.ts](https://github.com/vostride/id-agent/blob/main/src/wordlist.ts)
- [README.md](https://github.com/vostride/id-agent/blob/main/README.md)
</details>

# 确定性 ID 生成

## 概述

确定性 ID 生成是 id-agent 库的核心功能之一，允许从任意字符串输入生成唯一、可复现的 ID。与随机 ID 生成不同，相同的输入无论何时何地调用，都会产生完全相同的输出 ID。

该功能主要适用于：

- **用户标识**：基于邮箱、用户名等生成唯一用户 ID
- **内容寻址**：基于文件内容哈希生成确定性文件 ID
- **幂等操作**：为请求生成稳定的标识符用于去重

核心原理是通过 HMAC-SHA256 哈希函数将输入字符串转换为加密安全的伪随机数，然后将这些数字映射到精选的 4096 词表中的单词。

## 工作原理

### 架构流程

```mermaid
graph TD
    A[输入字符串] --> B[TextEncoder 编码]
    B --> C[导入 HMAC 密钥]
    C --> D[crypto.subtle.sign 使用 HMAC-SHA256]
    D --> E[DataView 读取签名结果]
    E --> F[每 2 字节映射到 WORDLIST 索引]
    F --> G[拼接单词为最终 ID]
    
    H[namespace 配置] --> C
    I[words 数量] --> F
    J[prefix 前缀] --> G
```

### 关键步骤解析

**步骤 1：输入验证与编码**

函数首先验证输入有效性，确保传入的是非空字符串：

```typescript
if (!input || typeof input !== 'string') {
  throw new Error('input must be a non-empty string')
}
```
资料来源：[src/deterministic.ts:10](https://github.com/vostride/id-agent/blob/main/src/deterministic.ts#L10)

**步骤 2：选项解析与默认值**

使用 Zod Schema 验证并应用默认配置，words 默认值为 8：

```typescript
const validated = IdAgentFromOptionsSchema.parse(opts ?? {})
const words = validated.words ?? 8
```
资料来源：[src/deterministic.ts:12-13](https://github.com/vostride/id-agent/blob/main/src/deterministic.ts#L12-L13)

**步骤 3：Web Crypto API 密钥导入**

使用 Web Crypto API 的 `crypto.subtle` 模块导入 HMAC 密钥：

```typescript
const enc = new TextEncoder()
const keyData = enc.encode(validated.namespace ?? 'id-agent')
const key = await globalThis.crypto.subtle.importKey(
  'raw',
  keyData,
  { name: 'HMAC', hash: 'SHA-256' },
  false,
  ['sign'],
)
```
资料来源：[src/deterministic.ts:18-24](https://github.com/vostride/id-agent/blob/main/src/deterministic.ts#L18-L24)

**步骤 4：HMAC-SHA256 签名**

对输入字符串进行加密签名：

```typescript
const sig = await globalThis.crypto.subtle.sign('HMAC', key, enc.encode(input))
```
资料来源：[src/deterministic.ts:26](https://github.com/vostride/id-agent/blob/main/src/deterministic.ts#L26)

**步骤 5：哈希值到单词的映射**

将签名结果转换为 DataView，每 2 字节（16 位）作为一个索引，取模 4096 获取词表中的单词：

```typescript
const view = new DataView(sig)
const selected: string[] = new Array(words)
for (let i = 0; i < words; i++) {
  selected[i] = WORDLIST[view.getUint16(i * 2) % 4096]
}
```
资料来源：[src/deterministic.ts:28-32](https://github.com/vostride/id-agent/blob/main/src/deterministic.ts#L28-L32)

**步骤 6：格式化输出**

使用 `formatId` 函数将前缀和单词数组拼接为最终 ID：

```typescript
return formatId(validated.prefix, selected.join('-'))
```
资料来源：[src/deterministic.ts:34](https://github.com/vostride/id-agent/blob/main/src/deterministic.ts#L34)

## API 参考

### idAgent.from(input, opts?)

生成确定性 ID 的主要方法，挂载在 `idAgent` 函数对象上。

```typescript
import { idAgent } from 'id-agent'

const id = await idAgent.from('user@example.com')
// => 例如：vivid-shade-glimmer (每次相同)
```

#### 参数说明

| 参数 | 类型 | 必填 | 默认值 | 说明 |
|------|------|------|--------|------|
| `input` | `string` | 是 | - | 用于生成 ID 的输入字符串 |
| `opts.prefix` | `string` | 否 | `undefined` | 类型前缀（小写字母数字） |
| `opts.words` | `number` | 否 | `8` | 单词数量（1-16），控制熵值 |
| `opts.namespace` | `string` | 否 | `'id-agent'` | HMAC 密钥，用于域隔离 |

资料来源：[src/generate.ts:8](https://github.com/vostride/id-agent/blob/main/src/generate.ts#L8)，[README.md](https://github.com/vostride/id-agent/blob/main/README.md)

#### 返回值

返回格式化后的确定性 ID 字符串，格式为：`{prefix_}word1-word2-word3-...`

#### 使用示例

**基础用法**

```typescript
const id = await idAgent.from('user@example.com')
// 每次调用都返回相同结果
```

**带前缀和命名空间**

```typescript
const userId = await idAgent.from('user@example.com', {
  namespace: 'my-app',
  prefix: 'user',
  words: 5,
})
// => "user_calm-bold-wake-tide-neat"
```

**不同命名空间产生不同 ID**

```typescript
const id1 = await idAgent.from('same-input', { namespace: 'app-a' })
const id2 = await idAgent.from('same-input', { namespace: 'app-b' })
// id1 !== id2 (因为命名空间不同)
```

## 配置选项详解

### words 参数

控制生成 ID 的单词数量，直接决定熵值大小。

| words 值 | 熵值 | ID 空间 | 适用场景 |
|----------|------|---------|----------|
| 3 | 36 bits | 6.9 × 10¹⁰ | 仅用于日志/调试 |
| 5 | 60 bits | 1.2 × 10¹⁸ | 生产级 SaaS 应用 |
| 8 | 96 bits | 7.9 × 10²⁸ | **默认**，高容量/分布式系统 |
| 10 | 120 bits | 1.3 × 10³⁶ | UUID v4 等效安全级别 |

资料来源：[README.md](https://github.com/vostride/id-agent/blob/main/README.md)

### namespace 参数

HMAC 密钥用于域隔离，确保相同输入在不同应用/租户间产生不同 ID。

```typescript
// 多租户场景
const id1 = await idAgent.from('shared-resource-id', { namespace: 'tenant-1' })
const id2 = await idAgent.from('shared-resource-id', { namespace: 'tenant-2' })
```

### prefix 参数

类型前缀用于区分不同实体的 ID，便于人工识别和日志分析。

- 必须是 **小写字母数字**
- 格式：`{prefix}_word-word-word`
- 例如：`user_`、`task_`、`file_`

```typescript
await idAgent.from('doc-123', { prefix: 'doc' })
// => "doc_river-wave-soft-wake-calm-dream-bloom"
```

## 验证与解析

### validate(id)

验证确定性 ID 的有效性，检查词表中的单词是否都存在：

```typescript
import { validate } from 'id-agent'

validate('task_storm-delta-stone')
// => { valid: true, prefix: 'task', wordCount: 3 }

validate('task_jump-notaword')
// => { valid: false, reason: 'unknown words: notaword' }
```
资料来源：[src/parse.ts](https://github.com/vostride/id-agent/blob/main/src/parse.ts)

### parse(id)

解析 ID 的结构组件：

```typescript
import { parse } from 'id-agent'

parse('task_storm-delta-stone')
// => {
//   prefix: 'task',
//   words: ['storm', 'delta', 'stone'],
//   wordCount: 3,
//   bits: 36,
//   raw: 'task_storm-delta-stone',
//   format: 'readable'
// }
```
资料来源：[src/parse.ts](https://github.com/vostride/id-agent/blob/main/src/parse.ts)

## 安全性分析

### HMAC-SHA256 保障

确定性 ID 生成使用 Web Crypto API 的 `crypto.subtle.sign` 方法，底层采用 HMAC-SHA256 算法：

```mermaid
graph LR
    A[输入] --> B[HMAC-SHA256]
    B --> C[128位签名]
    C --> D[选取前 2×words 字节]
    D --> E[每字节对 4096 取模]
    E --> F[映射到单词]
```

### 域隔离机制

通过 namespace 参数实现密钥隔离，即使输入相同，不同命名空间产生的 HMAC 签名完全不同：

```typescript
// 即使输入完全相同
idAgent.from('same-input', { namespace: 'ns-a' })  // => 完全不同的输出
idAgent.from('same-input', { namespace: 'ns-b' })  // => 完全不同的输出
```

### 熵值计算

每个单词贡献 12 bits 熵值（因为词表大小为 4096 = 2¹²）：

```
总熵值 = words × 12 bits
```

默认 8 个单词提供 96 bits 熵值，在 300 万亿个项目内碰撞概率低于 50%。

## 浏览器兼容性

该功能依赖 **Web Crypto API**，要求：

| 环境 | 支持情况 | 说明 |
|------|----------|------|
| 现代浏览器 | ✅ | HTTPS 环境下完整支持 |
| Node.js 18+ | ✅ | 内置 Web Crypto API |
| HTTP 页面 | ❌ | 浏览器安全限制 |
| Node.js <18 | ❌ | 需升级版本 |

```typescript
if (!globalThis.crypto?.subtle) {
  throw new Error('idAgent.from() requires Web Crypto API (crypto.subtle). Use HTTPS in browsers.')
}
```
资料来源：[src/deterministic.ts:15-17](https://github.com/vostride/id-agent/blob/main/src/deterministic.ts#L15-L17)

## 最佳实践

### 生产环境推荐配置

```typescript
// 高安全性场景
const secureId = await idAgent.from(userId, {
  words: 8,        // 默认值，96 bits 熵值
  prefix: 'user',
  namespace: process.env.APP_NAMESPACE
})

// 平衡可读性与安全性
const balancedId = await idAgent.from(resourceId, {
  words: 5,        // 60 bits，适合大多数应用
  prefix: 'resource'
})
```

### 常见错误处理

```typescript
try {
  const id = await idAgent.from('')
} catch (e) {
  // Error: input must be a non-empty string
}

try {
  const id = await idAgent.from('input', { words: 20 })
} catch (e) {
  // ZodError: Number must be less than or equal to 16
}
```

## 与随机 ID 对比

| 特性 | 确定性 ID (`from`) | 随机 ID (`idAgent()`) |
|------|-------------------|----------------------|
| 输入要求 | 任意字符串 | 无 |
| 可复现性 | ✅ 相同输入 → 相同输出 | ❌ 每次不同 |
| Web Crypto | ✅ 必须 | ❌ 可选 |
| 适用场景 | 用户/内容标识 | 会话/临时 ID |
| 熵值来源 | HMAC-SHA256 | CSPRNG |

资料来源：[src/generate.ts](https://github.com/vostride/id-agent/blob/main/src/generate.ts)

---

<a id='page-parsing-validation'></a>

## 解析与验证

### 相关页面

相关主题：[随机 ID 生成](#page-id-generation), [Zod 验证架构](#page-schemas-validation)

<details>
<summary>相关源码文件</summary>

以下源码文件用于生成本页说明：

- [src/parse.ts](https://github.com/vostride/id-agent/blob/main/src/parse.ts)
- [src/detect.ts](https://github.com/vostride/id-agent/blob/main/src/detect.ts)
- [src/alias.ts](https://github.com/vostride/id-agent/blob/main/src/alias.ts)
- [src/deterministic.ts](https://github.com/vostride/id-agent/blob/main/src/deterministic.ts)
- [src/wordlist.ts](https://github.com/vostride/id-agent/blob/main/src/wordlist.ts)
- [scripts/validate-wordlist.ts](https://github.com/vostride/id-agent/blob/main/scripts/validate-wordlist.ts)
- [package.json](https://github.com/vostride/id-agent/blob/main/package.json)
</details>

# 解析与验证

## 概述

解析与验证模块是 id-agent 项目中处理 ID 字符串的核心功能组件。该模块负责将人类可读的 ID 字符串解析为其组成成分，并检验其是否符合 id-agent 规范的格式要求。解析功能支持连字符分隔和下划线分隔两种格式，能够提取出前缀、单词数组、单词数量和熵位数等信息。验证功能则确保生成的 ID 仅包含有效的单词，并且格式完全符合规范要求。

在 id-agent 的整体架构中，解析与验证模块扮演着基础设施的角色，被别名映射（AliasMap）、确定性 ID 生成（deterministicId）以及重复检测（detectDuplicates）等多个功能模块所依赖。这种设计确保了整个系统在处理 ID 字符串时拥有一致性的验证标准和数据格式。

## 核心 API

### parse 函数

`parse` 函数是解析模块的入口函数，用于将 id-agent 格式的 ID 字符串分解为其组成成分。该函数支持连字符分隔（如 `task_storm-delta-stone`）和下划线分隔（如 `task_storm_delta_stone`）两种格式，并能够智能识别前缀与单词部分的分隔方式。

函数返回的对象包含以下属性：prefix 表示 ID 的前缀类型（如 `task`），若不存在前缀则返回 `undefined`；words 是一个字符串数组，包含 ID 中的所有单词；wordCount 表示单词的数量；bits 表示总熵位数，计算公式为 `words.length * 12`；raw 保存原始输入字符串；format 字段标识输入格式为 `readable`。当输入字符串无法被识别为有效的 id-agent 格式时，函数返回 `null`。

```typescript
import { parse } from 'id-agent'

parse('task_storm-delta-stone')
// => { prefix: 'task', words: ['storm', 'delta', 'stone'], wordCount: 3, bits: 36, raw: 'task_storm-delta-stone', format: 'readable' }

parse('task_storm_delta_stone')
// => { prefix: 'task', words: ['storm', 'delta', 'stone'], wordCount: 3, bits: 36, raw: 'task_storm_delta_stone', format: 'readable' }
```

解析算法首先尝试按下划线分割字符串，取第一部分作为候选前缀。若第一部分仅包含小写字母和数字，则将其识别为有效前缀；否则整个字符串将被视为纯单词序列。单词提取阶段通过正则表达式匹配连续的纯小写字母单词序列，支持连字符或下划线作为单词间的分隔符。这种双重格式支持使得 id-agent 能够兼容不同来源和风格的 ID 命名约定。

资料来源：[src/parse.ts:1-30]()

### validate 函数

`validate` 函数用于检验给定的字符串是否为合法的 id-agent ID。该函数执行多层次的验证检查，包括大写字符检测、无效字符检测、格式识别以及单词有效性验证。只有通过全部检查的 ID 才会被标记为有效。

验证流程首先检查字符串是否包含大写字符。id-agent 规范要求所有字符必须为小写，因此任何大写字母的出现都会导致验证失败并返回 `contains uppercase characters` 错误信息。资料来源：[src/parse.ts:41-43]()

接下来验证字符串是否包含非法字符。有效字符集限于小写字母、数字、连字符和下划线。若发现其他字符，函数返回 `contains invalid characters` 错误。资料来源：[src/parse.ts:44-46]()

然后调用 `parse` 函数尝试解析 ID。若解析失败（返回 `null`），说明字符串不符合 id-agent 的基本格式要求，验证将返回 `unrecognized format` 错误。资料来源：[src/parse.ts:47-49]()

最后一项验证是单词词汇表检查。解析成功后，函数会逐一检查每个单词是否存在于 id-agent 的 4096 词单词列表中。若发现任何未知单词，返回 `unknown words: ${invalid.join(', ')}` 错误信息，列出所有无效单词。资料来源：[src/parse.ts:50-58]()

```typescript
import { validate } from 'id-agent'

validate('storm-delta-stone')
// => { valid: true, prefix: undefined, wordCount: 3 }

validate('task_jump-notaword')
// => { valid: false, reason: 'unknown words: notaword' }

validate('INVALID')
// => { valid: false, reason: 'contains uppercase characters' }
```

成功验证时返回的对象包含 `valid: true`、可选的 `prefix` 字段以及 `wordCount` 表示单词数量。这种结构化的返回方式便于调用方根据验证结果进行后续处理，同时保留了必要的元数据信息。

## 重复检测功能

### detectDuplicates 函数

`detectDuplicates` 函数提供在文本中扫描重复 ID 的能力。该函数是纯函数实现，不涉及文件系统访问，仅依赖正则表达式进行模式匹配，因此可以在任何环境中安全使用。资料来源：[src/detect.ts:1-27]()

函数接受一个包含 `pattern` 和 `text` 两个属性的选项对象。`pattern` 是一个正则表达式，用于匹配待检测的 ID 格式；`text` 可以是单个字符串或字符串数组，函数会统一处理两种输入形式。资料来源：[src/detect.ts:3-7]()

重复检测的工作流程首先将 `text` 参数统一转换为数组形式，然后遍历每一段文本使用正则表达式进行全局匹配。正则表达式的 `g` 标志确保能够找到所有匹配项，同时代码会确保匹配器始终以全局模式运行。资料来源：[src/detect.ts:8-19]()

检测结果以数组形式返回，每个元素是一个包含 `id` 和 `count` 属性的对象。`id` 字段保存重复出现的 ID 字符串，`count` 字段表示该 ID 在文本中出现的次数。仅当 `count > 1` 时，结果才会被包含在返回值中，这意味着函数默认过滤掉仅出现一次的 ID。资料来源：[src/detect.ts:20-26]()

```typescript
import { detectDuplicates } from 'id-agent'

const dupes = detectDuplicates({
  pattern: /[a-z]+(?:-[a-z]+)+/,
  text: 'Found storm-delta-stone in file A and storm-delta-stone in file B',
})
// => [{ id: 'storm-delta-stone', count: 2 }]

const dupes2 = detectDuplicates({
  pattern: /task_[a-z]+(?:-[a-z]+)+/,
  text: ['const x = "task_red-fox-run"', 'const y = "task_red-fox-run"'],
})
```

该函数在实际应用场景中具有广泛的用途，包括但不限于：检测代码库中是否存在重复的 ID 定义、验证测试数据中的 ID 唯一性、以及在数据迁移过程中确保 ID 不发生冲突。纯函数的设计使其特别适合在持续集成环境中作为自动化检查工具使用。

## 别名映射系统

### createAliasMap 函数

`createAliasMap` 函数创建一个双向别名映射系统，用于在 LLM 上下文中实现令牌节省。该系统将长格式的原始标识符（如 UUID）映射为短格式的单词别名，并在需要时能够精确恢复原始值。资料来源：[src/alias.ts:1-67]()

别名映射对象提供三个核心方法：`set(original)` 用于添加新的映射关系并返回生成的别名；`get(alias)` 根据别名查找原始值；`replace(text, options)` 批量替换文本中所有已注册的标识符；`restore(text)` 恢复被替换的标识符。

```typescript
import { createAliasMap } from 'id-agent'

const aliases = createAliasMap({ words: 3 })
aliases.set('8cdda07b-85d2-459c-8a2a-83c8f9245dbe')
// => "storm-delta-stone" (3 random words from WORDLIST)

aliases.get('storm-delta-stone')
// => "8cdda07b-85d2-459c-8a2a-83c8f9245dbe"

const text = 'Process 8cdda07b-85d2-459c-8a2a-83c8f9245dbe then 6ba7b810-9dad-11d1-80b4-00c04fd430c8'
const shortened = aliases.replace(text, {
  pattern: /[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}/gi
})
// => "Process storm-delta-stone then cloud-train-scope"

const restored = aliases.restore(shortened)
// => original text
```

`set` 方法内部维护两个映射表：`forward` 将原始值映射到别名，`reverse` 将别名映射回原始值。当添加新的映射时，方法首检查是否存在已有映射以避免重复生成。若启用冲突允许选项，在生成别名时会进行碰撞检测。资料来源：[src/alias.ts:19-31]()

`replace` 方法支持可选的正则表达式参数，若提供则仅替换匹配该模式的字符串。这种设计允许调用方精确控制替换范围，避免意外替换不应被处理的文本内容。资料来源：[src/alias.ts:32-50]()

## 单词列表系统

### WORDLIST 常量

`WORDLIST` 是 id-agent 项目精心策划的 4096 词单词列表，每个单词都经过验证恰好是 o200k_base 分词器（GPT-4o、GPT-4.1 等模型使用）的单个 BPE 令牌。这个特性是 id-agent 实现令牌效率的基础。资料来源：[src/wordlist.ts](https://github.com/vostride/id-agent/blob/main/src/wordlist.ts)

单词列表构建过程包含多个严格的筛选阶段。首先从 o200k_base 词汇表中提取所有 3-6 个字符的候选单词，然后与系统词典进行交叉验证确保词汇的有效性。资料来源：[scripts/build-wordlist.ts:30-50]()

接下来进行两项 BPE 令牌验证：单令牌编码测试确保单词独立编码为单个令牌；连字符前缀测试确保单词在与其他内容连接时不会产生额外的令牌分割。资料来源：[scripts/build-wordlist.ts:51-65]()

最后进行语义过滤，使用 obscenity 库检测并移除不适当的词汇，同时人工审查移除同音异义词（如 "wait" 和 "weight"），避免在口语环境中造成混淆。资料来源：[scripts/build-wordlist.ts:66-90]()

```typescript
import { WORDLIST } from 'id-agent'

WORDLIST.length          // => 4096
Object.isFrozen(WORDLIST) // => true
```

单词列表以冻结数组形式导出，确保在运行期间不可被修改。这种不可变性保证了解析和验证结果的确定性和可靠性。

### validate-wordlist.ts 验证脚本

`scripts/validate-wordlist.ts` 是项目提供的单词列表验证工具，用于确保 WORDLIST 满足所有令牌效率和安全要求。该脚本通过编程方式验证列表中每个单词的特性。

验证包含两个主要检查：单令牌验证确保每个单词编码为恰好一个 BPE 令牌；连字符前缀验证确保单词在与其他内容连接时保持令牌边界。资料来源：[scripts/validate-wordlist.ts:1-25]()

脚本输出详细的验证报告，包括通过检查的项目数量和失败的单词列表（若存在）。所有检查通过时输出 `ALL CHECKS PASSED`，否则列出失败数量并返回非零退出码。

```bash
pnpm run validate
```

开发者可以通过运行此脚本快速验证单词列表的完整性，在修改单词列表或升级分词器版本后尤其重要。

## 数据结构

### 解析结果类型

| 字段 | 类型 | 描述 |
|------|------|------|
| `prefix` | `string \| undefined` | ID 前缀，若无前缀则为 undefined |
| `words` | `string[]` | 单词数组 |
| `wordCount` | `number` | 单词数量 |
| `bits` | `number` | 总熵位数（wordCount × 12） |
| `raw` | `string` | 原始输入字符串 |
| `format` | `'readable'` | 格式标识 |

### 验证结果类型

| 字段 | 类型 | 描述 |
|------|------|------|
| `valid` | `boolean` | 验证是否通过 |
| `prefix` | `string \| undefined` | 解析得到的前缀（仅在 valid 为 true 时） |
| `wordCount` | `number` | 单词数量（仅在 valid 为 true 时） |
| `reason` | `string` | 验证失败原因（仅在 valid 为 false 时） |

### 重复检测结果类型

| 字段 | 类型 | 描述 |
|------|------|------|
| `id` | `string` | 重复出现的 ID 值 |
| `count` | `number` | 出现次数 |

## 验证流程图

```mermaid
graph TD
    A[输入字符串] --> B{包含大写字符?}
    B -->|是| E[返回 invalid: contains uppercase characters]
    B -->|否| C{包含无效字符?}
    C -->|是| F[返回 invalid: contains invalid characters]
    C -->|否| D{格式可解析?}
    D -->|否| G[返回 invalid: unrecognized format]
    D -->|是| H{所有单词在词表中?}
    H -->|否| I[返回 invalid: unknown words]
    H -->|是| J[返回 valid: true]
    
    style J fill:#90EE90
    style E fill:#FFB6C1
    style F fill:#FFB6C1
    style G fill:#FFB6C1
    style I fill:#FFB6C1
```

## 架构关系图

```mermaid
graph LR
    A[用户输入] --> B[parse 函数]
    A --> C[validate 函数]
    B --> D{解析成功?}
    D -->|否| E[返回 null]
    D -->|是| F[返回解析结果]
    
    C --> G{多层验证}
    G --> H[大写检测]
    G --> I[字符检测]
    G --> J[格式解析]
    G --> K[词表验证]
    
    F --> L[别名映射系统]
    F --> M[确定性生成]
    C --> N[重复检测]
    
    H --> O{通过?}
    I --> P{通过?}
    J --> Q{通过?}
    K --> R{通过?}
    
    O -->|否| S[验证失败]
    P -->|否| S
    Q -->|否| S
    R -->|否| S
    
    O -->|是| T{下一检测}
    P -->|是| T
    Q -->|是| T
    R -->|是| U[验证成功]
```

## 依赖关系

解析与验证模块的正常运作依赖于以下核心组件：单词列表（WORDLIST）提供词汇验证所需的参考数据，`src/wordlist.ts` 导出包含 4096 个有效单词的冻结数组；密码学模块（crypto）提供 `selectRandomWords` 函数用于别名映射中的随机单词选择。资料来源：[src/alias.ts:2]()

验证选项使用 Zod 进行模式验证，确保用户输入的参数符合预期的类型和约束。资料来源：[package.json:29-30]()

## 使用建议

在实际项目中集成解析与验证功能时，建议遵循以下最佳实践。首先，对于需要频繁验证的场景（如 API 输入验证），可以在应用启动时创建单词集合（Set）以加速查找操作，尽管 id-agent 内部已经优化了验证流程。

其次，在使用 `detectDuplicates` 检测重复时，正则表达式的设计应当精确匹配目标 ID 格式，避免误匹配其他类似格式的字符串。建议为不同类型的 ID 使用专用的模式定义。

第三，别名映射系统适合在 LLM 对话场景中使用，通过 `createAliasMap` 创建的映射可以在多轮对话中复用，减少令牌消耗。确保在对话开始时注册所有需要处理的标识符，然后在对话结束时使用 `restore` 方法恢复原始值。

最后，对于安全敏感的应用场景，验证模块应作为防御性编程的一部分，在接收外部输入的 ID 时始终调用 `validate` 函数进行检查，切勿仅依赖格式解析结果假设 ID 有效。

---

<a id='page-wordlist-design'></a>

## 词表设计

### 相关页面

相关主题：[随机 ID 生成](#page-id-generation), [安装与快速开始](#page-installation)

<details>
<summary>相关源码文件</summary>

以下源码文件用于生成本页说明：

- [src/wordlist.ts](https://github.com/vostride/id-agent/blob/main/src/wordlist.ts)
- [scripts/validate-wordlist.ts](https://github.com/vostride/id-agent/blob/main/scripts/validate-wordlist.ts)
- [scripts/build-wordlist.ts](https://github.com/vostride/id-agent/blob/main/scripts/build-wordlist.ts)
- [src/parse.ts](https://github.com/vostride/id-agent/blob/main/src/parse.ts)
- [src/deterministic.ts](https://github.com/vostride/id-agent/blob/main/src/deterministic.ts)
</details>

# 词表设计

id-agent 的词表（Wordlist）是生成人类可读 ID 的核心组件，由 4096 个精心筛选的英文单词组成。本文档详细介绍词表的设计目标、构建流程、质量标准和使用方式。

## 概述

id-agent 的词表是一个经过多轮筛选的 4096 词集合，每个单词恰好对应 o200k_base 分词器中的一个 BPE token。这意味着使用该词表生成的 ID 在 token 效率上远优于传统的 UUID 或十六进制字符串。

词表的核心设计原则：

- **熵值保证**：每个单词贡献 12 bits 熵值（log₂(4096) = 12）
- **分词友好**：所有单词在主流 LLM 分词器中都是单 token
- **可读性**：单词长度控制在 3-6 个字符
- **安全性**：过滤了冒犯性词汇和同音异义词
- **不可变性**：词表数组被冻结（frozen），不可修改

资料来源：[src/wordlist.ts:1]()

## 构建流程

词表的构建是一个六阶段的筛选过程，每一阶段都有明确的质量目标：

```mermaid
graph TD
    A[o200k_base 词汇表] --> B[长度过滤 3-6字符]
    B --> C[系统词典验证]
    C --> D[BPE 单token验证]
    D --> E[连字符前缀验证]
    E --> F[冒犯词过滤]
    F --> G[同音异义词去重]
    G --> H[4096词最终词表]
```

### 第一阶段：候选词提取

从 o200k_base BPE 词汇表中提取所有 3-6 个小写字母组成的单词作为候选词。这一阶段通常产生数万个候选词。

```typescript
const parts = o200k_base.bpe_ranks.split(' ')
const candidateSet = new Set<string>()

for (const b64 of parts) {
  if (!b64.trim()) continue
  const bytes = Buffer.from(b64, 'base64')
  const text = bytes.toString('utf-8')
  const word = text.startsWith(' ') ? text.slice(1) : text
  if (/^[a-z]{3,6}$/.test(word)) candidateSet.add(word)
}
```

资料来源：[scripts/build-wordlist.ts:45-58]()

### 第二阶段：词典过滤

使用系统词典 `/usr/share/dict/words` 验证候选词的有效性，确保每个单词都是真实存在的英文单词。

```typescript
const dictFiltered = candidates.filter((w) => dictWords.has(w))
```

资料来源：[scripts/build-wordlist.ts:69-78]()

### 第三阶段：单 Token 验证

使用 `js-tiktoken` 库验证每个单词在 o200k_base 分词器中是否恰好编码为单个 token。这是确保 token 效率的关键步骤。

```typescript
const enc = new Tiktoken(o200k_base)
const singleToken = dictFiltered.filter((w) => enc.encode(w).length === 1)
```

资料来源：[scripts/build-wordlist.ts:79-82]()

### 第四阶段：连字符前缀验证

验证单词在添加连字符前缀后仍保持高效编码（不超过 2 个 token）。这是为了确保生成的 ID（如 `storm-delta-stone`）在 LLM 上下文中保持 token 效率。

```typescript
const hyphenValid = singleToken.filter((w) => enc.encode('-' + w).length <= 2)
```

资料来源：[scripts/build-wordlist.ts:83-85]()

### 第五阶段：冒犯词过滤

使用 `obscenity` 库检测并过滤冒犯性词汇，同时维护一个手动屏蔽列表：

```typescript
const MANUAL_BLOCKLIST = [
  'ass', 'crap', 'damn', 'hell', 'slut', 'rape', 'kill', 'die',
  'fag', 'gay', 'drug', 'dumb', 'lame', 'nazi', 'pimp', 'porn',
  'poop', 'puke', 'sexy', 'sick', 'anus', 'cunt', 'dick', 'tit',
  'tits', 'boob', 'piss', 'shit', 'cock', 'whore', 'bitch',
  'bastard', 'bloody', 'bugger', 'tosser', 'wank', 'twat',
  'arse', 'shag', 'meth', 'heroin', 'crack', 'coke', 'weed',
]

const matcher = new RegExpMatcher({
  ...englishDataset.build(),
  ...englishRecommendedTransformers,
})

const cleanWords = hyphenValid.filter((w) => {
  if (manualBlockSet.has(w)) return false
  if (matcher.hasMatch(w)) return false
  return true
})
```

资料来源：[scripts/build-wordlist.ts:87-106]()

### 第六阶段：同音异义词去重

过滤同音异义词（homophones），避免因拼写相似造成的混淆：

```typescript
const HOMOPHONE_GROUPS = [
  ['air', 'heir'],
  ['ate', 'eight'],
  ['bare', 'bear'],
  ['be', 'bee'],
  ['blue', 'blew'],
  ['buy', 'by', 'bye'],
  ['cell', 'sell'],
  ['cent', 'sent', 'scent'],
  ['dear', 'deer'],
  ['deer', 'dear'],
  ['die', 'dye'],
  ['eye', 'i'],
  ['fair', 'fare'],
  ['faze', 'phase'],
  ['find', 'fined'],
  ['flea', 'flee'],
  ['flew', 'flu', 'flue'],
  ['for', 'fore', 'four'],
  ['gait', 'gate'],
  ['greek', 'greak'],
  ['hair', 'hare'],
  ['hare', 'hair'],
  ['hall', 'haul'],
  ['heal', 'heel', 'heil'],
  ['hear', 'here'],
  ['him', 'hym'],
  ['hym', 'him'],
  ['isle', 'aisle'],
  ['knead', 'kneed', 'need'],
  ['knew', 'gnu'],
  ['know', 'no'],
  ['leach', 'leech'],
  ['loan', 'lone'],
  ['mail', 'male'],
  ['main', 'mane', 'mean'],
  ['meat', 'meet', 'mete'],
  ['medal', 'meddle', 'metal'],
  ['mede', 'meed'],
  ['miner', 'minor'],
  ['missed', 'mist'],
  ['mist', 'missed'],
  ['naval', 'navel'],
  ['nude', 'newed'],
  ['overdo', 'overdue'],
  ['pail', 'pale'],
  ['pain', 'pane'],
  ['pair', 'pear', 'pare'],
  ['palate', 'palette', 'pallet'],
  ['pare', 'pair', 'pear'],
  ['passed', 'past'],
  ['past', 'passed'],
  ['paten', 'pattern'],
  ['pause', 'paws', 'pores', 'pours'],
  ['peace', 'piece'],
  ['pear', 'pair', 'pare'],
  ['peer', 'pier'],
  ['pores', 'pause', 'paws', 'pours'],
  ['pour', 'pore', 'paw'],
  ['pours', 'pause', 'paws', 'pores'],
  ['pray', 'prey'],
  ['principal', 'principle'],
  ['rain', 'reign', 'rein'],
  ['raise', 'rays', 'raze', 'reis'],
  ['rapt', 'wrapped'],
  ['reign', 'rain', 'rein'],
  ['rein', 'rain', 'reign'],
  ['rider', 'writer'],
  ['right', 'rite', 'write', 'wright'],
  ['road', 'rode', 'rowed'],
  ['roe', 'row'],
  ['role', 'roll'],
  ['roux', 'rue'],
  ['rows', 'rose'],
  ['rye', 'wry'],
  ['sail', 'sale'],
  ['scene', 'seen'],
  ['sea', 'see', 'si'],
  ['seas', 'sees', 'seize'],
  ['seize', 'seas', 'sees'],
  ['senses', 'censes'],
  ['sew', 'sough', 'so'],
  ['sewn', 'sown'],
  ['shear', 'sheer'],
  ['shoe', 'shoo'],
  ['side', 'sighed'],
  ['sighed', 'side'],
  ['sign', 'sine'],
  ['sine', 'sign'],
  ['sla', 'sley'],
  ['sleigh', 'slay'],
  ['slight', 'sleight'],
  ['sley', 'sla'],
  ['sole', 'soul'],
  ['some', 'sum'],
  ['son', 'sun'],
  ['sown', 'sewn'],
  ['stare', 'stair'],
  ['stair', 'stare'],
  ['stake', 'steak'],
  ['steak', 'stake'],
  ['steal', 'steel'],
  ['steel', 'steal'],
  ['step', 'steppe'],
  ['steppe', 'step'],
  ['stew', 'stoo', 'stu'],
  ['stu', 'stew', 'stoo'],
  ['stoo', 'stew', 'stu'],
  ['suite', 'sweet', 'swete', 'sweat'],
  ['sweet', 'suite', 'swete', 'sweat'],
  ['swete', 'suite', 'sweet', 'sweat'],
  ['tack', 'tact'],
  ['tale', 'tail', 'tael'],
  ['tail', 'tale', 'tael'],
  ['tare', 'tear', 'tier'],
  ['team', 'teem'],
  ['tear', 'tare', 'tier'],
  ['teem', 'team'],
  ['teems', 'themes'],
  ['their', 'there', 'theyre'],
  ['threw', 'through'],
  ['throe', 'throw'],
  ['throne', 'thrown'],
  ['thrown', 'throne'],
  ['tide', 'tied'],
  ['tied', 'tide'],
  ['tier', 'tare', 'tear'],
  ['tile', 'trial'],
  ['to', 'too', 'two'],
  ['told', 'tolled'],
  ['tolled', 'told'],
  ['tone', 'towan'],
  ['towan', 'tone'],
  ['tray', 'trey'],
  ['tread', 'tred'],
  ['tred', 'tread'],
  ['treek', 'trig'],
  ['trig', 'treek'],
  ['troth', 'truth'],
  ['vane', 'vain', 'vein'],
  ['vain', 'vane', 'vein'],
  ['vein', 'vain', 'vane'],
  ['wade', 'weighed'],
  ['wait', 'weight'],
  ['war', 'wore'],
  ['waste', 'waist'],
  ['way', 'weigh'],
  ['weak', 'week'],
  ['wear', 'where'],
  ['wood', 'would'],
]
```

资料来源：[scripts/build-wordlist.ts:32-43]()

## 质量标准

词表必须满足以下质量标准：

| 标准 | 要求 | 验证方法 |
|------|------|----------|
| 词汇数量 | 恰好 4096 个 | 构建脚本最终输出验证 |
| 单词长度 | 3-6 个字符 | 正则表达式 `/^[a-z]{3,6}$/` |
| 分词效率 | 单 token（o200k_base） | js-tiktoken 编码测试 |
| 连字符效率 | ≤2 tokens（-prefix） | js-tiktoken 编码测试 |
| 词库有效性 | 存在于系统词典 | `/usr/share/dict/words` |
| 安全性 | 无冒犯词 | obscenity 库 + 手动列表 |
| 可读性 | 无同音异义词 | 手动同音词组列表 |
| 不可变性 | frozen 数组 | `Object.isFrozen(WORDLIST)` |

## 词表导出与使用

### 导出格式

词表以 TypeScript 常量形式导出，位于 `src/wordlist.ts`：

```typescript
export const WORDLIST = [
  'abb',
  'abel',
  'abets',
  'abhor',
  'abide',
  'abler',
  // ... 共 4096 个单词
] as const

// 冻结数组确保不可变
Object.freeze(WORDLIST)
```

资料来源：[src/wordlist.ts:1]()

### 使用方式

词表在内部模块中被广泛使用：

**随机 ID 生成**（用于 `createAliasMap` 等功能）：

```typescript
export function createAliasMap(opts: AliasOptions): AliasMap {
  const { words, allowCollision } = AliasOptionsSchema.parse(opts)
  // ...
  alias = selectRandomWords(words, WORDLIST).join('-')
  // ...
}
```

资料来源：[src/alias.ts:1-25]()

**确定性 ID 生成**（使用 HMAC-SHA256）：

```typescript
export async function deterministicId(input: string, opts?: IdAgentFromOptions): Promise<string> {
  // ...
  for (let i = 0; i < words; i++) {
    selected[i] = WORDLIST[view.getUint16(i * 2) % 4096]
  }
  return formatId(validated.prefix, selected.join('-'))
}
```

资料来源：[src/deterministic.ts:1-38]()

### ID 解析与验证

词表也用于验证和解析生成的 ID：

```typescript
export function validate(id: string): ValidateResult {
  // ...
  if (parsed.words.length > 0) {
    const invalid = parsed.words.filter(w => !wordSet.has(w))
    if (invalid.length > 0) {
      return { valid: false, reason: `unknown words: ${invalid.join(', ')}` }
    }
  }
  // ...
}
```

资料来源：[src/parse.ts:1-25]()

## 验证脚本

### validate-wordlist.ts

构建完成后，使用验证脚本确认词表质量：

```typescript
// 验证单 token 编码
const singleTokenFails = allWords.filter(w => enc.encode(w).length !== 1)

// 验证连字符前缀编码
const hyphenFails = singleTokenFails.filter(w => enc.encode('-' + w).length > 2)

check(`All words are single BPE tokens (failures: ${singleTokenFails.length})`, singleTokenFails.length === 0)
check(`All words pass hyphen-prefix test (failures: ${hyphenFails.length})`, hyphenFails.length === 0)
```

资料来源：[scripts/validate-wordlist.ts:1-20]()

### 运行验证

```bash
pnpm run validate
```

## 词表设计决策

### 为什么选择 4096 个单词？

- **数学基础**：4096 = 2¹²，每个单词贡献恰好 12 bits 熵值
- **空间效率**：4096 个条目可存储在 12 位索引中（2 字节）
- **映射便利**：确定性 ID 生成中，HMAC-SHA256 输出的 16 位字可映射到 4096 个单词（取模运算）

### 为什么限制 3-6 个字符？

- **BPE 兼容性**：在这个长度范围内的单词更可能在 o200k_base 中成为单 token
- **可读性平衡**：过短的单词（如 "a"、"I"）增加同音词冲突；过长的单词增加 token 消耗
- **ID 紧凑性**：较短的单词使生成的 ID 更紧凑易读

### 为什么过滤同音异义词？

在口语交流或听觉场景下，同音异义词（如 "there"/"their"/"they're"）会造成混淆。id-agent 主要用于 AI 上下文，但保持这种过滤可以：

- 减少口头沟通歧义
- 避免拼写相似性导致的视觉混淆
- 提高 ID 的整体可读性

## 总结

id-agent 的词表设计是一个精心策划的多阶段流程，确保最终产出的 4096 个单词满足分词效率、可读性、安全性和不可变性等多重质量标准。这个词表是实现高 token 效率和人类可读 ID 生成的核心基础设施。

词表在运行时被冻结，任何对 ID 格式的验证都依赖词表内容，这种设计保证了系统的一致性和可预测性。

---

<a id='page-crypto-module'></a>

## 加密模块

### 相关页面

相关主题：[随机 ID 生成](#page-id-generation), [确定性 ID 生成](#page-deterministic-ids)

<details>
<summary>相关源码文件</summary>

以下源码文件用于生成本页说明：

- [src/crypto.ts](https://github.com/vostride/id-agent/blob/main/src/crypto.ts)
- [src/generate.ts](https://github.com/vostride/id-agent/blob/main/src/generate.ts)
- [src/deterministic.ts](https://github.com/vostride/id-agent/blob/main/src/deterministic.ts)
- [src/alias.ts](https://github.com/vostride/id-agent/blob/main/src/alias.ts)
- [src/wordlist.ts](https://github.com/vostride/id-agent/blob/main/src/wordlist.ts)
</details>

# 加密模块

## 概述

id-agent 的加密模块是整个库的核心安全基础，负责生成密码学安全的随机数并将其映射到人类可读的单词列表。该模块采用双重加密策略：

1. **随机 ID 生成**：使用 Web Crypto API 的 CSPRNG（密码学安全伪随机数生成器）
2. **确定性 ID 生成**：使用 HMAC-SHA256 哈希函数实现输入到 ID 的确定性映射

加密模块的核心价值在于确保 ID 的唯一性和不可预测性，同时保持人类可读性和令牌效率。

## 架构设计

```mermaid
graph TD
    A[输入] --> B{ID类型选择}
    B -->|随机| C[随机ID生成流程]
    B -->|确定性| D[确定性ID生成流程]
    
    C --> E[crypto.getRandomValues]
    E --> F[从WORDLIST映射]
    F --> G[格式化输出]
    
    D --> H[TextEncoder编码输入]
    H --> I[HMAC-SHA256签名]
    I --> J[DataView读取哈希]
    J --> K[取模映射到WORDLIST]
    K --> G
    
    G --> L[最终ID格式<br/>如: storm-delta-stone]
```

## 随机 ID 生成

### 核心实现

随机 ID 生成依赖浏览器的 `crypto.getRandomValues()` 方法，这是 Web Crypto API 提供的密码学安全随机数接口。 资料来源：[src/generate.ts:6-12]()

```typescript
function createIdAgent(): IdAgent {
  const fn = ((opts?: IdAgentOptions): string => {
    const validated = IdAgentOptionsSchema.parse(opts ?? {})
    const words = validated.words ?? 8
    const selected = selectRandomWords(words, WORDLIST)
    return formatId(validated.prefix, selected.join('-'))
  }) as IdAgent
  // ...
}
```

### 随机词选择机制

`selectRandomWords` 函数从 4096 个单词的词表中选择随机单词。该函数内部调用 `crypto.getRandomValues()` 获取密码学安全的随机字节，然后通过取模运算将随机数映射到词表索引。 资料来源：[src/generate.ts:4-5]()

### 安全性保证

随机 ID 生成的安全性来源于：

| 保障措施 | 说明 |
|---------|------|
| CSPRNG | 使用浏览器原生的 `crypto.getRandomValues()`，确保随机数不可预测 |
| 均匀分布 | 取模运算确保每个词被选中的概率完全相等 |
| 独立选择 | 每个词的位置独立随机选择，互不影响 |

## 确定性 ID 生成

### 核心实现

确定性 ID 生成使用 HMAC-SHA256 算法，通过 Web Crypto API 实现。相同的输入总是产生相同的 ID，适用于需要可重现性的场景。 资料来源：[src/deterministic.ts:1-10]()

```typescript
export async function deterministicId(input: string, opts?: IdAgentFromOptions): Promise<string> {
  if (!input || typeof input !== 'string') {
    throw new Error('input must be a non-empty string')
  }
  const validated = IdAgentFromOptionsSchema.parse(opts ?? {})
  const words = validated.words ?? 8

  if (!globalThis.crypto?.subtle) {
    throw new Error('idAgent.from() requires Web Crypto API (crypto.subtle). Use HTTPS in browsers.')
  }
  // ...
}
```

### HMAC-SHA256 签名流程

```mermaid
graph LR
    A[输入字符串] --> B[TextEncoder]
    B --> C[UTF-8字节]
    C --> D[crypto.subtle.importKey]
    D --> E[HMAC密钥]
    C --> F[crypto.subtle.sign]
    E --> F
    F --> G[256位签名]
    G --> H[DataView读取]
    H --> I[每16位取模4096]
    I --> J[映射到WORDLIST]
```

### 关键步骤解析

1. **密钥导入**：使用命名空间（默认 "id-agent"）作为 HMAC 密钥，确保不同应用的输出不会冲突 资料来源：[src/deterministic.ts:16-20]()

2. **签名生成**：对输入字符串进行 HMAC-SHA256 签名，输出 256 位（32 字节）的签名 资料来源：[src/deterministic.ts:21-22]()

3. **词表映射**：从签名中每 16 位（2 字节）读取一个无符号整数，对 4096 取模得到词表索引 资料来源：[src/deterministic.ts:23-27]()

```typescript
const sig = await globalThis.crypto.subtle.sign('HMAC', key, enc.encode(input))
const view = new DataView(sig)

const selected: string[] = new Array(words)
for (let i = 0; i < words; i++) {
  selected[i] = WORDLIST[view.getUint16(i * 2) % 4096]
}
```

### 命名空间隔离

确定性 ID 支持自定义命名空间实现域分离：

```typescript
const id1 = await idAgent.from('user@example.com')
const id2 = await idAgent.from('user@example.com', { namespace: 'different-app' })
// id1 !== id2
```

这允许同一输入在不同命名空间下产生不同的确定性 ID。 资料来源：[src/deterministic.ts:12]()

## 别名映射模块

别名映射模块利用加密随机数生成短别名，用于减少 LLM 上下文中的令牌消耗。 资料来源：[src/alias.ts:1-8]()

### 别名生成算法

```mermaid
graph TD
    A[原始ID] --> B{ID已存在?}
    B -->|是| C[返回已有别名]
    B -->|否| D[生成新别名]
    D --> E[selectRandomWords]
    E --> F[从WORDLIST选择词]
    F --> G{别名冲突?}
    G -->|是| D
    G -->|否| H[存储forward/reverse映射]
    H --> I[返回别名]
```

### 加密安全保障

别名映射同样使用 `selectRandomWords` 从 CSPRNG 获取随机数，确保别名不可预测。即使原始 ID 已知，也无法推断别名（除非存在映射表）。 资料来源：[src/alias.ts:2]()

```typescript
export function createAliasMap(opts: AliasOptions): AliasMap {
  const { words, allowCollision } = AliasOptionsSchema.parse(opts)
  const forward = new Map<string, string>()
  const reverse = new Map<string, string>()
  
  // ...
  do {
    alias = selectRandomWords(words, WORDLIST).join('-')
  } while (reverse.has(alias) && !allowCollision)
  // ...
}
```

## 词表设计

### 词表规格

| 属性 | 值 | 说明 |
|-----|-----|------|
| 词数 | 4096 | 2^12，便于位运算映射 |
| 每词熵 | 12 bits | log2(4096) = 12 |
| 单词字符数 | 3-6 字符 | 经 o200k_base 分词器验证 |
| 令牌效率 | 每词 1 token | 针对 o200k_base 优化 |

### 词表约束

词表经过多重过滤确保安全性和可用性：

1. **词典验证**：所有单词必须存在于系统词典 `/usr/share/dict/words`
2. **同音词过滤**：移除如 `wait`/`weight`、`weak`/`week` 等易混淆的同音词
3. **冒犯性词汇移除**：使用 `obscenity` 库过滤不适当词汇
4. **单令牌验证**：每个词在 o200k_base 分词器中恰好为 1 个 token

## API 参考

### 随机 ID 生成

```typescript
const id = idAgent()                    // 默认 8 词 ID
const id5 = idAgent({ words: 5 })       // 5 词 ID
const idPrefixed = idAgent({ prefix: 'user', words: 4 })
```

### 确定性 ID 生成

```typescript
const id = await idAgent.from('user@example.com')
const idCustom = await idAgent.from('user@example.com', {
  namespace: 'my-app',
  prefix: 'user',
  words: 5
})
```

### 别名映射

```typescript
const aliases = createAliasMap({ words: 3 })
const alias = aliases.set('8cdda07b-85d2-459c-8a2a-83c8f9245dbe')
const original = aliases.get('storm-delta-stone')
```

## 安全注意事项

| 场景 | 建议 |
|------|------|
| 浏览器环境 | 确保使用 HTTPS，Web Crypto API 在不安全上下文中不可用 |
| 服务端环境 | Node.js 18+ 已原生支持 Web Crypto API |
| 确定性 ID 命名空间 | 生产环境应使用唯一的命名空间避免冲突 |
| 别名碰撞 | 默认情况下别名生成会避免碰撞，可通过 `allowCollision: true` 禁用 |

## 性能特性

- **随机 ID 生成**：同步操作，约 0.1-0.5ms
- **确定性 ID 生成**：异步操作，约 1-5ms（首次调用需初始化 HMAC 密钥）
- **别名映射**：O(1) 查找和插入

## 与 UUID 的对比

| 特性 | UUID v4 | id-agent (8词) |
|------|---------|----------------|
| 熵 | 122 bits | 96 bits |
| 令牌数 | ~23 | ~11 |
| 令牌节省 | - | ~52% |
| 50%碰撞阈值 | ~2.7 * 10^18 | ~300 trillion |
| 人类可读性 | 低 | 高 |

---

<a id='page-schemas-validation'></a>

## Zod 验证架构

### 相关页面

相关主题：[解析与验证](#page-parsing-validation), [随机 ID 生成](#page-id-generation)

<details>
<summary>相关源码文件</summary>

以下源码文件用于生成本页说明：

- [src/schemas.ts](https://github.com/vostride/id-agent/blob/main/src/schemas.ts)
- [src/types.ts](https://github.com/vostride/id-agent/blob/main/src/types.ts)
- [src/parse.ts](https://github.com/vostride/id-agent/blob/main/src/parse.ts)
- [src/deterministic.ts](https://github.com/vostride/id-agent/blob/main/src/deterministic.ts)
- [src/alias.ts](https://github.com/vostride/id-agent/blob/main/src/alias.ts)
</details>

# Zod 验证架构

## 概述

id-agent 使用 Zod 作为核心验证库，版本为 4.3.6，构建了一套完整的输入验证体系。该验证架构覆盖了所有公开 API 的用户输入，确保数据类型安全、参数合法，并提供清晰的错误信息。

**核心设计目标：**

- 在开发阶段捕获无效输入，防止运行时错误
- 提供人类可读的错误消息，帮助开发者快速定位问题
- 保持类型安全，实现编译时与运行时的双重保障
- 通过模式复用减少验证代码重复

**依赖配置：**

```json
"dependencies": {
  "zod": "4.3.6"
}
```

资料来源：[package.json:25-27](https://github.com/vostride/id-agent/blob/main/package.json)

---

## 验证模式分类

id-agent 的验证架构围绕三个核心 Schema 构建，分别服务于不同的功能模块。

### 模式层级关系

```mermaid
graph TD
    A[用户输入] --> B[IdAgentOptionsSchema]
    A --> C[IdAgentFromOptionsSchema]
    A --> D[AliasOptionsSchema]
    B --> E[创建随机 ID]
    C --> F[创建确定性 ID]
    D --> G[别名映射管理]
    E --> H[验证通过]
    F --> H
    G --> H
```

### Schema 清单

| Schema 名称 | 用途 | 使用场景 |
|------------|------|---------|
| `IdAgentOptionsSchema` | 随机 ID 生成选项 | `new IdAgent(opts?)` |
| `IdAgentFromOptionsSchema` | 确定性 ID 生成选项 | `idAgent.from(input, opts?)` |
| `AliasOptionsSchema` | 别名映射选项 | `createAliasMap(opts)` |

---

## IdAgentOptionsSchema

用于验证随机 ID 生成的配置参数。这是用户创建 IdAgent 实例时的输入验证层。

### 参数定义

| 参数 | 类型 | 默认值 | 约束条件 | 说明 |
|------|------|--------|----------|------|
| `prefix` | `string \| undefined` | `undefined` | 小写字母数字组合 | ID 类型前缀 |
| `words` | `number` | `8` | 1-16 整数 | 单词数量，控制熵值 |

### 验证规则

```typescript
// 伪代码表示验证逻辑
prefix?: string  // 可选，若提供则必须是 lowercase alphanumeric
words?: number   // 可选，默认 8，范围 [1, 16]
```

**前缀验证：** 必须是纯小写字母和数字组成，不允许大写字符、下划线以外的特殊字符。

**单词数验证：** 整数值必须在 1 到 16 之间。单词数直接决定 ID 的熵值：`总比特数 = words × 12`。

### 错误处理

当验证失败时，Zod 抛出 `ZodError`，包含详细的错误路径和消息。

```typescript
// 无效配置示例
new IdAgent({ words: 20 })    // 超出范围
new IdAgent({ prefix: 'USER' }) // 包含大写字母
```

资料来源：[src/schemas.ts](https://github.com/vostride/id-agent/blob/main/src/schemas.ts) 和 [src/deterministic.ts:7](https://github.com/vostride/id-agent/blob/main/src/deterministic.ts)

---

## IdAgentFromOptionsSchema

用于验证确定性 ID 生成（基于 HMAC-SHA256）的配置参数。与随机 ID 不同，确定性生成需要额外的命名空间支持。

### 参数定义

| 参数 | 类型 | 默认值 | 约束条件 | 说明 |
|------|------|--------|----------|------|
| `prefix` | `string \| undefined` | `undefined` | 小写字母数字组合 | ID 类型前缀 |
| `words` | `number` | `8` | 1-16 整数 | 单词数量 |
| `namespace` | `string` | `'id-agent'` | 非空字符串 | HMAC 密钥，用于域分离 |

### 验证流程

```typescript
const validated = IdAgentFromOptionsSchema.parse(opts ?? {})
const words = validated.words ?? 8  // 默认值处理
const namespace = validated.namespace ?? 'id-agent'
```

### 命名空间机制

命名空间参数实现了域分离功能，相同的输入在不同命名空间下产生不同的 ID：

```typescript
const id1 = await idAgent.from('user@example.com', { namespace: 'app1' })
const id2 = await idAgent.from('user@example.com', { namespace: 'app2' })
// id1 !== id2
```

资料来源：[src/deterministic.ts:6-10](https://github.com/vostride/id-agent/blob/main/src/deterministic.ts)

---

## AliasOptionsSchema

用于验证别名映射功能的配置参数。别名映射是 LLM 上下文优化的高级功能。

### 参数定义

| 参数 | 类型 | 默认值 | 约束条件 | 说明 |
|------|------|--------|----------|------|
| `words` | `number` | 是 | 1-16 整数 | 别名使用的单词数 |
| `allowCollision` | `boolean` | `false` | 布尔值 | 是否允许别名碰撞 |

### 别名生成逻辑

```mermaid
graph LR
    A[原始 ID] --> B{forward Map<br/>已有映射?}
    B -->|是| C[返回已有别名]
    B -->|否| D[生成新别名]
    D --> E{反向 Map<br/>存在冲突?}
    E -->|是 且 !allowCollision| D
    E -->|否 或 allowCollision| F[存储映射]
    F --> G[返回别名]
```

### 碰撞处理

当 `allowCollision` 为 `false`（默认）时，系统保证别名映射的双射性质，即每个原始 ID 映射到唯一别名，每个别名映射回唯一原始 ID。

资料来源：[src/alias.ts:4-9](https://github.com/vostride/id-agent/blob/main/src/alias.ts)

---

## ID 验证流程

### validate 函数

`validate` 函数是 ID 验证的核心入口，用于检查任意字符串是否为有效的 id-agent ID。

### 验证步骤

```mermaid
graph TD
    A[输入字符串] --> B{包含大写字母?}
    B -->|是| Z[无效: contains uppercase characters]
    B -->|否| C{包含无效字符?}
    C -->|是| Y[无效: contains invalid characters]
    C -->|否| D[调用 parse 函数]
    D --> E{解析结果为 null?}
    E -->|是| X[无效: unrecognized format]
    E -->|否| F{存在未知单词?}
    F -->|是| W[无效: unknown words: xxx]
    F -->|否| V[验证通过]
```

### 验证规则详解

| 步骤 | 检查项 | 错误消息 | 正则表达式 |
|------|--------|----------|------------|
| 1 | 大写字母 | `contains uppercase characters` | `/[A-Z]/` |
| 2 | 无效字符 | `contains invalid characters` | `/[^a-z0-9_-]/` |
| 3 | 格式识别 | `unrecognized format` | parse 返回 null |
| 4 | 词汇表验证 | `unknown words: {word}` | wordSet 查询 |

### 验证结果类型

```typescript
interface ValidationResult {
  valid: boolean
  prefix?: string      // 仅在 valid 为 true 时
  wordCount?: number   // 仅在 valid 为 true 时
  reason?: string     // 仅在 valid 为 false 时
}
```

### 示例

```typescript
validate('task_storm-delta-stone')
// => { valid: true, prefix: 'task', wordCount: 3 }

validate('task_jump-notaword')
// => { valid: false, reason: 'unknown words: notaword' }

validate('INVALID')
// => { valid: false, reason: 'contains uppercase characters' }
```

资料来源：[src/parse.ts:1-20](https://github.com/vostride/id-agent/blob/main/src/parse.ts)

---

## 类型系统集成

### 类型定义架构

```mermaid
graph TD
    A[types.ts] --> B[IdAgentOptions]
    A --> C[IdAgentFromOptions]
    A --> D[AliasOptions]
    A --> E[ValidationResult]
    B --> F[IdAgentOptionsSchema]
    C --> G[IdAgentFromOptionsSchema]
    D --> H[AliasOptionsSchema]
```

### Schema 与类型对应关系

| Schema | TypeScript 类型 | 来源 |
|--------|----------------|------|
| `IdAgentOptionsSchema` | `IdAgentOptions` | [src/types.ts](https://github.com/vostride/id-agent/blob/main/src/types.ts) |
| `IdAgentFromOptionsSchema` | `IdAgentFromOptions` | [src/types.ts](https://github.com/vostride/id-agent/blob/main/src/types.ts) |
| `AliasOptionsSchema` | `AliasOptions` | [src/types.ts](https://github.com/vostride/id-agent/blob/main/src/types.ts) |

### 验证执行模式

```typescript
// 标准模式：使用 .parse()，失败时抛出 ZodError
const result = schema.parse(input)

// 安全模式：使用 .safeParse()，返回结果对象
const result = schema.safeParse(input)
```

id-agent 默认使用 `.parse()` 模式，让无效输入直接抛出异常，便于开发阶段快速发现问题。

---

## 错误处理机制

### ZodError 结构

验证失败时抛出的错误对象包含完整的错误路径和上下文信息：

```typescript
try {
  new IdAgent({ words: 100 })
} catch (error) {
  if (error instanceof ZodError) {
    console.log(error.errors)
    // [{
    //   code: "too_big",
    //   maximum: 16,
    //   type: "number",
    //   path: ["words"],
    //   message: "Number must be less than or equal to 16"
    // }]
  }
}
```

### 错误码映射

| Zod 错误码 | 触发条件 | 示例消息 |
|-----------|---------|---------|
| `too_small` | 值小于最小值 | `Number must be greater than or equal to 1` |
| `too_big` | 值大于最大值 | `Number must be less than or equal to 16` |
| `invalid_type` | 类型不匹配 | `Expected string, received number` |
| `unrecognized_keys` | 包含未知键 | `Unrecognized key: unknownOption` |

---

## 验证性能考量

### 模式编译

Zod Schema 在首次使用时进行编译，后续调用直接使用优化后的验证逻辑。id-agent 的 Schema 定义简洁，验证开销极低。

### 词汇表查询优化

ID 验证中的词汇表检查使用 Set 数据结构：

```typescript
const wordSet = new Set(WORDLIST)  // O(1) 查找
```

`WORDLIST` 包含 4096 个单词，Set 查询复杂度为 O(1)，验证 3-16 个单词的总复杂度为 O(n)，其中 n 为单词数量。

---

## 架构优势

### 类型安全层次

```
TypeScript Compiler          Zod Runtime
      │                            │
      ▼                            ▼
   类型定义 ──────────────────► Schema 定义
   (编译期)                      (运行期)
      │                            │
      ▼                            ▼
   IDE 提示                  实际验证
   类型检查                  错误抛出
```

### 可维护性

- Schema 集中定义于 `schemas.ts`
- 类型集中定义于 `types.ts`
- 验证逻辑与业务逻辑分离
- 新增参数只需修改 Schema 定义

### 开发者体验

- 清晰的错误消息指明问题所在
- 与 TypeScript 类型系统无缝集成
- 支持 IDE 自动补全

---

## 相关资源

- [Zod 官方文档](https://zod.dev)
- [源码：schemas.ts](https://github.com/vostride/id-agent/blob/main/src/schemas.ts)
- [源码：types.ts](https://github.com/vostride/id-agent/blob/main/src/types.ts)
- [源码：parse.ts](https://github.com/vostride/id-agent/blob/main/src/parse.ts)

---

<a id='page-alias-system'></a>

## 别名系统

### 相关页面

相关主题：[重复检测](#page-duplicate-detection), [随机 ID 生成](#page-id-generation)

<details>
<summary>相关源码文件</summary>

以下源码文件用于生成本页说明：

- [src/alias.ts](https://github.com/vostride/id-agent/blob/main/src/alias.ts)
- [src/parse.ts](https://github.com/vostride/id-agent/blob/main/src/parse.ts)
- [src/wordlist.ts](https://github.com/vostride/id-agent/blob/main/src/wordlist.ts)
- [src/detect.ts](https://github.com/vostride/id-agent/blob/main/src/detect.ts)
- [README.md](https://github.com/vostride/id-agent/blob/main/README.md)
</details>

# 别名系统

## 概述

别名系统（Alias System）是 id-agent 提供的一种高效令牌压缩机制，旨在将长标识符（如 UUID）映射为短小的、基于单词的别名，以便在 LLM 上下文中的传输。系统支持完整的双向映射、文本替换和还原功能。

别名系统通过 `createAliasMap()` 工厂函数创建，返回一个 `AliasMap` 实例，该实例提供 `set()`、`get()`、`replace()`、`restore()` 和 `entries()` 等核心方法。

资料来源：[src/alias.ts:3-10]()

## 核心概念

### 设计目标

别名系统解决了 LLM 应用中的两个关键问题：

1. **令牌效率**：长 UUID（如 `8cdda07b-85d2-459c-8a2a-83c8f9245dbe`）在 BPE 分词器中需要约 23 个令牌，而 3 个单词的别名（如 `storm-delta-stone`）仅需约 5 个令牌，节省约 78% 的令牌开销。

2. **可读性**：单词形式的 ID 更容易在调试日志、API 响应和 LLM 输出中理解和引用。

资料来源：[README.md](https://github.com/vostride/id-agent/blob/main/README.md)

### 工作原理

别名系统内部维护两个 Map 数据结构：
- **正向映射**（forward）：存储原始 ID → 别名
- **反向映射**（reverse）：存储别名 → 原始 ID

```mermaid
graph LR
    A[原始ID<br/>8cdda07b-85d2-...] -->|set| B[正向Map]
    B -->|生成| C[别名<br/>storm-delta-stone]
    C -->|存储| D[反向Map]
    D -->|get| A
```

资料来源：[src/alias.ts:8-10]()

## API 参考

### createAliasMap(options?)

创建别名映射实例。

```typescript
import { createAliasMap } from 'id-agent'

const aliases = createAliasMap({ words: 3 })
```

#### 参数选项

| 参数 | 类型 | 默认值 | 必填 | 描述 |
|------|------|--------|------|------|
| `words` | `number` | `8` | 否 | 每个别名的单词数量（1-16） |
| `allowCollision` | `boolean` | `false` | 否 | 是否允许别名冲突 |

资料来源：[src/alias.ts:3-6]()

### AliasMap 实例方法

#### set(original: string): string

为给定的原始 ID 生成并存储一个别名。相同原始 ID 多次调用返回相同的别名。

```typescript
const alias1 = aliases.set('8cdda07b-85d2-459c-8a2a-83c8f9245dbe')
// => "storm-delta-stone"

const alias2 = aliases.set('8cdda07b-85d2-459c-8a2a-83c8f9245dbe')
// => "storm-delta-stone" (相同)
```

资料来源：[src/alias.ts:12-18]()

#### get(alias: string): string | undefined

根据别名查询对应的原始 ID。

```typescript
aliases.get('storm-delta-stone')
// => "8cdda07b-85d2-459c-8a2a-83c8f9245dbe"
```

资料来源：[src/alias.ts:20-22]()

#### replace(text: string, options?): string

将文本中所有匹配指定模式的原始 ID 替换为对应的别名。

```typescript
const text = 'Process 8cdda07b-85d2-459c-8a2a-83c8f9245dbe then 6ba7b810-9dad-11d1-80b4-00c04fd430c8'
const shortened = aliases.replace(text, {
  pattern: /[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}/gi
})
// => "Process storm-delta-stone then cloud-train-scope"
```

| 参数 | 类型 | 描述 |
|------|------|------|
| `text` | `string` | 要进行替换的文本 |
| `options.pattern` | `RegExp` | 匹配原始 ID 的正则表达式 |

资料来源：[src/alias.ts:24-37]()

#### restore(text: string): string

将文本中所有别名还原为原始 ID。

```typescript
const restored = aliases.restore('Process storm-delta-stone then cloud-train-scope')
// => "Process 8cdda07b-85d2-459c-8a2a-83c8f9245dbe then 6ba7b810-9dad-11d1-80b4-00c04fd430c8"
```

资料来源：[src/alias.ts:39-41]()

#### entries(): [original, alias][]

返回所有映射对的数组，格式为 `[原始ID, 别名]`。

```typescript
for (const [original, alias] of aliases.entries()) {
  console.log(`${original} => ${alias}`)
}
```

> ⚠️ 返回顺序是 `[original, alias]`，而非 `[alias, original]`。如需通过别名查询原始 ID，请使用 `get(alias)` 方法。

资料来源：[README.md](https://github.com/vostride/id-agent/blob/main/README.md)

## 典型使用场景

### LLM 上下文压缩

在向 LLM 发送请求前，将长 UUID 替换为短别名，并在处理完成后还原：

```mermaid
sequenceDiagram
    participant App as 应用
    participant AliasMap as AliasMap
    participant LLM as LLM
    participant Output as 输出

    App->>AliasMap: set(uuid1), set(uuid2)
    App->>AliasMap: replace(requestText)
    App->>LLM: 发送压缩后的请求
    LLM-->>App: 返回引用别名的响应
    App->>AliasMap: restore(responseText)
    App->>Output: 输出还原后的结果
```

```typescript
const aliases = createAliasMap({ words: 3 })

// 1. 准备阶段：注册所有需要的 ID
aliases.set('8cdda07b-85d2-459c-8a2a-83c8f9245dbe')
aliases.set('6ba7b810-9dad-11d1-80b4-00c04fd430c8')

// 2. 发送给 LLM 前：替换
const llmRequest = await sendToLLM(aliases.replace(prompt, {
  pattern: /[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}/gi
}))

// 3. 处理 LLM 返回后：还原
const finalOutput = aliases.restore(llmOutput)
```

资料来源：[src/alias.ts:24-41]()

### 与重复检测结合

别名系统可与 `detectDuplicates` 功能结合使用，用于在 LLM 输出中检测重复的 ID：

```typescript
import { createAliasMap, detectDuplicates } from 'id-agent'

const aliases = createAliasMap({ words: 3 })

// 检测文本中的重复 ID
const dupes = detectDuplicates({
  pattern: /[a-z]+(?:-[a-z]+)+/,
  text: 'Found storm-delta-stone in file A and storm-delta-stone in file B',
})
// => [{ id: 'storm-delta-stone', count: 2 }]
```

资料来源：[src/detect.ts:1-21]()

## 内部实现

### 别名生成算法

别名通过 `selectRandomWords` 函数从词表（WORDLIST）中随机选择指定数量的单词生成：

```typescript
alias = selectRandomWords(words, WORDLIST).join('-')
```

每个单词贡献 12 比特熵度（因为词表包含 4096 = 2¹² 个单词）。使用 3 个单词的别名提供 36 比特熵度。

| 单词数 | 熵度 | ID 空间 | 典型令牌数 | vs UUID 节省 |
|--------|------|---------|------------|---------------|
| 3 | 36 bits | 6.9 × 10¹⁰ | ~5 | 78% |
| 5 | 60 bits | 1.2 × 10¹⁸ | ~8 | 65% |
| 8 | 96 bits | 7.9 × 10²⁸ | ~11 | 52% |

资料来源：[src/wordlist.ts](https://github.com/vostride/id-agent/blob/main/src/wordlist.ts) 和 [README.md](https://github.com/vostride/id-agent/blob/main/README.md)

### 替换正则构建

`replace()` 方法内部按长度降序排序所有已注册的原始 ID，确保较长的 ID 优先匹配，避免部分匹配问题：

```typescript
function buildReplacementRegex(keys: string[]): RegExp | null {
  if (keys.length === 0) return null
  const sorted = [...keys].sort((a, b) => b.length - a.length)
  const escaped = sorted.map(s => s.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'))
  return new RegExp(escaped.join('|'), 'g')
}
```

例如，如果同时注册了 `abc` 和 `abcd`，会优先匹配 `abcd`。

资料来源：[src/alias.ts:8-11]()

### 冲突处理

默认情况下，`set()` 方法会检查生成的别名是否已存在（通过 `reverse.has(alias)`）。如果发生冲突，会重新生成：

```typescript
do {
  alias = selectRandomWords(words, WORDLIST).join('-')
} while (reverse.has(alias) && !allowCollision)
```

通过设置 `allowCollision: true` 可以禁用此检查，允许不同的原始 ID 共享相同别名（不推荐）。

资料来源：[src/alias.ts:14-16]()

## 最佳实践

### 词数选择指南

| 使用场景 | 建议词数 | 熵度 | 适用规模 |
|----------|----------|------|----------|
| 开发/测试 | 3 | 36 bits | < 309K items |
| 小型应用 | 5 | 60 bits | < 1B items |
| 生产 SaaS | 5 | 60 bits | < 1B items |
| 高流量/分布式 | 8 (默认) | 96 bits | < 300T items |

### 生命周期管理

```mermaid
graph TD
    A[创建 AliasMap] --> B[注册所有 ID]
    B --> C{处理}
    C -->|发送 LLM | D[replace]
    C -->|接收响应 | E[restore]
    D --> F[LLM 处理]
    F --> E
    E --> G{更多请求?}
    G -->|是| C
    G -->|否| H[销毁 AliasMap]
```

1. **预先注册**：在处理任何文本前，先通过 `set()` 注册所有需要用到的原始 ID
2. **重用实例**：在整个会话期间复用同一个 AliasMap 实例
3. **统一模式**：使用统一的正则表达式进行 `replace()` 和 `restore()`

资料来源：[src/alias.ts:12-22]()

## 错误处理

别名系统使用 Zod 进行配置验证：

```typescript
const { words, allowCollision } = AliasOptionsSchema.parse(opts)
```

无效选项会抛出 `ZodError`，并附带描述性错误信息。有效的 `words` 范围为 1-16。

资料来源：[src/alias.ts:4]()

## 与其他模块的关系

```mermaid
graph TB
    Alias[别名系统<br/>src/alias.ts] --> Crypto[加密模块<br/>src/crypto.ts]
    Alias --> Wordlist[词表<br/>src/wordlist.ts]
    Alias --> Parse[解析模块<br/>src/parse.ts]
    Parse --> Validate[验证模块<br/>src/validate.ts]
    Detect[重复检测<br/>src/detect.ts] -.->|组合使用| Alias
    
    classDef primary fill:#e1f5fe
    class Alias primary
```

- **依赖 `selectRandomWords`**：别名生成使用加密安全的随机数生成器
- **依赖 WORDLIST**：从 4096 个预验证单词中选择
- **可与 `detectDuplicates` 组合**：检测 LLM 输出中的重复别名

资料来源：[src/alias.ts:2-3]() 和 [src/parse.ts:1-3]()

---

<a id='page-duplicate-detection'></a>

## 重复检测

### 相关页面

相关主题：[别名系统](#page-alias-system), [解析与验证](#page-parsing-validation)

<details>
<summary>相关源码文件</summary>

以下源码文件用于生成本页说明：

- [src/detect.ts](https://github.com/vostride/id-agent/blob/main/src/detect.ts)
- [README.md](https://github.com/vostride/id-agent/blob/main/README.md)
</details>

# 重复检测

## 概述

重复检测（Duplicate Detection）是 id-agent 提供的核心功能之一，用于扫描文本内容中的重复 ID。该功能设计为纯函数，不依赖文件系统访问，适用于在 LLM 上下文中检测重复标识符、验证数据一致性以及在分布式系统中识别潜在的 ID 冲突问题。

重复检测模块位于 `src/detect.ts`，通过正则表达式模式匹配来识别文本中出现的重复标识符。资料来源：[src/detect.ts:1-24]()

## 工作原理

### 核心算法流程

重复检测采用基于正则表达式的模式匹配策略，通过以下步骤完成重复 ID 的识别：

```mermaid
graph TD
    A[输入: pattern + text] --> B{text 类型判断}
    B -->|string| C[转换为数组: text]
    B -->|string[]| D[直接使用数组]
    C --> E[初始化 Map 和 RegExp]
    D --> E
    E --> F[遍历每个文本]
    F --> G[重置 lastIndex]
    G --> H[执行正则匹配]
    H --> I{找到匹配?}
    I -->|是| J[更新 Map 计数]
    I -->|否| K{还有文本?}
    J --> K
    K -->|是| F
    K -->|否| L[过滤 count > 1]
    L --> M[返回 Duplicate 数组]
    I -->|否| K
```

### 关键设计决策

1. **纯函数设计**：不产生副作用，不访问外部状态，确保测试可重复性和并发安全性
2. **自动补全全局标志**：如果用户提供的正则表达式缺少 `g` 标志，函数会自动添加，确保能够匹配所有出现位置
3. **lastIndex 重置**：每次处理新文本前重置正则表达式的 `lastIndex`，避免跨文本匹配时的状态污染
4. **灵活输入支持**：支持单个字符串或字符串数组作为输入源

## API 参考

### detectDuplicates 函数签名

```typescript
function detectDuplicates(opts: DetectOptions): Duplicate[]
```

### 类型定义

| 类型 | 描述 |
|------|------|
| `DetectOptions` | 检测配置选项，包含匹配模式和待检测文本 |
| `Duplicate` | 重复检测结果，包含 ID 字符串和出现次数 |

### 参数配置

| 参数 | 类型 | 必填 | 描述 |
|------|------|------|------|
| `pattern` | `RegExp` | 是 | 用于匹配 ID 的正则表达式模式 |
| `text` | `string \| string[]` | 是 | 待扫描的文本内容，可以是单个字符串或字符串数组 |

### 返回值

返回 `Duplicate[]` 数组，每个元素包含：

| 字段 | 类型 | 描述 |
|------|------|------|
| `id` | `string` | 重复的 ID 字符串 |
| `count` | `number` | 该 ID 出现的次数（仅包含 count > 1 的项） |

## 使用示例

### 基本用法：检测字符串中的重复 ID

```typescript
import { detectDuplicates } from 'id-agent'

const dupes = detectDuplicates({
  pattern: /[a-z]+(?:-[a-z]+)+/,
  text: 'Found storm-delta-stone in file A and storm-delta-stone in file B',
})
// 返回值: [{ id: 'storm-delta-stone', count: 2 }]
```

资料来源：[README.md]()

### 多文本检测：分析代码仓库中的重复项

```typescript
import { detectDuplicates } from 'id-agent'

const dupes = detectDuplicates({
  pattern: /task_[a-z]+(?:-[a-z]+)+/,
  text: [
    'const x = "task_red-fox-run"',
    'const y = "task_red-fox-run"',
  ],
})
```

### 结合 UUID 模式检测

```typescript
import { detectDuplicates } from 'id-agent'

const dupes = detectDuplicates({
  pattern: /[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}/gi,
  text: [
    'Task A: 8cdda07b-85d2-459c-8a2a-83c8f9245dbe',
    'Task B: 8cdda07b-85d2-459c-8a2a-83c8f9245dbe', // 重复
    'Task C: 6ba7b810-9dad-11d1-80b4-00c04fd430c8',
  ],
})
// 返回值: [{ id: '8cdda07b-85d2-459c-8a2a-83c8f9245dbe', count: 2 }]
```

## 实现细节

### 源代码解析

以下为核心实现代码（资料来源：[src/detect.ts:5-24]()）：

```typescript
export function detectDuplicates(opts: DetectOptions): Duplicate[] {
  const texts = typeof opts.text === 'string' ? [opts.text] : opts.text
  const idMap = new Map<string, number>()
  const re = new RegExp(
    opts.pattern.source,
    opts.pattern.flags.includes('g') ? opts.pattern.flags : opts.pattern.flags + 'g',
  )

  for (const text of texts) {
    re.lastIndex = 0
    let match
    while ((match = re.exec(text)) !== null) {
      idMap.set(match[0], (idMap.get(match[0]) ?? 0) + 1)
    }
  }

  return [...idMap.entries()]
    .filter(([, count]) => count > 1)
    .map(([id, count]) => ({ id, count }))
}
```

### 全局标志处理逻辑

函数自动确保正则表达式携带 `g`（全局）标志：

```mermaid
graph LR
    A[输入 pattern] --> B{flags 包含 'g'?}
    B -->|是| C[保持原 flags]
    B -->|否| D[追加 'g' 标志]
    C --> E[创建 RegExp]
    D --> E
```

## 与其他模块的集成

### 与别名映射系统配合使用

重复检测可以与 `createAliasMap` 配合使用，用于验证映射前后的 ID 一致性：

| 功能 | 函数 | 用途 |
|------|------|------|
| 缩短长 ID | `createAliasMap.replace()` | 减少 LLM 上下文中的 token 消耗 |
| 恢复原始 ID | `createAliasMap.restore()` | 还原别名映射 |
| 验证唯一性 | `detectDuplicates()` | 检测替换后是否存在重复别名 |

### 典型工作流程

```mermaid
graph LR
    A[原始 UUID 列表] --> B[createAliasMap]
    B --> C[生成别名映射]
    C --> D[替换 UUID 为别名]
    D --> E[发送到 LLM]
    E --> F[LLM 响应]
    F --> G[恢复原始 UUID]
    G --> H[detectDuplicates 验证]
    H --> I{存在重复?}
    I -->|是| J[警告/处理冲突]
    I -->|否| K[处理完成]
```

## 最佳实践

### 正则表达式编写建议

| 建议 | 说明 | 示例 |
|------|------|------|
| 使用捕获组 | 明确指定要匹配的 ID 格式 | `/task_[a-z]+(?:-[a-z]+)+/` |
| 包含边界符 | 避免部分匹配问题 | `/\\b[a-f0-9-]{36}\\b/` |
| 区分大小写 | 根据 ID 规范选择标志 | `i` 标志用于大小写不敏感 |
| 避免过度贪婪 | 确保匹配精确的 ID 格式 | 使用 `{36}` 而非 `+` |

### 性能优化建议

1. **预编译正则表达式**：如果多次使用相同模式，预先创建正则表达式对象
2. **批量处理文本**：将多个文本片段合并为数组一次性处理，减少循环开销
3. **精确的 pattern**：避免过于宽泛的正则表达式，减少不必要的匹配尝试

## 注意事项

### 边界情况处理

| 场景 | 行为 | 说明 |
|------|------|------|
| 空字符串输入 | 返回空数组 `[]` | 正则匹配无结果 |
| 无匹配的文本 | 返回空数组 `[]` | 未发现任何匹配项 |
| 无重复项 | 返回空数组 `[]` | 所有 ID 都只出现一次 |
| 数组中有空字符串 | 正常处理 | 空字符串不产生匹配 |

### 限制说明

- 函数不验证匹配到的 ID 是否为有效的 id-agent 格式
- 如果需要验证 ID 有效性，应额外调用 `validate()` 函数
- 正则表达式的 `lastIndex` 属性在内部被管理，不会影响外部状态

---

---

## Doramagic 踩坑日志

项目：vostride/id-agent

摘要：发现 8 个潜在踩坑项，其中 0 个为 high/blocking；最高优先级：能力坑 - 能力判断依赖假设。

## 1. 能力坑 · 能力判断依赖假设

- 严重度：medium
- 证据强度：source_linked
- 发现：README/documentation is current enough for a first validation pass.
- 对用户的影响：假设不成立时，用户拿不到承诺的能力。
- 建议检查：将假设转成下游验证清单。
- 防护动作：假设必须转成验证项；没有验证结果前不能写成事实。
- 证据：capability.assumptions | hn_item:48191852 | https://news.ycombinator.com/item?id=48191852 | README/documentation is current enough for a first validation pass.

## 2. 维护坑 · 维护活跃度未知

- 严重度：medium
- 证据强度：source_linked
- 发现：未记录 last_activity_observed。
- 对用户的影响：新项目、停更项目和活跃项目会被混在一起，推荐信任度下降。
- 建议检查：补 GitHub 最近 commit、release、issue/PR 响应信号。
- 防护动作：维护活跃度未知时，推荐强度不能标为高信任。
- 证据：evidence.maintainer_signals | hn_item:48191852 | https://news.ycombinator.com/item?id=48191852 | last_activity_observed missing

## 3. 安全/权限坑 · 下游验证发现风险项

- 严重度：medium
- 证据强度：source_linked
- 发现：no_demo
- 对用户的影响：下游已经要求复核，不能在页面中弱化。
- 建议检查：进入安全/权限治理复核队列。
- 防护动作：下游风险存在时必须保持 review/recommendation 降级。
- 证据：downstream_validation.risk_items | hn_item:48191852 | https://news.ycombinator.com/item?id=48191852 | no_demo; severity=medium

## 4. 安全/权限坑 · 存在评分风险

- 严重度：medium
- 证据强度：source_linked
- 发现：no_demo
- 对用户的影响：风险会影响是否适合普通用户安装。
- 建议检查：把风险写入边界卡，并确认是否需要人工复核。
- 防护动作：评分风险必须进入边界卡，不能只作为内部分数。
- 证据：risks.scoring_risks | hn_item:48191852 | https://news.ycombinator.com/item?id=48191852 | no_demo; severity=medium

## 5. 安全/权限坑 · 来源证据：Consider an alternative wordlist

- 严重度：medium
- 证据强度：source_linked
- 发现：GitHub 社区证据显示该项目存在一个安全/权限相关的待验证问题：Consider an alternative wordlist
- 对用户的影响：可能影响授权、密钥配置或安全边界。
- 建议检查：来源问题仍为 open，Pack Agent 需要复核是否仍影响当前版本。
- 防护动作：不得脱离来源链接放大为确定性结论；需要标注适用版本和复核状态。
- 证据：community_evidence:github | cevd_c1936412c9da41088e71fab995197a90 | https://github.com/vostride/id-agent/issues/2 | 来源类型 github_issue 暴露的待验证使用条件。

## 6. 安全/权限坑 · 来源证据：Python port

- 严重度：medium
- 证据强度：source_linked
- 发现：GitHub 社区证据显示该项目存在一个安全/权限相关的待验证问题：Python port
- 对用户的影响：可能影响授权、密钥配置或安全边界。
- 建议检查：来源问题仍为 open，Pack Agent 需要复核是否仍影响当前版本。
- 防护动作：不得脱离来源链接放大为确定性结论；需要标注适用版本和复核状态。
- 证据：community_evidence:github | cevd_d733a90c7db44b9789900ed24e77220e | https://github.com/vostride/id-agent/issues/1 | 来源讨论提到 python 相关条件，需在安装/试用前复核。

## 7. 维护坑 · issue/PR 响应质量未知

- 严重度：low
- 证据强度：source_linked
- 发现：issue_or_pr_quality=unknown。
- 对用户的影响：用户无法判断遇到问题后是否有人维护。
- 建议检查：抽样最近 issue/PR，判断是否长期无人处理。
- 防护动作：issue/PR 响应未知时，必须提示维护风险。
- 证据：evidence.maintainer_signals | hn_item:48191852 | https://news.ycombinator.com/item?id=48191852 | issue_or_pr_quality=unknown

## 8. 维护坑 · 发布节奏不明确

- 严重度：low
- 证据强度：source_linked
- 发现：release_recency=unknown。
- 对用户的影响：安装命令和文档可能落后于代码，用户踩坑概率升高。
- 建议检查：确认最近 release/tag 和 README 安装命令是否一致。
- 防护动作：发布节奏未知或过期时，安装说明必须标注可能漂移。
- 证据：evidence.maintainer_signals | hn_item:48191852 | https://news.ycombinator.com/item?id=48191852 | release_recency=unknown

<!-- canonical_name: vostride/id-agent; human_manual_source: deepwiki_human_wiki -->
