Kaynağa Gözat

docs: expand aftersales agent table design

wzq 1 ay önce
ebeveyn
işleme
84f2a2e406

+ 268 - 74
docs/superpowers/specs/2026-07-08-enterprise-aftersales-agent-design.md

@@ -118,108 +118,302 @@ HIGH:
 
 ## 数据表
 
-核心表:
+表按职责拆成两组:
+
+- Java 业务库:`agent_tool_registry`、`agent_approval`、`agent_pending_action`、`agent_audit_log`、`aftersales_work_order`。首版按 MySQL 设计,跟 `zsElectric-boot` 当前业务库一致。
+- RAG 知识库:`aftersales_policy_doc`、`aftersales_policy_chunk`。首版按 PostgreSQL + pgvector 设计。Python FastAPI Agent 可以直接检索该知识库;Java MCP Server 也可以通过 `retrieve_aftersales_policy` 工具封装同一套检索能力。
+
+核心关系:
 
 ```text
-agent_tool_registry
-agent_approval
-agent_pending_action
-agent_audit_log
-aftersales_work_order
-aftersales_policy_doc
-aftersales_policy_chunk
+agent_approval 1 -> 1 agent_pending_action
+agent_approval 1 -> n agent_audit_log
+agent_pending_action 1 -> n agent_audit_log
+aftersales_policy_doc 1 -> n aftersales_policy_chunk
+trace_id 贯穿 agent_approval、agent_pending_action、agent_audit_log、aftersales_work_order
 ```
 
 ### agent_tool_registry
 
-记录 MCP 工具治理信息:
+记录 Java MCP Server 可暴露工具的治理信息。工具必须先注册到该表,再进入白名单判断。
+
+```sql
+CREATE TABLE agent_tool_registry (
+  id BIGINT PRIMARY KEY AUTO_INCREMENT COMMENT '主键',
+  tool_name VARCHAR(128) NOT NULL COMMENT 'MCP工具名',
+  tool_version VARCHAR(32) NOT NULL DEFAULT 'v1' COMMENT '工具版本',
+  description VARCHAR(512) NOT NULL COMMENT '工具说明',
+  transport VARCHAR(32) NOT NULL DEFAULT 'mcp' COMMENT '工具传输协议',
+  handler_bean VARCHAR(192) NOT NULL COMMENT 'Java处理器Bean或路由标识',
+  risk_level VARCHAR(16) NOT NULL COMMENT '风险等级: LOW, MEDIUM, HIGH',
+  enabled TINYINT(1) NOT NULL DEFAULT 1 COMMENT '是否启用',
+  require_approval TINYINT(1) NOT NULL DEFAULT 0 COMMENT '是否需要审批',
+  idempotent TINYINT(1) NOT NULL DEFAULT 1 COMMENT '是否支持幂等',
+  input_schema_json JSON NOT NULL COMMENT '输入参数JSON Schema',
+  output_schema_json JSON NULL COMMENT '输出结果JSON Schema',
+  allowed_roles JSON NULL COMMENT '允许调用的角色列表',
+  sensitive_fields JSON NULL COMMENT '需要脱敏的字段列表',
+  rate_limit_per_minute INT NOT NULL DEFAULT 60 COMMENT '单工具分钟限流',
+  timeout_ms INT NOT NULL DEFAULT 10000 COMMENT '工具超时时间',
+  remark VARCHAR(512) NULL COMMENT '备注',
+  create_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
+  update_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
+  deleted TINYINT(1) NOT NULL DEFAULT 0 COMMENT '逻辑删除标记',
+  UNIQUE KEY uk_agent_tool_name_version (tool_name, tool_version),
+  KEY idx_agent_tool_enabled_risk (enabled, risk_level),
+  KEY idx_agent_tool_handler (handler_bean)
+) COMMENT='Agent MCP工具注册表';
+```
+
+首版工具注册示例:
 
