大数跨境

优化 LLM 的 JSON

优化 LLM 的 JSON 索引目录
2026-01-08
0
导读:关注「索引目录」公众号,获取更多干货。如果你正在构建基于人工智能的功能,你很可能需要向语言模型发送大量的 JSON 数据。

关注「索引目录」公众号,获取更多干货。

如果你正在构建基于人工智能的功能,你很可能需要向语言模型发送大量的 JSON 数据。而如果你发送了大量的 JSON 数据,那么你消耗令牌的速度可能比你预期的要快得多。

Kollabe,我们使用人工智能生成回顾会议和站会的摘要、行动项和建议。当数十名团队成员每天提交更新时,JSON 数据量会迅速增长。我们需要在不丢失信息的情况下缩小数据规模的方法。

目前有一些更新的正式解决方案,例如TOON(面向标记的对象表示法),它可以将 LLM 的 JSON 压缩高达 40%。它是一个完整的规范,包含基准测试和 SDK。如果您想要一种标准化的方法,值得了解一下。

但有时您需要掌控一切。您不希望增加额外的依赖项。您希望确切地了解发送给模型的内容,并根据您的具体用例进行调整。以下是我们用来减少令牌使用量而不增加复杂性的简单技巧。

1. 将长 ID 替换为短 ID

UUID无处不在。它们对数据库来说很棒,但对令牌效率来说却很糟糕。

// This UUID is 4-5 tokens
"550e8400-e29b-41d4-a716-446655440000"

// This is 1 token
"u-1"

当你在数百个站立会议记录中引用同一个用户时,这些额外的令牌会迅速累积起来。

解决方案:在处理数据时构建一个简单的映射。遇到的第一个用户变成 1 u-1,第二个用户变成 2 u-2,依此类推。如果再次遇到相同的 UUID,则重复使用已分配的短 ID。

// Before: UUIDs everywhere
{
  odUserId: "550e8400-e29b-41d4-a716-446655440000",
  odQuestionId: "7c9e6679-7425-40de-944b-e07fc1f90ae7",
  odAnswerId: "f47ac10b-58cc-4372-a567-0e02b2c3d479"
}

// After: short, prefixed IDs
{
  uid: "u-1",
  qid: "q-1", 
  aid: "a-1"
}

关键在于,同一个 UUID 总是对应同一个短 ID。因此,当 LLMu-1在不同的答案中多次看到同一个 UUID 时,它就能理解这些条目属于同一个人。为不同的实体类型使用不同的前缀,以便模型能够区分用户 ID 和问题 ID。

2. 去掉格式

JSON.stringify还有第二个和第三个参数,大多数人都会忽略它们。第三个参数用于添加缩进:

// Pretty printed (wasteful)
JSON.stringify(data, null, 2);

// Minified (efficient)
JSON.stringify(data);

区别如下:

// Pretty: ~80 characters
{
  "name": "Alice",
  "role": "Engineer",
  "team": "Platform"
}

// Minified: ~45 characters
{"name":"Alice","role":"Engineer","team":"Platform"}

如果是小物件,无所谓。但如果是成千上万个站立式会议记录呢?那些空白加起来就不少了。反正LLM(立法程序管理员)也不在意格式。

3. 使用更短的键名

仔细想想,这似乎显而易见。对比一下:

// Verbose
type StandupEntry = {
  odUserId: string;
  userName: string;
  yesterdayUpdate: string;
  todayPlan: string;
  blockerDescription: string;
};

// Concise
type StandupEntry = {
  odUid: string;
  name: string;
  yesterday: string;
  today: string;
  blocker: string;
};

当有数百条记录时,较短的键可以节省实际的令牌。只需确保键足够易读,以便语言学习模型 (LLM) 能够理解上下文即可。

我们遵循以下几条规则:

  • 删除冗余词语:如果它明显是用户对象,userId则变为id
  • 使用常用缩写:desc而不是description
  • 措辞要清晰明确:y比如“昨天”这个说法太隐晦了,但yest效果不错。

4. 删除空值和空字符串

不要发送不存在的数据:

function removeEmpty<T extends object>(obj: T): Partial<T> {
  return Object.fromEntries(
    Object.entries(obj).filter(([_, v]) => {
      if (v === null || v === undefined) return false;
      if (v === "") return false;
      if (Array.isArray(v) && v.length === 0) return false;
      return true;
    })
  ) as Partial<T>;
}

// Before
{
  "name": "Alice",
  "blocker": null,
  "tags": [],
  "notes": ""
}

// After
{
  "name": "Alice"
}

如果没有人举报阻塞问题,为什么要告诉LLM呢?

5. 尽可能扁平化嵌套结构

有时嵌套只是组织上的冗余:

// Before
{
  "user": {
    "profile": {
      "name": "Alice",
      "team": "Platform"
    }
  },
  "update": "Finished feature"
}

// After
{
  "name": "Alice",
  "team": "Platform",
  "update": "Finished feature"
}

第二个版本用更少的结构标记传达了相同的信息。显然,如果层级结构本身就具有意义,就不应该将其扁平化,但通常情况下并非如此。

6. 使用数组代替重复对象

如果您有一系列相似项目,请考虑是否需要每个项目的完整对象结构:

// Before: 3 objects with repeated keys
{
  "entries": [
    { "name": "Alice", "status": "done" },
    { "name": "Bob", "status": "blocked" },
    { "name": "Carol", "status": "done" }
  ]
}

// After: header row + data rows
{
  "cols": ["name", "status"],
  "rows": [
    ["Alice", "done"],
    ["Bob", "blocked"],
    ["Carol", "done"]
  ]
}

