unis_crm/MCP优化方案.md

14 KiB
Raw Blame History

MCP 优化方案

基于当前 MCPLLM Agent 工具实现现状整理。日期2026-09-16。 前提:完整测试 132 个用例全部通过(含数据权限守卫 everyMcpMapperMethodShouldBeProtectedOrExplicitlyTenantSafe、SQL 可重写守卫等),服务可正常编译运行。


一、现状总览

1.1 MCP 工具清单24 个)

# 工具名 归属类 能力
1 crm_universal_search CrmUniversalSearchToolProvider 跨实体关键词通用搜索(客户/商机/拓客/日报/签到/待办/活动/跟进)
2 crm_user_profile UserProfileToolProvider 当前用户画像(账号/姓名/角色/部门/租户)
3 crm_entity_detail CrmEntityDetailToolProvider 按实体类型+ID 查详情可带相关明细customer/opportunity/daily_report/checkin/sales_expansion/channel_expansion/crm_expansion/todo
4 crm_work_report_search WorkReportSearchToolProvider 日报分页检索
5 crm_opportunity_search OpportunitySearchToolProvider 商机分页检索(阶段/金额/排序/字段投影)
6 crm_customer_search CrmDetailSearchToolProvider 客户分页检索
7 crm_checkin_search CrmCheckinSearchToolProvider 外勤打卡分页检索
8 crm_expansion_search CrmExpansionSearchToolProvider 销售/渠道拓客分页检索
9 crm_crm_expansion_search CrmCrmExpansionSearchToolProvider CRM 拓客crm_crm_expansion检索
10 crm_followup_search CrmFollowupSearchToolProvider 商机/拓客跟进检索
11 crm_todo_search CrmTodoSearchToolProvider 待办检索
12 crm_work_today_status CrmWorkTodayStatusToolProvider 今日工作状态
13 crm_org_user_search CrmOrgUserSearchToolProvider 组织用户检索
14 crm_report_query CrmReportQueryToolProvider 报表/统计查询(见 1.2
15 crm_report_catalog CrmReportCatalogToolProvider 报表与查询能力目录
16 crm_metadata_catalog CrmMetadataToolProvider 模块/字段/工具能力目录
17 crm_dict_options CrmDictOptionsToolProvider 系统字典类型和选项
18 crm_field_comment CrmFieldCommentToolProvider MCP 返回字段的中文注释(读 DB COMMENT

注:上表已覆盖全部 ToolProvider 类。crm_search/crm_detail 等仅表示内部方法,非独立注册工具。

1.2 crm_report_query 支持的 reportType10 种)

dashboard_summarysales_performanceopportunity_funnelopportunity_trenddaily_report_completioncheckin_summaryexpansion_summarycustomer_summarytodo_summarychannel_analytics(下含 channelTierDistributionchannelIntentDistributionchannelCoverageSummarychannelRevenueTierchannelContactWecomDistribution 5 个子维度)。

1.3 Mapper 规模LlmMcpMapper.xml83 个 select

  • 列表/搜索35 个(各实体 search + count + universalSearch
  • Dashboard/汇总27 个dashboard* 、Summary、funnel/trend/completion、channel 聚合)
  • 详情15 个selectDetail + 相关明细 selectFollowups/Contacts/Coverages/Comments/Messages/Opportunities
  • 基础数据selectUserProfile/Roles/Orgs、searchOrgUsers、searchOrganizations、searchRoles、selectDictTypes/Options、selectColumnComments

1.4 数据权限模型

McpDataPermissionInterceptor 通过 SQL 重写注入 owner 过滤。策略见 buildPolicies()McpDataPermissionInterceptor.java

RESOURCE 常量 owner 列 关键受管方法
RESOURCE_DAILY_REPORT r.user_id searchWorkReports、详情、comments、messages、日报完成率
RESOURCE_CHECKIN c.user_id 签到系列
RESOURCE_CUSTOMER c.owner_user_id 客户系列
RESOURCE_EXPANSION s.owner_user_id / c.owner_user_id / ce.owner_user_id 销售/渠道/CRM 拓客系列 + channel* 聚合
RESOURCE_WORK t.user_id / l.operator_user_id / u.user_id 待办、活动、今日状态
RESOURCE_OPPORTUNITY o.owner_user_id+项目归属地投影,预售后台可见) 商机系列、跟进、漏斗
RESOURCE_ALL u.user_id searchOrgUsers

