feat(aia): Implement Protocol Agent MVP with reusable Agent framework

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
This commit is contained in:
2026-01-24 17:29:24 +08:00
parent 61cdc97eeb
commit 96290d2f76
345 changed files with 13945 additions and 47 deletions

View File

@@ -6,7 +6,7 @@ generator client {
datasource db {
provider = "postgresql"
url = env("DATABASE_URL")
schemas = ["admin_schema", "aia_schema", "asl_schema", "capability_schema", "common_schema", "dc_schema", "ekb_schema", "iit_schema", "pkb_schema", "platform_schema", "public", "rvw_schema", "ssa_schema", "st_schema"]
schemas = ["admin_schema", "agent_schema", "aia_schema", "asl_schema", "capability_schema", "common_schema", "dc_schema", "ekb_schema", "iit_schema", "pkb_schema", "platform_schema", "protocol_schema", "public", "rvw_schema", "ssa_schema", "st_schema"]
}
/// 应用缓存表 - Postgres-Only架构
@@ -1393,3 +1393,303 @@ model EkbChunk {
@@map("ekb_chunk")
@@schema("ekb_schema")
}
// ============================================================
// Agent Framework Schema (agent_schema)
// 通用Agent框架 - 可复用于多种Agent类型
// ============================================================
/// Agent定义表 - 存储Agent的基本配置
model AgentDefinition {
id String @id @default(uuid())
code String @unique /// 唯一标识: protocol_agent, stat_agent
name String /// 显示名称
description String? /// 描述
version String @default("1.0.0") /// 版本号
/// Agent配置
config Json? @db.JsonB /// 全局配置 { defaultModel, maxTurns, timeout }
/// 状态
isActive Boolean @default(true) @map("is_active")
/// 关联
stages AgentStage[]
prompts AgentPrompt[]
sessions AgentSession[]
reflexionRules ReflexionRule[]
createdAt DateTime @default(now()) @map("created_at")
updatedAt DateTime @updatedAt @map("updated_at")
@@index([code], map: "idx_agent_def_code")
@@index([isActive], map: "idx_agent_def_active")
@@map("agent_definitions")
@@schema("agent_schema")
}
/// Agent阶段配置表 - 定义Agent的工作流阶段
model AgentStage {
id String @id @default(uuid())
agentId String @map("agent_id") /// 关联的Agent
/// 阶段标识
stageCode String @map("stage_code") /// 阶段代码: scientific_question, pico
stageName String @map("stage_name") /// 阶段名称: 科学问题梳理
sortOrder Int @map("sort_order") /// 排序顺序
/// 阶段配置
config Json? @db.JsonB /// 阶段特定配置
/// 状态机配置
nextStages String[] @map("next_stages") /// 可转换的下一阶段列表
isInitial Boolean @default(false) @map("is_initial") /// 是否为起始阶段
isFinal Boolean @default(false) @map("is_final") /// 是否为结束阶段
/// 关联
agent AgentDefinition @relation(fields: [agentId], references: [id], onDelete: Cascade)
prompts AgentPrompt[]
createdAt DateTime @default(now()) @map("created_at")
updatedAt DateTime @updatedAt @map("updated_at")
@@unique([agentId, stageCode], map: "unique_agent_stage")
@@index([agentId], map: "idx_agent_stage_agent")
@@index([sortOrder], map: "idx_agent_stage_order")
@@map("agent_stages")
@@schema("agent_schema")
}
/// Agent Prompt模板表 - 存储各阶段的Prompt
model AgentPrompt {
id String @id @default(uuid())
agentId String @map("agent_id") /// 关联的Agent
stageId String? @map("stage_id") /// 关联的阶段可选null表示通用Prompt
/// Prompt标识
promptType String @map("prompt_type") /// system, stage, extraction, reflexion
promptCode String @map("prompt_code") /// 唯一代码
/// Prompt内容
content String @db.Text /// Prompt模板内容支持变量
variables String[] /// 预期变量列表
/// 版本控制
version Int @default(1) /// 版本号
isActive Boolean @default(true) @map("is_active")
/// 关联
agent AgentDefinition @relation(fields: [agentId], references: [id], onDelete: Cascade)
stage AgentStage? @relation(fields: [stageId], references: [id], onDelete: SetNull)
createdAt DateTime @default(now()) @map("created_at")
updatedAt DateTime @updatedAt @map("updated_at")
@@unique([agentId, promptCode, version], map: "unique_agent_prompt_version")
@@index([agentId, promptType], map: "idx_agent_prompt_type")
@@index([stageId], map: "idx_agent_prompt_stage")
@@map("agent_prompts")
@@schema("agent_schema")
}
/// Agent会话表 - 存储Agent的运行时会话状态
model AgentSession {
id String @id @default(uuid())
agentId String @map("agent_id") /// 关联的Agent定义
conversationId String @map("conversation_id") /// 关联的对话IDaia_schema.conversations
userId String @map("user_id") /// 用户ID
/// 当前状态
currentStage String @map("current_stage") /// 当前阶段代码
status String @default("active") /// active, completed, paused, error
/// 上下文数据具体Agent的上下文存储在对应schema
contextRef String? @map("context_ref") /// 上下文引用ID如protocol_schema.protocol_contexts.id
/// 统计信息
turnCount Int @default(0) @map("turn_count") /// 对话轮数
totalTokens Int @default(0) @map("total_tokens") /// 总Token数
/// 关联
agent AgentDefinition @relation(fields: [agentId], references: [id])
traces AgentTrace[]
createdAt DateTime @default(now()) @map("created_at")
updatedAt DateTime @updatedAt @map("updated_at")
@@unique([conversationId], map: "unique_agent_session_conv")
@@index([agentId], map: "idx_agent_session_agent")
@@index([userId], map: "idx_agent_session_user")
@@index([status], map: "idx_agent_session_status")
@@map("agent_sessions")
@@schema("agent_schema")
}
/// Agent执行追踪表 - 记录每一步的执行详情
model AgentTrace {
id String @id @default(uuid())
sessionId String @map("session_id") /// 关联的会话
/// 追踪信息
traceId String @map("trace_id") /// 请求追踪ID用于关联日志
stepIndex Int @map("step_index") /// 步骤序号
stepType String @map("step_type") /// query, plan, execute, reflect, tool_call
/// 输入输出
input Json? @db.JsonB /// 步骤输入
output Json? @db.JsonB /// 步骤输出
/// 执行信息
stageCode String? @map("stage_code") /// 执行时的阶段
modelUsed String? @map("model_used") /// 使用的模型
tokensUsed Int? @map("tokens_used") /// 消耗的Token
durationMs Int? @map("duration_ms") /// 执行时长(毫秒)
/// 错误信息
errorType String? @map("error_type") /// 错误类型
errorMsg String? @map("error_msg") /// 错误信息
/// 关联
session AgentSession @relation(fields: [sessionId], references: [id], onDelete: Cascade)
createdAt DateTime @default(now()) @map("created_at")
@@index([sessionId, stepIndex], map: "idx_agent_trace_session_step")
@@index([traceId], map: "idx_agent_trace_trace_id")
@@index([stepType], map: "idx_agent_trace_step_type")
@@map("agent_traces")
@@schema("agent_schema")
}
/// Reflexion规则表 - 定义质量检查规则
model ReflexionRule {
id String @id @default(uuid())
agentId String @map("agent_id") /// 关联的Agent
/// 规则标识
ruleCode String @map("rule_code") /// 规则代码
ruleName String @map("rule_name") /// 规则名称
/// 触发条件
triggerStage String? @map("trigger_stage") /// 触发阶段null表示全局
triggerTiming String @map("trigger_timing") /// on_sync, on_stage_complete, on_generate
/// 规则类型
ruleType String @map("rule_type") /// rule_based, prompt_based
/// 规则内容
conditions Json? @db.JsonB /// 规则条件rule_based时使用
promptTemplate String? @map("prompt_template") @db.Text /// Prompt模板prompt_based时使用
/// 行为配置
severity String @default("warning") /// error, warning, info
failureAction String @default("warn") @map("failure_action") /// block, warn, log
/// 状态
isActive Boolean @default(true) @map("is_active")
sortOrder Int @default(0) @map("sort_order")
/// 关联
agent AgentDefinition @relation(fields: [agentId], references: [id], onDelete: Cascade)
createdAt DateTime @default(now()) @map("created_at")
updatedAt DateTime @updatedAt @map("updated_at")
@@unique([agentId, ruleCode], map: "unique_agent_rule")
@@index([agentId, triggerStage], map: "idx_reflexion_rule_agent_stage")
@@index([isActive], map: "idx_reflexion_rule_active")
@@map("reflexion_rules")
@@schema("agent_schema")
}
// ============================================================
// Protocol Agent Schema (protocol_schema)
// Protocol Agent专用 - 研究方案制定
// ============================================================
/// Protocol Context表 - 存储研究方案的核心上下文数据
model ProtocolContext {
id String @id @default(uuid())
conversationId String @unique @map("conversation_id") /// 关联的对话ID
userId String @map("user_id")
/// 当前状态
currentStage String @default("scientific_question") @map("current_stage")
status String @default("in_progress") /// in_progress, completed, abandoned
/// ===== 5个核心阶段数据 =====
/// 阶段1: 科学问题
scientificQuestion Json? @map("scientific_question") @db.JsonB
/// { content, background, significance, confirmed, confirmedAt }
/// 阶段2: PICO
pico Json? @db.JsonB
/// { P: {value, details}, I: {}, C: {}, O: {}, confirmed, confirmedAt }
/// 阶段3: 研究设计
studyDesign Json? @map("study_design") @db.JsonB
/// { type, blinding, randomization, duration, multiCenter, confirmed }
/// 阶段4: 样本量
sampleSize Json? @map("sample_size") @db.JsonB
/// { total, perGroup, alpha, power, effectSize, dropoutRate, justification, confirmed }
/// 阶段5: 观察指标(终点指标)
endpoints Json? @db.JsonB
/// { primary: [{name, definition, method, timePoint}], secondary: [], safety: [], confirmed }
/// ===== 元数据 =====
completedStages String[] @default([]) @map("completed_stages") /// 已完成的阶段列表
lastActiveAt DateTime @default(now()) @map("last_active_at")
/// 关联
generations ProtocolGeneration[]
createdAt DateTime @default(now()) @map("created_at")
updatedAt DateTime @updatedAt @map("updated_at")
@@index([userId], map: "idx_protocol_context_user")
@@index([status], map: "idx_protocol_context_status")
@@index([currentStage], map: "idx_protocol_context_stage")
@@map("protocol_contexts")
@@schema("protocol_schema")
}
/// Protocol生成记录表 - 存储一键生成的研究方案
model ProtocolGeneration {
id String @id @default(uuid())
contextId String @map("context_id") /// 关联的Context
userId String @map("user_id")
/// 生成内容
generatedContent String @map("generated_content") @db.Text /// 生成的研究方案全文Markdown
contentVersion Int @default(1) @map("content_version") /// 版本号
/// 使用的Prompt
promptUsed String @map("prompt_used") @db.Text /// 实际使用的Prompt
/// 生成参数
modelUsed String @map("model_used") /// 使用的模型
tokensUsed Int? @map("tokens_used") /// 消耗的Token
durationMs Int? @map("duration_ms") /// 生成耗时(毫秒)
/// 导出记录
wordFileKey String? @map("word_file_key") /// Word文件OSS Key
lastExportedAt DateTime? @map("last_exported_at")
/// 状态
status String @default("completed") /// generating, completed, failed
errorMessage String? @map("error_message")
/// 关联
context ProtocolContext @relation(fields: [contextId], references: [id], onDelete: Cascade)
createdAt DateTime @default(now()) @map("created_at")
updatedAt DateTime @updatedAt @map("updated_at")
@@index([contextId], map: "idx_protocol_gen_context")
@@index([userId, createdAt], map: "idx_protocol_gen_user_time")
@@map("protocol_generations")
@@schema("protocol_schema")
}