-- `id`
-- `tool_name`
-- `description`
-- `risk_level`
-- `enabled`
-- `input_schema_json`
-- `output_schema_json`
-- `created_at`
-- `updated_at`
+```text
+query_charge_order: LOW, require_approval=false
+query_charge_session: LOW, require_approval=false
+retrieve_aftersales_policy: LOW, require_approval=false
+create_aftersales_work_order: LOW, require_approval=false
+request_refund: HIGH, require_approval=true
+request_compensation: HIGH, require_approval=true
+resume_after_approval: HIGH, require_approval=false
+write_agent_audit: LOW, require_approval=false
+```
 
 ### agent_approval
 
-记录审批单:
-
-- `approval_id`
-- `trace_id`
-- `status`: `pending`, `approved`, `rejected`, `expired`, `executed`
-- `risk_level`
-- `request_user_id`
-- `request_username`
-- `approver_id`
-- `approver_username`
-- `reason`
-- `decision_comment`
-- `created_at`
-- `approved_at`
-- `expires_at`
+记录高风险动作审批单。审批单只表达“是否允许执行”,不直接保存完整执行参数;完整执行参数保存在 `agent_pending_action`。
+
+```sql
+CREATE TABLE agent_approval (
+  id BIGINT PRIMARY KEY AUTO_INCREMENT COMMENT '主键',
+  approval_id VARCHAR(64) NOT NULL COMMENT '审批ID,外部展示和恢复执行使用',
+  trace_id VARCHAR(64) NOT NULL COMMENT 'Agent运行链路ID',
+  pending_action_id BIGINT NULL COMMENT '关联冻结动作ID',
+  biz_type VARCHAR(64) NOT NULL COMMENT '业务类型: refund, compensation',
+  biz_no VARCHAR(128) NOT NULL COMMENT '业务编号,通常为订单号',
+  risk_level VARCHAR(16) NOT NULL COMMENT '风险等级: HIGH',
+  status VARCHAR(32) NOT NULL DEFAULT 'pending' COMMENT '状态: pending, approved, rejected, expired, executed',
+  request_user_id BIGINT NULL COMMENT '发起用户ID',
+  request_username VARCHAR(128) NULL COMMENT '发起用户名',
+  request_reason VARCHAR(1024) NOT NULL COMMENT '申请原因',
+  risk_reason VARCHAR(1024) NULL COMMENT '命中高风险的原因',
+  policy_evidence_json JSON NULL COMMENT '政策依据和RAG命中证据',
+  requested_amount DECIMAL(10,2) NULL COMMENT '申请退款或补偿金额',
+  approver_id BIGINT NULL COMMENT '审批人ID',
+  approver_username VARCHAR(128) NULL COMMENT '审批人名称',
+  decision_comment VARCHAR(1024) NULL COMMENT '审批意见',
+  decision_time DATETIME NULL COMMENT '审批时间',
+  expires_at DATETIME NOT NULL COMMENT '审批过期时间',
+  create_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
+  update_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
+  version INT NOT NULL DEFAULT 0 COMMENT '乐观锁版本',
+  deleted TINYINT(1) NOT NULL DEFAULT 0 COMMENT '逻辑删除标记',
+  UNIQUE KEY uk_agent_approval_id (approval_id),
+  KEY idx_agent_approval_trace (trace_id),
+  KEY idx_agent_approval_status_time (status, create_time),
+  KEY idx_agent_approval_request_user (request_user_id, status),
+  KEY idx_agent_approval_biz (biz_type, biz_no)
+) COMMENT='Agent高风险动作审批表';
+```
+
+状态流转:
+
+```text
+pending -> approved -> executed
+pending -> rejected
+pending -> expired
+```
+
+`approved` 只表示审批通过。真实退款或补偿必须由 `resume_after_approval(approval_id)` 根据冻结动作执行,执行成功后再把审批单标记为 `executed`。
 
 ### agent_pending_action
 
