Show HN: Id-agent – 为AI代理节省Token的UUID替代方案

Hacker News Top 工具

摘要

id-agent是一个开源npm库,生成可读的、节省Token的基于单词的ID,作为AI代理的UUID替代方案,将Token成本降低约40%,同时保持抗碰撞性。

暂无内容
查看原文
查看缓存全文

缓存时间: 2026/05/19 13:02

vostride/id-agent

Source: https://github.com/vostride/id-agent

id-agent

为 AI 智能体设计的令牌高效 ID

当 UUID 消耗约 23 个令牌且容易被 LLM 幻觉时,id-agent 生成可记忆的基于单词的 ID,约 14 个令牌,具有相同的抗碰撞能力。这是第一个为上下文窗口(而非数据库)构建的 ID 库。

  • 人类可读 —— 基于单词的 ID,人类和 LLM 都能真正记住
  • 令牌高效 —— 单词列表中的每个单词在 o200k_base 上恰好是 1 个 BPE 令牌
  • 抗碰撞 —— 可配置熵,范围从 ~12 到 ~192 位
  • 输入验证 —— 所有公共 API 均采用 zod 驱动的模式验证

令牌成本对比

格式示例令牌数(o200k_base)抗碰撞性
UUID v489b842d9-6df9-4cf4-8db0-9dc3aed3cfd7~23122 位
id-agent(默认,8 个单词)urd-antes-sorry-pac-dire-total-expire-going~14~96 位
id-agent(5 个单词)frame-beer-bell-tog-hoot~8~60 位

id-agent — 8 个单词,43 字符,12 令牌
UUID v4 — 36 字符,26 令牌

安装

npm install id-agent
pnpm add id-agent

快速上手

import { idAgent } from 'id-agent'

// 生成一个随机 ID(8 个单词,~96 位熵)
const id = idAgent()   // => "urd-antes-sorry-pac-dire-total-expire-going"

// 带类型前缀
const taskId = idAgent({ prefix: 'task' })
// => "task_slide-exact-cede-bury-linge-ease-bean-impact"

// 减少单词数量用于短生命周期 ID
const short = idAgent({ words: 3 })
// => "front-reject-tho"

API 参考

idAgent(opts?)

生成一个随机、人类可读的 ID。

import { idAgent } from 'id-agent'

idAgent()                            // 8 个单词,~96 位
idAgent({ words: 5 })                // 5 个单词,~60 位
idAgent({ prefix: 'user' })          // "user_cloud-train-scope-frame-match-level-paint-field"

选项:

选项类型默认值描述
prefixstringundefined类型前缀(仅小写字母数字)
wordsnumber8单词数量(1-16)。控制熵:单词数 * 12 位

无效选项会抛出带有描述信息的 ZodError

idAgent.from(input, opts?)

使用 HMAC-SHA256 从字符串输入生成确定性 ID。相同输入始终产生相同 ID。

const id = await idAgent.from('[email protected]')
// 始终返回相同输入对应的相同 ID

const namespaced = await idAgent.from('[email protected]', {
  namespace: 'my-app',
  prefix: 'user',
  words: 5,
})

选项:

选项类型默认值描述
prefixstringundefined类型前缀(仅小写字母数字)
wordsnumber8单词数量(1-16)
namespacestring'id-agent'用于域分离的 HMAC 密钥

parse(id)

解析任何 id-agent ID 为其组成部分。支持连字符和下划线分隔的单词。对于无法识别的格式返回 null

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' }

validate(id)

检查一个字符串是否为有效的 id-agent ID。验证所有单词是否存在于 WORDLIST 中。

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' }

createAliasMap(opts)

创建双向别名映射,用于 LLM 上下文中的令牌缩减。将长 ID 映射为短单词别名,支持完整的替换/恢复功能。

import { createAliasMap } from 'id-agent'

const aliases = createAliasMap({ words: 3 })

aliases.set('8cdda07b-85d2-459c-8a2a-83c8f9245dbe')
// => "storm-delta-stone" (来自 WORDLIST 的 3 个随机单词)

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

// 在发送给 LLM 之前替换文本中的所有 UUID
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"

// 在 LLM 输出中恢复原始值
const restored = aliases.restore(shortened)
// => 原始文本

选项:

选项类型必需描述
wordsnumber每个别名的单词数量(1-16)

entries() 返回 [original, alias] 对(而非 [alias, original])。使用 get(alias) 从别名查找原始值。

detectDuplicates(opts)

使用正则表达式模式扫描文本中的重复 ID。纯函数 —— 不访问文件系统。

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"'],
})

选项:

选项类型描述
patternRegExp匹配文本中 ID 的正则表达式
textstring | string[]要扫描重复项的文本

WORDLIST

直接访问精心挑选的 4096 单词列表。每个单词在 o200k_base 上恰好是 1 个 BPE 令牌。该数组是冻结的(不可变)。

import { WORDLIST } from 'id-agent'

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

数学原理

每个单词从精心挑选的 4096 单词列表(2^12)中均匀选取。ID 中的每个位置都是独立的随机选择:

每个单词的熵 = log2(4096) = 12 位
总熵 = 单词数 * 12 位
ID 空间 = 4096^words = 2^(words * 12)

无论单个单词的长度如何,该结论都成立 —— 一个 3 字符单词和一个 6 字符单词都恰好贡献 12 位,因为攻击者必须从同一个 4096 单词池中猜测。

碰撞概率(生日悖论)

n 个随机生成的 ID 中至少发生一次碰撞的概率:

P(collision) ≈ n^2 / (2 * 2^b)    其中 b = 总熵位数

这是生日悖论近似值,在 P 较小(P < 0.01)时有效。

单词数位数ID 空间P @ 1KP @ 10KP @ 100KP @ 1MP @ 1B50% 碰撞时的条目数
3366.9 * 10^107.3 * 10^-67.3 * 10^-47.3 * 10^-2~1~1~309K
4482.8 * 10^141.8 * 10^-91.8 * 10^-71.8 * 10^-51.8 * 10^-3~1~20M
5601.2 * 10^184.3 * 10^-134.3 * 10^-114.3 * 10^-94.3 * 10^-70.43~1.3B
8967.9 * 10^286.3 * 10^-246.3 * 10^-226.3 * 10^-206.3 * 10^-186.3 * 10^-12~331T
101201.3 * 10^363.8 * 10^-313.8 * 10^-293.8 * 10^-273.8 * 10^-253.8 * 10^-19~1.4 * 10^18
UUID v41225.3 * 10^369.4 * 10^-329.4 * 10^-309.4 * 10^-289.4 * 10^-269.4 * 10^-20~2.7 * 10^18

默认值(8 个单词,96 位) 在达到 50% 碰撞概率之前可安全用于超过 300 万亿个条目。实际上,大多数应用永远不会生成超过几百万个 ID。

计算示例

对于默认的 8 单词 ID,在 100 万个条目时:

b = 8 * 12 = 96 位
n = 1,000,000
P ≈ (10^6)^2 / (2 * 2^96) = 10^12 / (2 * 7.92 * 10^28) = 10^12 / (1.58 * 10^29) = 6.3 * 10^-18

这大约是 1 在 158 万万亿 —— 实际上为零。

令牌成本(实测)

所有测量基于 o200k_base(GPT-4o、GPT-4.1、o1、o3),使用 tiktoken。由于 BPE 与连字符的合并行为,每个 ID 的令牌数略有变化 —— 以下值为 100 个样本的平均值:

格式平均令牌数与 UUID 相比节省的令牌数节省比例
UUID v4~23122 位
id-agent(3 个单词)~536 位~1878%
id-agent(5 个单词)~860 位~1565%
id-agent(8 个单词,默认)~1496 位~939%
id-agent(10 个单词)~17120 位~626%

为什么不直接用更少的单词?

合适的单词数量取决于你的规模。默认的 8 是故意保守的(全局安全)。但如果你在构建较小的东西:

规模推荐原因
开发/测试words: 336 位快速、可记忆、约 5 令牌。在约 300K 条目时发生碰撞。
团队工具words: 448 位安全至约 20M 条目。适合内部 API。
生产级 SaaSwords: 560 位安全至约 1B 条目。与 UUID 相比节省 65% 令牌。
高吞吐/分布式words: 8(默认)96 位安全至约 300T 条目。安全的默认值。
UUID 等效words: 10120 位匹配 UUID v4 碰撞数学。

令牌效率:为什么单词胜过十六进制

BPE 分词器(所有主要 LLM 使用)基于自然语言训练。短英文单词默认就是单个令牌。UUID 是十六进制字符串,会不可预测地拆分:

"storm-delta-stone" => 4 个令牌(3 个单词 + 分隔符)
"dc193952-186a-4645" => 11 个令牌(同样 18 个字符!)

id-agent 的单词列表经过精心挑选,使得每个单词在 o200k_base 上恰好是 1 个 BPE 令牌。由于 BPE 合并行为,连字符每 6 个单词增加约 1 个令牌。这就是为什么基于单词的 ID 从根本上比随机十六进制/字母数字字符串更节省令牌。

工作原理

id-agent 使用一个精心挑选的 4096 个英文单词列表,每个单词已验证为 o200k_base 分词器(GPT-4o、GPT-4.1 使用)上的单个 BPE 令牌。单词长度为 3-6 个字符,已过滤掉攻击性词汇和同音词。

随机 ID 使用 crypto.getRandomValues()(CSPRNG)。确定性 ID 使用 HMAC-SHA256(通过 Web Crypto API),将哈希映射到单词列表索引。所有公共 API 输入均使用 zod (https://zod.dev) 模式进行验证。无效选项会抛出带描述的错误信息。

许可证

MIT

相似文章

AI Agent Registry:关于问责制的思想实验

Reddit r/ArtificialInteligence

作者介绍了一个开源AI Agent Registry,它为智能体分配唯一的合规UUID,支持违规报告和查询,以促进自主AI系统的问责制和信任。