一、问题的技术本质

间接采购供应商管理有一个工程层面的结构矛盾:风险是实时变化的,但监控是周期性的

间接采购_准入与监控逻辑

行业调研数据显示,超过60%的供应商风险事件发生在合作存续期而非准入阶段。传统模式下,采购团队在准入时做一次全面审查,之后靠人工定期回查——这个周期通常是半年甚至一年。结果:供应商的工商变更、司法风险、经营异常等信号,平均滞后3-6个月。

从系统设计的角度看,这不是人力执行问题,是架构问题:监控层的触发机制是拉取式(Pull)的,而非推送式(Push)的。

本文目标:将供应商动态监控设计为一个可工程化落地的系统,覆盖准入、监控、评价、处置四个环节,给出各环节的数据结构、接口映射和代码实现。

关键词 对应环节 核心技术点
客商准入风控 供应商入库前审查 四层穿透模型 + 多接口并发查询
供应商风险预警 合作期间持续监控 Pull → Push 范式转换 + 风险分级矩阵
供应商评价体系 定期/触发式重评 QCDS + 外部风险健康度五维模型
客商管理 全生命周期闭环 数据中台 + 控制塔架构

二、客商准入风控:四层穿透模型的技术实现

间接采购_准入四层模型

2.1 模型概述

多数企业的供应商准入在技术层面只做了工商状态核验和简单司法扫描。但实际上,一个可落地的准入风控系统至少需要四层穿透:

层级 名称 核心数据维度 行业覆盖率(估算) 对应 MCP Server
L1 主体资格核验 工商状态、法人身份、经营范围、注册资本 ~95% qcc-company
L2 司法与合规扫描 裁判文书、被执行、失信、行政处罚、经营异常 ~70% qcc-risk
L3 关联关系穿透 实控人、对外投资、任职网络、股东关联 ~30% qcc-company + qcc-executive
L4 经营稳健度评估 社保人数、实缴比例、年报一致性、空壳识别 ~20% qcc-operation + qcc-company

L1和L2是防线,L3和L4才是护城河。 多数企业的系统停留在L1-L2,缺失L3-L4带来的关联风险和空壳风险是当前间接采购准入的最大盲区。

2.2 L1+L2:主体资格与司法合规的并发查询

传统做法是串行查询——先查工商,再查司法,再查经营异常。在供应商数量较多时,延迟很高。工程上应该用并发请求:

import asyncio
import httpx

QCC_COMPANY = "https://agent.qcc.com/mcp/company/stream"
QCC_RISK = "https://agent.qcc.com/mcp/risk/stream"
HEADERS = {"Authorization": "Bearer YOUR_API_KEY"}

async def query_tool(base_url: str, tool: str, search_key: str) -> dict:
    """通用 MCP 工具调用"""
    async with httpx.AsyncClient(timeout=30) as client:
        resp = await client.post(
            base_url,
            json={"tool": tool, "arguments": {"searchKey": search_key}},
            headers=HEADERS
        )
        return resp.json()

async def supplier_basic_check(company_name: str) -> dict:
    """L1+L2 并发准入审查"""
    # L1: 主体资格
    l1_tasks = {
        "工商状态": query_tool(QCC_COMPANY, "get_company_base_info", company_name),
        "股东信息": query_tool(QCC_COMPANY, "get_shareholder_info", company_name),
        "受益所有人": query_tool(QCC_COMPANY, "get_beneficiary_owner", company_name),
    }
    # L2: 司法合规
    l2_tasks = {
        "失信被执行": query_tool(QCC_RISK, "get_dishonest_info", company_name),
        "被执行人": query_tool(QCC_RISK, "get_judgment_debtor_info", company_name),
        "裁判文书": query_tool(QCC_RISK, "get_judicial_documents", company_name),
        "行政处罚": query_tool(QCC_RISK, "get_administrative_penalty", company_name),
        "经营异常": query_tool(QCC_RISK, "get_business_exception", company_name),
        "破产重整": query_tool(QCC_RISK, "get_bankruptcy_reorganization", company_name),
    }

    all_tasks = {**l1_tasks, **l2_tasks}
    results = dict(zip(all_tasks.keys(), await asyncio.gather(*all_tasks.values())))

    # 简单准入判定
    passed = True
    risk_flags = []

    if results.get("失信被执行", {}).get("data"):
        passed = False
        risk_flags.append("存在失信被执行记录")
    if results.get("经营异常", {}).get("data"):
        passed = False
        risk_flags.append("存在经营异常记录")

    return {
        "company": company_name,
        "passed": passed,
        "risk_flags": risk_flags,
        "detail": results
    }

