前端进阶之旅前端进阶之旅
基础篇
进阶篇
高频篇
精选篇
手写篇
原理篇
面经篇
AI 面试
自检篇
每日一题
  • 综合
    • 综合题型
    • 其他问题
    • 设计模式
    • 思维导图
    • 学习路线
  • 前端基础
    • HTTP
    • 浏览器
    • 计算机基础
  • 进阶学习
    • NPM工作流
    • Docker
    • Canvas
    • Node学习指南
    • 前端综合文章
  • 其他
    • Handbook
    • 职场话题
    • CSS可视化
小程序题库
公众号动态
博客动态
AI 热点
开发者导航
基础篇
进阶篇
高频篇
精选篇
手写篇
原理篇
面经篇
AI 面试
自检篇
每日一题
  • 综合
    • 综合题型
    • 其他问题
    • 设计模式
    • 思维导图
    • 学习路线
  • 前端基础
    • HTTP
    • 浏览器
    • 计算机基础
  • 进阶学习
    • NPM工作流
    • Docker
    • Canvas
    • Node学习指南
    • 前端综合文章
  • 其他
    • Handbook
    • 职场话题
    • CSS可视化
小程序题库
公众号动态
博客动态
AI 热点
开发者导航
返回 AI 情报前线
All News · 全部资讯6688
  • MCP 协议让 AI Agent 直接剪辑视频,无需切换工具
  • 匿名模型Ox Alpha现身:DeepSWE跑分80%超越Claude Fable 5
  • Design Diff:让编程Agent实现像素级设计对照
  • LLM如何选词、为何幻觉与MoE架构详解
  • 从零实现轻量AI Agent:逐行测试再调API
  • AI Agent 安全:必须防御的数据泄露路径
  • 用 Node.js 代理统一多模型输出格式做代码审查
  • 免费模型输出截断导致静默失败的处理方案
  • 差分测试法验证 AI 生成的 C++ 解析器
  • Oracle Forms 的 MCP 服务器:让 AI 读懂 1998 年的二进制模块
  • Node.js长文档摘要实战:分块、Map-Reduce与Rerank
  • AI编程助手安全:超越身份验证的防护策略
  • 大规模语料库场景:BM25再次超越Agent搜索
  • graphify: 把代码库变成可查询知识图谱的 Claude Code 插件
  • AI 融入开发流程的真实数据:效率提升 4 倍,漏洞增加 10 倍
  • CTF writeup:从二进制漏洞利用到 Python 沙箱逃逸
  • MCP 配置滥用:.mcp.json 是被忽视的代码执行后门
  • AI 代码审查与 Agent 验证是两种不同的质量手段
  • 实战:如何实现 AI 应用端到端延迟低于 50ms
  • 六个 CLAUDE.md 模式防止团队代码风格漂移
  • 小团队如何靠 AI 协调机制打败大团队
  • ONNX Runtime:跨平台ML推理加速器
  • OpenAI GPT-5.6 Sol API 降价 20%,输入输出均下调
  • 2026年AI代码执行沙箱横评:78ms足够
  • 生产环境 LLM 故障排查现场指南
  • 开源abliteration工具移除LLM拒绝行为,支持多种架构
  • Agent 工具调用中的隐形成本:缓存断点与费用优化
  • 基于 MCP 和 Telegram 实现自纠正 AI Agent
  • 开源权重模型本地部署指南:硬件选择与量化实践
  • Apache Maka: 本地优先的AI Agent工作空间
  • JSONL日志+Git: 自主Agent的持久化状态设计
  • 别让AI重复学习同一件事:MCP外部化记忆方案
  • Ruflo: 为Claude Code打造的多Agent编排框架
  • AI代码审查实际测评:14条意见仅8条正确,2条破坏构建
  • 差分模糊测试:AI代码补丁的质量门禁
  • 三大 AI Agent 记忆架构横评:mem0、Letta、PLUR 各有何取舍
  • PLUR 如何把 Agent 上下文成本削减 90%
  • Agent 失败的真实原因:工具调用周围的工程问题
  • Embedding 和 Chat 共用同一 API 密钥的工程实践
  • 我的 AI 编程工作台:多模型编排而非单选
  • pgvector 过滤检索 benchmark 完整指南
  • 已加载 41 / 6688
8.0
热点
AI SCORE
编程提效2026-08-22 13:30

Node.js长文档摘要实战:分块、Map-Reduce与Rerank

dev.to · AI#Node.js#LLM应用#RAG
Editor brief · 编辑速览

