PAYATHON 2026

受限环境中如何为 Agent 生成保持跨文档关联的高保真 PDF?

技术老齐

结论:先确认云端能否携带浏览器运行环境

Headless Chrome 已经给出了最符合要求的效果,建议先解决部署问题。云端没有预装 Chrome,也没有现成的可执行文件路径,仍有可能运行浏览器。只要目标平台允许部署浏览器二进制文件及其系统依赖,就可以在构建阶段准备好,再随应用或容器部署。

如果云端明确禁止运行浏览器进程,或无法提供所需依赖,就需要放弃这一方案。此时可以继续使用 reportlab,通过固定模板控制版式,但需要投入更多布局开发工作。

跨文档一致性需要单独处理:先生成一份共享的合成数据,再用不同模板生成相关 PDF。更换 PDF 库本身无法保证账户、金额和交易记录一致。

用 Playwright 管理 Chromium,避免依赖办公电脑上的 Chrome 路径

Playwright 可以使用它管理的 Chromium,无需指定办公电脑上的 Chrome 安装路径。不过,安装 Python 包不会自动解决浏览器和系统依赖问题。浏览器文件仍须提前准备,并与 Playwright 版本匹配。参见 Playwright 浏览器安装说明。

如果公司允许在内部构建环境中安装依赖,可以在支持的 Linux 环境中执行:

python -m pip install playwright
python -m playwright install --with-deps chromium

这些命令需要下载文件,安装系统依赖也可能需要相应权限。应在具备网络和权限的构建环境中执行,不能假设受限的办公电脑可以直接运行。

部署时需要一起准备:

  • Python 应用及其依赖。
  • 匹配的 Chromium 和系统运行库。
  • 模板使用的字体、图片等资源。
  • 可写的临时目录和输出位置。

如果运行阶段不能访问外网,应提前把这些资源放进经过批准的镜像或部署包。构建环境与目标环境的操作系统和 CPU 架构也要匹配,不能把办公电脑上的浏览器目录直接复制到任意云端环境。

用固定 HTML 模板生成 PDF

下面是一个最小渲染示例,前提是 Chromium 及其依赖已经安装完成。示例数据为虚构数据,仅用于演示版式生成,不包含完整的对账业务逻辑。

from html import escape
from playwright.sync_api import sync_playwright

account = "TEST-0001"
closing_balance = "1080.00"

html = f"""
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<style>
  @page {{ size: A4; margin: 16mm; }}
  body {{ font-family: sans-serif; font-size: 11pt; }}
  table {{ width: 100%; border-collapse: collapse; }}
  th, td {{ border-bottom: 1px solid #ccc; padding: 8px; }}
  th {{ text-align: left; }}
  .amount {{ text-align: right; }}
  tr {{ break-inside: avoid; }}
</style>
</head>
<body>
  <h1>Synthetic Bank Statement</h1>
  <p>Account: {escape(account)}</p>
  <table>
    <thead><tr><th>Item</th><th class="amount">Amount</th></tr></thead>
    <tbody><tr><td>Closing balance</td>
      <td class="amount">{escape(closing_balance)}</td></tr></tbody>
  </table>
</body>
</html>
"""

with sync_playwright() as p:
    browser = p.chromium.launch(headless=True)
    try:
        page = browser.new_page()
        page.set_content(html, wait_until="load")
        page.evaluate("document.fonts.ready")
        page.pdf(
            path="synthetic_statement.pdf",
            print_background=True,
            prefer_css_page_size=True,
        )
    finally:
        browser.close()

page.pdf() 默认使用打印媒体样式;prefer_css_page_size=True 让 CSS 中的页面尺寸优先,print_background=True 用于输出背景色和背景图片。相关行为见 Playwright PDF API。

正式模板需要检查长表格分页、重复表头、长字段换行和页脚位置。中文文档还要部署可用的中文字体,并在导出前等待字体加载。示例中的基础样式并不代表已经复刻了银行文档的完整外观。

用同一份数据生成相互关联的文档

建议让 Agent 按以下流程工作:

  1. 从输入 PDF 中提取账户、期间、交易及文档间的对应关系;提取方法取决于 PDF 是否包含可读取文本。
  2. 生成共享的合成数据对象,并统一建立账户、交易和文档标识的替换映射。
  3. 用程序计算余额及汇总值,再检查关联关系。
  4. 将同一数据对象分别传入对账单模板和余额调节表模板。
  5. 导出 PDF 后检查字段值和视觉排版。

例如,共享数据可以包含:

{
  "account_id": "TEST-0001",
  "period": "2025-01",
  "opening_balance": "1000.00",
  "transactions": [
    {"id": "T001", "amount": "100.00"},
    {"id": "T002", "amount": "-20.00"}
  ],
  "closing_balance": "1080.00"
}

在这个简化例子中,约定收入为正、支出为负,期末余额就是 1000.00 + 100.00 - 20.00 = 1080.00。金额计算应使用整数最小货币单位或 Decimal,再统一格式化。

银行余额调节表可能包含未达账项,应按实际业务规则验证调整后的对应关系,不能简单要求它的所有余额都与对账单余额相同。不要让模型分别为两份文档独立生成金额,再期待它们自动吻合。

如果浏览器确实无法部署

对于版式固定的对账单,可以使用 reportlab 明确控制文字、表格、线条和分页。它提供直接绘图能力及用于文档布局的 Platypus。实现效果取决于模板设计,不能仅凭当前生成结果认定它无法制作正式业务文档。参见 ReportLab 官方介绍。

这条路线需要明确设置列宽、字体、行高、页边距和分页规则,不适合直接复用复杂 HTML/CSS。可以先选一页典型样本,把布局做准确,再处理多页和字段长度变化。

目前缺少云平台、运行时和安装权限信息,因此无法断言哪种部署方式一定可行。下一步应确认目标环境是否允许自定义镜像、运行浏览器进程及携带依赖。Claude Sonnet 可以参与数据提取和合成,但更换模型无法解决这些运行环境限制。

备注:内容仅供参考。