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:
@@ -0,0 +1,244 @@
|
||||
# **研究方案制定 Agent 技术实现手册 V3.0**
|
||||
|
||||
版本: v3.0
|
||||
关联文档: Protocol\_Agent\_Architecture\_Design\_V3.md
|
||||
核心内容: 数据库 Schema、核心服务代码、API 协议。
|
||||
|
||||
## **1\. 数据库设计 (Prisma Schema)**
|
||||
|
||||
### **1.1 记忆层 (Memory Layer)**
|
||||
|
||||
存储“活的”方案数据,实现长程记忆。
|
||||
|
||||
// aia\_schema.prisma
|
||||
|
||||
model ProtocolContext {
|
||||
id String @id @default(uuid())
|
||||
conversationId String @unique @map("conversation\_id")
|
||||
userId String @map("user\_id")
|
||||
|
||||
// 状态机
|
||||
currentStage String @default("SCIENTIFIC\_QUESTION")
|
||||
status String @default("IN\_PROGRESS")
|
||||
|
||||
// 活的方案数据 (JSONB)
|
||||
// 包含: scientific\_question, pico, study\_design, outcomes, sample\_size 等
|
||||
data Json @default("{}")
|
||||
|
||||
// V3 新增: 存储上一次的反思结果,避免重复报错
|
||||
lastReflexion Json? @map("last\_reflexion")
|
||||
|
||||
createdAt DateTime @default(now()) @map("created\_at")
|
||||
updatedAt DateTime @updatedAt @map("updated\_at")
|
||||
|
||||
@@table("protocol\_contexts")
|
||||
@@schema("aia\_schema")
|
||||
}
|
||||
|
||||
### **1.2 配置层 (Configuration Layer)**
|
||||
|
||||
这是 V3 的核心,支持后端配置 CoT。
|
||||
|
||||
// capability\_schema.prisma
|
||||
|
||||
model PromptTemplate {
|
||||
id String @id @default(uuid())
|
||||
code String @unique // e.g., AIA\_SAMPLE\_SIZE
|
||||
version Int @default(1)
|
||||
|
||||
// 基础人设
|
||||
content String @db.Text
|
||||
|
||||
// V3 新增: 思维链配置 (JSONB)
|
||||
// 存储 ChainStep\[\] 数组
|
||||
chainConfig Json? @map("chain\_config")
|
||||
|
||||
// V3 新增: 路由规则配置 (JSONB, 可选)
|
||||
// 用于定义何时切出该阶段
|
||||
routerConfig Json? @map("router\_config")
|
||||
|
||||
isActive Boolean @default(true)
|
||||
updatedAt DateTime @updatedAt
|
||||
|
||||
@@table("prompt\_templates")
|
||||
@@schema("capability\_schema")
|
||||
}
|
||||
|
||||
model AgentTrace {
|
||||
id String @id @default(uuid())
|
||||
conversationId String @map("conversation\_id")
|
||||
stage String
|
||||
|
||||
// 记录完整上下文
|
||||
inputPayload Json @map("input\_payload")
|
||||
outputPayload Json @map("output\_payload")
|
||||
|
||||
// 耗时与消耗
|
||||
latencyMs Int @map("latency\_ms")
|
||||
tokens Int @default(0)
|
||||
|
||||
createdAt DateTime @default(now())
|
||||
|
||||
@@table("agent\_traces")
|
||||
@@schema("capability\_schema")
|
||||
}
|
||||
|
||||
## **2\. 核心服务代码 (Orchestrator Engine)**
|
||||
|
||||
### **2.1 动态 CoT 组装器 (promptBuilder.ts)**
|
||||
|
||||
负责将 DB 中的 SOP 配置编译成 System Prompt。
|
||||
|
||||
import { prisma } from '@/common/db';
|
||||
|
||||
interface ChainStep {
|
||||
key: string;
|
||||
desc: string;
|
||||
instruction: string;
|
||||
}
|
||||
|
||||
export async function buildDynamicSystemPrompt(stage: string, contextData: any) {
|
||||
// 1\. 加载配置
|
||||
const template \= await prisma.promptTemplate.findUnique({ where: { code: stage } });
|
||||
if (\!template) throw new Error(\`Prompt not found: ${stage}\`);
|
||||
|
||||
const chainSteps \= template.chainConfig as ChainStep\[\] || \[\];
|
||||
|
||||
// 2\. 组装基础 Prompt (Persona)
|
||||
let systemPrompt \= \`${template.content}\\n\\n\`;
|
||||
|
||||
// 3\. 注入当前上下文 (Memory)
|
||||
systemPrompt \+= \`=== 当前方案状态 (Context) \===\\n${JSON.stringify(contextData, null, 2)}\\n\\n\`;
|
||||
|
||||
// 4\. 注入思维链 SOP (V3 核心)
|
||||
if (chainSteps.length \> 0\) {
|
||||
systemPrompt \+= \`=== 思考步骤 (SOP) \===\\n\`;
|
||||
systemPrompt \+= \`请严格按照以下步骤进行思考,并使用 XML 标签包裹每一步的内容:\\n\`;
|
||||
chainSteps.forEach((step, idx) \=\> {
|
||||
systemPrompt \+= \`${idx \+ 1}. \<${step.key}\>: ${step.instruction}\\n\`;
|
||||
});
|
||||
systemPrompt \+= \`最后,在 \<response\> 标签中输出给用户的回复。\\n\`;
|
||||
}
|
||||
|
||||
return systemPrompt;
|
||||
}
|
||||
|
||||
### **2.2 编排器主逻辑 (ProtocolOrchestrator.ts)**
|
||||
|
||||
协调 Brain, Memory, Knowledge 和 Hands。
|
||||
|
||||
export class ProtocolOrchestrator {
|
||||
|
||||
async handleMessage(userId: string, conversationId: string, content: string) {
|
||||
// 1\. 获取上下文 (Memory)
|
||||
let ctx \= await prisma.protocolContext.findUnique({ where: { conversationId } });
|
||||
|
||||
// 2\. \[Reflexion Guard\] 检查数据变更
|
||||
// 如果之前状态是 WAITING\_USER 且数据变了,说明工具执行回来了 (Hands 回调)
|
||||
if (ctx.status \=== 'WAITING\_USER\_ACTION' && await this.checkDataChanged(ctx)) {
|
||||
const validation \= await this.runReflexionCheck(ctx);
|
||||
if (\!validation.pass) {
|
||||
return this.streamResponse(\`⚠️ \*\*校验未通过\*\*: ${validation.reason}\`);
|
||||
}
|
||||
// 校验通过,重置状态
|
||||
await this.updateStatus(ctx.id, 'IN\_PROGRESS');
|
||||
}
|
||||
|
||||
// 3\. \[Knowledge RAG\] 混合检索 (自建 EKB)
|
||||
// 仅在需要知识的阶段调用
|
||||
const ragContext \= await knowledgeService.search(content, ctx.currentStage);
|
||||
|
||||
// 4\. \[Prompt Build\] 动态组装 (Brain)
|
||||
const systemPrompt \= await buildDynamicSystemPrompt(ctx.currentStage, ctx.data);
|
||||
|
||||
// 5\. \[Execution\] 流式生成
|
||||
const traceId \= await traceService.startTrace(conversationId, 'GENERATE');
|
||||
|
||||
return streamingService.streamGenerate({
|
||||
systemPrompt,
|
||||
userMessage: content \+ (ragContext ? \`\\n\\n参考资料:\\n${ragContext}\` : ''),
|
||||
onFinish: async (output) \=\> {
|
||||
await traceService.endTrace(traceId, output);
|
||||
// 异步触发:结构化提取任务 (更新 Memory)
|
||||
await pgBoss.send('extract-protocol-data', { conversationId, text: output });
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
## **3\. 交互协议 (Deep Link Protocol)**
|
||||
|
||||
### **3.1 Action Card Payload (Backend \-\> Frontend)**
|
||||
|
||||
Orchestrator 决定需要用户操作时,发送此 JSON。
|
||||
|
||||
{
|
||||
"type": "action\_card",
|
||||
"data": {
|
||||
"title": "建议:样本量计算",
|
||||
"tool\_code": "SAMPLE\_SIZE\_CALC",
|
||||
"path": "/tools/st/sample-size",
|
||||
"params": {
|
||||
"ctx\_id": "uuid-1234", // 关键:传递上下文ID,让工具知道往哪里回写
|
||||
"alpha": 0.05,
|
||||
"power": 0.8
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
### **3.2 同步回写 API (Tool \-\> Backend)**
|
||||
|
||||
工具端(如样本量计算器)计算完成后,调用此接口回写结果。
|
||||
|
||||
**POST** /api/v1/aia/protocol/:ctxId/sync
|
||||
|
||||
{
|
||||
"stage": "SAMPLE\_SIZE",
|
||||
"data": {
|
||||
"n\_total": 386,
|
||||
"method": "t-test",
|
||||
"params": { "alpha": 0.05, "power": 0.8 }
|
||||
}
|
||||
}
|
||||
|
||||
## **4\. 提取与反思 (Extraction & Reflexion)**
|
||||
|
||||
### **4.1 异步提取 Worker**
|
||||
|
||||
负责从非结构化对话中“提纯”信息存入 Memory。
|
||||
|
||||
// workers/extractionWorker.ts
|
||||
|
||||
export async function extractProtocolData(job) {
|
||||
const { conversationId, text } \= job.data;
|
||||
|
||||
// 调用廉价模型 (DeepSeek-Flash) 进行 JSON 提取
|
||||
const extracted \= await llm.extractJson(text, EXTRACT\_PROMPT);
|
||||
|
||||
if (extracted) {
|
||||
// 智能合并策略 (Deep Merge)
|
||||
await prisma.protocolContext.update({
|
||||
where: { conversationId },
|
||||
data: { data: deepMerge(currentData, extracted) }
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
### **4.2 反思校验规则 (Reflexion Rules)**
|
||||
|
||||
**Brain** 对 **Hands** 操作结果的质检逻辑。
|
||||
|
||||
function runReflexionCheck(ctx: ProtocolContext) {
|
||||
const { sample\_size } \= ctx.data;
|
||||
if (\!sample\_size) return { pass: true };
|
||||
|
||||
// 规则 1: 伦理红线
|
||||
if (sample\_size.n\_total \< 10\)
|
||||
return { pass: false, reason: "样本量过小 (\<10),无法通过伦理审查" };
|
||||
|
||||
// 规则 2: 可行性预警
|
||||
if (sample\_size.n\_total \> 10000\)
|
||||
return { pass: false, reason: "样本量过大,请确认经费和周期是否支持" };
|
||||
|
||||
return { pass: true };
|
||||
}
|
||||
Reference in New Issue
Block a user