2.3 L3:关联关系穿透——从企业到实控人的链路追溯

L3是当前行业落地的薄弱环节。技术上需要两步:

Step 1:从企业查实控人和主要人员
Step 2:从实控人/法人回溯其全部关联企业,交叉比对风险库

async def relation_penetration(company_name: str, blacklist: list[str]) -> dict:
    """
    L3 关联关系穿透
    blacklist: 已被拉黑的统一社会信用代码或企业名称列表
    """
    # Step 1: 获取实控人 + 法人代表信息
    controller = await query_tool(QCC_COMPANY, "get_actual_controller", company_name)
    legal_rep = await query_tool(QCC_COMPANY, "get_legal_representative", company_name)

    # 提取实控人和法人姓名
    persons = []
    if controller.get("data"):
        persons.append(controller["data"].get("name", ""))
    if legal_rep.get("data"):
        persons.append(legal_rep["data"].get("name", ""))

    # Step 2: 查询每个关键人的全部关联企业(qcc-executive 需双参数)
    related_companies = set()
    QCC_EXECUTIVE = "https://agent.qcc.com/mcp/executive/stream"

    for person in persons:
        if not person:
            continue
        all_related = await query_tool(
            QCC_EXECUTIVE, "get_all_related_enterprises",
            search_key=f"{company_name}|{person}"
        )
        if all_related.get("data"):
            for ent in all_related["data"].get("list", []):
                related_companies.add(ent.get("name", ""))

    # Step 3: 交叉比对黑名单
    hits = [c for c in related_companies if c in blacklist]

    return {
        "company": company_name,
        "key_persons": persons,
        "total_related": len(related_companies),
        "blacklist_hits": len(hits),
        "hit_companies": hits,
        "risk_level": "HIGH" if hits else "LOW"
    }

预期返回示例

{
  "company": "某供应链管理有限公司",
  "key_persons": ["张某", "李某"],
  "total_related": 17,
  "blacklist_hits": 2,
  "hit_companies": [
    "某已被列入黑名单的贸易公司",
    "某已注销的关联企业"
  ],
  "risk_level": "HIGH"
}

2.4 L4:经营稳健度评估——空壳企业识别

L4用一组结构化指标判断供应商是否为"存在但不运营"的空壳:

async def shell_company_detection(company_name: str) -> dict:
    """
    L4 空壳企业识别
    核心判定维度:社保 / 实缴 / 年报一致性 / 地址重合度
    """
    tasks = {
        "年报信息": query_tool(QCC_COMPANY, "get_annual_report", company_name),
        "社保信息": query_tool(QCC_OPERATION, "get_social_security_info", company_name),
        "变更记录": query_tool(QCC_COMPANY, "get_change_records", company_name),
        "联络信息": query_tool(QCC_COMPANY, "get_contact_info", company_name),
    }

    results = dict(zip(tasks.keys(), await asyncio.gather(*tasks.values())))

    flags = []
    score = 100  # 满分100,逐项扣分

    # 社保参保人数为0
    social = results.get("社保信息", {})
    if social.get("data", {}).get("insured_count", 0) == 0:
        flags.append("社保参保人数为0")
        score -= 30

    # 实缴比例过低
    annual = results.get("年报信息", {})
    if annual.get("data"):
        registered = annual["data"].get("registered_capital", 0)
        paid = annual["data"].get("paid_in_capital", 0)
        if registered > 0 and paid / registered < 0.2:
            flags.append(f"实缴比例仅{paid/registered*100:.1f}%")
            score -= 20

    # 频繁高管变更(最近12个月超过2次)
    changes = results.get("变更记录", {})
    recent_changes = changes.get("data", {}).get("recent_count", 0)
    if recent_changes > 2:
        flags.append(f"近12个月高管变更{recent_changes}次")
        score -= 15

    # 注册地址集中(与大量企业共享同一地址)
    contact = results.get("联络信息", {})
    if contact.get("data", {}).get("shared_address_count", 0) > 10:
        flags.append("注册地址共享超过10家企业")
        score -= 15

    # 风险定级
    if score < 40:
        risk = "HIGH——高度疑似空壳"
    elif score < 60:
        risk = "MEDIUM——需人工复核"
    elif score < 80:
        risk = "LOW——基本正常"
    else:
        risk = "NORMAL"

    return {
        "company": company_name,
        "score": score,
        "risk": risk,
        "flags": flags
    }

