docs: test reports + knowledge iteration design + PRDs
提交 OTP/RBAC/Tier0/Tier1/P0+P2 测试报告、方案A E2E 验证、知识库迭代设计(PRD/mermaid/html 原型)、项目状态看板更新; 根配置 docker-compose.yml/mkdocs.yml。
This commit is contained in:
@@ -0,0 +1,321 @@
|
||||
classDiagram
|
||||
direction TB
|
||||
|
||||
%% ── 枚举 ──────────────────────────────────────────
|
||||
class AudienceEnum {
|
||||
<<enumeration>>
|
||||
employee_quick_reply
|
||||
engineer_workguide
|
||||
}
|
||||
|
||||
class SuggestionStatusEnum {
|
||||
<<enumeration>>
|
||||
pending
|
||||
queued
|
||||
approved
|
||||
rejected
|
||||
applied
|
||||
graph_synced
|
||||
expired
|
||||
}
|
||||
|
||||
class GraphSyncStatusEnum {
|
||||
<<enumeration>>
|
||||
pending
|
||||
synced
|
||||
failed
|
||||
}
|
||||
|
||||
class SourceTypeEnum {
|
||||
<<enumeration>>
|
||||
annotation
|
||||
conversation
|
||||
ai_uncertain
|
||||
manual
|
||||
document_ragflow
|
||||
}
|
||||
|
||||
class RelationTypeEnum {
|
||||
<<enumeration>>
|
||||
LEADS_TO
|
||||
RELATES_TO
|
||||
CAN_JUMP_TO
|
||||
}
|
||||
|
||||
%% ── PostgreSQL 模型 ───────────────────────────────
|
||||
class KnowledgeSuggestion {
|
||||
+str id
|
||||
+str suggestion_type
|
||||
+SuggestionStatusEnum status
|
||||
+str title
|
||||
+str content
|
||||
+str category
|
||||
+List~str~ tags
|
||||
+SourceTypeEnum source_type
|
||||
+List~str~ source_data
|
||||
+str reason
|
||||
+str reject_reason
|
||||
+str reviewer_id
|
||||
+datetime reviewed_at
|
||||
+datetime created_at
|
||||
+datetime updated_at
|
||||
+float confidence
|
||||
+AudienceEnum audience
|
||||
+str issue
|
||||
+str action
|
||||
+RelationTypeEnum relation_type
|
||||
+str parent_issue
|
||||
+dict graph_meta
|
||||
+GraphSyncStatusEnum graph_sync_status
|
||||
+bool source_failed
|
||||
+datetime queued_at
|
||||
+datetime applied_at
|
||||
}
|
||||
|
||||
class KnowledgeBase {
|
||||
+str id
|
||||
+str category
|
||||
+str title
|
||||
+str content
|
||||
+List~str~ tags
|
||||
+int view_count
|
||||
+int use_count
|
||||
+GraphSyncStatusEnum graph_sync_status
|
||||
+str graph_node_uuid
|
||||
+datetime created_at
|
||||
+datetime updated_at
|
||||
}
|
||||
|
||||
class Conversation {
|
||||
+str id
|
||||
+str employee_id
|
||||
+str status
|
||||
+str session_type
|
||||
+datetime created_at
|
||||
}
|
||||
|
||||
%% ── Neo4j 图节点模型 ──────────────────────────────
|
||||
class IssueNode {
|
||||
+str uuid
|
||||
+str name
|
||||
+str category
|
||||
+datetime created_at
|
||||
+datetime updated_at
|
||||
+str source_suggestion_id
|
||||
}
|
||||
|
||||
class ActionNode {
|
||||
+str uuid
|
||||
+str name
|
||||
+str description
|
||||
+datetime created_at
|
||||
+str source_suggestion_id
|
||||
}
|
||||
|
||||
class InfoNode {
|
||||
+str uuid
|
||||
+str name
|
||||
+str value
|
||||
+List~str~ modifiers
|
||||
+datetime created_at
|
||||
}
|
||||
|
||||
class RelationEdge {
|
||||
+str from_uuid
|
||||
+str to_uuid
|
||||
+RelationTypeEnum type
|
||||
+int order
|
||||
+float weight
|
||||
}
|
||||
|
||||
%% ── Pydantic Schema ───────────────────────────────
|
||||
class KnowledgeSuggestionCreate {
|
||||
+str suggestion_type
|
||||
+str title
|
||||
+str content
|
||||
+str category
|
||||
+List~str~ tags
|
||||
+SourceTypeEnum source_type
|
||||
+List~str~ source_data
|
||||
+str reason
|
||||
+float confidence
|
||||
+AudienceEnum audience
|
||||
+str issue
|
||||
+str action
|
||||
+RelationTypeEnum relation_type
|
||||
+str parent_issue
|
||||
+dict graph_meta
|
||||
}
|
||||
|
||||
class KnowledgeSuggestionResponse {
|
||||
+str id
|
||||
+str suggestion_type
|
||||
+SuggestionStatusEnum status
|
||||
+str title
|
||||
+str content
|
||||
+str category
|
||||
+List~str~ tags
|
||||
+SourceTypeEnum source_type
|
||||
+float confidence
|
||||
+AudienceEnum audience
|
||||
+str issue
|
||||
+str action
|
||||
+RelationTypeEnum relation_type
|
||||
+str parent_issue
|
||||
+dict graph_meta
|
||||
+GraphSyncStatusEnum graph_sync_status
|
||||
+bool source_failed
|
||||
+datetime queued_at
|
||||
+datetime applied_at
|
||||
+datetime created_at
|
||||
}
|
||||
|
||||
class KnowledgeSuggestionApprove {
|
||||
<<request>>
|
||||
}
|
||||
|
||||
class KnowledgeSuggestionReject {
|
||||
<<request>>
|
||||
+str reject_reason
|
||||
}
|
||||
|
||||
class KnowledgeSuggestionRewrite {
|
||||
<<request>>
|
||||
+str title
|
||||
+str content
|
||||
+str category
|
||||
+List~str~ tags
|
||||
+float confidence
|
||||
+AudienceEnum audience
|
||||
+str issue
|
||||
+str action
|
||||
+RelationTypeEnum relation_type
|
||||
+str parent_issue
|
||||
}
|
||||
|
||||
class VisionRequest {
|
||||
<<request>>
|
||||
+str conversation_id
|
||||
+bytes image_file
|
||||
}
|
||||
|
||||
class VisionResponse {
|
||||
+str description
|
||||
+float confidence
|
||||
+dict metadata
|
||||
}
|
||||
|
||||
class RagflowIngestionRequest {
|
||||
<<request>>
|
||||
+str file_name
|
||||
+bytes file_data
|
||||
+str category_hint
|
||||
}
|
||||
|
||||
class RagflowIngestionResponse {
|
||||
+str task_id
|
||||
+str status
|
||||
+List~KnowledgeSuggestionResponse~ suggestions
|
||||
}
|
||||
|
||||
%% ── 服务类 ────────────────────────────────────────
|
||||
class KnowledgeIterationService {
|
||||
-str ai_api_url
|
||||
-str ai_api_key
|
||||
+analyze_and_generate_suggestions(db, days) dict
|
||||
-_analyze_annotation_data(db, days) dict
|
||||
-_analyze_conversation_data(db, days) dict
|
||||
-_generate_update_suggestion(db, source_type, source_data, reason) KnowledgeSuggestion
|
||||
-_generate_new_faq_suggestion(db, source_type, source_data, reason) KnowledgeSuggestion
|
||||
-_check_existing_suggestion(db, source_id) bool
|
||||
-_auto_tag_audience(db, source_type, source_data) AudienceEnum
|
||||
+approve_suggestion(db, suggestion_id, reviewer_id) KnowledgeSuggestion
|
||||
+reject_suggestion(db, suggestion_id, reviewer_id, reason) KnowledgeSuggestion
|
||||
+rewrite_suggestion(db, suggestion_id, reviewer_id, data) KnowledgeSuggestion
|
||||
+queue_suggestion(db, suggestion_id) KnowledgeSuggestion
|
||||
+dequeue_approve(db, suggestion_id, reviewer_id) KnowledgeSuggestion
|
||||
+sync_to_neo4j(neo4j_client, suggestion) bool
|
||||
+get_suggestion_stats(db) dict
|
||||
+get_queue_stats(db) dict
|
||||
}
|
||||
|
||||
class WingmanService {
|
||||
-str api_url
|
||||
-str api_key
|
||||
-int timeout
|
||||
-httpx.AsyncClient _client
|
||||
+generate_draft(conversation_id, messages, db) dict
|
||||
+generate_summary(conversation_id, messages) dict
|
||||
+suggest_tags(conversation_id, messages, existing_tags) dict
|
||||
+generate_knowledge_suggestion(context_messages) dict
|
||||
-_build_context_messages(messages, system_prompt) list
|
||||
-_call_wingman_api(context_messages) str
|
||||
-_parse_json_response(content, default) dict
|
||||
-_estimate_confidence(content) float
|
||||
+close()
|
||||
}
|
||||
|
||||
class Neo4jClient {
|
||||
-str uri
|
||||
-str user
|
||||
-str password
|
||||
-str database
|
||||
-AsyncDriver _driver
|
||||
+initialize()
|
||||
+close()
|
||||
+create_issue_node(issue) IssueNode
|
||||
+create_action_node(action) ActionNode
|
||||
+create_relation(from_uuid, to_uuid, rel) RelationEdge
|
||||
+merge_issue(name, category, props) IssueNode
|
||||
+merge_action(name, props) ActionNode
|
||||
+find_issue_by_name(name) IssueNode
|
||||
+find_related_issues(uuid, rel_type) List~IssueNode~
|
||||
+execute_write_query(cypher, params) result
|
||||
+execute_read_query(cypher, params) result
|
||||
+health_check() bool
|
||||
}
|
||||
|
||||
class VisionService {
|
||||
-str dify_vision_api_url
|
||||
-str dify_vision_api_key
|
||||
-str local_vision_model
|
||||
+analyze_screenshot(image_bytes, conversation_id) VisionResponse
|
||||
-_preprocess_image(image_bytes) bytes
|
||||
-_call_vision_workflow(processed_image) dict
|
||||
+inject_to_conversation_context(description, conversation_id)
|
||||
}
|
||||
|
||||
class RagflowIngestionService {
|
||||
-RagflowClient client
|
||||
+upload_and_process(file_data, file_name, category_hint) RagflowIngestionResponse
|
||||
+poll_processing_status(task_id) str
|
||||
+create_suggestions_from_result(result) List~KnowledgeSuggestion~
|
||||
}
|
||||
|
||||
%% ── 关系 ──────────────────────────────────────────
|
||||
KnowledgeSuggestion ..> AudienceEnum : uses
|
||||
KnowledgeSuggestion ..> SuggestionStatusEnum : uses
|
||||
KnowledgeSuggestion ..> SourceTypeEnum : uses
|
||||
KnowledgeSuggestion ..> RelationTypeEnum : uses
|
||||
KnowledgeSuggestion ..> GraphSyncStatusEnum : uses
|
||||
KnowledgeBase ..> GraphSyncStatusEnum : uses
|
||||
|
||||
KnowledgeIterationService --> WingmanService : 调用 AI 生成
|
||||
KnowledgeIterationService --> Neo4jClient : 写图同步
|
||||
KnowledgeIterationService --> KnowledgeSuggestion : 管理
|
||||
KnowledgeIterationService --> KnowledgeBase : 落库
|
||||
|
||||
KnowledgeSuggestionCreate --> KnowledgeSuggestion : 创建
|
||||
KnowledgeSuggestionResponse --> KnowledgeSuggestion : 返回
|
||||
KnowledgeSuggestionApprove --> KnowledgeSuggestion : 状态变更
|
||||
KnowledgeSuggestionReject --> KnowledgeSuggestion : 状态变更
|
||||
KnowledgeSuggestionRewrite --> KnowledgeSuggestion : 内容更新
|
||||
|
||||
IssueNode <--> RelationEdge : 关联
|
||||
ActionNode <--> RelationEdge : 关联
|
||||
Neo4jClient --> IssueNode : CRUD
|
||||
Neo4jClient --> ActionNode : CRUD
|
||||
Neo4jClient --> RelationEdge : 管理
|
||||
|
||||
VisionService --> WingmanService : 复用 _call_wingman_api 范式
|
||||
RagflowIngestionService --> KnowledgeSuggestion : 产出
|
||||
@@ -0,0 +1,106 @@
|
||||
sequenceDiagram
|
||||
actor 员工 as 👤 员工
|
||||
actor 坐席 as 👤 坐席
|
||||
actor 训练师 as 👤 AI训练师
|
||||
participant H5 as H5前端
|
||||
participant AgentFE as 坐席控制台
|
||||
participant API as FastAPI
|
||||
participant KIS as KnowledgeIterationService
|
||||
participant WS as WingmanService
|
||||
participant Dify as Dify AI Platform
|
||||
participant DB as PostgreSQL
|
||||
participant NEO as Neo4jClient
|
||||
participant N4J as Neo4j 图数据库
|
||||
|
||||
Note over 员工,N4J: === 通道 A: 会话→Dify→建议 ===
|
||||
|
||||
员工->>H5: 发送 IT 问题(如"VPN 连不上")
|
||||
H5->>API: POST /api/h5/conversations/current/messages
|
||||
API->>Dify: 调用 Dify Agent(员工端 AI)
|
||||
Dify-->>API: AI 回复 + confidence: 0.62
|
||||
API-->>H5: 返回消息(含 confidence)
|
||||
|
||||
alt confidence < 0.7(门控触发)
|
||||
H5->>H5: 渲染「转人工」卡片 + 已收集上下文
|
||||
员工->>H5: 点击「转人工」
|
||||
H5->>API: POST 转人工请求(附上下文快照)
|
||||
end
|
||||
|
||||
Note over API,N4J: === 会话结束后触发分析 ===
|
||||
|
||||
API->>KIS: analyze_and_generate_suggestions(db, days=7)
|
||||
KIS->>DB: 查询过去N天转人工/标注为无用 的会话
|
||||
DB-->>KIS: 返回候选数据
|
||||
|
||||
loop 每个候选会话
|
||||
KIS->>WS: generate_knowledge_suggestion(context_messages)
|
||||
WS->>WS: _build_context_messages(messages, KN_SUGGEST_PROMPT)
|
||||
WS->>Dify: _call_wingman_api(context_messages)
|
||||
Dify-->>WS: 结构化 JSON(title/content/category/tags/confidence/issue/action/relation)
|
||||
WS->>WS: _parse_json_response(content, default)
|
||||
WS-->>KIS: dict {title, content, category, confidence, issue, action, ...}
|
||||
|
||||
KIS->>KIS: _auto_tag_audience(source_type, source_data)
|
||||
Note over KIS: source_session_type=="employee" → employee_quick_reply<br/>source_session_type=="engineer" → engineer_workguide
|
||||
|
||||
KIS->>DB: INSERT KnowledgeSuggestion(status=pending, 含图字段)
|
||||
end
|
||||
|
||||
KIS->>API: 返回分析结果统计
|
||||
|
||||
Note over 坐席,N4J: === D7 内联审批 ===
|
||||
|
||||
坐席->>AgentFE: 浏览会话中的提案卡片
|
||||
AgentFE->>API: GET /api/admin/knowledge-iteration/suggestions?status=pending
|
||||
API-->>AgentFE: 提案列表(含拓扑预览、confidence、audience)
|
||||
|
||||
alt 坐席选择「内联审批」
|
||||
坐席->>AgentFE: 在会话内联卡片点击「采纳」
|
||||
AgentFE->>API: POST /api/admin/knowledge-iteration/suggestions/{id}/approve
|
||||
Note over API: 鉴权: require_admin / require_trainer
|
||||
|
||||
API->>KIS: approve_suggestion(db, suggestion_id, reviewer_id)
|
||||
KIS->>DB: UPDATE status=approved, reviewed_at=now()
|
||||
KIS->>DB: INSERT KnowledgeBase (含 graph_sync_status=pending)
|
||||
KIS->>DB: UPDATE suggestion status=applied
|
||||
|
||||
Note over KIS,N4J: D1 解读2·直接写图
|
||||
|
||||
KIS->>NEO: merge_issue(issue_name, category, props)
|
||||
NEO->>N4J: MERGE (i:Issue {name: $name}) ON CREATE SET i+=$props
|
||||
N4J-->>NEO: IssueNode(uuid=...)
|
||||
|
||||
KIS->>NEO: merge_action(action_name, props)
|
||||
NEO->>N4J: MERGE (a:Action {name: $name}) ON CREATE SET a+=$props
|
||||
N4J-->>NEO: ActionNode(uuid=...)
|
||||
|
||||
KIS->>NEO: create_relation(issue_uuid, action_uuid, rel)
|
||||
NEO->>N4J: MATCH (i),(a) WHERE i.uuid=$i AND a.uuid=$a CREATE (i)-[:LEADS_TO {order:$o,weight:$w}]->(a)
|
||||
|
||||
KIS->>DB: UPDATE suggestion graph_sync_status=synced
|
||||
KIS->>DB: UPDATE KnowledgeBase graph_sync_status=synced, graph_node_uuid=...
|
||||
|
||||
API-->>AgentFE: 200 OK(含更新后提案)
|
||||
else 坐席选择「驳回」
|
||||
AgentFE->>API: POST /api/admin/knowledge-iteration/suggestions/{id}/reject {reject_reason}
|
||||
API->>KIS: reject_suggestion(db, id, reviewer_id, reason)
|
||||
KIS->>DB: UPDATE status=rejected
|
||||
API-->>AgentFE: 200 OK
|
||||
else 坐席选择「改写」
|
||||
AgentFE->>API: POST /api/admin/knowledge-iteration/suggestions/{id}/rewrite {title, content, ...}
|
||||
API->>KIS: rewrite_suggestion(db, id, reviewer_id, data)
|
||||
KIS->>DB: UPDATE title/content/category/tags/confidence...
|
||||
KIS->>DB: UPDATE status=pending(重新审批)
|
||||
API-->>AgentFE: 200 OK
|
||||
end
|
||||
|
||||
Note over 训练师,N4J: === D7 独立队列(未处理提案) ===
|
||||
|
||||
训练师->>AgentFE: 打开独立队列页
|
||||
AgentFE->>API: GET /api/admin/approval-queue/queued?status=pending
|
||||
Note over API: 未处理的=SESSION_CLOSED 后仍 pending 的提案<br/>或手动标记 queued
|
||||
API-->>AgentFE: 队列列表
|
||||
|
||||
训练师->>AgentFE: 审核队列中的提案
|
||||
AgentFE->>API: POST /api/admin/approval-queue/{id}/dequeue-approve
|
||||
Note over API,N4J: 同 approve_suggestion 流程→写图
|
||||
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user