-记录审批通过后要恢复执行的冻结动作:
+记录审批通过后要恢复执行的冻结动作。审批前后的执行参数必须保持一致,不能让模型在审批后重新生成参数。
+
+```sql
+CREATE TABLE agent_pending_action (
+  id BIGINT PRIMARY KEY AUTO_INCREMENT COMMENT '主键',
+  action_id VARCHAR(64) NOT NULL COMMENT '冻结动作ID',
+  approval_id VARCHAR(64) NOT NULL COMMENT '关联审批ID',
+  trace_id VARCHAR(64) NOT NULL COMMENT 'Agent运行链路ID',
+  tool_name VARCHAR(128) NOT NULL COMMENT '待执行MCP工具名',
+  tool_version VARCHAR(32) NOT NULL DEFAULT 'v1' COMMENT '工具版本',
+  risk_level VARCHAR(16) NOT NULL COMMENT '风险等级',
+  params_json JSON NOT NULL COMMENT '冻结后的工具参数',
+  params_hash CHAR(64) NOT NULL COMMENT '参数SHA-256摘要,防篡改',
+  idempotency_key VARCHAR(128) NOT NULL COMMENT '幂等键',
+  execute_status VARCHAR(32) NOT NULL DEFAULT 'pending' COMMENT '执行状态: pending, executing, executed, failed, expired, rejected',
+  execute_result_json JSON NULL COMMENT '执行结果',
+  error_message TEXT NULL COMMENT '失败原因',
+  retry_count INT NOT NULL DEFAULT 0 COMMENT '重试次数',
+  executed_at DATETIME NULL COMMENT '执行完成时间',
+  expires_at DATETIME NOT NULL COMMENT '冻结动作过期时间',
+  create_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
+  update_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
+  version INT NOT NULL DEFAULT 0 COMMENT '乐观锁版本',
+  deleted TINYINT(1) NOT NULL DEFAULT 0 COMMENT '逻辑删除标记',
+  UNIQUE KEY uk_agent_action_id (action_id),
+  UNIQUE KEY uk_agent_action_idempotency (idempotency_key),
+  KEY idx_agent_action_approval (approval_id),
+  KEY idx_agent_action_trace (trace_id),
+  KEY idx_agent_action_status_time (execute_status, create_time),
+  KEY idx_agent_action_tool (tool_name, tool_version)
+) COMMENT='Agent审批后待恢复执行动作表';
+```
 
-- `id`
-- `approval_id`
-- `trace_id`
-- `tool_name`
-- `params_json`
-- `params_hash`
-- `execute_status`: `pending`, `executed`, `failed`, `expired`
-- `execute_result_json`
-- `error_message`
-- `idempotency_key`
-- `created_at`
-- `executed_at`
-- `expires_at`
+恢复执行校验顺序:
 
-审批恢复时使用 `pending_action` 中的冻结参数,不重新让模型生成参数。执行前必须校验审批状态、过期时间、params hash、工具白名单、风险等级和幂等键。
+```text
+approval_id 存在
+-> approval.status = approved
+-> pending_action.execute_status = pending
+-> 当前时间未超过 expires_at
+-> tool_name 仍在 agent_tool_registry 白名单且启用
+-> params_hash 与 params_json 重算结果一致
+-> idempotency_key 未执行过
+-> 执行业务工具
+-> 更新 execute_status、execute_result_json、agent_approval.status
+-> 写 agent_audit_log
+```
 
 ### agent_audit_log
 
