用 Codex 把财务月报、差异分析和情景规划从手工活变成可复现流程

2026-05-12 13 预计阅读时间:1 分钟
来源:openai.com AI 摘要 原文链接

免责声明:本文为 AI 摘要整理,建议结合原文阅读。摘要可能省略上下文、版本差异或边界条件,不作为官方说明。

预计阅读时间:11 分钟

财务团队每个月都在重复同一套苦活:拼 MBR(月度经营回顾)、组装 Reporting Pack、搭 Variance Bridge、跑 Model Check、做 Planning Scenario。数据来源散落在 Excel、ERP、BI 工具里,格式不统一,人肉拼接极易出错。Codex 的思路是——把这些流程变成代码驱动的可复现任务,让 agent 从真实工作输入中自动生成结果,人只做审核和决策。

Codex 在财务场景里到底做什么

Codex 不是"替你写一段 VBA"的代码补全工具。它是一个可以接收任务描述、读取文件、执行代码、输出结果的 agent。财务团队用它,核心价值在于三点:

  • 输入标准化:把散乱的 Excel、CSV、API 数据统一读进 Python 脚本,不再依赖"某个人记得哪个单元格是哪个数字"。
  • 流程可复现:每月跑同一套脚本生成 MBR 和 Reporting Pack,差异可追溯,不再靠手工复制粘贴。
  • 情景快速迭代:改一个参数就能生成新的 Planning Scenario,不用重新搭整张模型表。

下面按具体场景拆开看。

MBR 与 Reporting Pack:从散装数据到结构化输出

传统做法是把各业务线的数据手动填进模板,格式对齐、单位换算、历史对比全靠人。用 Codex,你可以给 agent 一个任务:

"读取 data/ 目录下所有业务线本月 CSV,按 config/mbr_schema.yaml 的结构生成 MBR 数据包,输出到 output/mbr_2025_07.json。"

Codex 会自己写脚本读文件、按 schema 聚合、输出结构化结果。人只需要检查 schema 定义和最终数字是否合理。

Variance Bridge:自动拆解差异来源

Variance Bridge 是财务分析里最耗精力的部分——实际与预算的差异要拆到价格、量、混合效应等多个驱动因子。手工拆容易漏项、算错符号。交给 Codex 的好处是:拆解逻辑一旦写成代码,每月自动跑,逻辑透明可审计。

Model Check:给模型加一道自动校验

财务模型越复杂,越容易藏硬伤——公式引用错行、假设参数过期、边界条件没覆盖。Codex 可以跑一套校验脚本,检查模型输出的合理性范围、关键比率是否在历史区间内、输入参数是否与最新假设一致。

Planning Scenario:参数驱动,一键出多版

情景规划的本质是"同一套逻辑,不同参数"。用 Codex,你定义一个 scenario 配置文件,agent 就能批量生成乐观/基准/悲观三版预测,输出对比表和关键指标汇总。

实战:用 Codex 任务跑一套 Variance Bridge + Scenario

下面给一个可以直接改造运行的项目结构示例。假设你已安装 OpenAI Codex CLI(npm install -g @openai/codex),项目目录如下:

finance-codex/
├── data/
   ├── actual_2025_07.csv
   ├── budget_2025_07.csv
   └── assumptions.yaml
├── config/
   └── mbr_schema.yaml
├── scripts/
   └── variance_bridge.py
   └── scenario_runner.py
├── output/
└── prompts/
   └── variance_task.md

第一步:定义任务 prompt

prompts/variance_task.md

# 任务:生成 2025年7月 Variance Bridge

1. 读取 `data/actual_2025_07.csv``data/budget_2025_07.csv`2. 按产品线和区域维度,计算实际与预算的总差异。
3. 将总差异拆解为:量差(volume)、价差(price)、混合差(mix)。
4. 拆解公式参考 `scripts/variance_bridge.py` 中的逻辑。
5. 输出 JSON 结果到 `output/variance_bridge_2025_07.json`,格式与 `config/mbr_schema.yaml` 中 variance 部分一致。
6. 如果某行数据缺失或格式异常,跳过该行并在输出中记录 warning。

第二步:核心计算脚本

scripts/variance_bridge.py——这是 Codex 会参考和执行的逻辑,你也可以直接手动运行调试:

"""
Variance Bridge 计算:量差、价差、混合差
输入:actual CSV 与 budget CSV,列名需包含 product, region, units, revenue
输出:JSON 格式的差异拆解结果
"""

import csv
import json
import yaml
from pathlib import Path


def load_csv(path: Path) -> list[dict]:
    rows = []
    with open(path, newline="", encoding="utf-8") as f:
        reader = csv.DictReader(f)
        for row in reader:
            try:
                row["units"] = float(row["units"])
                row["revenue"] = float(row["revenue"])
                rows.append(row)
            except (ValueError, KeyError):
                print(f"WARNING: skip malformed row in {path}: {row}")
    return rows