注意get_social_security_infoget_contact_info 等函数仅供参考,实际工具名以企查查MCP当前版本为准。企查查企业经营罗盘Server(qcc-operation)包含资质证书、招投标、融资记录等多种经营活跃度判定维度,可替代社保等不可直接获取的指标。


三、供应商风险预警:Push 模式的工程实现

3.1 从 Pull 到 Push 的架构差异

传统 Pull 模式:
  采购人员 → 定时登录SRM → 手动检索 → 发现风险 → 上报
  延迟:数天至数月

Push 模式(本文方案):
  外部数据源变更 → MCP 实时推流 → 风险分级引擎 → 钉钉/飞书/邮件通知
  延迟:T+0

3.2 风险分级矩阵

不是所有数据变更都值得实时推送。有效的预警系统需要两级过滤:

象限 特征 处理策略 技术实现
红色 高频 + 高影响 即时推送(5分钟内) Webhook + 即时消息
橙色 低频 + 高影响 即时推送 Webhook + 即时消息
黄色 高频 + 低影响 每日汇总报告 定时任务 + 邮件
绿色 低频 + 低影响 记录备查 数据库写入
from datetime import datetime
from enum import Enum

class RiskLevel(Enum):
    RED = "即时推送——5分钟内"
    ORANGE = "即时推送"
    YELLOW = "每日汇总"
    GREEN = "记录备查"

# 风险信号→影响等级 映射表
RISK_SIGNAL_MAP = {
    "法人变更":              {"impact": "HIGH",   "freq": "HIGH",  "level": RiskLevel.RED},
    "新增被执行":            {"impact": "HIGH",   "freq": "HIGH",  "level": RiskLevel.RED},
    "股权冻结":              {"impact": "HIGH",   "freq": "HIGH",  "level": RiskLevel.RED},
    "经营异常":              {"impact": "HIGH",   "freq": "LOW",   "level": RiskLevel.ORANGE},
    "行政处罚":              {"impact": "HIGH",   "freq": "LOW",   "level": RiskLevel.ORANGE},
    "破产重整":              {"impact": "HIGH",   "freq": "LOW",   "level": RiskLevel.ORANGE},
    "注册资本变更":          {"impact": "LOW",    "freq": "HIGH",  "level": RiskLevel.YELLOW},
    "经营范围调整":          {"impact": "LOW",    "freq": "HIGH",  "level": RiskLevel.YELLOW},
    "联系方式更新":          {"impact": "LOW",    "freq": "LOW",   "level": RiskLevel.GREEN},
    "股东结构调整":          {"impact": "LOW",    "freq": "LOW",   "level": RiskLevel.GREEN},
}

def classify_risk_signal(signal_type: str) -> dict:
    """根据信号类型返回风险等级和处理策略"""
    mapping = RISK_SIGNAL_MAP.get(signal_type, {
        "level": RiskLevel.YELLOW,  # 未知信号默认黄色
        "impact": "UNKNOWN",
        "freq": "UNKNOWN"
    })
    return {
        "signal": signal_type,
        "level": mapping["level"].value,
        "timestamp": datetime.now().isoformat(),
        "action": {
            RiskLevel.RED:    "推送到采购负责人企业微信 + 短信 + 系统弹窗",
            RiskLevel.ORANGE: "推送到采购负责人企业微信 + 系统弹窗",
            RiskLevel.YELLOW: "加入每日供应商风险汇总邮件",
            RiskLevel.GREEN:  "写入风险日志,备查"
        }[mapping["level"]]
    }

3.3 增量监控的数据结构

监控引擎的核心是基线快照比对——记录每个供应商在上次检查时的状态,与最新数据做差分,只推送变更项:

# 供应商监控基线快照数据结构(伪代码)
SUPPLIER_SNAPSHOT_SCHEMA = {
    "supplier_id": "USCI_18位统一社会信用代码",
    "last_check": "2026-06-15T10:00:00Z",
    "baseline": {
        "legal_person": "张某",           # 法人
        "registered_capital": 10000000,   # 注册资本(元)
        "judicial_records_count": 3,      # 司法记录总数
        "dishonest_count": 0,             # 失信记录数
        "abnormal_count": 0,              # 经营异常数
        "equity_pledge_ratio": 0.0,       # 股权质押比例
        "business_status": "正常",        # 经营状态
    },
    "alerts": []  # 待存储的增量变更
}

差分检测逻辑