受两类守卫测试保护:每个 mapper 方法要么受策略保护、要么显式 tenant-safe受保护语句必须能被重写器正确注入过滤条件。


二、可优化点

按「优先级 P0(高) / P1(中) / P2(低)」与「收益」分组,每条含:现状、优化建议、影响。

P0-1 actual_signed_summary 报表「已声明但不可用」(实际缺陷)

  • 现状CrmReportQueryToolProvider.java
    • reportType 参数枚举里含 "actual_signed_summary"L64crm_report_catalog 也声明了该 reportTypeL61
    • query() 的分发 switchL87-98没有 case "actual_signed_summary",会落到 defaultBusinessException("不支持的 reportType")
    • 而 L110 的 if ("actual_signed_summary".equals(reportType)) { signedSummary(...) } 分支位于 switch 之后,因 switch 先抛异常而永远不可达
    • 底层 signedSummaryRows / signedSummaryQuality mapper 已就绪XML 2508/2548且已注册数据权限只是没被 switch 接上。
  • 建议(核心修复,最小改动):在 switch 增加 case "actual_signed_summary" -> signedSummaryRows/... 或在 query() 入口先处理该 reportType使声明与实现一致。建议顺带新增一个「枚举声明的 reportType 与 switch 分支一一对应、且 catalog 同步」的守卫测试,防止再次漂移。
  • 影响Agent 按 catalog 调用该报表当前会直接报错 → 属功能性缺陷,建议优先修复。

P0-2 商机筛选/权限口径的「预售后台」与 SDK 差异(一致性风险中)

  • 现状McpDataPermissionInterceptor.java 中商机策略 preSalesVisible=true 并带 o.project_ownership_location 投影,而日报/签到/客户/拓客等 preSalesVisible=false。这个差异是有意的(对应商机模块的预售后台可见规则),但没有注释说明为什么商机特殊
  • 建议:在策略处补注释说明「商机为何独享 preSalesVisible 与项目归属地投影」,避免后续维护误改。纯注释改动,零回归。
  • 收益:提升可维护性,防止未来误删权限差异导致商机数据越权或越收窄。

P0-3 用户相关查询的敏感字段需审校(安全加固)

  • 现状:用户画像已暴露工号/职位/入职日期等。需核验 selectUserProfile / searchOrgUsers 是否为显式列(而非 *),确认无 password/salt/token/密钥字段带出。
  • 建议:通读 selectUserProfilesearchOrgUsers 两个查询,确认全部为显式列,且不含密码/盐/token/密钥类字段。若有 *,改为显式列。同时补一个黑名单断言测试:任何 MCP 返回的字段名不得出现 password/secret/token/key 等(类似现有权限守卫)。
  • 收益:杜绝敏感信息经 MCP 泄漏的隐患,测试固化。

P0-4 数据权限守卫测试存在,但缺乏「跨实体 join 越权」用例

  • 现状:现有测试验证每个受保护语句可被重写,但未覆盖关联明细查询(如 selectChannelExpansionOpportunitiesselectCustomerOpportunitiesselectSalesExpansionOpportunities)在注入 owner 条件后,相联合的 on 条件是否真正约束到目标行。
  • 建议:增加针对性测试:构造「主实体可见但关联实体不可见」的数据,断言关联明细不会越权返回超此 owner 范围的行。
  • 收益:堵住「通过详情联查旁路越权」的潜在漏洞。

P1-1 报表 channel_analytics 的 groupBy 口径无文档校验

  • 现状channel_analytics 有参数 groupByCrmReportQueryToolProvider.java但内部各聚合方法tier/intent/coverage/revenue/wecomgroupBy 的支持程度看不到统一校验。
  • 建议:明确每个子维度「是否接受 groupBy、接受哪些取值」对不支持的值在入口做显式校验并报错而非静默忽略避免返回误导性聚合。补充文档化说明到 crm_report_catalog
  • 收益:提升统计可信度、避免 Agent 拿到「以为分组了其实没有」的数据。