这样虽然牺牲了一些可读性,但提高了效率。对于大型数据集来说,这是值得的。

7. 删除不必要的元数据

人工智能处理通常不需要时间戳、审计字段和内部 ID:

// Before: full database record
{
  odAnswerId: "f47ac10b-58cc-4372-a567-0e02b2c3d479",
  odUserId: "550e8400-e29b-41d4-a716-446655440000",
  text: "Great sprint!",
  createdAt: "2024-01-15T10:30:00.000Z",
  updatedAt: "2024-01-15T10:30:00.000Z",
  isDeleted: false,
  version: 1
}

// After: just what the LLM needs
{
  uid: "u-1",
  text: "Great sprint!"
}

问问自己:模型真的需要这个字段才能生成有用的响应吗?如果不需要,就把它删掉。

8. 高效地表示布尔值

对于布尔标志,请考虑当其值为 false 时是否还需要该字段:

// Before
{ "name": "Alice", "isAdmin": false, "isActive": true, "isVerified": false }

// After: only include truthy flags
{ "name": "Alice", "active": true }

// Or use a flags array for multiple true values
{ "name": "Alice", "flags": ["active", "verified"] }

如果大多数用户都不是管理员,则不要isAdmin: false在每个记录中包含该信息。

综合起来

以下是 Kollabe 生成的一份真实回顾总结中的前后对比图:

优化前:

{
  "retrospectiveData": {
    "questions": [
      {
        "odQuestionId": "7c9e6679-7425-40de-944b-e07fc1f90ae7",
        "questionText": "What went well this sprint?",
        "questionType": "positive"
      },
      {
        "odQuestionId": "f47ac10b-58cc-4372-a567-0e02b2c3d479",
        "questionText": "What could be improved?",
        "questionType": "negative"
      }
    ],
    "answers": [
      {
        "odAnswerId": "1b9d6bcd-bbfd-4b2d-9b5d-ab8dfbbd4bed",
        "odQuestionId": "7c9e6679-7425-40de-944b-e07fc1f90ae7",
        "odUserId": "550e8400-e29b-41d4-a716-446655440000",
        "userName": "Alice Chen",
        "answerText": "Team collaboration was excellent during the release",
        "createdAt": "2024-01-15T10:30:00.000Z",
        "voteCount": 3
      },
      {
        "odAnswerId": "6ec0bd7f-11c0-43da-975e-2a8ad9ebae0b",
        "odQuestionId": "7c9e6679-7425-40de-944b-e07fc1f90ae7",
        "odUserId": "6ba7b810-9dad-11d1-80b4-00c04fd430c8",
        "userName": "Bob Smith",
        "answerText": "CI/CD pipeline improvements saved us hours",
        "createdAt": "2024-01-15T10:32:00.000Z",
        "voteCount": 5
      },
      {
        "odAnswerId": "3f333df6-90a4-4fda-8dd3-9485d27cee36",
        "odQuestionId": "f47ac10b-58cc-4372-a567-0e02b2c3d479",
        "odUserId": "550e8400-e29b-41d4-a716-446655440000",
        "userName": "Alice Chen",
        "answerText": "Documentation was often outdated",
        "createdAt": "2024-01-15T10:35:00.000Z",
        "voteCount": null
      }
    ]
  }
}

优化后:

{"qs":[{"id":"q-1","text":"What went well this sprint?","type":"positive"},{"id":"q-2","text":"What could be improved?","type":"negative"}],"ans":[{"id":"a-1","qid":"q-1","uid":"u-1","name":"Alice Chen","text":"Team collaboration was excellent during the release","votes":3},{"id":"a-2","qid":"q-1","uid":"u-2","name":"Bob Smith","text":"CI/CD pipeline improvements saved us hours","votes":5},{"id":"a-3","qid":"q-2","uid":"u-1","name":"Alice Chen","text":"Documentation was often outdated"}]}

发生了哪些变化:

  • UUID 已替换为短 ID (q-1,,a-1u-1
  • 长键名缩写(odQuestionIdqidanswerTexttext
  • 已移除包装对象(retrospectiveData
  • 已删除空值(无voteCount: null
  • 已移除时间戳(生成摘要时不需要)
  • 无空格格式

优化后的版本体积缩小了约 50%。对于一个拥有 50 名成员、数百条回复的团队来说,这能显著降低令牌成本并加快推理速度。

何时优化

并非所有 JSON 数据都需要这种处理。如果您发送的是一个小型配置对象或单个用户查询,那么优化带来的额外开销就得不偿失了。

但是,当你构建需要处理大量结构化数据的功能时,比如我们在 Kollabe 开发的回顾和站会总结功能,这些技巧就显得尤为重要。它们易于实现,无需外部依赖,并且能立即带来成效。

掌控数据管道也至关重要。编写自己的优化层,就能完全了解其运行机制。您可以调整短 ID 前缀,决定删除哪些字段,并随着数据的变化调整策略。一切都无需担心,没有黑箱操作。

最棒的是什么?LLM 可以完美处理优化后的 JSON 数据。它们不需要漂亮的格式或冗长的键名就能理解你的数据。它们只需要信息本身。

关注「索引目录」公众号,获取更多干货。


【声明】内容源于网络
0
0
索引目录
索引目录是一家专注于医疗、技术开发、物联网应用等领域的创新型公司。我们致力于为客户提供高质量的服务和解决方案,推动技术与行业发展。
内容 444
粉丝 0
索引目录 索引目录是一家专注于医疗、技术开发、物联网应用等领域的创新型公司。我们致力于为客户提供高质量的服务和解决方案,推动技术与行业发展。
总阅读12
粉丝0
内容444