-记录全链路审计:
-
-- `id`
-- `trace_id`
-- `approval_id`
-- `step`
-- `tool_name`
-- `input_json`
-- `output_json`
-- `status`
-- `error_message`
-- `operator_id`
-- `operator_username`
-- `created_at`
+记录 Agent 全链路审计。审计表只追加,不更新业务含义,用于追踪、排障和责任回溯。
+
+```sql
+CREATE TABLE agent_audit_log (
+  id BIGINT PRIMARY KEY AUTO_INCREMENT COMMENT '主键',
+  trace_id VARCHAR(64) NOT NULL COMMENT 'Agent运行链路ID',
+  span_id VARCHAR(64) NULL COMMENT '步骤Span ID',
+  parent_span_id VARCHAR(64) NULL COMMENT '父级Span ID',
+  approval_id VARCHAR(64) NULL COMMENT '关联审批ID',
+  pending_action_id VARCHAR(64) NULL COMMENT '关联冻结动作ID',
+  actor_type VARCHAR(32) NOT NULL COMMENT '操作者类型: user, agent, system, approver',
+  actor_id VARCHAR(64) NULL COMMENT '操作者ID',
+  actor_name VARCHAR(128) NULL COMMENT '操作者名称',
+  step VARCHAR(64) NOT NULL COMMENT '步骤: user_input, intent_detected, rag_retrieved, tool_called, approval_created, approval_decided, action_resumed, final_answer',
+  event_type VARCHAR(64) NOT NULL COMMENT '事件类型',
+  tool_name VARCHAR(128) NULL COMMENT '工具名',
+  risk_level VARCHAR(16) NULL COMMENT '风险等级',
+  input_json JSON NULL COMMENT '输入快照,敏感字段脱敏后保存',
+  output_json JSON NULL COMMENT '输出快照,敏感字段脱敏后保存',
+  status VARCHAR(32) NOT NULL COMMENT '状态: success, failed, pending, skipped',
+  error_message TEXT NULL COMMENT '错误信息',
+  duration_ms BIGINT NULL COMMENT '步骤耗时毫秒',
+  ip_address VARCHAR(64) NULL COMMENT '客户端IP',
+  user_agent VARCHAR(512) NULL COMMENT '客户端User-Agent',
+  create_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
+  KEY idx_agent_audit_trace_time (trace_id, create_time),
+  KEY idx_agent_audit_approval (approval_id),
+  KEY idx_agent_audit_action (pending_action_id),
+  KEY idx_agent_audit_tool_time (tool_name, create_time),
+  KEY idx_agent_audit_status_time (status, create_time)
+) COMMENT='Agent全链路审计日志表';
+```
 
 审计步骤包括用户输入、意图判断、RAG 命中文档、工具调用、审批创建、审批结果、恢复执行和最终回复。
 
 ### aftersales_work_order
 
-记录售后工单:
-
-- `id`
-- `trace_id`
-- `order_no`
-- `issue_type`
-- `suggestion`
-- `evidence_json`
-- `status`
-- `created_by_agent`
-- `created_at`
-- `updated_at`
+记录低风险售后自动建单结果,也可以承接高风险审批后的售后处理记录。
+
+```sql
+CREATE TABLE aftersales_work_order (
+  id BIGINT PRIMARY KEY AUTO_INCREMENT COMMENT '主键',
+  work_order_no VARCHAR(64) NOT NULL COMMENT '售后工单号',
+  trace_id VARCHAR(64) NOT NULL COMMENT 'Agent运行链路ID',
+  order_no VARCHAR(128) NOT NULL COMMENT '充电订单号',
+  charge_record_id BIGINT NULL COMMENT '充电记录ID',
+  user_id BIGINT NULL COMMENT '用户ID',
+  phone_masked VARCHAR(64) NULL COMMENT '脱敏手机号',
+  issue_type VARCHAR(64) NOT NULL COMMENT '问题类型: charge_failed, payment_issue, refund_request, compensation_request',
+  issue_level VARCHAR(16) NOT NULL DEFAULT 'normal' COMMENT '问题等级: normal, urgent',
+  source VARCHAR(32) NOT NULL DEFAULT 'agent' COMMENT '来源: agent, manual, third_party',
+  suggestion TEXT NOT NULL COMMENT 'Agent处理建议',
+  policy_evidence_json JSON NULL COMMENT '政策依据和RAG命中证据',
+  order_snapshot_json JSON NULL COMMENT '订单和充电记录快照',
+  status VARCHAR(32) NOT NULL DEFAULT 'created' COMMENT '状态: created, processing, resolved, closed, canceled',
+  created_by_agent TINYINT(1) NOT NULL DEFAULT 1 COMMENT '是否Agent创建',
+  created_by VARCHAR(64) NULL COMMENT '创建人',
+  assigned_to VARCHAR(64) NULL COMMENT '处理人',
+  resolve_result TEXT NULL COMMENT '处理结果',
+  closed_at DATETIME NULL COMMENT '关闭时间',
+  create_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
+  update_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
+  deleted TINYINT(1) NOT NULL DEFAULT 0 COMMENT '逻辑删除标记',
+  UNIQUE KEY uk_aftersales_work_order_no (work_order_no),
+  KEY idx_aftersales_order_no (order_no),
+  KEY idx_aftersales_trace (trace_id),
+  KEY idx_aftersales_status_time (status, create_time),
+  KEY idx_aftersales_issue_type (issue_type, create_time)
+) COMMENT='售后工单表';
+```
 
 ### aftersales_policy_doc / aftersales_policy_chunk
 
 `aftersales_policy_doc` 保存政策原文和版本,`aftersales_policy_chunk` 保存分片文本、embedding 和元数据,用于 pgvector 检索。
 