P1-2 crm_report_catalog 的工具清单可能未随新工具同步

  • 现状CrmReportCatalogToolProvider.java 内联维护了一个工具清单(含 crm_universal_searchcrm_work_report_search 等),但未见 crm_user_profile/crm_work_today_status/crm_crm_expansion_search/crm_report_query 之外全部 24 个工具是否都在清单内,且是手工维护,易遗漏。
  • 建议:改为从注册表动态生成工具清单(遍历已注册 ToolProvider 的名称与描述),消除手工同步漂移;或至少补齐缺失工具并加「清单与注册工具数量一致」的守卫测试。
  • 收益Agent 发现工具的能力与真实能力一致,避免「目录找不到但实际能调」。

P1-3 selectColumnCommentscrm_field_comment的表白名单是硬编码

  • 现状FieldCommentRegistry.java 以硬编码 tables() / TABLE_COLUMNS 维护「别名→物理列」映射,新增表/字段需人工双处登记(列表+注释),易漏。
  • 建议:为映射的完整性加守卫测试:TABLE_COLUMNS 键集合与 tables() 返回的说明集合一致;并可核对每个映射的物理列是否在本批次已暴露的查询字段内。
  • 收益:固化「新增字段必登记注释」这一约定,避免字段有值但无注释。

P1-4 limit 上限保护已较好,但部分列表可细化

  • 现状:商机等已统一 pageSize/limit 默认 10、最大 50OpportunitySearchToolProvider.java,含 offset 计算)。这是好实践。
  • 建议:核验所有其余 search 工具(日报/客户/打卡/拓客/跟进/待办/CRM拓客是否都用了同一套 MAX_LIMITgetOffset 兜底,避免个别工具直接透传 limit 造成大结果集。可抽公共参数抽取器统一。
  • 收益:统一防爆量,避免个别查询成为性能/响应放大点。

P2-1 列表 keyword 搜索未纳入 coverage/联系人等子表字段

  • 现状:销售/渠道列表已新增 coverageSummary 聚合列(本轮),但 keyword 匹配仍只针对主表字段,不会命中覆盖省/市或渠道联系人姓名。
  • 建议:如需「按覆盖地市、按联系人搜索」,在 keyword 的 LIKE 条件里补充对 coverage 子表(省/市)与 contact 表的关联匹配。
  • 收益:搜索召回更贴合业务;成本是 SQL 变复杂,需先确认是否为业务目标。

P2-2 覆盖地市 / 日报消息只存在于「详情联查」,无独立搜索工具

  • 现状coveragework_report_message 已通过 crm_entity_detail 的相关明细暴露,但无独立搜索入口。
  • 建议:若 Agent 需要「按覆盖省/市全局统计」或「全局检索某条日报消息」,可新增 crm_coverage_search / crm_report_message_search 独立工具;否则保持现状(避免工具爆炸)。
  • 收益按需增强过度新增会导致工具面过大、Agent 选择成本上升。

P2-3 未处理缺口(已知合理保留)

  • sys_org.parent_id/org_code/sort_order:框架表无建表脚本,列名未核实,暂不补真实值。
  • business_calendar_dayreport_reminder_*speech_recognition_configdashboard_analytics_card_config:配置类表,未暴露属合理(报告鉴权用白名单、配置不属业务数据)。
  • crm_oms_dict_mappingOMS 后调用映射表,按需求明确不暴露

三、推荐落地顺序(不含重构)

序号 工作量 回归风险
1 P0-1 修复 actual_signed_summary 不可用缺陷(核心)
2 P0-3 敏感字段审校 + 黑名单测试
3 P0-4 关联明细越权测试 零(纯加测试)
4 P1-1 channel_analytics groupBy 校验
5 P1-2 report_catalog 动态化/补全 + 守卫
6 P1-3 field_comment 注册一致性守卫 零(纯加测试)
7 P1-4 limit 兜底统一 小-中
8 P2-1/P2-2 按需 视需求 视改动

四、当前状态结论

  • 功能完整性:核心业务主表 + 详情 + 报表 + 数据权限均已覆盖132 用例全绿,服务可启动。不存在阻断性缺陷
  • 最值得优先做P0-2敏感字段黑名单与 P0-3关联明细越权测试——属于「安全加固」性质风险低、收益高建议放到下一批次。
  • 其余 P1/P2 多为可维护性与体验增强,可按迭代排期,不必一次性做完。