pipeline-bidding — 投标产线模块

模块定位

产线平台pipeline-app / pipeline-core的第二条产线能力包投标产线 bidding_general。 验证并落地「产线能力包住自己仓库、宿主不装则零接触」的分层原则——能力模块全部住在本仓库, 不进 pipeline-service;宿主只要不 import pipeline_bidding,一切都不会发生。

模块 = 数据(bid_* 表 + CRUD+ 能力(bid_*_capability+ 流转(bid_flow 状态对账器)

  • 主 agent 能力包(bid_ability+ 角色技能(部署期随 pipeline-core skills_library 分发)。

产线起点 = 上传招标文件import_tender_file 无 project_id 时自动立项)。阶段链:

收到招标文件(自动立项)→ 解析(评分项/资质/投标文件要求/商务要素/章节骨架) → QC 契合度审核四类逐类10 分制,>9.5 放行)→ 资料准备 → 分角色并发编写 business→bid_biz_writer / technical→bid_writer→ 章节评审(含篇幅门禁)→ 合成 → 整书评分 → 交付确认。

核心机制:

  • 角色任务流转不用 RoleSpec.next_role(全留空):投标是「一章一任务 + 两级回退循环」 扇出结构,由 bid_flow 状态对账器(每 15s 一轮)补派,对账器是角色任务的唯一创建者
  • 阻塞门禁在创建源头(对账器判 pipeline_human_tasks.project_id + pending 不写进引擎 poller SQL。tenant_id=project_id 只是角色任务约定,禁止写进引擎层。
  • 两级回退循环:章节级(得分率 < bid_chapter_pass_ratio 或篇幅不达标 → rejected+意见 → 自动重写,超 bid_max_revise 抛人工);整书级(< bid_pass_ratio 或否决项未响应 → 按 target_chapter_id 打回 → 重写→重审→重合成→重评分,超 bid_max_round 抛人工)。
  • QC 门禁:四类解析产出逐类审核落 bid_qc_reviews;不通过 → 清空该类产出 → 对账器重派 解析(params.qc_redo=1 + 改进意见)→ 重审;轮次超 bid_qc_max_roundqc_escalation 阻塞人工(逃逸阀:人工修产出后在记录页把 passed 改 1 即生效)。
  • 门限参数全部读 appbase params 表 + DEFAULT_PARAMS 兜底,不硬编码: bid_chapter_pass_ratio(0.8) / bid_pass_ratio(0.85) / bid_max_revise(3) / bid_max_round(3) / bid_qc_pass_score(9.5) / bid_qc_max_round(3) / bid_chapter_min_words(800) / bid_chapter_min_words_biz(500) / bid_write_concurrency(4)。
  • 章节配图形态硬门禁2026-09-15 用户要求):技术方案/标书中的图必须 invoke_model 调 t2i/i2i 生成真实图片(![图N 标题](URL) 嵌入,合成 docx 自动嵌真图),禁 mermaid/plantuml/ ASCII 字符画。write_chapter 机制层确定性检测拒写伪图,review_chapter 评审兜底同款检测必退 (存量正文/绕行写入);检测器复用 pipeline_service.diagram_gateImportError 逃逸阀); 豁免钥匙=文中如实标注「配图缺失:平台无可用文生图模型」(仅 t2i/i2i 全无时)。

表清单models/*.json建表产物 mysql.ddl.sql

表名 说明 关键字段
bid_tenders 招标商务要素 project_id, source, title, purchaser, tender_no, industry
bid_tender_files 招标文件 project_id, tender_id, file_name, file_path, file_type, content_text
bid_scoring_items 评分项与得分规则 project_id, section, item_no, item_name, max_score, scoring_rule, is_veto
bid_qualifications 招标所需资质 project_id, qual_name, requirement, is_mandatory, owner, kb_doc_id, match_status
bid_doc_requirements 投标文件要求 project_id, req_type, chapter_no, chapter_title, requirement, page_limit, source_ref
bid_chapters 投标文件章节 project_id, chapter_no, parent_no, title, section, outline, status, content, word_count, review_score
bid_reviews 标书评审记录 project_id, scope, chapter_id, document_id, round, reviewer, review_type
bid_scores 标书评分明细 project_id, review_id, scoring_item_id, item_name, score, max_score, reason
bid_documents 合成标书 project_id, version, doc_name, file_path, page_count, chapter_count, total_score
bid_qc_reviews 解析产出 QC 审核记录 project_id, qc_type, round, reviewer, review_type, fit_score, pass_score
bid_analysis_history QC 分析历史快照(每轮 QC 逐审核记录归档2026-09-10 归籍补 models 定义,此前是孤儿表) project_id, qc_type, round, task_id, fit_score, improvement, payload
bid_cost_benefit 成本收益分析分析维度4单项+summary 结论行m0006 建表未进 models2026-09-10 归籍) project_id, kind, category, item_name, amount, confidence
bid_kb_docs 公司投标知识库 org_id, doc_type(sample_bid 等), doc_name, doc_no, tags, file_path, content_text
bid_members 投标项目参与人员 project_id, user_id, user_name, member_role, duty, status

种子数据(init/data.jsonbuild.sh 幂等写入):pipelines 产线主记录 bidding_general + appcodes 12 组码表bid_qc_type / bid_tender_source / bid_member_role / bid_file_type / bid_scoring_section / bid_qual_match_status / bid_qual_owner / bid_req_type / bid_chapter_status / bid_review_scope / bid_kb_doc_type / bid_doc_status

对外 API / dspy 端点wwwroot/

部署后挂载在宿主 wwwroot/pipeline-bidding/(软链):

  • api/bid_probe.dspy — 服务内探针(诊断)。?action=status 返回模块装载状态 + poller 心跳 + 活跃投标项目数;?action=reconcile 在服务进程内跑一轮全量对账返回动作明细。
  • api/bid_task_tree.dspy — 任务树懒加载(根 → role:阶段 → 任务 → step:/del: 叶子)。 项目解析三级兜底session_settings(default_bidding_general) → agent_settings → 最近 in_progress 项目。
  • api/bid_task_io.dspy — 任务树右侧详情面板:输入 = 任务描述 + QC 改进意见, 执行步骤,输出 = 交付件(复用 pipeline_service/task_io_render.py 统一渲染规范)。
  • bid_task_tree_popup.ui — ResourceBrowser 复合 widget 弹窗(左树右详情联动)。
  • agent/index.ui — 驾驶舱入口页(顶栏含任务树按钮)。
  • 12 个 CRUD 目录bid_tenders / bid_tender_files / bid_scoring_items / bid_qualifications / bid_doc_requirements / bid_chapters / bid_reviews / bid_scores / bid_documents / bid_qc_reviews / bid_kb_docs / bid_members— 每个含 index.ui + get/add/update/delete_*.dspy 标准五件套。

⚠️ RBAC 铁律:/api/ 前缀不覆盖具体 dspy新 API 必须逐条显式注册scripts/load_path.py 否则 403注册后 redis db0 FLUSHDB 即生效。

load 注册函数

宿主入口pipeline_app.py两步缺一不可

from pipeline_bidding.init import load_pipeline_bidding
load_pipeline_bidding()   # import 后必须再显式调用,漏了无任何日志(静默大坑)

load_pipeline_bidding()(幂等)做三件事:

  1. role_tool_schemas.register_role_tools() — 把约 55 个投标角色工具 schema read_tender_file / extract_* / add_* / patch_chapters / write_chapter / review_chapter / start_qc / finish_qc / compose_bid / start_bid_score / finalize_bid_score / dispatch_analysis_dim 等)注册进引擎 pipeline_service.capability_tools.TOOL_SCHEMAS(引擎 exec_capability_toolmodule 支持全路径,裸名仍走 pipeline_service.*SDLC 零变化)。
  2. import bid_ability — 主 agent 能力包 + slash 命令注册import 即注册)。
  3. bid_flow.start_poller() — 状态对账器启动(PIPELINE_MODE=web 时不注册, 与引擎 poller 同款模式开关)。

角色工具装配链:角色技能 frontmatter capability+tools_capability_to_tools_mapTOOL_SCHEMAS两者交集才是可见工具(技能声明了但 schema 没注册 = 工具静默缺失)。 独立脚本验证必须先显式调 load_pipeline_bidding(),仅 import 包不触发注册。

码表导入自持:scripts/import_init_bidding.py(幂等 + 废弃清理 + 产线描述), 不依赖宿主 import_init.py 的 INIT_MODULES。

宿主集成(部署)

在宿主应用pipeline-app根目录或本目录执行一键脚本

./build.sh

build.sh 职责(运行期禁止 schema 变更,建表只在部署期):

  1. 建表:读 mysql.ddl.sqljson2ddl 产物),把 drop table if exists 剔除、 CREATE TABLE 改为 CREATE TABLE IF NOT EXISTS 幂等化,用宿主 config 的 pipeline 库连接执行。
  2. 种子数据init/data.json 幂等写入 pipelines 产线记录 + appcodes/appcodes_kv 码表。
  3. wwwroot 软链ln -sf 本仓库/wwwroot → $APP_ROOT/wwwroot/pipeline-bidding
  4. pip install$APP_ROOT/py3/bin/pip install 本目录(非 editable 安装)。

宿主负责的后续app 入口 import + 调用 load_pipeline_bidding() RBAC 用 scripts/load_path.py(其中 set_role_perm.py 必须用宿主根绝对路径 i18n 合并用 merge_i18n.py。

部署注意(实测踩坑)

  1. 非 editable 安装:测试机只 git pull 仓库不会更新 site-packages改码后必须 ./py3/bin/pip install pkgs/pipeline-bidding 再重启(可对比 site-packages 与仓库文件 md5 确认加载版本)。
  2. 运行时技能树独立仓库:在 /d/pipeline/pipeline-app/skills/git: yumoqing/pipeline-sdlc.git不是 pipeline_core 的 skills_library改了 bid-workflow 等技能必须同步 SKILL.md 到 pipelines/bidding_general/common/<技能名>/ 再重启。
  3. 宿主入口漏调用 load_pipeline_bidding() 是静默大坑:无任何日志。诊断走 api/bid_probe.dspy?action=status 心跳探针。
  4. RBAC 缓存:新路径注册后 redis db0 FLUSHDB 即生效(旧说须重启已过时); 精确 path 匹配,父路径不覆盖子路径。
  5. 角色任务 failed 必须是对账器阻塞态:否则每 15s 重复造任务(机构未配 LLM 时必现); 测试环境无 LLM 模型时任务 failed 属预期。
  6. 自动立项的项目不继承模型:不带 default_model解析链兜底全局默认名可能不存在 → 401 建后必查/补 sd_projects.default_model
  7. bid_chapters 键归一resolve_project_id 先按 id 校验、按 name 反查归一, 名字歧义拒绝(防「项目名当 project_id」写库产生孤儿骨架
  8. 对账器结构铁律:维度过滤(等上游 QC 的不算掉链)必须在 _open_orch_tasks 判定前 无条件执行,编排任务创建/掉链计数留在「无编排任务在办」的 else 分支内, 否则每 15s 重复建编排任务堆积。
  9. 共享工具 create_task 有产线角色校验守卫get_role_spec 查不到即拒绝), list_roles 查看本产线可用角色。

详细设计见 docs/DESIGN.md;技能库见 pipeline-core skills_library/pipelines/bidding_general/common 7 技能 + roles 9 角色含 bid_biz_writer

Description
No description provided
Readme 25 KiB