Sprint 1-3 Completed (Backend + Frontend): Backend (Sprint 1-2): - Implement 5-layer Agent framework (Query->Planner->Executor->Tools->Reflection) - Create agent_schema with 6 tables (agent_definitions, stages, prompts, sessions, traces, reflexion_rules) - Create protocol_schema with 2 tables (protocol_contexts, protocol_generations) - Implement Protocol Agent core services (Orchestrator, ContextService, PromptBuilder) - Integrate LLM service adapter (DeepSeek/Qwen/GPT-5/Claude) - 6 API endpoints with full authentication - 10/10 API tests passed Frontend (Sprint 3): - Add Protocol Agent entry in AgentHub (indigo theme card) - Implement ProtocolAgentPage with 3-column layout - Collapsible sidebar (Gemini style, 48px <-> 280px) - StatePanel with 5 stage cards (scientific_question, pico, study_design, sample_size, endpoints) - ChatArea with sync button and action cards integration - 100% prototype design restoration (608 lines CSS) - Detailed endpoints structure: baseline, exposure, outcomes, confounders Features: - 5-stage dialogue flow for research protocol design - Conversation-driven interaction with sync-to-protocol button - Real-time context state management - One-click protocol generation button (UI ready, backend pending) Database: - agent_schema: 6 tables for reusable Agent framework - protocol_schema: 2 tables for Protocol Agent - Seed data: 1 agent + 5 stages + 9 prompts + 4 reflexion rules Code Stats: - Backend: 13 files, 4338 lines - Frontend: 14 files, 2071 lines - Total: 27 files, 6409 lines Status: MVP core functionality completed, pending frontend-backend integration testing Next: Sprint 4 - One-click protocol generation + Word export
26 KiB
26 KiB
Protocol Agent 数据库设计
版本:v1.0
创建日期:2026-01-24
一、Schema规划
┌─────────────────────────────────────────────────────────────────────────┐
│ 数据库Schema架构 │
├─────────────────────────────────────────────────────────────────────────┤
│ │
│ agent_schema (通用Agent框架 - 可复用) │
│ ├── agent_configs Agent配置表 │
│ ├── agent_stages 阶段配置表 │
│ ├── agent_tools 工具注册表 │
│ ├── action_cards Action Card配置表 │
│ ├── reflexion_rules 反思规则表 │
│ ├── agent_sessions Agent会话表 │
│ └── agent_traces 追踪日志表 │
│ │
│ protocol_schema (研究方案Agent专用) │
│ ├── protocol_contexts 研究方案上下文表 │
│ ├── protocol_versions 版本历史表 │
│ └── protocol_exports 导出记录表 │
│ │
│ knowledge_schema (知识库 - Phase 2) │
│ ├── knowledge_docs 知识文档表 │
│ ├── knowledge_chunks 知识块表 │
│ └── knowledge_embeddings 向量嵌入表 │
│ │
│ aia_schema (已有 - 复用) │
│ ├── conversations 对话表 │
│ └── messages 消息表 │
│ │
│ capability_schema (已有 - 复用) │
│ └── prompt_templates Prompt模板表 │
│ │
└─────────────────────────────────────────────────────────────────────────┘
二、agent_schema - 通用Agent框架表
2.1 agent_configs (Agent配置表)
/// Agent配置表 - 定义每个Agent的基础信息
model AgentConfig {
id String @id @default(uuid())
agentId String @unique @map("agent_id")
agentName String @map("agent_name")
agentDescription String? @map("agent_description")
baseSystemPrompt String @map("base_system_prompt") @db.Text
// 全局配置
toneOfVoice String? @map("tone_of_voice")
globalKnowledge String[] @map("global_knowledge")
memoryStrategy String @default("full") @map("memory_strategy")
maxHistoryTurns Int @default(20) @map("max_history_turns")
// LLM配置
defaultModel String @default("deepseek-v3") @map("default_model")
temperature Float @default(0.7)
maxTokens Int @default(4096) @map("max_tokens")
// 状态
isActive Boolean @default(true) @map("is_active")
version Int @default(1)
createdAt DateTime @default(now()) @map("created_at")
updatedAt DateTime @updatedAt @map("updated_at")
// 关联
stages AgentStage[] @relation("AgentConfigStages")
tools AgentTool[] @relation("AgentConfigTools")
reflexionRules ReflexionRule[] @relation("AgentConfigReflexion")
@@index([agentId, isActive])
@@map("agent_configs")
@@schema("agent_schema")
}
字段说明:
| 字段 | 类型 | 说明 |
|---|---|---|
| agentId | string | Agent唯一标识,如 protocol_agent |
| baseSystemPrompt | text | 基础系统Prompt |
| toneOfVoice | string | 语气风格,如"专业但亲和" |
| memoryStrategy | string | 记忆策略:full/sliding_window/summary |
| maxHistoryTurns | int | 最大保留对话轮数 |
2.2 agent_stages (阶段配置表)
/// 阶段配置表 - 定义Agent的各个阶段
model AgentStage {
id String @id @default(uuid())
agentConfigId String @map("agent_config_id")
stageId String @map("stage_id")
stageName String @map("stage_name")
stageOrder Int @map("stage_order")
// Prompt配置
instruction String @db.Text
extractionSchema Json @map("extraction_schema")
completionCriteria String? @map("completion_criteria") @db.Text
// 流转配置
nextStageId String? @map("next_stage_id")
transitionMode String @default("user_confirm") @map("transition_mode")
transitionCondition Json? @map("transition_condition")
// 工具配置
availableToolIds String[] @map("available_tool_ids")
isActive Boolean @default(true) @map("is_active")
createdAt DateTime @default(now()) @map("created_at")
updatedAt DateTime @updatedAt @map("updated_at")
agentConfig AgentConfig @relation("AgentConfigStages", fields: [agentConfigId], references: [id], onDelete: Cascade)
actionCards ActionCard[] @relation("StageActionCards")
@@unique([agentConfigId, stageId])
@@index([agentConfigId, stageOrder])
@@map("agent_stages")
@@schema("agent_schema")
}
extractionSchema 示例 (PICO阶段):
{
"type": "object",
"properties": {
"P": {
"type": "object",
"properties": {
"value": { "type": "string", "description": "研究人群" },
"details": { "type": "string" },
"confidence": { "type": "number" }
}
},
"I": { ... },
"C": { ... },
"O": { ... }
}
}
2.3 agent_tools (工具注册表)
/// 工具注册表 - 定义Agent可用的工具
model AgentTool {
id String @id @default(uuid())
agentConfigId String? @map("agent_config_id")
toolId String @unique @map("tool_id")
toolName String @map("tool_name")
toolDescription String @map("tool_description") @db.Text
toolType String @map("tool_type")
// Function定义
functionSchema Json? @map("function_schema")
// 执行配置
handlerType String @map("handler_type")
handlerConfig Json @map("handler_config")
// 权限和限制
requiresAuth Boolean @default(false) @map("requires_auth")
rateLimit Int? @map("rate_limit")
timeout Int @default(30000)
isActive Boolean @default(true) @map("is_active")
createdAt DateTime @default(now()) @map("created_at")
updatedAt DateTime @updatedAt @map("updated_at")
agentConfig AgentConfig? @relation("AgentConfigTools", fields: [agentConfigId], references: [id], onDelete: Cascade)
@@index([agentConfigId, isActive])
@@index([toolType])
@@map("agent_tools")
@@schema("agent_schema")
}
toolType 枚举值:
internal: 内部计算工具external: 外部API工具deep_link: 深度链接跳转rag: RAG知识检索
2.4 action_cards (Action Card配置表)
/// Action Card配置表
model ActionCard {
id String @id @default(uuid())
stageId String @map("stage_id")
cardId String @map("card_id")
title String
description String? @db.Text
iconType String? @map("icon_type")
// 触发配置
triggerType String @map("trigger_type")
triggerCondition Json? @map("trigger_condition")
// Action配置
actionType String @map("action_type")
actionPayload Json @map("action_payload")
// 回调配置
onCompleteAction String? @map("on_complete_action")
resultMapping Json? @map("result_mapping")
displayOrder Int @default(0) @map("display_order")
isActive Boolean @default(true) @map("is_active")
createdAt DateTime @default(now()) @map("created_at")
updatedAt DateTime @updatedAt @map("updated_at")
stage AgentStage @relation("StageActionCards", fields: [stageId], references: [id], onDelete: Cascade)
@@unique([stageId, cardId])
@@map("action_cards")
@@schema("agent_schema")
}
actionPayload 示例 (Deep Link):
{
"targetAgent": "sample_calculator",
"targetPath": "/aia/sample-calculator",
"params": {
"studyType": "{{studyDesign.type}}",
"primaryEndpoint": "{{endpoints.primary[0].name}}"
},
"openMode": "modal"
}
2.5 reflexion_rules (反思规则表)
/// Reflexion规则表
model ReflexionRule {
id String @id @default(uuid())
agentConfigId String @map("agent_config_id")
ruleId String @map("rule_id")
ruleName String @map("rule_name")
ruleDescription String? @map("rule_description") @db.Text
// 触发配置
triggerStageId String? @map("trigger_stage_id")
triggerTiming String @map("trigger_timing")
// 规则内容
ruleType String @map("rule_type")
promptTemplate String? @map("prompt_template") @db.Text
ruleLogic Json? @map("rule_logic")
// 失败处理
severity String @default("warning")
failureAction String @map("failure_action")
isActive Boolean @default(true) @map("is_active")
priority Int @default(0)
createdAt DateTime @default(now()) @map("created_at")
updatedAt DateTime @updatedAt @map("updated_at")
agentConfig AgentConfig @relation("AgentConfigReflexion", fields: [agentConfigId], references: [id], onDelete: Cascade)
@@unique([agentConfigId, ruleId])
@@index([triggerStageId, triggerTiming])
@@map("reflexion_rules")
@@schema("agent_schema")
}
2.6 agent_sessions (Agent会话表)
/// Agent会话表 - 扩展conversation的Agent状态
model AgentSession {
id String @id @default(uuid())
conversationId String @unique @map("conversation_id")
agentId String @map("agent_id")
userId String @map("user_id")
// 状态管理
currentStageId String @map("current_stage_id")
stageStatus String @default("in_progress") @map("stage_status")
// 元数据
sessionMetadata Json? @map("session_metadata")
// 生命周期
startedAt DateTime @default(now()) @map("started_at")
lastActiveAt DateTime @default(now()) @map("last_active_at")
completedAt DateTime? @map("completed_at")
createdAt DateTime @default(now()) @map("created_at")
updatedAt DateTime @updatedAt @map("updated_at")
@@index([agentId, userId])
@@index([currentStageId])
@@index([lastActiveAt])
@@map("agent_sessions")
@@schema("agent_schema")
}
2.7 agent_traces (追踪日志表)
/// Agent追踪日志表 - 可观测性
model AgentTrace {
id String @id @default(uuid())
conversationId String @map("conversation_id")
messageId String? @map("message_id")
traceId String @map("trace_id")
// 步骤信息
stepType String @map("step_type")
stepOrder Int @map("step_order")
// 输入输出
stepInput Json? @map("step_input")
stepOutput Json? @map("step_output")
// LLM信息
llmModel String? @map("llm_model")
llmPromptTokens Int? @map("llm_prompt_tokens")
llmCompletionTokens Int? @map("llm_completion_tokens")
// 性能
durationMs Int? @map("duration_ms")
// 状态
status String @default("success")
errorMessage String? @map("error_message") @db.Text
createdAt DateTime @default(now()) @map("created_at")
@@index([conversationId, traceId])
@@index([traceId, stepOrder])
@@index([createdAt])
@@index([stepType, status])
@@map("agent_traces")
@@schema("agent_schema")
}
三、protocol_schema - 研究方案专用表
3.1 protocol_contexts (研究方案上下文表)
/// Protocol上下文表 - 研究方案的结构化数据存储
model ProtocolContext {
id String @id @default(uuid())
sessionId String @unique @map("session_id")
conversationId String @unique @map("conversation_id")
userId String @map("user_id")
// ===== Phase 1 核心字段 =====
/// 阶段1:科学问题
scientificQuestion Json? @map("scientific_question") @db.JsonB
/// 阶段2:PICO
pico Json? @db.JsonB
/// 阶段3:研究设计
studyDesign Json? @map("study_design") @db.JsonB
/// 阶段4:样本量
sampleSize Json? @map("sample_size") @db.JsonB
/// 阶段5:终点指标
endpoints Json? @db.JsonB
// ===== Phase 2 扩展字段 =====
/// 入选标准
inclusionCriteria Json? @map("inclusion_criteria") @db.JsonB
/// 排除标准
exclusionCriteria Json? @map("exclusion_criteria") @db.JsonB
/// 统计分析计划
statisticalPlan Json? @map("statistical_plan") @db.JsonB
// ===== Phase 3 扩展字段 =====
/// 伦理考量
ethicsConsiderations Json? @map("ethics_considerations") @db.JsonB
/// 研究时间线
timeline Json? @db.JsonB
/// 预算估算
budget Json? @db.JsonB
// ===== 元数据 =====
/// 总体进度 0-100
overallProgress Float @default(0) @map("overall_progress")
/// 已完成阶段
completedStages String[] @map("completed_stages")
/// 版本号
version Int @default(1)
createdAt DateTime @default(now()) @map("created_at")
updatedAt DateTime @updatedAt @map("updated_at")
versions ProtocolVersion[] @relation("ProtocolContextVersions")
@@index([userId])
@@index([conversationId])
@@map("protocol_contexts")
@@schema("protocol_schema")
}
各字段JSON结构:
scientificQuestion
{
"content": "探究新型降糖药X对2型糖尿病患者的降糖效果及安全性",
"clinicalBackground": "2型糖尿病患病率逐年上升...",
"researchGap": "目前缺乏针对中国人群的大规模临床研究",
"significance": "填补该领域空白,为临床用药提供依据",
"confidence": 0.95,
"sourceMessageIds": ["msg_123", "msg_125"],
"lastUpdated": "2026-01-24T10:30:00Z"
}
pico
{
"P": {
"value": "2型糖尿病患者",
"details": "年龄18-70岁,HbA1c 7.0-10.0%",
"confidence": 0.9
},
"I": {
"value": "新型降糖药X",
"details": "口服,每日一次,剂量10mg",
"confidence": 0.95
},
"C": {
"value": "二甲双胍",
"details": "口服,每日两次,剂量500mg",
"confidence": 0.88
},
"O": {
"value": "HbA1c变化",
"details": "治疗12周后HbA1c相对基线的变化值",
"confidence": 0.92
},
"sourceMessageIds": ["msg_130", "msg_132"],
"lastUpdated": "2026-01-24T11:00:00Z"
}
studyDesign
{
"type": "RCT",
"phase": "III",
"blinding": "双盲",
"randomization": "中心随机",
"allocationRatio": "1:1",
"controlType": "阳性对照",
"multiCenter": true,
"centerCount": 20,
"duration": "12周治疗期 + 4周随访期",
"confidence": 0.9,
"sourceMessageIds": ["msg_140"],
"lastUpdated": "2026-01-24T11:30:00Z"
}
sampleSize
{
"total": 500,
"perGroup": 250,
"groups": 2,
"calculationMethod": "优效性检验",
"assumptions": {
"alpha": 0.05,
"power": 0.8,
"effectSize": 0.5,
"dropoutRate": 0.15,
"standardDeviation": 1.2
},
"justification": "基于既往研究,预期效应量0.5%...",
"toolUsed": "sample_calculator",
"confidence": 0.95,
"sourceMessageIds": ["msg_150"],
"lastUpdated": "2026-01-24T12:00:00Z"
}
endpoints
{
"primary": [{
"name": "HbA1c变化值",
"definition": "治疗12周后HbA1c相对基线的变化",
"measurementMethod": "高效液相色谱法",
"timePoint": "第12周",
"analysisMethod": "ANCOVA"
}],
"secondary": [{
"name": "空腹血糖",
"definition": "...",
"measurementMethod": "...",
"timePoint": "第4、8、12周"
}],
"safety": [{
"name": "低血糖发生率",
"definition": "血糖<3.9mmol/L的事件"
}],
"exploratory": [],
"sourceMessageIds": ["msg_160", "msg_162"],
"lastUpdated": "2026-01-24T12:30:00Z"
}
3.2 protocol_versions (版本历史表)
/// Protocol版本历史表 - 支持回溯
model ProtocolVersion {
id String @id @default(uuid())
contextId String @map("context_id")
version Int
changeType String @map("change_type")
changedFields String[] @map("changed_fields")
previousSnapshot Json @map("previous_snapshot") @db.JsonB
changeReason String? @map("change_reason")
changedBy String @map("changed_by")
createdAt DateTime @default(now()) @map("created_at")
context ProtocolContext @relation("ProtocolContextVersions", fields: [contextId], references: [id], onDelete: Cascade)
@@unique([contextId, version])
@@index([contextId, createdAt])
@@map("protocol_versions")
@@schema("protocol_schema")
}
3.3 protocol_generations (研究方案生成表)
/// Protocol生成记录表 - 一键生成研究方案
model ProtocolGeneration {
id String @id @default(uuid())
contextId String @map("context_id")
userId String @map("user_id")
// 生成内容
generatedContent String @map("generated_content") @db.Text // 生成的研究方案全文
contentVersion Int @default(1) @map("content_version") // 版本号(重新生成时递增)
// 使用的Prompt和参数
promptUsed String @map("prompt_used") @db.Text
generationParams Json? @map("generation_params") @db.JsonB // 生成参数
// LLM调用信息
modelUsed String @map("model_used")
tokensUsed Int? @map("tokens_used")
durationMs Int? @map("duration_ms")
// 导出记录
wordFileKey String? @map("word_file_key") // Word文件OSS Key
pdfFileKey String? @map("pdf_file_key") // PDF文件OSS Key
lastExportedAt DateTime? @map("last_exported_at")
// 用户编辑(如有)
userEditedContent String? @map("user_edited_content") @db.Text
isEdited Boolean @default(false) @map("is_edited")
status String @default("completed") // generating, completed, failed
errorMessage String? @map("error_message")
createdAt DateTime @default(now()) @map("created_at")
updatedAt DateTime @updatedAt @map("updated_at")
@@index([contextId])
@@index([userId, createdAt])
@@map("protocol_generations")
@@schema("protocol_schema")
}
字段说明:
| 字段 | 类型 | 说明 |
|---|---|---|
| generatedContent | text | LLM生成的完整研究方案 |
| contentVersion | int | 版本号,重新生成时递增 |
| promptUsed | text | 使用的Prompt(便于复现和调试) |
| userEditedContent | text | 用户编辑后的内容(可选) |
| wordFileKey | string | 导出的Word文件在OSS中的Key |
3.4 protocol_exports (导出记录表)
/// Protocol导出记录表
model ProtocolExport {
id String @id @default(uuid())
contextId String @map("context_id")
userId String @map("user_id")
exportType String @map("export_type")
exportVersion Int @map("export_version")
fileKey String? @map("file_key")
status String @default("pending")
errorMessage String? @map("error_message")
createdAt DateTime @default(now()) @map("created_at")
completedAt DateTime? @map("completed_at")
@@index([contextId])
@@index([userId, createdAt])
@@map("protocol_exports")
@@schema("protocol_schema")
}
四、knowledge_schema - 知识库表 (Phase 2)
4.1 knowledge_docs (知识文档表)
/// 专家知识文档表
model KnowledgeDoc {
id String @id @default(uuid())
agentId String? @map("agent_id")
docType String @map("doc_type")
title String
description String? @db.Text
content String @db.Text
source String?
author String?
publishDate DateTime? @map("publish_date")
tags String[]
status String @default("active")
isPublic Boolean @default(true) @map("is_public")
createdAt DateTime @default(now()) @map("created_at")
updatedAt DateTime @updatedAt @map("updated_at")
chunks KnowledgeChunk[] @relation("DocChunks")
@@index([agentId, docType])
@@index([status, isPublic])
@@map("knowledge_docs")
@@schema("knowledge_schema")
}
4.2 knowledge_chunks (知识块表)
/// 知识块表(用于RAG检索)
model KnowledgeChunk {
id String @id @default(uuid())
docId String @map("doc_id")
chunkIndex Int @map("chunk_index")
content String @db.Text
contentHash String @map("content_hash")
metadata Json? @db.JsonB
createdAt DateTime @default(now()) @map("created_at")
doc KnowledgeDoc @relation("DocChunks", fields: [docId], references: [id], onDelete: Cascade)
embedding KnowledgeEmbedding? @relation("ChunkEmbedding")
@@unique([docId, chunkIndex])
@@index([contentHash])
@@map("knowledge_chunks")
@@schema("knowledge_schema")
}
4.3 knowledge_embeddings (向量嵌入表)
/// 向量嵌入表(pgvector)
model KnowledgeEmbedding {
id String @id @default(uuid())
chunkId String @unique @map("chunk_id")
embedding Unsupported("vector(1536)")
embeddingModel String @map("embedding_model")
createdAt DateTime @default(now()) @map("created_at")
chunk KnowledgeChunk @relation("ChunkEmbedding", fields: [chunkId], references: [id], onDelete: Cascade)
@@map("knowledge_embeddings")
@@schema("knowledge_schema")
}
五、数据库迁移计划
5.1 迁移步骤
# 1. 创建新Schema
CREATE SCHEMA IF NOT EXISTS agent_schema;
CREATE SCHEMA IF NOT EXISTS protocol_schema;
CREATE SCHEMA IF NOT EXISTS knowledge_schema;
# 2. 更新Prisma schema.prisma中的schemas配置
schemas = ["...", "agent_schema", "protocol_schema", "knowledge_schema"]
# 3. 生成迁移
npx prisma migrate dev --name add_agent_framework
# 4. 应用迁移
npx prisma migrate deploy
5.2 初始数据
-- 插入Protocol Agent配置
INSERT INTO agent_schema.agent_configs (
id, agent_id, agent_name, base_system_prompt,
memory_strategy, max_history_turns, default_model, is_active
) VALUES (
gen_random_uuid(),
'protocol_agent',
'研究方案制定助手',
'你是一位经验丰富的临床研究方法学专家,正在帮助研究者制定研究方案...',
'full',
20,
'deepseek-v3',
true
);
-- 插入阶段配置(示例:科学问题阶段)
INSERT INTO agent_schema.agent_stages (
id, agent_config_id, stage_id, stage_name, stage_order,
instruction, extraction_schema, next_stage_id, transition_mode
) VALUES (
gen_random_uuid(),
(SELECT id FROM agent_schema.agent_configs WHERE agent_id = 'protocol_agent'),
'scientific_question',
'科学问题澄清',
1,
'引导用户明确研究的核心科学问题...',
'{"type": "object", "properties": {...}}',
'pico',
'user_confirm'
);
六、ER关系图
agent_schema
┌───────────────────┐
│ AgentConfig │
│ (agent_configs) │
└────────┬──────────┘
│
┌────┴────┬─────────────┐
│ │ │
▼ ▼ ▼
┌─────────┐ ┌─────────┐ ┌─────────────┐
│AgentStage│ │AgentTool│ │ReflexionRule│
└────┬────┘ └─────────┘ └─────────────┘
│
▼
┌─────────────┐
│ ActionCard │
└─────────────┘
┌─────────────┐ ┌─────────────┐
│AgentSession │ ───────→│ AgentTrace │
└─────────────┘ └─────────────┘
│
│ conversationId
▼
aia_schema
┌─────────────┐ ┌─────────────┐
│Conversation │────────<│ Message │
└─────────────┘ └─────────────┘
protocol_schema
┌─────────────────┐ ┌─────────────────┐
│ProtocolContext │────<│ProtocolVersion │
└─────────────────┘ └─────────────────┘