采购比价·同口径
一页说明
- 给谁用:要买东西或外包服务的人——小公司老板、采购、行政、跨境卖家、做项目的服务商。拿到的是别人发来的几份报价。
- 解决什么:看单价会被坑——一家不含税、一家含税;一家运费另计、一家包邮;一家起订量比你要的多一倍;一家报价上周就过期了;一家少报了一项。肉眼比、手算、让 AI 心算,都容易算错或漏项。
- 原来几步:把几份报价抄到一张表 → 手动换算税 → 加运费安装 → 查有效期和起订量 → 列出要追问的事 → 重新算一遍。
- 用了技能剩几步:给报价和需求 → 回答一次缺口问题 → 拿到报告。
- 产出长什么样:
比价报告.md:一、能不能比(逐家状态和原因);二、已知总成本表;三、情景(条件折扣、按起订量下单);四、账期/质保/交期/有效期并排;五、逐行计价明细;六、要向对方确认的问题;七、本次做的假设。比价汇总.csv.txt、比价明细.csv.txt:同一份结果,Excel 里能筛选、能核对到原表行号。- 可选 Word 版(第 6 步)。
完整样例在 examples/,期望结论见 examples/期望要点.md。
核心原则(判断依据)
- 只比口径一致的。 缺项、税口径不清、币种没汇率、有未知费用、有未确认的条件折扣、起订量高于需求、报价已过期,这几类只列“已知部分”,不参与排名。
- 未知不是 0。 运费等费用留空或写“另计”是未知;明确写“无/包邮/含”才是 0。
- “已知总成本最低”只代表价格。 不写“推荐”,更不写“建议下单”。非价格条件并排给用户看。
- 数字只来自脚本。 你(模型)不心算、不改脚本输出的金额;要解释,直接引用报告里的数。
工作流
所有命令在技能目录下运行,路径用参数传入;python 不可用换 python3。输出放用户指定位置,没指定就放原文件旁边的 比价结果/,不放进技能目录,不改用户原文件。
第 1 步:问清基线(一次问完)
用户已经说清的不再问。缺什么就合并成一条消息问:
- 这次要买什么、每样多少(品名、数量、规格)?有没有交付地点、验收、周期要求?
- 统一用含税还是不含税比?(默认含税,因为多数企业付的是含税款。)
- 有外币报价吗?有的话请给汇率及来源日期。
- 要不要把账期折成钱?要的话给一个资金年化利率;不给就只并排显示账期天数。
- 比价日期(默认今天,用来判断报价是否过期)。
- 要求几号前到货?(给了日期,脚本会按各家交期判断来不来得及。)
- 看了报价原文后,补问你发现的缺口:不含税的几家税率是多少;运费、安装费是“每件多少”还是“整单多少”、含不含税;各家交期。能看出来的先一并问,允许整理完表、跑完第一遍后再合并问一次(最多两轮)。
第 2 步:把各家报价整理成一张表
报价可能是 Excel、CSV、PDF 里复制的文字、微信/邮件里的话。统一整理成每家每个品名一行的表,存成 UTF-8 的 CSV(或 xlsx)。列名参考 examples/报价汇总-示例.csv.txt:
供应商、品名、规格、数量、单位、单价、总价、含税、税率、折扣、折扣条件、运费、安装费、其他费用、费用含税、账期(天)、起订量、质保(月)、交期(天)、有效期、币种、备注
整理规则:
- 只抄原文,不算、不改。 对方写“含税13%”就在“含税”列抄“含税”、“税率”列抄“13%”;写“月结30天”就抄“月结30”。
- 供应商级的信息(账期、质保、交期、有效期、币种、整单的运费/安装费)填在该供应商任意一行即可。
- 运费、安装费等费用:对方写“每套 15 元”就原样填“15元/套”,写在对应品名那一行,脚本会乘需求数量;对方写整单总额就填数字(如 300)。不要自己乘。对方写“包邮/含/免费”就填原文;写“另算/待定”就填“另计”。
- 费用的含税口径默认和这家的单价一致,脚本按同一税率折算。对方明确说费用口径不同时,在“费用含税”列填“含税”或“不含税”。
- 账期、交期抄原文要点(“月结30”“货到付款”“15”),不要换算。
- 对方没写的格子留空,不要猜。“包邮、含、无”是对方明确说了的才填。
- 同一件东西各家叫法不同,统一成一个品名(在备注里留原名);拿不准是不是同一个东西,列出来问用户。
- 对方只给“整包总价”(如 20 套含运含装共 14000 元):填在“总价”列,“单价”列留空,“数量”写对应的数量;脚本不会拿总价再乘数量,也不会除出单价。总价对应的数量和需求不同,要请对方按需求数量重报。
- 阶梯价:按需求数量落在哪一档,把该档单价填进单价列,备注写档位;数量落在档位边缘就问用户。
- 一个格子里同时有多个信息(如“含税,运费另计”)要拆到各自的列。
检查点:整理完告诉用户“共 N 家、每家 M 行”,并抽 2–3 个关键数字(如某家的办公椅单价)请用户对一下原件。表里读不准的格子单独列出问用户。
需求清单(可选)单独一张 品名、数量,用 --need 传入;不给,则取各家一致的报价数量。
第 3 步:运行比价
python <技能目录>/scripts/quote_compare.py compare 报价汇总.xlsx --need 需求清单.csv --out-dir 比价结果 \
[--basis incl|excl] [--fx USD=7.10] [--base-currency CNY] [--as-of 2026-10-24] [--annual-rate 0.06] \
[--need-by 2026-11-15] [--rename 旧名=新名]
- 支持
.xlsx(标准库直接读,只读第一张表,--sheet可指定)、.csv、.tsv、.txt;粘贴的表格先原样存成.txt再读。 - 退出码 0:完成。2:缺信息(如各家数量不一致、缺必要列),把打印的问题清单整理成一条消息问用户,得到答案后重跑。1:复算对不上,停下,把输出原文告诉用户,说明是工具问题。
- 打印里的“未识别的列”要看一眼:如果有你以为会参与计算的列没被识别,改列名后重跑。
--rename只在各家对同一件东西叫法不同、又不想改表时用;品名已经一致就不用加。
检查点:看第一节“能不能比”。如果几乎全是“部分可比”,先和用户确认哪些缺口能补,不要急着给结论。
第 4 步:向用户汇报
按这个顺序,3–8 句话,不重抄整份报告:
1. 可比的有几家,已知总成本最低的是哪家、多少钱、比第二低差多少。如果一家都排不了名,就直说“目前没有一家能正式排名”,然后列出各家“已知部分”的数字(标明只是已知部分)和每家缺什么,把补价清单排在最前面。
2. 价格最低但不能排名的是哪家、为什么(缺项/过期/运费未知等)。
3. 情景:条件折扣、起订量会让结果怎么变。
4. 非价格条件里最影响取舍的 1–2 项(账期、质保、交期)。
5. 要向对方确认的前 3 个问题,其余指向报告第六节。
所有金额直接引用报告,不另算。写“已知总成本最低”,不写“推荐/最划算”。
第 5 步:补价后重跑
对方补了价、改了税口径、延长了有效期:更新表格另存新版本(不覆盖旧版),重跑。新旧报告各留一份,汇报时说明变了什么。
第 6 步:Word 版(可选)
python <技能目录>/scripts/md2docx.py 比价结果/比价报告.md 比价结果/比价报告.docx --landscape
表格列多,用横向。
依赖与环境
- Python 3.8 及以上,只用标准库:读 xlsx 用
zipfile+ XML,金额用Decimal,独立复算用Fraction。无需 pip。 - Windows、macOS 都能跑;路径全部由参数传入。
- 自测:
python <技能目录>/scripts/quote_compare.py --selftest。
边界
- 不替用户选供应商,不评价供应商信誉、质量,不做背调。
- 不联系供应商、不发询价/还价消息;
references/谈判问题模板.md只提供问法,由用户自己发。 - 不做税务、发票抵扣、合同条款、法律意见;能否抵扣进项税、合同怎么写,交给财务和法务。
- 汇率只用用户提供的,不查、不猜。
- 不处理阶梯价自动选档、混合币种的单一供应商、多期付款现值;遇到先请用户折算成单价或明确说不支持。
- 卖方出报价单、做报价计算器:请用
quote-sheet-builder。
目录
scripts/quote_compare.py:入口(compare / --selftest)scripts/tabular.py:读 xlsx/csv/粘贴文本scripts/md2docx.py:Markdown 转 Wordreferences/口径对齐清单.md:范围、税、费用、数量、币种、折扣、非价格条件的判断依据references/谈判问题模板.md:把问题清单变成对外的问法examples/:虚构的 5 家办公家具报价(csv)、需求清单、期望要点.md、输出/