|
|
@@ -1,930 +0,0 @@
|
|
|
-# 企业售后 Agent 实战项目设计
|
|
|
-
|
|
|
-## 目标
|
|
|
-
|
|
|
-构建一个面向充电业务售后场景的企业 Agent 项目。用户描述问题后,Agent 能判断售后意图,检索售后政策,查询充电订单和充电记录,生成处理建议。低风险动作自动创建售后工单,高风险退款或补偿进入审批,审批后按冻结动作恢复执行,并记录全链路审计。
|
|
|
-
|
|
|
-首版目标不是做普通聊天机器人,而是做一个受控的企业执行者:能查、能建议、能调用工具,但高风险动作必须可审批、可恢复、可追责。
|
|
|
-
|
|
|
-## 范围
|
|
|
-
|
|
|
-首版采用双服务垂直切片:
|
|
|
-
|
|
|
-- Java `zsElectric-boot`:企业业务系统和 MCP Server,负责业务工具、审批、冻结动作、审计、售后政策和数据库。
|
|
|
-- Python `zsElectric-agent-service`:独立兄弟服务,使用 FastAPI 作为服务框架,使用 LangGraph 作为 Agent 状态图编排层,作为 MCP Client 调用 Java MCP Server。
|
|
|
-- PostgreSQL + pgvector:作为售后政策 RAG 知识库。
|
|
|
-- Swagger 或 Postman:用于审批演示,不开发审批管理页面。
|
|
|
-
|
|
|
-不在首版范围内:
|
|
|
-
|
|
|
-- 不把所有 Java REST Controller 自动暴露为工具。
|
|
|
-- Python 不直连 Java 业务数据库。
|
|
|
-- 不做完整前端审批后台。
|
|
|
-- 不接入 MCP 之外的泛化工具网关。
|
|
|
-
|
|
|
-## 架构
|
|
|
-
|
|
|
-```text
|
|
|
-用户
|
|
|
- -> Python zsElectric-agent-service (FastAPI)
|
|
|
- -> LangGraph StateGraph
|
|
|
- -> LLM Adapter
|
|
|
- -> RAG Retriever (PostgreSQL + pgvector)
|
|
|
- -> MCP Client
|
|
|
- -> Graph Checkpointer
|
|
|
- -> Java zsElectric-boot MCP Server
|
|
|
- -> tool registry / whitelist / risk policy
|
|
|
- -> approval / pending action / audit log
|
|
|
- -> existing service / mapper / DB
|
|
|
-```
|
|
|
-
|
|
|
-Python 只负责 Agent 编排:LangGraph 状态流转、意图判断、对话状态、工具选择、RAG 上下文组装、最终建议生成。
|
|
|
-
|
|
|
-Java 负责企业能力暴露:通过 MCP tools 暴露受控业务动作,内部仍然走现有 service 层,保留鉴权、参数校验、风险分级、审批、审计和幂等保护。
|
|
|
-
|
|
|
-HTTP 可以作为 MCP 的传输方式存在,但对 Python 来说,调用边界是 MCP tool,不是普通业务 REST API。
|
|
|
-
|
|
|
-## Java 模块
|
|
|
-
|
|
|
-在 `zsElectric-boot` 中新增 `platform.agent` 模块:
|
|
|
-
|
|
|
-```text
|
|
|
-platform.agent
|
|
|
-├─ mcp # MCP endpoint 和 tool 暴露层
|
|
|
-├─ tool # 工具注册、白名单、风险等级、schema
|
|
|
-├─ approval # 审批和 pending_action
|
|
|
-├─ audit # Agent 全链路审计
|
|
|
-├─ policy # 售后政策文档和 RAG 元数据
|
|
|
-└─ aftersales # 售后工单、退款、补偿业务适配
|
|
|
-```
|
|
|
-
|
|
|
-Java MCP Server 暴露的工具必须来自白名单,并带明确参数 schema、风险等级、trace_id、operator/user 上下文。模型不能直接访问 Mapper、数据库或内部通用 Controller。
|
|
|
-
|
|
|
-## Python 模块
|
|
|
-
|
|
|
-在兄弟目录创建 `E:\wzq\workCode\zswl\zsElectric-agent-service`:
|
|
|
-
|
|
|
-```text
|
|
|
-app
|
|
|
-├─ main.py # FastAPI app
|
|
|
-├─ graph # LangGraph StateGraph、state、nodes、edges
|
|
|
-├─ checkpoint # LangGraph checkpoint 持久化适配
|
|
|
-├─ llm # OpenAI兼容LLM客户端、Prompt、输出解析
|
|
|
-├─ mcp_client # 连接 Java MCP Server
|
|
|
-├─ rag # pgvector 检索和上下文组装
|
|
|
-├─ schemas # 请求、响应、工具结果结构
|
|
|
-├─ api # chat、resume、trace、health 路由
|
|
|
-└─ evals # 测试问题集和期望结果
|
|
|
-```
|
|
|
-
|
|
|
-FastAPI 接口:
|
|
|
-
|
|
|
-```text
|
|
|
-POST /api/v1/agent/chat
|
|
|
-POST /api/v1/agent/resume/{approval_id}
|
|
|
-GET /api/v1/agent/runs/{trace_id}
|
|
|
-GET /health
|
|
|
-```
|
|
|
-
|
|
|
-## LangGraph 编排
|
|
|
-
|
|
|
-首版不再使用 OpenAI Agents SDK。Python `zsElectric-agent-service` 使用 LangGraph 显式建模售后处理状态图,LLM 只作为图中节点的模型能力,MCP 工具调用、审批暂停、恢复执行和错误降级都由图节点和边控制。
|
|
|
-
|
|
|
-状态图节点:
|
|
|
-
|
|
|
-```text
|
|
|
-receive_input
|
|
|
- -> detect_intent
|
|
|
- -> retrieve_policy
|
|
|
- -> query_order
|
|
|
- -> plan_action
|
|
|
- -> route_by_risk
|
|
|
- -> create_work_order
|
|
|
- -> request_approval
|
|
|
- -> final_answer
|
|
|
-
|
|
|
-resume_after_approval
|
|
|
- -> load_run_state
|
|
|
- -> call_java_resume_tool
|
|
|
- -> final_answer
|
|
|
-```
|
|
|
-
|
|
|
-核心状态 `AfterSalesAgentState`:
|
|
|
-
|
|
|
-```text
|
|
|
-trace_id
|
|
|
-thread_id
|
|
|
-user_input
|
|
|
-messages
|
|
|
-intent
|
|
|
-issue_type
|
|
|
-risk_level
|
|
|
-policy_evidence
|
|
|
-order_context
|
|
|
-tool_plan
|
|
|
-tool_results
|
|
|
-approval_id
|
|
|
-pending_action_id
|
|
|
-resume_result
|
|
|
-final_answer
|
|
|
-error
|
|
|
-```
|
|
|
-
|
|
|
-`thread_id` 默认等于 `trace_id`。LangGraph checkpointer 负责保存 Python 图状态,用于 `/resume/{approval_id}` 找回审批前的对话、证据和工具结果;Java `agent_approval` 与 `agent_pending_action` 仍是审批和冻结动作的事实来源。审批通过后,Python 从 checkpointer 读取状态,再通过 MCP 调 Java `resume_after_approval(approval_id)`,不能重新让模型生成退款或补偿参数。
|
|
|
-
|
|
|
-生产环境使用 PostgreSQL checkpointer,测试环境可使用内存 checkpointer。所有高风险中断点必须在进入 `request_approval` 后保存 checkpoint,并把 `approval_id`、`pending_action_id`、`trace_id` 写入状态。
|
|
|
-
|
|
|
-## LLM 与 LangGraph 接入方案
|
|
|
-
|
|
|
-主链路采用 LangGraph 编排:Python `zsElectric-agent-service` 接入真实 LLM,Java `zsElectric-boot` 继续只做 MCP 工具控制面。Python 的 LangGraph 节点负责模型调用、意图识别、工具计划、MCP 调用路由、审批暂停和最终回复;Java 负责工具白名单、风险分级、审批、冻结动作、幂等、审计和真实业务落库。
|
|
|
-
|
|
|
-该方案的核心边界是:LLM 可以“建议调用哪个工具、用什么参数”,但不能直接访问数据库,也不能绕过 Java 的 MCP 工具治理。退款、补偿等高风险动作即使由 LLM 识别出来,也只能通过 Java `request_refund`、`request_compensation` 创建审批和冻结动作,审批通过后再由 `resume_after_approval` 恢复执行。
|
|
|
-
|
|
|
-### 配置归属
|
|
|
-
|
|
|
-LLM 与 LangGraph 配置归属 Python `zsElectric-agent-service`,不复用 Java 现有 `platform.ai` 的 `ai:` 配置作为售后 Agent 主链路配置。原因是售后 Agent 的模型、Prompt、状态图节点、工具计划、RAG 参数、最大步数、checkpoint 和降级策略都属于 Agent 编排层;Java `platform.ai` 可以继续服务后台 AI 命令系统,二者避免共享配置造成运行边界不清。
|
|
|
-
|
|
|
-Python 首版使用 OpenAI 兼容协议,支持 OpenAI、DashScope/Qwen、DeepSeek 等兼容 `/chat/completions` 的模型服务。模型名称不写死在代码里,由环境变量或配置文件决定。
|
|
|
-
|
|
|
-Python `.env` 示例:
|
|
|
-
|
|
|
-```dotenv
|
|
|
-AGENT_LLM_ENABLED=true
|
|
|
-AGENT_LLM_PROVIDER=openai
|
|
|
-AGENT_LLM_API_KEY=
|
|
|
-AGENT_LLM_BASE_URL=https://api.openai.com/v1
|
|
|
-AGENT_LLM_MODEL=
|
|
|
-AGENT_LLM_FAST_MODEL=
|
|
|
-AGENT_LLM_TEMPERATURE=0.2
|
|
|
-AGENT_LLM_TIMEOUT_SECONDS=60
|
|
|
-AGENT_LLM_TOOL_TIMEOUT_SECONDS=15
|
|
|
-
|
|
|
-LANGGRAPH_CHECKPOINT_ENABLED=true
|
|
|
-LANGGRAPH_CHECKPOINT_DSN=postgresql+psycopg://agent:agent@127.0.0.1:5432/zselectric_agent
|
|
|
-LANGGRAPH_THREAD_ID_STRATEGY=trace_id
|
|
|
-LANGGRAPH_MAX_STEPS=8
|
|
|
-
|
|
|
-AGENT_PROMPT_VERSION=aftersales-agent-v1
|
|
|
-AGENT_TOOL_PLAN_MODE=structured_json
|
|
|
-AGENT_RULE_FALLBACK_ENABLED=true
|
|
|
-
|
|
|
-EMBEDDING_PROVIDER=openai
|
|
|
-EMBEDDING_API_KEY=
|
|
|
-EMBEDDING_BASE_URL=https://api.openai.com/v1
|
|
|
-EMBEDDING_MODEL=
|
|
|
-EMBEDDING_DIMENSIONS=1536
|
|
|
-
|
|
|
-RAG_TOP_K=5
|
|
|
-RAG_MIN_SCORE=0.75
|
|
|
-RAG_MAX_CONTEXT_TOKENS=3000
|
|
|
-
|
|
|
-ZSELECTRIC_BOOT_URL=http://127.0.0.1:8080
|
|
|
-JAVA_MCP_BASE_PATH=/api/v1/agent/mcp
|
|
|
-```
|
|
|
-
|
|
|
-生产环境要求:
|
|
|
-
|
|
|
-- `AGENT_LLM_API_KEY`、`EMBEDDING_API_KEY` 只允许来自环境变量或密钥管理系统,不写入仓库。
|
|
|
-- `AGENT_LLM_MODEL` 必须显式配置;服务启动时不依赖 SDK 默认模型。
|
|
|
-- `AGENT_LLM_FAST_MODEL` 可选;如果为空,快速分类步骤复用 `AGENT_LLM_MODEL`。
|
|
|
-- `LANGGRAPH_CHECKPOINT_ENABLED=true` 时必须配置持久化 checkpointer;生产环境不使用内存 checkpoint。
|
|
|
-- `LANGGRAPH_MAX_STEPS` 必须限制在 3 到 12 之间,防止图循环失控。
|
|
|
-- `EMBEDDING_DIMENSIONS` 必须与 `aftersales_policy_chunk.embedding VECTOR(...)` 一致,不一致时服务启动失败。
|
|
|
-- 启动日志只打印脱敏配置摘要,例如 provider、base_url host、model、prompt_version、RAG 参数,不打印 API Key。
|
|
|
-
|
|
|
-### Python 新增组件
|
|
|
-
|
|
|
-`zsElectric-agent-service` 增加以下组件:
|
|
|
-
|
|
|
-```text
|
|
|
-app
|
|
|
-├─ core
|
|
|
-│ └─ settings.py # 读取 LLM、LangGraph、RAG、Java MCP 配置
|
|
|
-├─ llm
|
|
|
-│ ├─ client.py # OpenAI 兼容 chat/completions 客户端
|
|
|
-│ ├─ prompts.py # Prompt 模板和版本号
|
|
|
-│ └─ planner.py # plan_action 节点的结构化输出解析
|
|
|
-├─ graph
|
|
|
-│ ├─ state.py # AfterSalesAgentState
|
|
|
-│ ├─ nodes.py # detect_intent、retrieve_policy、query_order 等节点
|
|
|
-│ ├─ edges.py # 风险路由和错误路由
|
|
|
-│ └─ aftersales_graph.py # StateGraph 编译入口
|
|
|
-├─ checkpoint
|
|
|
-│ └─ store.py # PostgreSQL checkpointer 配置
|
|
|
-└─ evals
|
|
|
- └─ aftersales_cases.jsonl # 模型回归用例
|
|
|
-```
|
|
|
-
|
|
|
-`settings.py` 负责配置校验,启动时检查:
|
|
|
-
|
|
|
-- LLM 启用时 `AGENT_LLM_API_KEY`、`AGENT_LLM_BASE_URL`、`AGENT_LLM_MODEL` 必填。
|
|
|
-- `LANGGRAPH_MAX_STEPS` 必须大于 0 且不超过 12,防止状态图无限循环。
|
|
|
-- 生产环境必须启用持久化 checkpointer;只有单元测试允许内存 checkpointer。
|
|
|
-- `ZSELECTRIC_BOOT_URL` 必填且不能指向外部未知域名。
|
|
|
-- RAG 参数必须在安全范围内,例如 `RAG_TOP_K` 在 1 到 10 之间。
|
|
|
-
|
|
|
-`client.py` 只处理模型 HTTP 调用,不包含业务规则。它向 `{AGENT_LLM_BASE_URL}/chat/completions` 发送请求,统一返回:
|
|
|
-
|
|
|
-```json
|
|
|
-{
|
|
|
- "content": "...",
|
|
|
- "model": "actual-model-name",
|
|
|
- "provider": "openai",
|
|
|
- "usage": {
|
|
|
- "prompt_tokens": 123,
|
|
|
- "completion_tokens": 45,
|
|
|
- "total_tokens": 168
|
|
|
- }
|
|
|
-}
|
|
|
-```
|
|
|
-
|
|
|
-`planner.py` 负责把 `plan_action` 节点的模型输出解析成固定 JSON。如果模型返回非法 JSON、工具名不在 Python 本地白名单、参数缺少必填字段,LangGraph 进入规则降级或人工处理节点,不把非法工具请求传给 Java。
|
|
|
-
|
|
|
-### 工具计划结构
|
|
|
-
|
|
|
-LangGraph 的 `plan_action` 节点只生成工具计划,不直接生成最终客服回复。工具计划必须是结构化 JSON:
|
|
|
-
|
|
|
-```json
|
|
|
-{
|
|
|
- "intent": "refund_request",
|
|
|
- "risk_level": "HIGH",
|
|
|
- "need_order_lookup": true,
|
|
|
- "tool_calls": [
|
|
|
- {
|
|
|
- "tool_name": "retrieve_aftersales_policy",
|
|
|
- "params": {
|
|
|
- "issue_type": "refund_request",
|
|
|
- "keywords": "用户要求退款"
|
|
|
- }
|
|
|
- },
|
|
|
- {
|
|
|
- "tool_name": "query_charge_order",
|
|
|
- "params": {
|
|
|
- "order_no": "CD001"
|
|
|
- }
|
|
|
- },
|
|
|
- {
|
|
|
- "tool_name": "request_refund",
|
|
|
- "params": {
|
|
|
- "order_no": "CD001",
|
|
|
- "reason": "用户反馈充电失败要求退款"
|
|
|
- }
|
|
|
- }
|
|
|
- ],
|
|
|
- "customer_message_draft": "该问题涉及退款,需要先进入审批。"
|
|
|
-}
|
|
|
-```
|
|
|
-
|
|
|
-Python 本地白名单必须与 Java `AgentToolCatalog` 保持一致,首版允许的工具名为:
|
|
|
-
|
|
|
-```text
|
|
|
-query_charge_order
|
|
|
-query_charge_session
|
|
|
-retrieve_aftersales_policy
|
|
|
-create_aftersales_work_order
|
|
|
-request_refund
|
|
|
-request_compensation
|
|
|
-get_approval_status
|
|
|
-resume_after_approval
|
|
|
-write_agent_audit
|
|
|
-```
|
|
|
-
|
|
|
-LangGraph 只执行白名单中的工具,并且执行顺序受状态图控制:
|
|
|
-
|
|
|
-1. 总是先执行 `retrieve_aftersales_policy`。
|
|
|
-2. 请求中存在 `order_no`、`user_id` 或 `phone` 时,才允许执行订单查询。
|
|
|
-3. 高风险工具最多执行一个,且必须位于政策检索和必要订单查询之后。
|
|
|
-4. 模型不得直接调用 `resume_after_approval`;该工具只允许 `/api/v1/agent/resume/{approval_id}` 路由进入 `resume_after_approval` 子图后触发。
|
|
|
-
|
|
|
-### 主调用流程
|
|
|
-
|
|
|
-LangGraph 接入后的低风险流程:
|
|
|
-
|
|
|
-```text
|
|
|
-1. FastAPI /chat 接收 ChatRequest,生成 trace_id。
|
|
|
-2. FastAPI 调用 aftersales_graph,thread_id=trace_id。
|
|
|
-3. detect_intent 节点识别意图和问题类型。
|
|
|
-4. retrieve_policy 节点检索售后政策。
|
|
|
-5. query_order 节点按需调用 Java MCP 查询订单或充电记录。
|
|
|
-6. plan_action 节点调用 LLM 生成结构化工具计划。
|
|
|
-7. route_by_risk 节点校验 JSON schema、工具白名单、顺序、参数和最大工具次数。
|
|
|
-8. create_work_order 节点调用 Java MCP 创建售后工单。
|
|
|
-9. final_answer 节点把工具结果、政策证据、工单号交给 LLM 生成最终客服回复。
|
|
|
-10. Python 返回 AgentResponse,并把模型、checkpoint 和工具调用摘要写审计。
|
|
|
-```
|
|
|
-
|
|
|
-LangGraph 接入后的高风险流程:
|
|
|
-
|
|
|
-```text
|
|
|
-1. FastAPI /chat 接收退款或补偿诉求,生成 trace_id。
|
|
|
-2. LangGraph 执行 detect_intent、retrieve_policy、query_order、plan_action。
|
|
|
-3. route_by_risk 节点发现 request_refund 或 request_compensation。
|
|
|
-4. request_approval 节点调用 Java MCP。
|
|
|
-5. Java AgentToolOrchestrator 判断 HIGH 风险,创建 agent_approval 和 agent_pending_action。
|
|
|
-6. Java 冻结 tool_name、tool_version、params_json、params_hash、idempotency_key。
|
|
|
-7. Java 返回 pending_approval、approval_id、pending_action_id。
|
|
|
-8. LangGraph 将 approval_id 和 pending_action_id 写入 checkpoint。
|
|
|
-9. final_answer 节点不让 LLM 编造执行结果,只生成“已进入审批”的客服回复。
|
|
|
-10. 审批人通过 Java 审批接口 approve 或 reject。
|
|
|
-11. 前端或运营后台调用 Python /resume/{approval_id}。
|
|
|
-12. Python 从 checkpoint 找回 trace_id/thread_id 和审批前状态。
|
|
|
-13. resume_after_approval 子图只透传 approval_id 调 Java resume_after_approval。
|
|
|
-14. Java 校验审批状态、冻结参数 hash、幂等状态后执行冻结动作。
|
|
|
-15. final_answer 节点根据 Java 结果生成审批后的最终回复。
|
|
|
-```
|
|
|
-
|
|
|
-### Prompt 约束
|
|
|
-
|
|
|
-系统 Prompt 首版固定为 `aftersales-agent-v1`,核心规则:
|
|
|
-
|
|
|
-```text
|
|
|
-你是充电业务售后 Agent。
|
|
|
-你只能根据工具返回结果回答,不得编造订单、退款、补偿或审批状态。
|
|
|
-你必须先检索售后政策,再决定是否需要查询订单或创建工单。
|
|
|
-退款、补偿、账户权益变更属于高风险动作,只能调用 request_refund 或 request_compensation 发起审批。
|
|
|
-当 Java 工具返回 pending_approval 时,你必须明确告知需要人工审批,不能声称退款或补偿已经完成。
|
|
|
-当工具失败或证据不足时,你必须建议人工核查。
|
|
|
-你必须输出符合 JSON schema 的工具计划,不得输出额外解释。
|
|
|
-```
|
|
|
-
|
|
|
-最终回复 Prompt 与工具计划 Prompt 分开。最终回复只接收已执行的工具结果,不允许再产生新工具调用,避免模型在回复阶段绕过工具治理。
|
|
|
-
|
|
|
-### 降级策略
|
|
|
-
|
|
|
-LangGraph 节点或 LLM 调用失败时:
|
|
|
-
|
|
|
-- 如果 `AGENT_RULE_FALLBACK_ENABLED=true`,回退到当前规则编排:关键词判断退款/补偿,低风险建工单,高风险进审批。
|
|
|
-- 如果规则也无法判断,返回“当前智能判断不可用,请人工核查”,并写失败审计。
|
|
|
-- 任何节点失败都必须写入 `state.error` 和 `agent_audit_log`,不能跳过审计直接结束。
|
|
|
-
|
|
|
-LLM 输出非法工具计划时:
|
|
|
-
|
|
|
-- 记录 `tool_plan_parse_failed` 审计。
|
|
|
-- 不调用 Java MCP。
|
|
|
-- 尝试一次低温重试;重试仍失败则进入规则降级。
|
|
|
-
|
|
|
-Java MCP 工具失败时:
|
|
|
-
|
|
|
-- Python 不让 LLM 猜测结果。
|
|
|
-- 将错误、tool_name、trace_id 写审计。
|
|
|
-- 最终回复固定为需要人工核查。
|
|
|
-
|
|
|
-RAG 无命中时:
|
|
|
-
|
|
|
-- 允许查询订单和创建普通工单。
|
|
|
-- 不允许发起退款或补偿审批,除非用户明确表达退款/补偿诉求且订单证据完整。
|
|
|
-
|
|
|
-### 审计与可观测性
|
|
|
-
|
|
|
-每次 Agent run 必须写入以下审计信息:
|
|
|
-
|
|
|
-```text
|
|
|
-trace_id
|
|
|
-thread_id
|
|
|
-checkpoint_id
|
|
|
-graph_version
|
|
|
-graph_node
|
|
|
-prompt_version
|
|
|
-llm_provider
|
|
|
-llm_model
|
|
|
-fast_model
|
|
|
-embedding_model
|
|
|
-rag_top_k
|
|
|
-rag_min_score
|
|
|
-tool_plan_json
|
|
|
-tool_call_count
|
|
|
-token_usage_json
|
|
|
-fallback_used
|
|
|
-final_status
|
|
|
-```
|
|
|
-
|
|
|
-审计写入分两层:
|
|
|
-
|
|
|
-- Python 侧记录 LLM 输入输出摘要、工具计划、token usage、fallback 状态。
|
|
|
-- LangGraph checkpointer 保存图状态,但不替代审计日志。
|
|
|
-- Java 侧继续记录工具调用、审批创建、审批决策、冻结动作恢复和业务执行结果。
|
|
|
-
|
|
|
-两侧用同一个 `trace_id` 串联。高风险动作以 Java 审计为准,Python 审计不能替代 Java 审批和冻结动作记录。
|
|
|
-
|
|
|
-### 安全约束
|
|
|
-
|
|
|
-- LLM 不接触数据库连接串,不直连 Java 业务库。
|
|
|
-- LLM 不接触完整手机号、身份证、支付密钥等敏感字段;进入 prompt 前必须脱敏。
|
|
|
-- Python 本地工具白名单和 Java 工具白名单双重校验。
|
|
|
-- 高风险工具必须由 Java 判断风险并创建审批,不能只靠 Prompt 文案限制。
|
|
|
-- `resume_after_approval` 不允许从 LLM 工具计划触发,只能由 `/resume/{approval_id}` 入口触发。
|
|
|
-- 模型输出的金额、原因、证据只能作为申请参数,真实执行仍以 Java 冻结参数和审批状态为准。
|
|
|
-- 每次模型或 Prompt 版本变更,必须跑 eval 数据集后再进入生产。
|
|
|
-
|
|
|
-### 测试策略
|
|
|
-
|
|
|
-Python 新增测试:
|
|
|
-
|
|
|
-- LLM 配置缺失时启动失败。
|
|
|
-- LLM 工具计划 JSON 解析成功。
|
|
|
-- 非白名单工具被拒绝,且不调用 Java MCP。
|
|
|
-- 模型非法 JSON 时重试一次,然后规则降级。
|
|
|
-- 低风险意图生成 `create_aftersales_work_order`。
|
|
|
-- 退款意图生成 `request_refund`,Java 返回 `pending_approval` 后不生成“已退款”回复。
|
|
|
-- `/resume/{approval_id}` 只能调用 `resume_after_approval`,不走 LLM 工具计划。
|
|
|
-- 高风险审批返回后写入 LangGraph checkpoint。
|
|
|
-- `/resume/{approval_id}` 能从 checkpoint 找回审批前状态。
|
|
|
-- checkpoint 丢失时返回可解释错误,并提示人工核查。
|
|
|
-- token usage、model、prompt_version 写入审计。
|
|
|
-
|
|
|
-Java 现有测试保持:
|
|
|
-
|
|
|
-- 高风险工具创建审批和冻结动作。
|
|
|
-- 审批通过后按冻结参数恢复执行。
|
|
|
-- `params_hash` 篡改保护。
|
|
|
-- 重复恢复返回历史结果,避免重复执行。
|
|
|
-
|
|
|
-集成 eval 用例至少覆盖:
|
|
|
-
|
|
|
-```text
|
|
|
-充电失败咨询 -> 检索政策 + 查询订单 + 创建工单
|
|
|
-充电失败要求退款 -> 检索政策 + 查询订单 + 创建审批
|
|
|
-用户要求补偿余额 -> 检索政策 + 查询订单 + 创建审批
|
|
|
-只有手机号没有订单号 -> 查询最近订单后建单或进入人工核查
|
|
|
-政策无命中 -> 不自动退款/补偿
|
|
|
-Java MCP 超时 -> 返回人工核查
|
|
|
-审批通过后 resume -> 执行冻结动作
|
|
|
-审批拒绝后 resume -> 返回 rejected
|
|
|
-```
|
|
|
-
|
|
|
-## MCP 工具
|
|
|
-
|
|
|
-首版工具清单:
|
|
|
-
|
|
|
-```text
|
|
|
-query_charge_order(order_no | user_id | phone)
|
|
|
-query_charge_session(order_no)
|
|
|
-retrieve_aftersales_policy(issue_type, keywords)
|
|
|
-create_aftersales_work_order(order_no, issue_type, suggestion, evidence)
|
|
|
-request_refund(order_no, amount, reason, evidence)
|
|
|
-request_compensation(order_no, compensation_type, amount, reason)
|
|
|
-get_approval_status(approval_id)
|
|
|
-resume_after_approval(approval_id)
|
|
|
-write_agent_audit(trace_id, step, input, output, status)
|
|
|
-```
|
|
|
-
|
|
|
-风险等级:
|
|
|
-
|
|
|
-```text
|
|
|
-LOW:
|
|
|
- query_charge_order
|
|
|
- query_charge_session
|
|
|
- retrieve_aftersales_policy
|
|
|
- create_aftersales_work_order
|
|
|
- write_agent_audit
|
|
|
-
|
|
|
-HIGH:
|
|
|
- request_refund
|
|
|
- request_compensation
|
|
|
- resume_after_approval
|
|
|
-```
|
|
|
-
|
|
|
-低风险工具可以直接执行。高风险工具不直接退款或补偿,而是由 Java 创建审批单和冻结动作,返回 `approval_required`。
|
|
|
-
|
|
|
-## 数据表
|
|
|
-
|
|
|
-表按职责拆成两组:
|
|
|
-
|
|
|
-- 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_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
|
|
|
-
|
|
|
-记录 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工具注册表';
|
|
|
-```
|
|
|
-
|
|
|
-首版工具注册示例:
|
|
|
-
|
|
|
-```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
|
|
|
-
|
|
|
-记录高风险动作审批单。审批单只表达“是否允许执行”,不直接保存完整执行参数;完整执行参数保存在 `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审批后待恢复执行动作表';
|
|
|
-```
|
|
|
-
|
|
|
-恢复执行校验顺序:
|
|
|
-
|
|
|
-```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
|
|
|
-
|
|
|
-记录 Agent 全链路审计。审计表只追加,不更新业务含义,用于追踪、排障和责任回溯。
|
|
|
-
|
|
|
-```sql
|
|
|
-CREATE TABLE agent_audit_log (
|
|
|
- id BIGINT PRIMARY KEY AUTO_INCREMENT COMMENT '主键',
|
|
|
- trace_id VARCHAR(64) NOT NULL COMMENT 'Agent运行链路ID',
|
|
|
- thread_id VARCHAR(64) NULL COMMENT 'LangGraph线程ID,默认等于trace_id',
|
|
|
- checkpoint_id VARCHAR(128) NULL COMMENT 'LangGraph checkpoint 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 '事件类型',
|
|
|
- graph_version VARCHAR(64) NULL COMMENT 'LangGraph图版本',
|
|
|
- graph_node VARCHAR(128) NULL COMMENT '当前图节点',
|
|
|
- tool_name VARCHAR(128) NULL COMMENT '工具名',
|
|
|
- risk_level VARCHAR(16) NULL COMMENT '风险等级',
|
|
|
- model_provider VARCHAR(64) NULL COMMENT '模型供应商,如openai',
|
|
|
- model_name VARCHAR(128) NULL COMMENT '实际调用模型名',
|
|
|
- prompt_version VARCHAR(64) NULL COMMENT 'Prompt版本',
|
|
|
- token_usage_json JSON NULL COMMENT 'Token用量',
|
|
|
- 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_thread_time (thread_id, create_time),
|
|
|
- KEY idx_agent_audit_checkpoint (checkpoint_id),
|
|
|
- KEY idx_agent_audit_approval (approval_id),
|
|
|
- KEY idx_agent_audit_action (pending_action_id),
|
|
|
- KEY idx_agent_audit_graph_node (graph_node, create_time),
|
|
|
- KEY idx_agent_audit_tool_time (tool_name, create_time),
|
|
|
- KEY idx_agent_audit_model_time (model_name, create_time),
|
|
|
- KEY idx_agent_audit_status_time (status, create_time)
|
|
|
-) COMMENT='Agent全链路审计日志表';
|
|
|
-```
|
|
|
-
|
|
|
-审计步骤包括用户输入、LLM 配置快照、意图判断、RAG 命中文档、工具调用、审批创建、审批结果、恢复执行和最终回复。
|
|
|
-
|
|
|
-### aftersales_work_order
|
|
|
-
|
|
|
-记录低风险售后自动建单结果,也可以承接高风险审批后的售后处理记录。
|
|
|
-
|
|
|
-```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 模型,必须同步迁移分片表维度并重建向量索引。
|
|
|
-
|
|
|
-## 主流程
|
|
|
-
|
|
|
-低风险流程:
|
|
|
-
|
|
|
-```text
|
|
|
-1. FastAPI /chat 接收用户问题,生成 trace_id
|
|
|
-2. Agent 判断意图,例如“充电失败咨询”
|
|
|
-3. Agent 通过 RAG 检索售后政策
|
|
|
-4. Agent 通过 MCP 调 query_charge_order 和 query_charge_session
|
|
|
-5. Agent 生成处理建议
|
|
|
-6. Agent 通过 MCP 调 create_aftersales_work_order
|
|
|
-7. Java 创建工单并写 audit_log
|
|
|
-8. FastAPI 返回建议、工单号、trace_id
|
|
|
-```
|
|
|
-
|
|
|
-高风险流程:
|
|
|
-
|
|
|
-```text
|
|
|
-1. FastAPI /chat 接收用户问题,生成 trace_id
|
|
|
-2. Agent 判断意图,例如“充电失败要求退款”
|
|
|
-3. Agent 检索政策并查询订单、充电记录
|
|
|
-4. Agent 判断需要退款或补偿
|
|
|
-5. Agent 通过 MCP 调 request_refund 或 request_compensation
|
|
|
-6. Java 判断为 HIGH 风险,创建 agent_approval
|
|
|
-7. Java 创建 agent_pending_action,冻结 tool_name 和 params_json
|
|
|
-8. Java 返回 approval_required、approval_id、建议说明
|
|
|
-9. 人在 Swagger/Postman 调 Java 审批接口 approve 或 reject
|
|
|
-10. FastAPI /resume/{approval_id} 调 MCP resume_after_approval
|
|
|
-11. Java 校验审批和 pending_action,执行真实退款或补偿
|
|
|
-12. Java 写 audit_log 并返回工具结果
|
|
|
-13. Agent 生成最终客服回复
|
|
|
-```
|
|
|
-
|
|
|
-## Java 审批接口
|
|
|
-
|
|
|
-审批演示接口放在 Java:
|
|
|
-
|
|
|
-```text
|
|
|
-GET /api/v1/agent/approvals
|
|
|
-GET /api/v1/agent/approvals/{approval_id}
|
|
|
-POST /api/v1/agent/approvals/{approval_id}/approve
|
|
|
-POST /api/v1/agent/approvals/{approval_id}/reject
|
|
|
-```
|
|
|
-
|
|
|
-审批通过只改变审批状态,不直接执行退款或补偿。真实执行由 `resume_after_approval(approval_id)` 触发,保证“审批”和“执行恢复”边界清楚。
|
|
|
-
|
|
|
-## 错误处理
|
|
|
-
|
|
|
-```text
|
|
|
-RAG 无命中:
|
|
|
- 返回“政策依据不足”,只允许生成建议,不允许自动退款或补偿。
|
|
|
-
|
|
|
-订单不存在:
|
|
|
- 停止工具链路,写 audit_log,返回需要人工核查。
|
|
|
-
|
|
|
-MCP 工具失败:
|
|
|
- 记录 trace_id、tool_name、input、error,不让 Agent 猜测执行结果。
|
|
|
-
|
|
|
-审批过期:
|
|
|
- pending_action 标记 expired,需要重新发起申请。
|
|
|
-
|
|
|
-审批拒绝:
|
|
|
- resume_after_approval 返回 rejected,Agent 生成拒绝后的客服回复。
|
|
|
-
|
|
|
-参数被篡改:
|
|
|
- params_hash 校验失败,拒绝执行并写高危审计。
|
|
|
-
|
|
|
-重复恢复:
|
|
|
- pending_action 已执行则返回历史结果,保证幂等。
|
|
|
-```
|
|
|
-
|
|
|
-## 测试
|
|
|
-
|
|
|
-Java 测试:
|
|
|
-
|
|
|
-- 工具白名单测试。
|
|
|
-- 高低风险分级测试。
|
|
|
-- approval 和 pending_action 落库测试。
|
|
|
-- approve/reject 状态流转测试。
|
|
|
-- resume_after_approval 幂等测试。
|
|
|
-- params_hash 篡改保护测试。
|
|
|
-- audit_log 写入测试。
|
|
|
-
|
|
|
-Python FastAPI 测试:
|
|
|
-
|
|
|
-- `/chat` 低风险自动建工单。
|
|
|
-- `/chat` 高风险返回 `approval_required`。
|
|
|
-- `/resume/{approval_id}` 审批后恢复执行。
|
|
|
-- MCP client 工具调用失败。
|
|
|
-- RAG 无命中降级。
|
|
|
-- LLM 配置加载、默认模型、快速模型、embedding 维度一致性测试。
|
|
|
-- 模型变更后的 eval 数据集回归测试。
|
|
|
-
|
|
|
-集成演示:
|
|
|
-
|
|
|
-- 充电失败但只需普通售后处理,自动建工单。
|
|
|
-- 充电失败要求退款,进入审批。
|
|
|
-- 审批通过,resume 后执行退款或补偿。
|
|
|
-- 审批拒绝,Agent 生成拒绝说明。
|
|
|
-- 通过 trace_id 查询完整审计链路。
|
|
|
-
|
|
|
-## 里程碑
|
|
|
-
|
|
|
-### M1 Java MCP Server 与治理表
|
|
|
-
|
|
|
-交付 MCP endpoint、tool registry、approval、pending_action、audit_log,以及基础售后政策表。
|
|
|
-
|
|
|
-### M2 Python FastAPI Agent
|
|
|
-
|
|
|
-交付 FastAPI 服务、LangGraph 状态图、持久化 checkpoint、LLM 配置管理、MCP client、基础 RAG 检索、`/chat` 和 `/resume`。
|
|
|
-
|
|
|
-### M3 售后业务闭环
|
|
|
-
|
|
|
-交付订单查询、充电记录查询、政策检索、工单创建、退款/补偿审批和审批恢复。
|
|
|
-
|
|
|
-### M4 验证与演示
|
|
|
-
|
|
|
-交付种子数据、Swagger/Postman 脚本、eval case、README 跑通文档。
|
|
|
-
|
|
|
-## 验收标准
|
|
|
-
|
|
|
-- Python 服务不直连 Java 业务数据库。
|
|
|
-- Java 只暴露白名单 MCP tools,不把全部业务接口自动暴露给模型。
|
|
|
-- 低风险售后问题可以自动创建工单。
|
|
|
-- 高风险退款或补偿必须产生审批单和冻结动作。
|
|
|
-- 审批通过后可以按 `approval_id` 恢复执行。
|
|
|
-- 审批拒绝、审批过期、重复恢复、参数篡改都有确定结果。
|
|
|
-- 每次 Agent 运行都能通过 `trace_id` 查到完整审计链路。
|
|
|
-- 每次 Agent 运行都能在审计日志中看到实际模型、prompt 版本、RAG 参数和 token 用量。
|
|
|
-- 高风险审批暂停后,LangGraph checkpoint 能保存审批前状态,`/resume/{approval_id}` 能从 checkpoint 恢复上下文。
|
|
|
-- Embedding 模型维度与 pgvector 表结构不一致时,Python 服务启动失败。
|
|
|
-- 项目文档能解释 LangGraph 状态图、RAG、MCP Tool Calling、权限、审批、状态恢复、审计和测试案例。
|