Ledger-X:结构化工具调用加速的可验证对账引擎。
- 技术栈:Python、FastAPI、DuckDB、Pydantic、vLLM、OpenAI-compatible API。
- 项目背景:面向商户结算对账场景,解决 LLM 直接计算金额不可靠、工具调用生成慢、对账证据难追踪等问题,将自然语言问题拆解为受控工具选择 → 确定性账务计算 → 证据化回答生成的流程。
- 设计 模式感知草稿生成,根据工具 JSON Schema 和当前已生成内容,提前生成工具名、必填字段、枚举值、JSON key 和括号等结构化片段,再将候选草稿交由目标模型验证,减少模型在固定格式输出上的重复生成成本。
- 引入 检索增强推测,按工具定义、商户权限与请求语义检索历史中通过结构校验的工具调用,将匹配的 token 续写片段作为候选草稿交由目标模型验证,提升结构化工具调用的生成效率。
- 基于 DuckDB 构建可复现的合成账本,覆盖支付流水、退款流水、结算批次、手续费规则、结算明细和到账凭证,并同步生成独立校验数据,用于自动核验工具选择、账务计算、证据链以及回答中关键事实与工具结果的一致性。
- 构建分层上下文与记忆机制:working memory 维护当前任务的执行状态和工具证据,case memory 按租户与商户权限沉淀跨会话的已验证事实,retrieved context 根据当前问题按需召回相关证据;结合字段白名单、显著性排序和上下文预算控制记忆质量与提示长度。
- 将所有工具封装为只读接口,Agent 会校验授权商户范围、拦截写操作意图、限制日期范围,并记录每轮模型消息、工具调用、工具结果、策略判定、记忆读写和耗时,便于复盘完整执行过程。
- 实验评估基于同一套 Qwen3-14B-FP8 推理服务:400 个单步工具调用问题重复 3 轮共 1,200 次,p50 延迟从普通自回归生成(AR)基线的 2132.8ms 降至 Ledger-X 的 372.5ms,约 5.7× 加速且工具调用正确率保持 100%;进一步把该加速带入完整流程后,80 条独立构造的多步骤 Agent test 任务端到端中位延迟下降 19.95%。结果验证了 Ledger-X 能在不牺牲工具调用正确性的前提下显著压缩结构化生成耗时,并将收益传导到完整 Agent 流程。
- 合成账本生成:生成商户、手续费规则、支付、退款、结算批次、结算明细和到账凭证。
- 只读工具接口:模型只能调用受控 typed tools,不能直接执行 SQL、写库或发起资金操作。
- 对账工具集:支持结算汇总、异常批次列表、批次复算、交易追踪、规则查询和商户解析。
- 策略护栏:限制授权商户范围,拦截写操作意图、越权商户和异常工具调用。
- 上下文管理:按预算注入 system policy、working memory、case memory 和 retrieved context。
- 证据记忆:只把工具返回的结构化证据写入记忆,不写入模型自由文本。
- 审计轨迹:每次运行记录模型消息、工具调用、工具结果、策略判定、记忆读写和耗时。
- 结构化调用加速:在工具调用生成阶段提出 draft tokens,并由同一个目标模型验证后接受。
.
├── README.md
├── pyproject.toml
├── requirements.txt
└── src/ledger_x/
├── app/ # Agent、工具、策略、合成账本和 Web demo
├── specdec/ # 结构化工具调用推测解码运行时
├── __main__.py
└── paths.py
benchmarks/ 中包含可提交的端到端评测脚本;experiments/、artifacts/、runtime/ 是本地开发和实验输出目录,默认不提交。
安装依赖:
python3 -m venv .venv
.venv/bin/python -m pip install -r requirements.txt生成一个本地合成账本:
.venv/bin/python -m ledger_x seed --db runtime/ledger.duckdb直接调用只读工具:
.venv/bin/python -m ledger_x tool query_settlement_summary \
'{"merchant_id":"M001","start_date":"2026-03-01","end_date":"2026-09-01","group_by":"channel"}' \
--db runtime/ledger.duckdb连接本地或内网 OpenAI-compatible 模型服务后运行 Agent:
LEDGERX_BASE_URL=http://127.0.0.1:2011/v1 \
LEDGERX_MODEL=qwen3-14b-fp8-ledger-x \
.venv/bin/python -m ledger_x ask \
'查询 M001 从2026年3月1日到9月1日的结算异常,选出差额最大的批次并解释原因。'启动本地 Web 工作台:
LEDGERX_BASE_URL=http://127.0.0.1:2011/v1 \
LEDGERX_MODEL=qwen3-14b-fp8-ledger-x \
.venv/bin/python -m ledger_x serve --port 8090Ledger-X 使用 DuckDB 作为本地合成账本数据库。默认数据库文件是 runtime/ledger.duckdb,由命令行生成,不连接真实银行、支付平台或商户账本。
数据库里保存了完整对账链路需要的只读事实:
merchants:合成商户信息。fee_rules:不同渠道在不同日期生效的手续费规则。payments:支付流水,金额单位为分。refunds:退款流水。settlement_batches:商户、渠道、月份维度的结算批次。settlement_items:批次内的支付/退款明细和渠道侧记录的手续费。bank_receipts:到账凭证,用来判断缺失到账、延迟到账和短款。
数据库还定义了 expected_items 和 expected_batches 两个 view,用于按规则确定性复算“应结算金额”。生成账本时会同步保存一份由数据生成器直接维护的标准答案,它不依赖工具 SQL 计算,benchmark 用它核验工具调用、账务证据以及回答中关键事实的一致性。
模型不会直接写 SQL。Agent 只把受控工具 schema 交给模型,模型选择工具和参数;工具层再用参数化只读 SQL 查询 DuckDB。这样数据库承担四个作用:
- 提供可复现的合成业务事实。
- 执行确定性的金额计算和异常识别。
- 作为 Agent 最终回答的证据来源。
- 为 benchmark 提供可自动评分的标准答案。
Ledger-X 不把完整历史消息直接塞回模型,而是把上下文分成四类:
system policy:合成数据边界、只读工具约束、授权商户、金额单位和日期口径。working memory:当前任务内从工具结果提取的证据,例如批次号、差额、异常类型、规则号。case memory:同一租户和授权商户范围内的长期已验证事实。retrieved context:根据批次号、交易号、规则号、异常类型或商户范围检索出来的少量历史事实。
记忆写入遵循证据优先策略:
- 允许写入:工具返回的
batch_id、merchant_id、transaction_id、rule_id、difference_fen、异常类型等结构化证据。 - 禁止写入:模型最终回答、用户原文中的未验证金额、工具错误文本。
- 作用域隔离:M001 的证据不会注入到 M002 的请求。
每次运行的执行记录会保存:
context:本轮注入模型的上下文块。context_budget:压缩前后字符数、working facts 数和 retrieved facts 数。memory_reads:本轮检索到的历史证据。memory_writes:本轮从工具结果写入的证据。filled_from_context:从授权商户范围或历史上下文安全补全的字段。
如果问题缺少必要上下文,例如没有商户或没有日期范围,Agent 会返回 needs_clarification,不会猜测参数后直接调用工具。
Ledger-X 的加速发生在模型生成工具调用的阶段。流程如下:
- Agent 将问题、商户范围、工具 schema、工作记忆和检索上下文组成 prompt。
- 目标模型正常生成工具调用。
- 运行时根据 schema、当前 token 后缀和历史已验证工具调用提出一小段 draft tokens。
- 同一个目标模型验证 draft tokens。
- 只有验证通过的 tokens 才会进入最终输出。
这种方式不缓存金融结果,不绕过目标模型,也不会把历史参数强行写入当前请求。它只加速稳定的结构化 token,例如工具名、JSON key、枚举值、括号和固定格式片段。
Ledger-X 分开评测两件事:
- 工具调用生成:只测模型生成一次结构化工具调用需要多久,例如生成
list_reconciliation_exceptions({"merchant_id":"M001", ...})的工具名和 JSON 参数。 - 完整 Agent 端到端任务:测用户提出问题后,Agent 完成上下文整理、策略检查、工具调用、工具结果读取、证据记忆和最终回答生成的完整耗时。
400 个工具调用问题本身也是自然语言问题,但它们是为单步工具调用生成设计的,主要覆盖 query_settlement_summary 和 list_reconciliation_exceptions 两个工具;评分也只检查工具名、JSON 参数和部分工具结果是否正确,不检查最终自然语言回答。把这批问题直接加上工具执行和回答生成也可以形成一个端到端实验,但它会更偏向“单步查询 + 回答”,覆盖不到多工具调查、交易追踪和规则核验。
因此,下面的 1,200 次工具调用生成评测和 80 条端到端 Agent 评测不是同一批样本,也不是包含关系。前者衡量“工具调用这一步快了多少”,后者使用独立构造的完整 Agent workload,衡量“真实多步骤任务整体快了多少”。
两个 workload 都按 warm / tune / test 划分,三者不是难度等级,而是为了避免把开发调参和最终报告混在一起:
warm:预热集,用来让模型服务、prefix cache、检索记忆和数据库查询进入稳定状态,不计入最终结果。tune:开发集,用来调阈值、查失败样例和选择配置,不作为最终效果。test:冻结后的正式评测集,README 中报告的加速和正确性都来自 test split。
工具调用生成 workload 共 600 条:warm=100、tune=100、test=400。正式结果使用 400 条 test 问题,每条重复 3 轮,所以表中是 1,200 次结构化工具调用生成。
端到端 Agent workload 共 120 条:warm=20、tune=20、test=80。正式结果使用 80 条 test 任务,每条任务可能包含上下文整理、策略检查、一到多次工具调用、证据记忆写入和最终回答生成。
这里使用 p50,也就是中位延迟,表示把所有请求耗时从小到大排序后排在中间的典型耗时。LLM 服务偶尔会因为排队、网络或 GPU 状态出现极慢请求,平均值容易被少数异常值拉偏。例如 5 次请求耗时是 300ms, 340ms, 371ms, 390ms, 2000ms,平均值是 680ms,但 p50 是 371ms,更接近日常一次请求的体验。
实验中的 AR 是普通自回归生成,不启用 Ledger-X 自定义 speculative decoding;full 模式启用 Schema-Aware Drafting 和 Retrieval-Augmented Speculation。两种模式使用同一个 Qwen3-14B-FP8、同一个 vLLM 配置、同样的 prefix cache、batch size 1 和关闭异步调度设置。MTP 在两种模式中都关闭,因此结果不会混入 Qwen 原生 MTP 加速。
在同一个 Qwen/Qwen3-14B-FP8 目标模型上,对 400 个测试问题重复 3 轮,共比较每种模式 1,200 次结构化工具调用生成。
最核心的数据是:
| 模式 | p50 响应时间 | p95 响应时间 | 工具调用正确率 |
|---|---|---|---|
| 普通生成(AR) | 2132.8 ms | 2584.7 ms | 1200 / 1200 |
| Ledger-X 加速 | 372.5 ms | 486.6 ms | 1200 / 1200 |
也就是说,模型生成一次工具调用的配对中位延迟降低 82.53%(95% bootstrap CI:80.54%–82.62%),约 5.7× 更快。
正确性保持不变:
- 数值校验:609 / 609 次标准答案校验一致。
- 结构化参数归一化后一致:1,200 / 1,200。
- speculative draft token 接受率:83.23%。
测试使用的合成账本包含 100,000 笔支付、7,056 笔退款和 90 个结算批次。这里的加速只针对“生成工具调用”的响应时间。
完整 Agent 任务还包括上下文整理、策略检查、工具执行、证据记忆和最终回答生成,所以端到端提升通常会小于单次工具调用生成提升。
当前端到端评测入口会记录:
agent_p50_ms / agent_p95_ms:完整任务耗时。llm_p50_ms / llm_p95_ms:所有模型轮次耗时。tool_p50_ms:工具执行耗时。mean_llm_rounds / mean_tool_calls:平均模型轮次和工具调用数。task_success_rate:工具链和证据是否完整,以及回答中的关键事实是否与标准答案一致。
在 80 条完整 Agent test case 上,分别运行普通生成和 Ledger-X full 加速模式,结果如下:
| 模式 | 任务成功率 | 端到端 p50 | 端到端 p95 | LLM p50 | 平均 LLM 轮数 | 平均工具调用 |
|---|---|---|---|---|---|---|
| 普通生成(AR) | 64 / 80 | 9298.9 ms | 16923.5 ms | 9240.5 ms | 2.13 | 1.13 |
| Ledger-X full | 66 / 80 | 5810.3 ms | 13386.6 ms | 5750.6 ms | 2.16 | 1.16 |
80 条端到端任务由独立的 Agent workload 生成,不是从 1,200 次工具调用生成评测中抽样。任务类型覆盖异常定位、批次复算、交易追踪和规则核验,用来衡量完整 Agent 流程。
如果要做严格同源评测,后续可以从同一批 Agent 任务中同时抽取“工具调用生成阶段”和“完整端到端流程”两组指标。当前 README 报告的是两套已冻结 workload 的结果。
按两种模式都成功的 64 个任务做配对比较,完整 Agent 端到端中位延迟下降 19.95%,95% bootstrap CI 为 10.73%–40.48%。full 模式在这轮评测中提出 14,082 个 draft tokens,目标模型接受 6,841 个,接受率约 48.58%。
full 模式统计可以证明检索分支实际参与生成:在端到端实验的 14,082 个草稿 token 中,6,051 个来自 retrieval,占 42.97%;在本轮单步工具调用实验的 85,711 个草稿 token 中,64,782 个来自 retrieval,占 75.58%。但 full 模式的总体接受率混合了 schema、retrieval 和 n-gram 三种来源,不能解释为 retrieval 的召回率或独立接受率。
Ledger-X 使用以下指标单独评估检索增强推测:
候选可用率@10:具备有效检索条件的请求中,top-10 内至少存在一个同作用域历史候选的比例。检索草稿覆盖率:具备有效检索条件的请求中,至少有一个历史续写片段真正形成 draft tokens 的比例。retrieval token 接受率:在 retrieval-only 模式下,目标模型接受的 retrieval draft tokens 占提出 token 的比例。retrieval-only 延迟与正确率:与同模型 AR 基线比较响应延迟,同时检查工具参数和账务校验结果是否保持一致。
在同一批 400 个 test 问题、3 轮共 1,200 次请求上,retrieval-only 的实测结果如下:
| 指标 | 结果 |
|---|---|
| 候选可用率@10 | 1200 / 1200(100%) |
| 检索草稿覆盖率 | 1200 / 1200(100%) |
| retrieval draft tokens | 81,670 |
| 目标模型接受的 retrieval tokens | 68,689 |
| retrieval token 接受率 | 84.11% |
| retrieval-only p50 / p95 | 424.5 ms / 618.3 ms |
| 工具调用正确率 | 1200 / 1200(100%) |
| 数值校验 | 609 / 609(100%) |
相对 AR 基线,retrieval-only 的配对中位延迟降低 80.10%(95% bootstrap CI:77.83%–80.18%),约 5.0× 更快。候选可用率和草稿覆盖率达到 100%,与本实验先用 100 条 warm 数据填充记忆、且 test workload 具有重复工具结构有关,不表示任意开放场景都能达到相同覆盖率。
候选可用率和草稿覆盖率属于运行时活动指标,并不等同于信息检索中的 Recall@K。严格计算 Recall@K 需要为每个问题标注所有相关历史调用;当前 workload 没有这类相关性标注,因此不使用“召回率”描述这些数字。
benchmarks/ 中包含配对评测脚本,可按下面流程生成端到端对比报告。
.venv/bin/python -m benchmarks.agent_workload \
--db runtime/ledger.duckdb \
--out runtime/agent-workload.jsonl
LEDGERX_BASE_URL=http://127.0.0.1:2011/v1 \
LEDGERX_MODEL=qwen3-14b-fp8-ledger-x \
.venv/bin/python -m benchmarks.agent_benchmark \
--workload runtime/agent-workload.jsonl \
--db runtime/ledger.duckdb \
--manifest runtime/service-manifest.json \
--out artifacts/evidence/agent-e2e-ar \
--split test --limit 80 --repeats 1
LEDGERX_BASE_URL=http://127.0.0.1:2011/v1 \
LEDGERX_MODEL=qwen3-14b-fp8-ledger-x \
.venv/bin/python -m benchmarks.agent_benchmark \
--workload runtime/agent-workload.jsonl \
--db runtime/ledger.duckdb \
--manifest runtime/service-manifest.json \
--out artifacts/evidence/agent-e2e-full \
--split test --limit 80 --repeats 1
.venv/bin/python -m benchmarks.agent_report \
--ar artifacts/evidence/agent-e2e-ar \
--candidate artifacts/evidence/agent-e2e-full \
--candidate-name full \
--out artifacts/evidence/agent-e2e-comparison.json.venv/bin/python -m pytest tests -q当前本地测试覆盖:
- 只读工具和合成账本生成
- 工具参数校验和商户授权范围
- Agent 策略护栏
- 上下文压缩和证据记忆
- 结构化调用 draft engine
- benchmark 结果汇总逻辑
- 只使用合成 CNY 数据,不连接真实银行、支付平台或商户账本。
- 工具只读,不执行转账、退款、写库或外部副作用。
- 模型输出不能作为账务事实来源,最终回答必须基于工具证据。
- 延迟实验只针对固定模型、固定工具集、batch size 1 和 frozen workload。
MIT