ARTICLE DETAIL

资讯详情

深耕编程入门与网站建设的一线实战洞察。

用工程手段约束大模型:BoqCalc管道如何杜绝AI价格幻觉

用工程手段约束大模型:BoqCalc管道如何杜绝AI价格幻觉 在工程造价数字化项目里最让人头疼的往往不是模型能力不够而是模型“一本正经地胡说八道”。你问它 C30 混凝土的单价它可能给你一个看起来合理、实际上完全对不上的数字你问它某项清单的综合单价它甚至会把单位“立方米”换算成“平方米”之后还信心满满地给出结果。这种问题在工程量清单BOQ定价场景中尤其致命。本文将围绕 BoqCalc 这个项目完整拆解一套能对 500 行规模 BOQ 自动定价、同时尽量杜绝 AI 幻觉的 Pipeline 设计方案。文章会覆盖背景概念、总体架构、防幻觉策略、完整代码实现、评估方法和工程落地建议。无论你是做造价软件、AI 应用开发还是想了解如何用工程手段约束大模型这篇文章都值得读完。1. 背景BOQ 定价场景为什么最怕 AI 幻觉1.1 什么是 BOQBOQ 全称是 Bill of Quantities也就是工程量清单。它是建筑工程、市政工程、安装工程等项目中非常重要的一份文件通常由招标方或造价咨询方编制用来描述一个项目需要完成的所有工程内容。一张典型的 BOQ 表格一般包含以下几个字段项目编码项目名称项目特征描述计量单位工程量数量综合单价合价举个简单例子项目编码项目名称项目特征单位工程量010101001001平整场地土壤类别三类土m²1200010402001001矩形柱C30 混凝土截面尺寸 400×400m³86.5010501001001屋面卷材防水SBS 改性沥青防水卷材厚度 4mmm²980造价的本质就是把这些条目逐项定价再汇总成整个项目的造价。这个过程要求每一条都有一个明确、可追溯、有依据的单价而不是一个“大概数”。1.2 大模型直接报价的四个坑很多人第一次尝试用 AI 做造价都会直接扔给大模型一句“帮我给这份清单报个价”。这看起来是 AI 最擅长的任务但实际上踩坑非常严重。第一个坑是价格幻觉。大模型内部并没有存储一份权威、实时、分地区的价格数据库。它的训练数据里可能有价格但那些价格可能是三年前某地的、可能会被“平均”成不存在的区间值。当你要求它给出具体单价时它会在概率上生成一个看起来像价格的数字——这就是典型的价格幻觉hallucinating rates。第二个坑是单位混淆。BOQ 里最常见的单位有 m、m²、m³、kg、t、个、套等。模型经常会把“m³ 混凝土”和“m² 防水卷材”的单位逻辑搞混导致单价直接差一个数量级。第三个坑是地区与时间差异。同样的 C30 混凝土在 A 城市和 B 城市的价格可能差 10% 以上在不同月份也可能波动。通用大模型无法感知“你当前项目所在地”和“报价基准期”自然无法给出准确价格。第四个坑是不可追溯。造价行业强调“有据可查”。如果你问模型为什么这个单价是 480 元而不是 520 元它给不出依据。而没有依据的报价在审计和结算阶段根本无法通过。1.3 BoqCalc 的定位让 AI 只做擅长的事BoqCalc 的核心思路不是让 AI 直接报价而是让 AI 只做它擅长的事解析非结构化文本、理解清单描述、做名称归一化和特征提取。至于价格数值本身从可靠的价格知识库中检索金额计算用代码完成而不是让模型算数。这样设计的好处很明显模型不需要“记住”价格就不会在价格上产生幻觉模型不负责算术就不会出现加减乘除错误。整条链路变成了解析、检索、计算、校验的工程化流程。2. BoqCalc Pipeline 总体设计2.1 这里说的 Pipeline 是什么在 AI 工程实践里Pipeline 指的是一条由多个处理阶段串联而成的数据处理流水线。每个阶段只负责一类任务前一阶段的输出作为后一阶段的输入。这里要区分一下它和我们常说的 Redis Pipeline、Jenkins Pipeline 不是一回事。Redis Pipeline 是批量发送命令的机制Jenkins Pipeline 是 CI/CD 流程编排。BoqCalc 里的 Pipeline 指的是“从 BOQ 文件输入到定价结果输出”的完整数据处理流程。采用 Pipeline 而不是“一次大模型调用”的原因很现实造价任务环节多每个环节都有可能出错拆开以后可以针对每个环节分别做降错、校验和兜底。某个环节出现问题也能快速定位。2.2 五个阶段的职责划分BoqCalc Pipeline 可以拆成五个阶段输入解析读取 Excel、CSV 或 PDF 文件把 BOQ 条目转成结构化数据。名称归一化把项目名称、项目特征等非结构化文本标准化成可以检索的物料名称、规格、单位和数量。价格检索根据归一化后的结果从价格知识库中检索匹配的基准单价。金额计算用“工程量 × 单价”计算合价并做四舍五入。校验与输出检查金额一致性、标记异常条目、输出带来源与置信度的结果表。用一张简图可以表示成BOQ 文件 → 解析 → 名称归一化 → 价格检索 → 金额计算 → 校验输出2.3 为什么分阶段能抑制幻觉分阶段抑制幻觉的本质是把“事实查询”和“文本理解”两种截然不同的任务分开。大模型适合做语义理解但不适合做事实记忆。价格属于“事实”放进数据库比塞进模型参数更可靠。而工程量清单里的项目特征、规格描述是“文本”模型擅长把它转成结构化字段。举个例子清单里写的是“SBS 改性沥青防水卷材厚度 4mm热熔法施工”。模型只需要负责识别出物料是 SBS 防水卷材规格是 4mm。至于单价是多少由代码去价格表里查“SBS 防水卷材 4mm”这一行的数值。模型不需要输出任何价格数字自然就没有“编价格”的机会。3. 技术选型与环境准备3.1 环境版本本文的示例以 Python 环境为主重点演示 Pipeline 的实现思路。版本需要根据你的项目实际情况调整本文示例以常见环境为例重点演示配置思路。推荐环境Python 3.10 或更高版本虚拟环境venv 或 conda依赖管理pip 或 poetry本地数据库SQLite 可用于演示生产环境建议使用 PostgreSQL大模型接口OpenAI 兼容接口可对接云端模型或本地部署模型需要提醒的是大模型接口的包名和调用方式迭代很快。本文代码以 OpenAI 兼容接口为例实际使用时请根据你选择的模型服务商调整 endpoint 和参数。3.2 项目结构建议按下面这种结构组织代码方便后续扩展boqcalc/ ├── boqcalc/ │ ├── __init__.py │ ├── models.py # 数据模型 │ ├── parser.py # BOQ 文件解析 │ ├── normalize.py # 名称归一化LLM 调用 │ ├── price_db.py # 价格知识库查询 │ ├── validator.py # 校验逻辑 │ ├── pipeline.py # Pipeline 主流程 │ └── config.py # 配置项 ├── data/ │ ├── boq_demo.xlsx # 示例 BOQ │ └── price_library.db # 价格知识库 ├── output/ │ └── result.xlsx # 定价结果 ├── requirements.txt └── README.md3.3 数据准备BOQ 样例与价格知识库为了演示我们需要准备两份数据。第一份是 BOQ 样例可以用 pandas 直接生成也可以从真实项目脱敏后整理。关键字段至少包含项目编码、项目名称、项目特征、计量单位、工程量。第二份是价格知识库设计一张价格表。这张表可以放在 SQLite、MySQL 或 PostgreSQL 中核心字段包括物料编码、物料名称、规格、单位、基准单价、地区、生效日期和价格来源。价格表建表语句示例CREATE TABLE price_library ( id INTEGER PRIMARY KEY, material_code TEXT NOT NULL, item_name TEXT NOT NULL, spec TEXT, unit TEXT, base_price REAL NOT NULL, region TEXT, effective_date TEXT, source TEXT );这里的核心思想是价格数值必须来自这一张可审计、可更新的表而不是来自大模型生成。4. 核心模块设计四条防幻觉策略4.1 策略一数值计算与文本生成分离这是 BoqCalc 最重要的一条防幻觉策略。它的原则是大模型只负责理解和提取文本不负责输出任何价格数字。具体来说在 Prompt 里就明确约束模型只输出 JSON 结构包含 item_code、item_name、spec、unit、quantity 等字段。不输出 unit_price、amount 等价格字段。不确定的字段设置为 null不要猜测。这样模型输出的内容里压根没有“价格”这个维度自然不可能编造价格。这条策略在很多 AI 工程实践中都值得借鉴。当你发现模型在某类数值上频繁出错时最有效的办法不是换更大的模型而是把数值产生逻辑从模型生成逻辑里剥离出来。4.2 策略二用价格知识库做检索增强纯靠 Prompt 约束还不够因为名称归一化后需要真正拿到价格。这里我们引入价格知识库作为“事实来源”。检索增强生成RAG在传统方案里通常用于让模型根据文档回答问题。但在 BoqCalc 里我们不追求让模型“引用”文档生成答案而是直接让代码查询数据库拿到结构化价格记录。这样做有几个好处价格有来源可以追踪到某个价格文件、某期信息价或某份合同。价格可批量更新市场变化时只需要更新数据库。可以按地区、时间、材料类型做精确过滤。价格检索不是简单地等值匹配。对于有明确项目编码的条目直接用编码匹配对于没有编码或编码不完整的需要结合 item_name spec unit 做多条件匹配。如果匹配不到宁可标记为 missing_price也不能让系统自动生成一个随机数字。4.3 策略三后置规则校验即使前面做了分离计算环节仍可能出现浮点误差、单位不一致、金额异常等问题。因此 Pipeline 末尾必须加一层规则校验。常见校验规则包括金额是否等于“工程量 × 单价”的结果。单价是否为合理的正数且不超过某个合理范围。单位是否与价格库中的单位一致。是否存在大额异常值比如某条金额比其他同类型条目高出 100 倍。校验不通过的条目要设置为特殊状态比如“人工复核”而不是直接当作正常结果输出。4.4 策略四来源引用与置信度标记造价用户很关心“这个价格凭什么”。因此每条定价结果都要带上价格来源比如来源是信息价、市场询价、历史合同还是数据库默认值。同时我们可以根据匹配方式给每条结果标注置信度高置信度项目编码精确匹配且单位一致。中置信度名称规格匹配编码为空。低置信度仅名称模糊匹配或需要人工确认。低置信度的条目在输出时单独列出提醒造价人员复核。这样既保证了自动化效率也把“可能出错”的地方暴露出来而不是让错误悄悄混入最终报价。5. 完整代码实现5.1 定义数据模型先用 Pydantic 定义 BOQ 条目的数据结构。使用数据模型的好处是每个阶段的数据流转都有类型约束不容易出现字段错乱。# 文件路径boqcalc/models.py from typing import Optional from pydantic import BaseModel class BOQItem(BaseModel): line_no: int # 清单行号 item_code: Optional[str] None # 项目编码 item_name: str # 项目名称 spec: Optional[str] None # 项目特征/规格 unit: Optional[str] None # 计量单位 quantity: float 0.0 # 工程量 unit_price: Optional[float] None # 综合单价 amount: Optional[float] None # 合价 source: Optional[str] None # 价格来源 confidence: str unknown # 置信度 status: str pending # pending/priced/missing_price/needs_review5.2 BOQ 文件解析模块下面实现对 Excel 文件的解析。实际项目中BOQ 可能来自 Excel、CSV、PDF 甚至 OCR 识别结果但解析逻辑都是类似的把每一行表格记录转成字典。# 文件路径boqcalc/parser.py import pandas as pd def parse_boq_file(file_path: str) - list[dict]: 读取 BOQ Excel 文件返回条目字典列表。 注意表头列名需要根据实际文件调整。 df pd.read_excel(file_path) rows [] for idx, row in df.iterrows(): rows.append({ line_no: idx 1, item_code: str(row.get(项目编码, )).strip(), item_name: str(row.get(项目名称, )).strip(), spec: str(row.get(项目特征, )).strip(), unit: str(row.get(计量单位, )).strip(), quantity: float(row.get(工程量, 0) or 0), }) return rows这里大家要注意不同项目的 BOQ 模板表头可能差异很大。有的叫“项目特征”有的叫“项目描述”有的把规格写在单独一列。建议在实际工程中配置一个字段映射表而不是写死列名。5.3 价格知识库查询模块价格查询模块是整个防幻觉体系的核心所有价格数值都必须经过这里。# 文件路径boqcalc/price_db.py import sqlite3 from contextlib import closing class PriceLibrary: def __init__(self, db_path: str): self.db_path db_path def lookup(self, material_code: str, item_name: str, spec: str, unit: str, region: str, quote_date: str): 根据物料信息、地区、报价日期查询价格。 优先使用编码匹配其次使用名称规格匹配。 with closing(sqlite3.connect(self.db_path)) as conn: conn.row_factory sqlite3.Row # 1. 精确编码匹配 if material_code: row conn.execute( SELECT * FROM price_library WHERE material_code ? AND region ? AND effective_date ? ORDER BY effective_date DESC LIMIT 1 , (material_code, region, quote_date), ).fetchone() if row: return self._to_price_info(row, high) # 2. 名称 规格匹配 if item_name: row conn.execute( SELECT * FROM price_library WHERE item_name ? AND (? OR spec ?) AND unit ? AND region ? AND effective_date ? ORDER BY effective_date DESC LIMIT 1 , (item_name, spec or , spec or , unit, region, quote_date), ).fetchone() if row: confidence high if spec else medium return self._to_price_info(row, confidence) return None staticmethod def _to_price_info(row: sqlite3.Row, confidence: str) - dict: return { unit_price: row[base_price], source: row[source], effective_date: row[effective_date], confidence: confidence, }这里的查询策略值得展开说一下。先尝试用项目编码精确匹配因为编码是唯一的编码匹配不到时再降级到“名称规格单位”匹配。匹配置信度也会随之变化方便后续人工复核。5.4 名称归一化模块对于编码缺失、名称不规范、规格复杂的清单条目我们需要借助大模型做名称归一化。这个模块只负责从非结构化文本中提取结构化信息不负责定价。# 文件路径boqcalc/normalize.py import json import os from openai import OpenAI # 通过环境变量配置 Key 和 Base URL不要把密钥写进仓库 client OpenAI( api_keyos.getenv(OPENAI_API_KEY), base_urlos.getenv(OPENAI_BASE_URL), ) SYSTEM_PROMPT 你是工程量清单解析助手。 请从用户给出的 BOQ 条目中提取结构化信息只输出 JSON。 字段包括item_code, item_name, spec, unit, quantity。 规则 1. 不确定的字段设为 null不要猜测。 2. 严禁输出价格、单价、金额相关字段。 3. 数量只保留数字不要带单位。 4. 单位统一转换为 m、m2、m3、kg、t、个、套 等标准单位。 def normalize_with_llm(raw_item: dict) - dict: resp client.chat.completions.create( modelos.getenv(LLM_MODEL, gpt-4o-mini), messages[ {role: system, content: SYSTEM_PROMPT}, {role: user, content: json.dumps(raw_item, ensure_asciiFalse)}, ], temperature0, ) content resp.choices[0].message.content.strip() # 实际项目中可能要处理模型返回的 markdown 代码块包裹需要做清理 if content.startswith(): content content.strip() content content.removeprefix(json).strip() return json.loads(content)如果要在生产环境使用建议开启模型的 JSON 输出模式或者使用 response_format 约束而不是靠解析纯文本 JSON。模型版本不同支持的参数名也不同请以对应模型文档为准。5.5 Pipeline 主流程把上面的模块串起来就得到了 BoqCalc Pipeline 的主流程。# 文件路径boqcalc/pipeline.py from boqcalc.models import BOQItem from boqcalc.parser import parse_boq_file from boqcalc.normalize import normalize_with_llm from boqcalc.price_db import PriceLibrary class BoqCalcPipeline: def __init__(self, price_db: PriceLibrary, region: str, quote_date: str): self.price_db price_db self.region region self.quote_date quote_date def run(self, file_path: str) - list[BOQItem]: raw_items parse_boq_file(file_path) results [] for raw in raw_items: item BOQItem(**raw) # 第 1 步如果编码为空或编码查不到价格则用 LLM 归一化 normalized self._normalize(item) # 第 2 步查价格库 price_info self.price_db.lookup( material_codenormalized.get(item_code) or , item_namenormalized.get(item_name) or , specnormalized.get(spec) or , unitnormalized.get(unit) or , regionself.region, quote_dateself.quote_date, ) # 第 3 步处理检索结果 if price_info is None: item.status missing_price item.confidence low else: item.unit_price price_info[unit_price] item.amount round(item.quantity * price_info[unit_price], 2) item.source price_info[source] item.confidence price_info[confidence] item.status priced results.append(item) return results def _normalize(self, item: BOQItem) - dict: # 如果已经有编码且库中能查到就不需要调用 LLM if item.item_code: price_info self.price_db.lookup( material_codeitem.item_code, item_nameitem.item_name, specitem.spec or , unititem.unit or , regionself.region, quote_dateself.quote_date, ) if price_info: return { item_code: item.item_code, item_name: item.item_name, spec: item.spec, unit: item.unit, quantity: item.quantity, } # 编码缺失或编码查不到时用 LLM 提取结构化信息 try: result normalize_with_llm(item.model_dump()) return result except Exception: # LLM 调用失败时保留原始字段让价格库做模糊匹配 return { item_code: item.item_code, item_name: item.item_name, spec: item.spec, unit: item.unit, quantity: item.quantity, }这里有一个工程细节优先用规则和编码匹配只有在规则覆盖不到时才调用大模型。这样既能减少外部接口调用成本也能降低延迟。500 行 BOQ 如果全部走 LLM可能需要几分钟但如果大部分条目能靠编码命中速度会快很多。5.6 运行与输出示例下面看一下运行主流程的方式# 文件路径run_pipeline.py from boqcalc.pipeline import BoqCalcPipeline from boqcalc.price_db import PriceLibrary if __name__ __main__: price_db PriceLibrary(data/price_library.db) pipeline BoqCalcPipeline( price_dbprice_db, region杭州, quote_date2025-06-01, ) results pipeline.run(data/boq_demo.xlsx) for item in results: print(item)预期输出的核心字段如下行号项目名称单位工程量单价合价状态置信度1平整场地m²12005.206240.00pricedhigh2矩形柱 C30m³86.5486.0042039.00pricedhigh3屋面卷材防水m²98042.5041650.00pricedmedium4某某特殊材料t2NoneNonemissing_pricelow所有 priced 的条目都有 source 字段标明价格来自哪个信息价文件或哪期价格库。missing_price 条目被单独暴露出来不会自动生成一个“编造”的价格。6. 如何用数据验证“不幻觉”6.1 三个评估维度要证明一个 AI Pipeline“不幻觉”不能靠感觉要靠数据。建议从三个维度评估。第一个维度是准确率。也就是定价结果与人工审核结果一致的比例。建议拿历史项目中已经审定过的 BOQ 做回测跑完 Pipeline 后与审定单价对比。第二个维度是幻觉率。我们把“没有价格依据但系统仍输出了价格”的条目定义为幻觉条目。BoqCalc 的设计目标是让幻觉率归零。也就是说查不到价格时就标记 missing_price绝不硬编一个数字。第三个维度是可追溯率。也就是“有明确价格来源”的条目占总定价条目的比例。对造价审计来说可追溯率比准确率更重要。即使某个价格和实际有偏差只要来源清晰就能人工检查并修正。6.2 500 行 BOQ 的测试方法以 500 行 BOQ 的测试集为例可以这样设计测试流程准备一份包含约 500 条清单的测试文件其中约有 50 条故意设置为复杂描述或缺少编码。运行 BoqCalc Pipeline。统计 priced、missing_price、needs_review 三个状态的条目数量。抽取 priced 中置信度低的条目和全部 missing_price 条目交给造价人员复核。将测试文件跑 3 次检查同一输入是否得到稳定输出重点看 LLM 解析部分是否出现随机抖动。这里还要关注一个性能问题。500 行 BOQ 串行调用 LLM 可能较慢建议在 Pipeline 中加入缓存和批量处理机制。对相同或相似的清单描述直接命中缓存减少重复调用。6.3 预期结果与人工复核一个合格的运行结果应该是这样的500 条中约 450 条直接命中价格库标记为 high 置信度。20 条需要 LLM 归一化后才能匹配标记为 medium 置信度。20 条被标记为 missing_price等待人工补充价格依据。10 条被标记为 needs_review可能存在单位问题或规格歧义。整个过程中不应该出现一条“没有来源但系统自动给出一个数字”的记录。如果有那说明 Pipeline 的某个环节违反了设计原则需要立即修复。7. 常见问题与排查思路7.1 高频问题对照表问题现象常见原因解决思路部分条目标记为 missing_price但实际存在价格价格库缺少别名或规格不统一扩充价格库别名映射增加规格字段清洗LLM 解析返回的不是合法 JSON模型输出格式不稳定启用 JSON 输出约束增加异常后的重试逻辑单价匹配错误比如把“C30 矩形柱”匹配成“C25 矩形柱”仅按名称匹配忽略规格匹配时加入规格维度模糊匹配后增加候选排序金额与“数量×单价”不一致浮点精度问题或四舍五入时机不一致统一用 Decimal 或统一 round 规则Pipeline 创建时报依赖错误依赖版本冲突例如 pydantic 版本与 openai 库不兼容用 requirements 或 poetry 锁定版本在虚拟环境中重建500 行跑得很慢每条都调用了大模型规则优先命中、增加缓存、使用批量请求同一输入两次运行结果不一致大模型温度未设置或随机性导致设置 temperature0必要时固定随机种子7.2 一次典型幻觉问题的排查过程假设你在测试时发现有一条“C30 矩形柱”的单价变成了 980 元而价格库里 C30 矩形柱的价格明明是 486 元。排查过程可以按下面几步走。第一步看 pipeline 日志确认这条记录是否走了 LLM 归一化。如果走了说明原始 BOQ 里可能没有项目编码或者编码没有命中。第二步查看 LLM 归一化后的 JSON确认 item_name 和 spec 是否被正确解析。这里可能出现了“矩形柱混凝土”和“矩形柱模板”的混淆spec 字段没有提取出来。第三步查看价格库查询条件确认查询传入了错误的 spec。如果 spec 为空查询就退化成“仅按名称匹配”此时很容易命中同名称但不同规格的第一条记录。第四步修复方案是在 _normalize 阶段加强规格提取并让价格库查询在命中多条记录时按“规格相似度”排序而不是直接取第一条。这种排查思路的核心是把问题定位到具体阶段而不是笼统地归因于“AI 不靠谱”。只要每个阶段都有日志和中间结果排错效率会非常高。8. 工程落地最佳实践8.1 价格知识库治理BoqCalc 的准确性下限由价格知识库决定。知识库质量越高Pipeline 的表现越好。建议做好以下几点每条价格记录都必须有 source 字段注明价格来源。价格要按地区、有效期管理过期价格自动失效。物料名称和规格要建立统一的规范化标准避免“C30混凝土”和“C30 砼”同时存在。定期更新价格库并保留历史版本方便追溯报价时用了哪一期价格。8.2 模型与部署建议如果项目对数据安全要求较高可以采用本地部署的 AI 模型例如通过 vLLM 或 Ollama 部署开源模型。BOQ 数据属于项目敏感数据要谨慎发送到外部 API。本地部署时名称归一化任务难度不高选用 7B 到 14B 级别的开源模型通常足够。真正的大头是价格知识库和规则引擎而不是模型参数规模。8.3 安全与审计工程落地必须考虑安全和审计。至少要做到API Key 放在环境变量或密钥管理系统中不要提交到 Git 仓库。Pipeline 的每次运行记录日志包括输入文件、模型版本、知识库版本、输出结果。涉及生产数据的操作要经过授权并在测试环境验证后再执行。对自动生成的结果保留人工复核机制尤其是金额异常或低置信度的条目。这些要求不是可有可无的而是造价行业审计流程的基本要求。没有审计痕迹的自动报价很难真正投入使用。8.4 性能优化500 行 BOQ 对计算来说压力不大真正的性能瓶颈在 LLM 调用。优化思路有三个方向。第一是减少调用。能通过规则、编码、别名表匹配的条目不要调用大模型。第二是批量处理。把多条待归一化的清单条目打包成一次请求让模型输出一个 JSON 数组减少网络往返。不过要注意控制单次请求的 token 量避免超过模型上下文限制。第三是缓存。相同或相似的清单描述直接把第一次归一化结果缓存下来。在大型项目里同一批 BOQ 中很多条目描述是重复的缓存收益非常明显。9. 总结与下一步学习路线BoqCalc 这个项目最有价值的点不在于它用了多强大的模型而在于它用工程手段重新分配了任务边界大模型负责理解文本数据库负责记住事实代码负责计算和校验。这才是 AI 工程实践中真正值得反复体会的设计思路。如果要把这个方案继续深入下去可以从三个方向延伸。第一个方向是 Agent 化。把价格库查询、异常复核、人工反馈闭环做成一个 Agent 工作流让系统在遇到 missing_price 时自动发送给造价人员收到反馈后自动更新知识库。第二个方向是评估集建设。积累一批带标准答案的 BOQ 测试集每次模型升级或价格库更新后都跑一遍回归测试用数字衡量系统是否“退化”。第三个方向是模型中台化。把名称归一化能力封装成内部服务供投标、估算、结算等多个业务线复用。最后建议你动手跑一遍本文代码拿一份自己的 BOQ 模板和价格表试一试。重点看两条逻辑一条是“查不到价格时不硬编数字”另一条是“每条价格都有来源”。这两条做到了这个 Pipeline 就真正拥有了在业务中落地的底气。
返回列表