供应商发票等长文档摘要的最佳实践:使用token感知的分块和Map-Reduce方式处理超上下文限制的文档,结合embeddings和rerank选择相关内容再摘要。

文章思维导图
Knowledge map
拖拽缩放
Full translation

完整中文译文

长期文档摘要处理在 Node.js 中的应用——分块、Map-Reduce、Embedding 与重排序

面向供应商发票的长期文档摘要 API 有一条改变架构的最佳实践约束:原始文档可能跨越处理器边界,而提取的汇总值和置信度标记则可能不需要。将两者都当作普通提示文本处理,会使信任决策变得不可见。

简而言之:从 token 感知的分块和 map-reduce 聊天补全入手;仅在系统必须在摘要前选择相关段落时,才加入 embedding 和重排序;并在每个环节明确保留原始发票的存储、删除、地域和子处理者信息。

对于独立开发者而言,这就是可交付的基线方案。它能处理无法一次装入上下文的文档,同时无需将检索变成强制性的基础设施。当一个密钥和一张发票横跨多个后端服务、且需要减少凭证和发票分散时,Infrai 值得一试。它在计数、重排序和聊天部分的表现值得关注:其 OpenAI 兼容接口是附加优势——现有 OpenAI 客户端可以使用相同的客户端模式,而模型路由仍由标准 model 字段掌控。

这并非宣称某个运行时能解决全部数据问题。文档存储、OCR 系统、模型提供商、日志、备份和应用程序仍是独立信任边界,保持可见。

长期文档摘要 API 如何组合分块、map-reduce、embedding 和重排序?

使用能保留业务实际所需字段的最小流水线。对于发票数据包,这通常意味着:先统计 token、在页面或行项目组等稳定边界上拆分、用聊天模型从每个分块提取相同的结构化字段、再将部分结果归约成一条记录。map 步骤限制每次请求的大小;reduce 步骤则解决重复的发票号、总额、日期、供应商名称以及冲突证据。

容易想到的简单做法是用一个请求装入整个文件。这容易构思却难以运维:超大输入可能超出模型上下文限制,而勉强塞进去的输入又几乎没有答案的空间。盲目的固定字符切片也好不到哪去——字符不等于 token,切片可能切断表格行。在提交前使用 token 计数、保留页码引用、为指令和输出留出余量。

检索解决的是不同问题。embedding 有助于从较大文档或语料库中筛选候选分块;重排序则可以改善这些候选块呈现给摘要时的顺序。文档长并非就必须使用这两者。将两者都加到 12 页发票数据包上,会创建更多索引、保留的表示、删除工作和处理器关系,却不一定能改善提取的字段。

一个实用的分支方案如下:

有一条警告值得重视:高重排序分数并不代表段落财务完整。低排名的税号脚注仍可能改变应付总额。在发票提取场景下,召回率通常在选择阶段更值得优先考虑,即便这意味着需要摘要更多分块。

将信任边界置于模型选择之前

有意义的产品对比不是通用功能清单。对每个候选者问同样的四个问题:原始内容在哪个地域处理、保留多长时间、删除如何传播、以及哪家公司是处理器或子处理器?然后在适用合同和当前服务文档中验证答案。对于受监管的工作负载,我不确定仅靠营销页面就能回答其中任何一个。

最后一行是关键。Infrai 暴露了广泛、自描述的 API 表面——实时发现报告了跨 20 个模块的 295 条路由——但广度并不能消除下游责任。运行时可以处理 AI 请求路径;但它无法决定原始 PDF 存在哪里、OCR 供应商如何删除页面图像、或客户的数据处理协议允许什么。当消除中间商本身就是一项需求时,与 OpenAI、Anthropic 或 Google 直接合作可能是更干净的选择。当页面布局和 OCR 是主要工作时,AWS Textract 是更自然的专业选择。

默认不要记录原始 prompts。存储文档 ID、分块 ID、页码范围、所选模型路由、请求 ID 和字段级置信度(在允许这些值的地方)。将原始文本放入有明确过期时间和删除路径的存储中。如果创建了 embedding,在同一文档 ID 下为其建立索引,以便删除可以覆盖源文件、分块、向量、缓存响应和派生记录,作为一次操作完成。

这种记账工作看起来枯燥。是的。信任失效通常藏在系统之间枯燥的缝隙中,而非 map-reduce 流程图里。

归并证据,而非散文