+```sql
+CREATE TABLE aftersales_policy_doc (
+  id BIGSERIAL PRIMARY KEY,
+  doc_code VARCHAR(64) NOT NULL,
+  title VARCHAR(256) NOT NULL,
+  category VARCHAR(64) NOT NULL,
+  issue_type VARCHAR(64) NOT NULL,
+  version VARCHAR(32) NOT NULL,
+  content TEXT NOT NULL,
+  content_hash CHAR(64) NOT NULL,
+  source_type VARCHAR(32) NOT NULL DEFAULT 'manual',
+  source_uri VARCHAR(512),
+  effective_at TIMESTAMPTZ,
+  expired_at TIMESTAMPTZ,
+  enabled BOOLEAN NOT NULL DEFAULT TRUE,
+  metadata JSONB,
+  create_time TIMESTAMPTZ NOT NULL DEFAULT now(),
+  update_time TIMESTAMPTZ NOT NULL DEFAULT now(),
+  UNIQUE (doc_code, version)
+);
+
+CREATE INDEX idx_policy_doc_issue_enabled
+  ON aftersales_policy_doc (issue_type, enabled);
+
+CREATE INDEX idx_policy_doc_category
+  ON aftersales_policy_doc (category);
+```
+
+```sql
+CREATE EXTENSION IF NOT EXISTS vector;
+
+CREATE TABLE aftersales_policy_chunk (
+  id BIGSERIAL PRIMARY KEY,
+  doc_id BIGINT NOT NULL REFERENCES aftersales_policy_doc(id),
+  chunk_no INT NOT NULL,
+  chunk_text TEXT NOT NULL,
+  token_count INT,
+  embedding VECTOR(1536) NOT NULL,
+  content_hash CHAR(64) NOT NULL,
+  issue_type VARCHAR(64) NOT NULL,
+  metadata JSONB,
+  enabled BOOLEAN NOT NULL DEFAULT TRUE,
+  create_time TIMESTAMPTZ NOT NULL DEFAULT now(),
+  update_time TIMESTAMPTZ NOT NULL DEFAULT now(),
+  UNIQUE (doc_id, chunk_no)
+);
+
+CREATE INDEX idx_policy_chunk_doc
+  ON aftersales_policy_chunk (doc_id);
+
+CREATE INDEX idx_policy_chunk_issue_enabled
+  ON aftersales_policy_chunk (issue_type, enabled);
+
+CREATE INDEX idx_policy_chunk_metadata
+  ON aftersales_policy_chunk USING GIN (metadata);
+
+CREATE INDEX idx_policy_chunk_embedding
+  ON aftersales_policy_chunk USING hnsw (embedding vector_cosine_ops);
+```
+
+`VECTOR(1536)` 是首版 embedding 维度约定,后续如果更换 embedding 模型,必须同步迁移分片表维度并重建向量索引。
+
 ## 主流程
 
 低风险流程: