pipeline-bidding/README.md

183 lines
13 KiB
Markdown
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 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→ 章节评审(含篇幅门禁)→ 合成
> → 整书评分 → 交付确认。
**多流程模板2026-09-15 批2**:本产线声明两条流程(`BID_FLOW_TEMPLATES`,引擎
FlowTemplate 机制首个接入)——`bid_standard`(上述标准链)与 `bid_tech_proposal`
**纯技术方案流程**:输入=技术需求书而非招标文件,产出=技术方案书):
> 技术需求书 → 六类技术评估项解析(功能清单/功能点/硬件配置/技术架构/功能架构/部署架构,
> 落 `bid_tech_items`)→ QC 对标需求书qc_type=tech_items→ 模版三级检索知识库→RAG→网络
> + 骨架拟定(六类覆盖度硬校验,漏类拒绝)+ **用户确认待办**tech_template_confirm全局阻塞
> agent 无确认权)→ 分章编写 → 章节评审(对标需求书覆盖度)→ 合成 → 交付确认。
首文件导入后对账器 LLM 自动判流(`detect_flow_template`,置信度+判据摘录进确认待办);
判流失败发人工待办不默认硬跑。已确认计划 `base_flow_key=bid_tech_proposal` 的项目走
`bid_flow._reconcile_tech_proposal` 独立对账分支,不碰评分项/资质/成本收益。
规范见技能 `bid-tech-proposal`;确认端点 `api/tech_template_confirm.dspy`
核心机制:
- **角色任务流转不用 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_round` `qc_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_gate`ImportError 逃逸阀
豁免钥匙=文中如实标注「配图缺失:平台无可用文生图模型」(仅 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_tech_items` | 技术评估项纯技术方案流程 tech_analysis 产出kind=item/summarycategory 六类m0034 建表 | project_id, kind, category, item_name, requirement, mandatory, source_ref |
| `bid_kb_docs` | 公司投标知识库 | org_id, doc_type(sample_bid ), doc_name, doc_no, tags, file_path, content_text |
| `bid_material_gaps` | 投标材料缺口清单占位符规范正文 `【材料待补:…】` 自动登记合成后出清单人工/产线补齐m0035 建表 | project_id, chapter_no, material_name, placeholder_text, fingerprint, status(pending/filled/waived) |
| `bid_members` | 投标项目参与人员 | project_id, user_id, user_name, member_role, duty, status |
种子数据`init/data.json`build.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` 统一渲染规范)。
- **api/tech_template_confirm.dspy** 技术方案骨架用户确认/驳回端点2026-09-15)。
入参 human_task_id/decision(confirm|reject)/comment驳回必填)。用户专属同机构+
超管/创建者校验复用引擎 `_check_confirm_operator`agent 无对应工具无法代确认
确认后骨架落 bid_chapters(section=technical) 开写驳回意见由对账器注入重派模版任务
- **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两步缺一不可
```python
from pipeline_bidding.init import load_pipeline_bidding
load_pipeline_bidding() # import 后必须再显式调用,漏了无任何日志(静默大坑)
```
`load_pipeline_bidding()`幂等做三件事
1. `role_tool_schemas.register_role_tools()` 把约 60 个投标角色工具 schema
read_tender_file / extract_* / add_* / list_cost_benefit / update_cost_benefit_item /
delete_cost_benefit_item / patch_chapters / write_chapter支持 mode=append 分批追加超长章节/
review_chapter支持 material_missing=1 实体材料缺失如实披露放行/ start_qc / finish_qc /
compose_bid / start_bid_score /
finalize_bid_score / dispatch_analysis_dim 注册进引擎
`pipeline_service.capability_tools.TOOL_SCHEMAS`引擎 `exec_capability_tool`
`module` 支持全路径裸名仍走 `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_map`
`TOOL_SCHEMAS` **两者交集才是可见工具**技能声明了但 schema 没注册 = 工具静默缺失)。
独立脚本验证必须先显式调 `load_pipeline_bidding()` import 包不触发注册
码表导入自持`scripts/import_init_bidding.py`幂等 + 废弃清理 + 产线描述
不依赖宿主 `import_init.py` INIT_MODULES
## 宿主集成(部署)
在宿主应用pipeline-app根目录或本目录执行一键脚本
```bash
./build.sh
```
build.sh 职责运行期禁止 schema 变更建表只在部署期
1. **建表** `mysql.ddl.sql`json2ddl 产物 `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)。