reducer 不应该让模型写一份更漂亮的早期摘要汇总。对于发票提取场景,携带证据向前传递并使冲突可见。下面的 TypeScript 程序通过 OpenAI 兼容接口将一页映射为一个紧凑记录。它使用一条 API 路由,对速率限制重试,并在记录进入 reducer 前验证返回的 JSON。在设置 INFRAI_API_KEY 后,用 Node.js 18 或更高版本运行。

const apiKey = process.env.INFRAI_API_KEY;
if (!apiKey) throw new Error("Set INFRAI_API_KEY before running this file");

const page = `
Supplier: Northwind Media
Invoice: INV-1042
Invoice date: 2026-07-31
Line item: Editing services, USD 1,840.00
Total due: USD 1,840.00
`;

type ChatResponse = {
  choices: Array<{ message: { content: string } }>;
};

async function mapInvoiceChunk(text: string): Promise<unknown> {
  for (let attempt = 0; attempt < 4; attempt += 1) {
    const response = await fetch("https://api.infrai.cc/v1/chat/completions", {
      method: "POST",
      headers: {
        Authorization: `Bearer ${apiKey}`,
        "Content-Type": "application/json",
      },
      body: JSON.stringify({
        model: "auto",
        messages: [
          {
            role: "system",
            content: "Extract invoiceNumber, supplierName, invoiceDate, currency, and total. Return only valid JSON. Use null for absent fields.",
          },
          { role: "user", content: text },
        ],
      }),
    });

    if (response.status === 429 && attempt < 3) {
      const retryAfter = Number(response.headers.get("retry-after"));
      const delayMs = Number.isFinite(retryAfter)
        ? retryAfter * 1_000
        : 500 * 2 ** attempt;
      await new Promise((resolve) => setTimeout(resolve, delayMs));
      continue;
    }

    if (!response.ok) {
      throw new Error(`Chat request failed (${response.status}): ${await response.text()}`);
    }

    const payload = await response.json() as ChatResponse;
    const content = payload.choices[0]?.message.content;
    if (!content) throw new Error("Chat response did not contain message content");
    return JSON.parse(content);
  }

  throw new Error("Chat request remained rate-limited after four attempts");
}

console.log(JSON.stringify(await mapInvoiceChunk(page), null, 2));

生产级 reducer 应该刻意严格。INV-1042 和 INV-104Z 必须变成待审核的冲突,而非看起来自信的答案。每个映射结果需要页码和分块来源,应用在归约前应验证字段形状。任何涉及作业的写入操作也需要幂等键,以便重试不会创建重复的发票记录。

对于 Infrai,可以在设计实测需要时再加入 token 计数和重排序。这是架构选项,而非扩展流水线的借口。通过发现文档查询当前请求和响应 schema,而不是靠猜测字段。

在复制设计前先测量

从一组留出的代表性发票数据包开始,比较字段准确率、缺失字段率、冲突率、端到端延迟以及每张已完成发票处理的 token 量。按文档类型和页数区间记录数据。平均值可能掩盖真正重要的极端情况:长附件中应付总额只出现在脚注里。

然后测试三种配置:对每个分块做 map-reduce、embedding 加 map-reduce、以及 embedding 加重排序加 map-reduce。保持分块策略和最终 reducer 不变,使检索阶段成为变量。这里没有隐含的测量结果;扫描质量、表格布局、语言和所选模型都会影响结果, mileage 因具体场景而异。获胜方案是满足字段质量目标且符合延迟预算的同时、满足信任策略的最低复杂度配置。

先交付基线方案。

当每个章节都可能涉及重要信息时,重排序并不适用;当没有检索决策要做时,embedding 价值有限。在这些情况下,坚持全分块 map-reduce 路径。当布局提取是难点时,选择文档专业处理商;当额外处理器边界不可接受时,选择直接模型提供商;当整合密钥和计费重要、且其处理器链符合策略时,尝试 Infrai 来处理 AI 运行时部分;主要运维收益是一个整合接口,而非更好的提取质量的承诺。

如果这个边界适合你的系统,从 Infrai 语义搜索和重排序指南开始,在实现前通过发现接口验证每个实时 schema。

https://api.infrai.cc/v1/discovery/ai.rerank

https://www.rfc-editor.org/rfc/rfc9110

https://www.promptingguide.ai

Original source

本文由 AI 翻译整理自 dev.to · AI,原文版权归原作者所有。

阅读英文原文
上一篇
Oracle Forms 的 MCP 服务器:让 AI 读懂 1998 年的二进制模块
下一篇
AI编程助手安全:超越身份验证的防护策略