def variance_bridge(actual: list[dict], budget: list[dict]) -> dict:
    """按 (product, region) 聚合,拆解差异"""
    def aggregate(rows):
        result = {}
        for r in rows:
            key = (r["product"], r["region"])
            result.setdefault(key, {"units": 0.0, "revenue": 0.0})
            result[key]["units"] += r["units"]
            result[key]["revenue"] += r["revenue"]
        return result

    a = aggregate(actual)
    b = aggregate(budget)

    bridge = {}
    total_variance = 0.0

    for key in b:
        a_val = a.get(key, {"units": 0.0, "revenue": 0.0})
        b_val = b[key]

        b_price = b_val["revenue"] / b_val["units"] if b_val["units"] else 0
        a_price = a_val["revenue"] / a_val["units"] if a_val["units"] else 0

        volume_var = (a_val["units"] - b_val["units"]) * b_price
        price_var = (a_price - b_price) * b_val["units"]
        mix_var = a_val["revenue"] - b_val["revenue"] - volume_var - price_var

        bridge[f"{key[0]}|{key[1]}"] = {
            "volume_variance": round(volume_var, 2),
            "price_variance": round(price_var, 2),
            "mix_variance": round(mix_var, 2),
            "total_variance": round(a_val["revenue"] - b_val["revenue"], 2),
        }
        total_variance += a_val["revenue"] - b_val["revenue"]

    bridge["_summary"] = {"total_variance": round(total_variance, 2)}
    return bridge


def main():
    data_dir = Path("data")
    output_dir = Path("output")
    output_dir.mkdir(exist_ok=True)

    actual = load_csv(data_dir / "actual_2025_07.csv")
    budget = load_csv(data_dir / "budget_2025_07.csv")

    result = variance_bridge(actual, budget)

    with open(output_dir / "variance_bridge_2025_07.json", "w", encoding="utf-8") as f:
        json.dump(result, f, indent=2, ensure_ascii=False)

    print(f"Done. Total variance: {result['_summary']['total_variance']}")


if __name__ == "__main__":
    main()

运行前准备两份 CSV,列头至少包含 product, region, units, revenue

product,region,units,revenue
WidgetA,North,1200,36000
WidgetA,South,800,24000
WidgetB,North,500,50000
WidgetB,South,300,30000

直接手动测试:

cd finance-codex
python scripts/variance_bridge.py
# 输出: Done. Total variance: xxx
cat output/variance_bridge_2025_07.json

第三步:用 Codex agent 执行任务

cd finance-codex
codex --task prompts/variance_task.md --full-auto

--full-auto 让 Codex 自动读取文件、执行脚本、输出结果。你审核 output/ 下的 JSON 即可。

第四步:情景规划扩展

data/assumptions.yaml 定义多版参数:

scenarios:
  base:
    growth_rate: 0.05
    price_increase: 0.02
  optimistic:
    growth_rate: 0.10
    price_increase: 0.05
  pessimistic:
    growth_rate: -0.02
    price_increase: 0.00

scripts/scenario_runner.py

"""基于 assumptions.yaml 的多情景预测生成"""

import csv
import json
import yaml
from pathlib import Path


def apply_scenario(budget_rows: list[dict], params: dict) -> list[dict]:
    result = []
    for row in budget_rows:
        new_units = row["units"] * (1 + params["growth_rate"])
        old_price = row["revenue"] / row["units"] if row["units"] else 0
        new_price = old_price * (1 + params["price_increase"])
        result.append({
            "product": row["product"],
            "region": row["region"],
            "units": round(new_units, 2),
            "revenue": round(new_units * new_price, 2),
        })
    return result


def main():
    data_dir = Path("data")
    output_dir = Path("output")
    output_dir.mkdir(exist_ok=True)

    budget = []
    with open(data_dir / "budget_2025_07.csv", newline="", encoding="utf-8") as f:
        for row in csv.DictReader(f):
            row["units"] = float(row["units"])
            row["revenue"] = float(row["revenue"])
            budget.append(row)

    assumptions = yaml.safe_load(open(data_dir / "assumptions.yaml", encoding="utf-8"))

    all_scenarios = {}
    for name, params in assumptions["scenarios"].items():
        projected = apply_scenario(budget, params)
        total_revenue = sum(r["revenue"] for r in projected)
        all_scenarios[name] = {
            "params": params,
            "projected": projected,
            "total_revenue": round(total_revenue, 2),
        }

    with open(output_dir / "scenarios_2025_07.json", "w", encoding="utf-8") as f:
        json.dump(all_scenarios, f, indent=2, ensure_ascii=False)

    for name, data in all_scenarios.items():
        print(f"{name}: total_revenue = {data['total_revenue']}")


if __name__ == "__main__":
    main()
python scripts/scenario_runner.py
# base: total_revenue = xxx
# optimistic: total_revenue = xxx
# pessimistic: total_revenue = xxx

落地前想清楚几件事

  • 数据质量是前提:Codex 能自动跑流程,但输入数据脏,输出也脏。先花时间统一 CSV 格式和列名规范,再让 agent 上场。
  • schema 先定再跑mbr_schema.yaml 是你和 agent 的契约。结构不定,agent 生成的格式每次都可能漂移,审核成本反而更高。
  • 从单点切入:别一口气把 MBR + Bridge + Scenario 全交给 agent。先从 Variance Bridge 这种逻辑明确、输入固定的场景开始,验证流程可靠后再扩展。
  • 人审不可省:Codex 输出的数字必须与已知口径交叉验证。agent 替你算,不替你担责。
  • 版本控制输出output/ 下的 JSON 按月份命名归档,配合 git 管理,任何月度的数字都能回溯。

财务团队用 Codex 的本质不是"AI 替我做表",而是把反复出现的分析流程变成代码 + 配置驱动的可复现 pipeline。手工拼接的月报永远有"这次忘了改那个链接"的风险;代码跑出来的月报,风险只在于你有没有审过输出数字。


相关推荐