1. 项目概述:从通用Agent到招标文件合规引擎的工程化实践
在AI技术快速发展的今天,智能体(Agent)技术已经从实验室走向实际业务场景。然而,当我们真正将通用Agent技术应用于严肃的业务领域——如招标文件合规审查时,会发现一个关键问题:一个能回答问题的模型,并不等同于一个能承担合规责任的系统。
招标合规审查不是简单的问答游戏,而是涉及实质性排他条款识别、废标风险评估、资格条件审查等专业判断的工作。这些判断背后往往关联着法律风险和经济责任。传统基于Prompt的智能体方案在实际工程落地时面临三大核心挑战:
- 执行边界模糊:模型可以生成文本,但不应该无限制地访问文件系统或执行命令
- 规则管理困难:业务规则如果只写在Prompt中,难以进行版本控制和审计追踪
- 流程不可复现:每次审查结果受温度参数、上下文等因素影响,缺乏确定性
本文将以openJiuwen平台为基础,详细解析如何构建一个真正可落地的招标文件合规审查引擎。这套方案的核心创新在于:
- 通过Skills机制将业务能力模块化、工程化
- 通过SysOperation实现受控的系统级操作
- 构建完整的规则引擎和报告生成链路
2. 技术选型:为什么选择openJiuwen作为基座
2.1 传统方案的局限性
在招标合规审查场景中,简单的"LLM+Prompt"组合暴露出明显不足:
| 问题类型 | 具体表现 | 业务影响 |
|---|---|---|
| 执行边界问题 | 模型可能越权访问文件系统或执行命令 | 安全风险高,不符合企业IT规范 |
| 规则管理问题 | 规则修改需要重发Prompt,无法版本化管理 | 难以审计,合规性存疑 |
| 流程复现问题 | 结果受随机性影响,相同输入可能产生不同输出 | 无法作为正式审查依据 |
2.2 openJiuwen的核心优势
openJiuwen是一个开源的Agent平台,专门为解决上述问题而设计。其核心架构包含两个关键组件:
Skills机制:
- 将业务能力封装为可管理的Markdown文件
- 支持能力版本控制和团队共享
- 示例:一个PDF解析Skill包含使用场景、输入输出定义和示例
SysOperation:
- 提供受控的文件系统、代码执行和命令行操作能力
- 所有操作都有日志留痕
- 支持本地和沙箱两种执行模式
这种设计使得openJiuwen特别适合需要高可靠性的业务场景,如招标合规审查。
3. 系统设计与实现
3.1 整体架构设计
招标合规审查系统的核心工作流可以分为四个阶段:
- 文件接入与结构化:解析PDF文件,提取文本和结构信息
- 规则匹配与审查:应用业务规则进行合规检查
- 问题分类与评级:根据严重程度对发现问题进行分类
- 报告生成与归档:生成结构化审查报告
3.2 Skills模块划分
我们将合规审查能力拆分为七个核心Skills模块:
| 模块名称 | 主要功能 | 输出格式 |
|---|---|---|
| 文件接入 | 校验输入文件完整性,生成项目清单 | JSON |
| 文件解析 | 提取PDF文本和结构信息 | JSON |
| 强规则审查 | 检查废标/否决条款 | JSON |
| 资格条件审查 | 检查不合理资格限制 | JSON |
| 技术参数审查 | 检查技术规格公平性 | JSON |
| 合同条款审查 | 检查合同风险条款 | JSON |
| 报告生成 | 汇总问题生成最终报告 | Markdown |
3.3 关键技术实现
3.3.1 文件解析实现
文件解析是后续所有工作的基础。我们采用pdfplumber作为主要解析库,配合Tesseract OCR作为扫描件兜底方案:
def parse_pdf(file_path: str, enable_ocr: bool = False) -> dict: """ 解析PDF文件,返回结构化数据 :param file_path: PDF文件路径 :param enable_ocr: 是否启用OCR :return: 包含页面文本和章节结构的字典 """ result = {"pages": [], "sections": []} with pdfplumber.open(file_path) as pdf: for i, page in enumerate(pdf.pages): page_data = {"page_no": i+1} # 优先尝试文本提取 text = page.extract_text() if not text and enable_ocr: # OCR兜底 img = page.to_image() text = pytesseract.image_to_string(img) page_data["text_source"] = "ocr" else: page_data["text_source"] = "pdf_text" page_data["text"] = text result["pages"].append(page_data) # 章节检测逻辑... return result3.3.2 规则引擎设计
规则引擎采用YAML定义规则,支持三种匹配方式:
- 关键词匹配:简单但有效,适合明确的关键条款
- 正则表达式:灵活性高,可以处理复杂模式
- 结构化字段匹配:精准定位特定章节
示例规则定义:
rules: - rule_key: BRAND_SPECIFIED_ONLY severity: HIGH category: 技术条款 match_type: regex pattern: "(指定品牌|必须为.*品牌|仅限.*品牌|推荐品牌为)" explanation: "技术要求出现品牌指向性表述" suggestion: "改为性能指标或提供'或同等'机制"3.3.3 受控执行实现
通过SysOperation实现安全的文件操作:
@sys_op.fs() def read_file(file_path: str) -> str: """ 受控的文件读取操作 :param file_path: 文件路径 :return: 文件内容 """ with open(file_path, 'r', encoding='utf-8') as f: return f.read() @sys_op.code() def run_rules_engine(tender_data: dict, rules: list) -> list: """ 受控的规则引擎执行 :param tender_data: 招标文件数据 :param rules: 规则列表 :return: 问题列表 """ # 规则匹配逻辑... return issues4. 工程实践与经验分享
4.1 环境配置建议
| 组件 | 推荐版本 | 备注 |
|---|---|---|
| Python | 3.11.4+ | 需要兼容openJiuwen |
| openJiuwen | 0.1.7+ | 核心框架 |
| pdfplumber | 0.x | PDF解析 |
| pytesseract | 0.3.x | OCR支持 |
安装命令:
pip install openjiuwen==0.1.7 pdfplumber==0.* pytesseract==0.3.*4.2 性能优化技巧
- 并行处理:对大型招标文件,可将不同章节分配给不同Worker并行处理
- 缓存机制:对已解析的文件保存中间结果,避免重复解析
- 增量处理:当文件有更新时,只处理变更部分
4.3 常见问题排查
问题1:PDF解析结果为空
- 检查文件是否是扫描件,考虑启用OCR
- 验证pdfplumber是否能正常打开文件
问题2:规则匹配过多误报
- 调整匹配模式,优先使用结构化字段匹配
- 增加规则上下文约束条件
问题3:执行权限问题
- 检查SysOperation白名单配置
- 验证工作目录权限设置
5. 实际应用效果
在实际招标项目中,该系统展现出三大核心价值:
- 效率提升:将人工审查时间从4-6小时缩短至30分钟内
- 风险控制:系统性识别出98%以上的合规风险点
- 过程可审计:完整的执行日志和中间结果留存
典型审查报告片段:
## 高风险问题(3) 1. [BRAND_SPECIFIED_ONLY] 技术参数中指定品牌"XX设备" - 位置:第三章 技术规范 第15页 - 建议:改为性能指标描述或增加"或同等"条�� 2. [LOCAL_VENDOR_RESTRICTION] 要求投标人必须为本地注册企业 - 位置:第二章 投标人资格 第5页 - 建议:删除地域限制或改为服务响应时间要求6. 未来演进方向
- 规则自学习:基于历史审查结果优化规则库
- 多文档关联分析:结合招标文件、投标文件、合同等建立完整视图
- 行业知识图谱:构建招标采购领域的专业知识图谱
在实际部署过程中,我们发现最大的挑战不是技术实现,而是如何平衡规则的严格性和灵活性。过于严格的规则会产生大量误报,而过于宽松又会漏掉重要风险点。我们的经验是采用"分级审查"策略:先快速扫描识别高风险点,再对中低风险点进行人工复核。