def diff_supplier_snapshot(old: dict, new: dict) -> list[dict]:
    """对比新旧快照,返回变更列表"""
    changes = []
    for field in old["baseline"]:
        if old["baseline"][field] != new["baseline"].get(field):
            changes.append({
                "field": field,
                "old_value": old["baseline"][field],
                "new_value": new["baseline"].get(field),
                "risk_level": classify_risk_signal(field)["level"]
            })
    return changes

四、供应商评价体系:外部风险健康度的技术嵌入

4.1 模型对比

模型 维度结构 数据来源 局限性
传统 QCDS Quality / Cost / Delivery / Service 内部ERP/SRM 只看历史,无法预测未来风险
QCDS+R(推荐) QCDS + 外部风险健康度 内部数据 + 企查查MCP 历史表现+当前经营状态双轨制

4.2 外部风险健康度的量化计算

async def calculate_external_risk_score(company_name: str) -> dict:
    """
    供应商外部风险健康度量化评分
    满分100,从企查查MCP多维度信号自动采集并结构化处理
    """
    # 并行查询各风险维度
    checks = {
        "失信被执行": query_tool(QCC_RISK, "get_dishonest_info", company_name),
        "被执行人": query_tool(QCC_RISK, "get_judgment_debtor_info", company_name),
        "裁判文书": query_tool(QCC_RISK, "get_judicial_documents", company_name),
        "行政处罚": query_tool(QCC_RISK, "get_administrative_penalty", company_name),
        "经营异常": query_tool(QCC_RISK, "get_business_exception", company_name),
        "股权出质": query_tool(QCC_RISK, "get_equity_pledge_info", company_name),
        "股权冻结": query_tool(QCC_RISK, "get_equity_freeze", company_name),
        "破产重整": query_tool(QCC_RISK, "get_bankruptcy_reorganization", company_name),
        "环保处罚": query_tool(QCC_RISK, "get_environmental_penalty", company_name),
        "税收违法": query_tool(QCC_RISK, "get_tax_violation", company_name),
    }

    results = dict(zip(checks.keys(), await asyncio.gather(*checks.values())))

    score = 100

    # 扣分规则(数值可根据实际业务调整)
    SCORING_RULES = {
        "失信被执行": {"per_record": 30, "max": 60},
        "被执行人":   {"per_record": 20, "max": 40},
        "裁判文书":   {"per_record": 10, "max": 30},
        "行政处罚":   {"per_record": 10, "max": 30},
        "经营异常":   {"per_record": 20, "max": 40},
        "股权出质":   {"per_10pct": 10,  "max": 30},
        "股权冻结":   {"exists": 25,     "max": 25},
        "破产重整":   {"exists": 50,     "max": 50},
        "环保处罚":   {"per_record": 5,  "max": 15},
        "税收违法":   {"per_record": 15, "max": 30},
    }

    detail = {}
    for dim, data in results.items():
        rule = SCORING_RULES[dim]
        records = data.get("data", {}).get("total", 0) if isinstance(data.get("data"), dict) else (1 if data.get("data") else 0)

        if "per_record" in rule:
            deduction = min(records * rule["per_record"], rule["max"])
        elif "per_10pct" in rule:
            pct = float(data.get("data", {}).get("ratio", 0)) if isinstance(data.get("data"), dict) else 0
            deduction = min(int(pct * 100 / 10) * rule["per_10pct"], rule["max"])
        elif "exists" in rule:
            deduction = rule["exists"] if records > 0 else 0
        else:
            deduction = 0

        score -= deduction
        detail[dim] = {"records": records, "deduction": deduction}

    # 风险定级
    if score >= 80:
        grade = "A——低风险"
    elif score >= 60:
        grade = "B——关注"
    elif score >= 40:
        grade = "C——预警"
    else:
        grade = "D——高风险"

    return {
        "company": company_name,
        "risk_score": max(0, score),
        "grade": grade,
        "detail": detail
    }

预期返回

{
  "company": "某原材料供应商",
  "risk_score": 72,
  "grade": "B——关注",
  "detail": {
    "失信被执行": {"records": 0, "deduction": 0},
    "被执行人": {"records": 1, "deduction": 20},
    "股权出质": {"records": 0, "deduction": 0},
    "行政处罚": {"records": 1, "deduction": 8}
  }
}

五、MCP工具与业务场景对照表

以下是间接采购供应商动态监控各环节可直接调用的企查查MCP工具:

业务环节 工具函数 所属 Server 查询参数 用途
L1 主体资格 get_company_base_info qcc-company searchKey 工商登记基础信息
L1 主体资格 get_shareholder_info qcc-company searchKey 股东及出资比例
L1 主体资格 get_beneficiary_owner qcc-company searchKey 受益所有人识别
L2 司法合规 get_dishonest_info qcc-risk searchKey 失信被执行
L2 司法合规 get_judgment_debtor_info qcc-risk searchKey 被执行人
L2 司法合规 get_judicial_documents qcc-risk searchKey 裁判文书
L2 司法合规 get_administrative_penalty qcc-risk searchKey 行政处罚
L2 司法合规 get_business_exception qcc-risk searchKey 经营异常
L3 关联穿透 get_actual_controller qcc-company searchKey 实际控制人识别
L3 关联穿透 get_all_related_enterprises qcc-executive 企业+姓名 董监高全部关联企业
L3 关联穿透 get_company_related_risk_scan qcc-risk searchKey 关联风险自动扫描
L4 经营稳健 get_annual_report qcc-company searchKey 工商年报(实缴/营收)
L4 经营稳健 get_change_records qcc-company searchKey 工商变更记录
预警监控 get_company_risk_scan qcc-risk searchKey 企业风险全量扫描
预警监控 get_equity_pledge_info qcc-risk searchKey 股权出质
预警监控 get_equity_freeze qcc-risk searchKey 股权冻结
预警监控 get_bankruptcy_reorganization qcc-risk searchKey 破产重整
评价体系 get_tax_violation qcc-risk searchKey 税收违法
评价体系 get_environmental_penalty qcc-risk searchKey 环保处罚
评价体系 get_bidding_info qcc-operation searchKey 招投标活跃度(经营佐证)
评价体系 get_qualifications qcc-operation searchKey 资质证书

六、MCP Server 完整配置

{
  "mcpServers": {
    "qcc-company": {
      "url": "https://agent.qcc.com/mcp/company/stream",
      "headers": { "Authorization": "Bearer YOUR_API_KEY" }
    },
    "qcc-risk": {
      "url": "https://agent.qcc.com/mcp/risk/stream",
      "headers": { "Authorization": "Bearer YOUR_API_KEY" }
    },
    "qcc-ipr": {
      "url": "https://agent.qcc.com/mcp/ipr/stream",
      "headers": { "Authorization": "Bearer YOUR_API_KEY" }
    },
    "qcc-operation": {
      "url": "https://agent.qcc.com/mcp/operation/stream",
      "headers": { "Authorization": "Bearer YOUR_API_KEY" }
    },
    "qcc-executive": {
      "url": "https://agent.qcc.com/mcp/executive/stream",
      "headers": { "Authorization": "Bearer YOUR_API_KEY" }
    },
    "qcc-history": {
      "url": "https://agent.qcc.com/mcp/history/stream",
      "headers": { "Authorization": "Bearer YOUR_API_KEY" }
    }
  }
}

说明:6个Server共用同一API Key。qcc-history(历史存档)需企业认证后开通。企业类Server统一使用 searchKey 参数(企业名称/统一社会信用代码),董监高Server需 企业名称 + 姓名 双参数锚定。


七、系统架构建议:从单体到控制塔

商务部等8部门在2025年5月发布的《加快数智供应链发展行动计划》(商流通函〔2025〕56号)中提出建设「数智供应链控制塔」——利用物联网、AI、数字孪生技术实现供应链的「实时洞察、运行分析和智能响应」。

政策

从工程角度,供应商动态监控系统的演进路径如下:

阶段一(基础)          阶段二(自动化)        阶段三(智能化)
┌─────────────┐      ┌─────────────┐      ┌─────────────┐
│ 手动查询     │  →   │ 定时巡检     │  →   │ 实时推流     │
│ 静态审查     │      │ 批量对比     │      │ 风险预判     │
│ 单点工具     │      │ 接口打通     │      │ 控制塔架构   │
└─────────────┘      └─────────────┘      └─────────────┘

间接采购的供应商数量通常是直接采购的3-5倍,品类杂、金额散,人工管理不可行。三个阶段的核心差异不在于功能多少,而在于触发机制——从人工触发到定时触发到事件触发。

供应商动态监控的技术门槛正在快速降低。当外部数据源通过MCP实现标准化接入,当185个原子工具覆盖企业、风险、知产、经营、历史、董监高六个维度,开发一个自动化的供应商监控引擎不再是基础设施问题,而是工程整合问题。未来三年,动态监控会成为间接采购数字化的标准配置。

Logo

欢迎加入 MCP 技术社区!与志同道合者携手前行,一同解锁 MCP 技术的无限可能!

更多推荐