Files
AIclinicalresearch/docs/03-业务模块/AIA-AI智能问答/04-开发计划/04-Protocol_Agent开发计划/03-代码结构设计.md
HaHafeng 2481b786d8 deploy: Complete 0126-27 deployment - database upgrade, services update, code recovery
Major Changes:
- Database: Install pg_bigm/pgvector plugins, create test database
- Python service: v1.0 -> v1.1, add pymupdf4llm/openpyxl/pypandoc
- Node.js backend: v1.3 -> v1.7, fix pino-pretty and ES Module imports
- Frontend: v1.2 -> v1.3, skip TypeScript check for deployment
- Code recovery: Restore empty files from local backup

Technical Fixes:
- Fix pino-pretty error in production (conditional loading)
- Fix ES Module import paths (add .js extensions)
- Fix OSSAdapter TypeScript errors
- Update Prisma Schema (63 models, 16 schemas)
- Update environment variables (DATABASE_URL, EXTRACTION_SERVICE_URL, OSS)
- Remove deprecated variables (REDIS_URL, DIFY_API_URL, DIFY_API_KEY)

Documentation:
- Create 0126 deployment folder with 8 documents
- Update database development standards v2.0
- Update SAE deployment status records

Deployment Status:
- PostgreSQL: ai_clinical_research_test with plugins
- Python: v1.1 @ 172.17.173.84:8000
- Backend: v1.7 @ 172.17.173.89:3001
- Frontend: v1.3 @ 172.17.173.90:80

Tested: All services running successfully on SAE
2026-01-27 08:13:27 +08:00

1133 lines
29 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Protocol Agent 代码结构设计
> 版本v1.0
> 创建日期2026-01-24
---
## 一、目录结构
```
apps/api/src/
├── modules/
│ │
│ ├── agent-framework/ # 【新增】通用Agent框架
│ │ ├── core/
│ │ │ ├── BaseAgentOrchestrator.ts # 抽象基类
│ │ │ ├── QueryAnalyzer.ts # Query层-意图分析
│ │ │ ├── Planner.ts # Planner层-执行规划
│ │ │ ├── Executor.ts # Executor层-任务执行
│ │ │ ├── ToolInvoker.ts # 工具调用器
│ │ │ └── ReflexionEngine.ts # Reflection层-质量反思
│ │ │
│ │ ├── memory/
│ │ │ ├── MemoryManager.ts # 记忆管理器
│ │ │ └── ContextManager.ts # 上下文管理器
│ │ │
│ │ ├── config/
│ │ │ ├── ConfigLoader.ts # 配置加载器
│ │ │ └── StageManager.ts # 阶段状态机
│ │ │
│ │ ├── prompt/
│ │ │ ├── PromptBuilder.ts # Prompt构建器
│ │ │ └── PromptTemplates.ts # Prompt模板常量
│ │ │
│ │ ├── trace/
│ │ │ ├── TraceLogger.ts # 追踪日志记录
│ │ │ └── TraceAnalyzer.ts # 追踪分析(调试)
│ │ │
│ │ ├── tools/
│ │ │ ├── ToolRegistry.ts # 工具注册表
│ │ │ ├── DeepLinkGenerator.ts # Deep Link生成器
│ │ │ └── BaseToolHandler.ts # 工具处理基类
│ │ │
│ │ ├── types/
│ │ │ ├── agent.types.ts # Agent核心类型
│ │ │ ├── query.types.ts # Query相关类型
│ │ │ ├── plan.types.ts # Plan相关类型
│ │ │ ├── execution.types.ts # 执行相关类型
│ │ │ ├── reflexion.types.ts # 反思相关类型
│ │ │ └── tool.types.ts # 工具相关类型
│ │ │
│ │ └── index.ts # 模块导出
│ │
│ ├── aia/
│ │ ├── agents/
│ │ │ │
│ │ │ ├── protocol/ # 【新增】Protocol Agent
│ │ │ │ ├── ProtocolOrchestrator.ts # Protocol编排器
│ │ │ │ ├── ProtocolContextService.ts # Context服务
│ │ │ │ ├── ProtocolStageConfig.ts # 阶段配置
│ │ │ │ ├── ProtocolPrompts.ts # 专用Prompt
│ │ │ │ ├── ProtocolExtractor.ts # 数据提取器
│ │ │ │ ├── tools/
│ │ │ │ │ ├── SampleCalculatorTool.ts # 样本量计算工具
│ │ │ │ │ ├── DeepLinkTools.ts # Deep Link工具
│ │ │ │ │ └── index.ts
│ │ │ │ └── index.ts
│ │ │ │
│ │ │ └── (future agents)/
│ │ │ ├── statistics/ # 未来统计分析Agent
│ │ │ └── data-cleaning/ # 未来数据清洗Agent
│ │ │
│ │ ├── routes/
│ │ │ ├── protocolAgent.routes.ts # 【新增】Protocol Agent路由
│ │ │ ├── chat.routes.ts # 现有聊天路由
│ │ │ └── index.ts
│ │ │
│ │ ├── services/
│ │ │ ├── chat.service.ts # 现有聊天服务
│ │ │ ├── conversation.service.ts # 现有对话服务
│ │ │ └── protocolAgent.service.ts # 【新增】Protocol Agent服务
│ │ │
│ │ └── (existing files)
│ │
│ └── (other modules)
├── shared/
│ ├── llm/ # 现有LLM Gateway
│ └── (other shared)
└── (other folders)
```
---
## 二、核心类型定义
### 2.1 agent.types.ts - Agent核心类型
```typescript
// ============================================================
// Agent核心类型定义
// ============================================================
/**
* Agent配置从数据库加载
*/
export interface AgentConfig {
id: string;
agentId: string;
agentName: string;
baseSystemPrompt: string;
toneOfVoice?: string;
globalKnowledge: string[];
memoryStrategy: 'full' | 'sliding_window' | 'summary';
maxHistoryTurns: number;
defaultModel: string;
temperature: number;
maxTokens: number;
stages: StageConfig[];
tools: ToolConfig[];
reflexionRules: ReflexionRuleConfig[];
}
/**
* 阶段配置
*/
export interface StageConfig {
id: string;
stageId: string;
stageName: string;
stageOrder: number;
instruction: string;
extractionSchema: JSONSchema;
completionCriteria?: string;
nextStageId: string | null;
transitionMode: 'user_confirm' | 'auto' | 'condition';
transitionCondition?: Record<string, any>;
availableToolIds: string[];
actionCards: ActionCardConfig[];
}
/**
* Action Card配置
*/
export interface ActionCardConfig {
cardId: string;
title: string;
description?: string;
iconType?: string;
triggerType: 'stage_enter' | 'condition' | 'manual';
triggerCondition?: Record<string, any>;
actionType: 'deep_link' | 'api_call' | 'modal';
actionPayload: Record<string, any>;
onCompleteAction?: string;
resultMapping?: Record<string, string>;
}
/**
* Agent会话状态
*/
export interface AgentSessionState {
sessionId: string;
conversationId: string;
agentId: string;
userId: string;
currentStageId: string;
stageStatus: 'in_progress' | 'completed' | 'paused';
lastActiveAt: Date;
}
/**
* Agent响应
*/
export interface AgentResponse {
traceId: string;
message: string;
thinkingContent?: string;
actionCards: ActionCardPayload[];
contextUpdate?: Record<string, any>;
currentStage: string;
stageStatus: string;
suggestions?: string[];
}
```
### 2.2 query.types.ts - Query相关类型
```typescript
// ============================================================
// Query Analysis 类型定义
// ============================================================
/**
* 意图类型
*/
export type IntentType =
| 'provide_info' // 提供信息
| 'ask_question' // 询问问题
| 'request_change' // 请求修改
| 'confirm_complete' // 确认完成
| 'navigate_stage' // 跳转阶段
| 'request_tool' // 请求工具
| 'chitchat' // 闲聊
| 'unclear'; // 不明确
/**
* 提取的实体
*/
export interface ExtractedEntity {
type: string; // 实体类型,如 'population', 'intervention'
value: string; // 实体值
confidence: number; // 置信度 0-1
span?: { // 在原文中的位置
start: number;
end: number;
};
}
/**
* Query分析结果
*/
export interface QueryAnalysisResult {
intent: {
primary: IntentType;
confidence: number;
subIntent?: string;
};
entities: ExtractedEntity[];
resolvedQuery: string;
sentiment?: 'positive' | 'neutral' | 'confused' | 'frustrated';
requiresClarification: boolean;
clarificationQuestion?: string;
}
/**
* Query分析器配置
*/
export interface QueryAnalyzerConfig {
enableEntityExtraction: boolean;
enableSentimentAnalysis: boolean;
enableContextResolution: boolean;
confidenceThreshold: number;
}
```
### 2.3 plan.types.ts - Plan相关类型
```typescript
// ============================================================
// Planner 类型定义
// ============================================================
/**
* 执行策略
*/
export type ExecutionStrategy =
| 'guide_and_extract' // 引导对话并提取数据
| 'answer_question' // 回答用户问题
| 'update_context' // 更新已有数据
| 'trigger_tool' // 触发工具调用
| 'transition_stage' // 执行阶段流转
| 'request_clarification' // 请求澄清
| 'handle_chitchat'; // 处理闲聊
/**
* 执行任务
*/
export interface ExecutionTask {
taskId: string;
taskType: 'llm_generate' | 'tool_call' | 'data_extract' | 'context_update';
priority: number;
params: Record<string, any>;
dependsOn?: string[]; // 依赖的其他任务ID
}
/**
* 执行计划
*/
export interface ExecutionPlan {
strategy: ExecutionStrategy;
tasks: ExecutionTask[];
toolsNeeded: string[];
promptOverrides?: {
systemPrompt?: string;
userPromptPrefix?: string;
};
shouldExtract: boolean;
shouldReflect: boolean;
metadata: {
planReason: string;
estimatedTokens?: number;
};
}
/**
* 阶段流转结果
*/
export interface StageTransitionResult {
success: boolean;
previousStage: string;
nextStage?: string;
issues?: string[];
suggestions?: string[];
summary?: string;
}
```
### 2.4 execution.types.ts - 执行相关类型
```typescript
// ============================================================
// Executor 类型定义
// ============================================================
/**
* LLM响应
*/
export interface LLMResponse {
content: string;
thinkingContent?: string;
finishReason: 'stop' | 'length' | 'tool_calls';
usage: {
promptTokens: number;
completionTokens: number;
totalTokens: number;
};
model: string;
}
/**
* 提取的数据
*/
export interface ExtractedData {
hasNewData: boolean;
data: Record<string, any>;
confidence: number;
sourceMessageId: string;
extractionMethod: 'inline' | 'post_process';
}
/**
* 工具调用结果
*/
export interface ToolCallResult {
toolId: string;
success: boolean;
result?: any;
error?: string;
durationMs: number;
}
/**
* 执行结果
*/
export interface ExecutionResult {
response: LLMResponse;
extracted?: ExtractedData;
toolResults?: ToolCallResult[];
actionCards: ActionCardPayload[];
}
/**
* Action Card载荷返回给前端
*/
export interface ActionCardPayload {
cardId: string;
title: string;
description?: string;
iconType?: string;
actionType: 'deep_link' | 'api_call' | 'modal';
actionUrl?: string;
actionParams?: Record<string, any>;
priority: number;
}
```
### 2.5 reflexion.types.ts - 反思相关类型
```typescript
// ============================================================
// Reflexion 类型定义
// ============================================================
/**
* 反思规则配置
*/
export interface ReflexionRuleConfig {
ruleId: string;
ruleName: string;
triggerStageId?: string;
triggerTiming: 'on_extract' | 'on_complete' | 'on_transition';
ruleType: 'prompt_based' | 'rule_based' | 'hybrid';
promptTemplate?: string;
ruleLogic?: RuleLogic;
severity: 'error' | 'warning' | 'info';
failureAction: 'block' | 'warn' | 'log';
priority: number;
}
/**
* 规则逻辑rule_based类型
*/
export interface RuleLogic {
field: string;
condition: 'required' | 'min_length' | 'max_length' | 'pattern' | 'custom';
value?: any;
customValidator?: string; // 自定义验证函数名
}
/**
* 反思检查项
*/
export interface ReflexionCheck {
ruleId: string;
ruleName: string;
passed: boolean;
severity: 'error' | 'warning' | 'info';
message?: string;
suggestion?: string;
}
/**
* 反思结果
*/
export interface ReflexionResult {
passed: boolean;
checks: ReflexionCheck[];
issues: string[];
suggestions: string[];
blockTransition: boolean;
}
```
### 2.6 tool.types.ts - 工具相关类型
```typescript
// ============================================================
// Tool 类型定义
// ============================================================
/**
* 工具类型
*/
export type ToolType = 'internal' | 'external' | 'deep_link' | 'rag';
/**
* 工具配置
*/
export interface ToolConfig {
toolId: string;
toolName: string;
toolDescription: string;
toolType: ToolType;
functionSchema?: FunctionSchema;
handlerType: 'code' | 'api' | 'deep_link';
handlerConfig: Record<string, any>;
requiresAuth: boolean;
timeout: number;
}
/**
* Function Schema (OpenAI格式)
*/
export interface FunctionSchema {
name: string;
description: string;
parameters: {
type: 'object';
properties: Record<string, JSONSchemaProperty>;
required?: string[];
};
}
/**
* JSON Schema属性
*/
export interface JSONSchemaProperty {
type: 'string' | 'number' | 'boolean' | 'array' | 'object';
description?: string;
enum?: string[];
items?: JSONSchemaProperty;
properties?: Record<string, JSONSchemaProperty>;
}
/**
* 工具处理器接口
*/
export interface IToolHandler {
toolId: string;
execute(params: Record<string, any>, context: ToolContext): Promise<any>;
validate?(params: Record<string, any>): boolean;
}
/**
* 工具执行上下文
*/
export interface ToolContext {
conversationId: string;
userId: string;
agentId: string;
currentStage: string;
protocolContext?: Record<string, any>;
}
```
---
## 三、核心类实现
### 3.1 BaseAgentOrchestrator.ts
```typescript
/**
* Agent编排器基类
* 所有Agent都继承此类实现标准的Query→Plan→Execute→Reflect流程
*/
export abstract class BaseAgentOrchestrator<TContext> {
protected config: AgentConfig;
protected queryAnalyzer: QueryAnalyzer;
protected planner: Planner;
protected executor: Executor;
protected reflexionEngine: ReflexionEngine;
protected memoryManager: MemoryManager;
protected configLoader: ConfigLoader;
protected traceLogger: TraceLogger;
constructor(dependencies: AgentDependencies) {
// 注入依赖
}
/**
* 子类必须实现的抽象方法
*/
abstract getAgentId(): string;
abstract getContextSchema(): TContext;
abstract getContext(conversationId: string): Promise<TContext>;
abstract updateContext(conversationId: string, data: Partial<TContext>): Promise<void>;
/**
* 主处理入口
*/
async handleMessage(
conversationId: string,
userMessage: string,
messageId: string
): Promise<AgentResponse> {
const traceId = this.traceLogger.startTrace(conversationId);
try {
// Step 1: 加载配置和上下文
const config = await this.configLoader.getAgentConfig(this.getAgentId());
const context = await this.getContext(conversationId);
const session = await this.getSession(conversationId);
const stageConfig = this.getStageConfig(config, session.currentStageId);
// Step 2: Query Analysis
const queryResult = await this.queryAnalyzer.analyze(
userMessage,
context,
session
);
this.traceLogger.logStep(traceId, 'query_analysis', { input: userMessage, output: queryResult });
// Step 3: Planning
const plan = await this.planner.createPlan(
queryResult,
stageConfig,
context
);
this.traceLogger.logStep(traceId, 'planning', { input: queryResult, output: plan });
// Step 4: Execution
const execResult = await this.executor.execute(
plan,
config,
stageConfig,
context,
conversationId
);
this.traceLogger.logStep(traceId, 'execution', { input: plan, output: execResult });
// Step 5: Data Extraction
if (plan.shouldExtract && execResult.extracted?.hasNewData) {
await this.updateContext(conversationId, execResult.extracted.data);
}
// Step 6: Reflection (可选)
let reflexionResult: ReflexionResult | undefined;
if (plan.shouldReflect) {
reflexionResult = await this.reflexionEngine.reflect(
execResult,
context,
stageConfig
);
this.traceLogger.logStep(traceId, 'reflexion', { output: reflexionResult });
}
// Step 7: 构建响应
const response = this.buildResponse(
execResult,
reflexionResult,
session,
stageConfig
);
this.traceLogger.endTrace(traceId, 'success');
return response;
} catch (error) {
this.traceLogger.endTrace(traceId, 'error', error);
throw error;
}
}
/**
* 处理阶段完成
*/
async handleStageComplete(conversationId: string): Promise<StageTransitionResult> {
// ... 阶段流转逻辑
}
/**
* 处理Action Card回调
*/
async handleActionCallback(
conversationId: string,
cardId: string,
result: any
): Promise<void> {
// ... Action回调处理
}
// ... 其他protected方法
}
```
### 3.2 ProtocolOrchestrator.ts
```typescript
/**
* Protocol Agent 编排器
* 继承BaseAgentOrchestrator实现研究方案特定逻辑
*/
export class ProtocolOrchestrator extends BaseAgentOrchestrator<ProtocolContext> {
private contextService: ProtocolContextService;
private protocolExtractor: ProtocolExtractor;
constructor(dependencies: ProtocolAgentDependencies) {
super(dependencies);
this.contextService = dependencies.contextService;
this.protocolExtractor = dependencies.protocolExtractor;
}
getAgentId(): string {
return 'protocol_agent';
}
getContextSchema(): ProtocolContext {
return ProtocolContextSchema;
}
async getContext(conversationId: string): Promise<ProtocolContext> {
return this.contextService.getOrCreate(conversationId);
}
async updateContext(conversationId: string, data: Partial<ProtocolContext>): Promise<void> {
await this.contextService.update(conversationId, data);
}
/**
* 重写Protocol特定的提取逻辑
*/
protected async extractData(
llmResponse: LLMResponse,
stageConfig: StageConfig
): Promise<ExtractedData> {
return this.protocolExtractor.extract(llmResponse, stageConfig);
}
/**
* 重写Protocol特定的阶段完成检查
*/
protected async validateStageCompletion(
context: ProtocolContext,
stageConfig: StageConfig
): Promise<ReflexionResult> {
// Protocol特定的验证逻辑
const stageData = context[stageConfig.stageId as keyof ProtocolContext];
// 检查必填字段
// 检查数据完整性
// 调用Reflexion引擎
return this.reflexionEngine.reflectOnStageComplete(stageData, stageConfig);
}
}
```
### 3.3 PromptBuilder.ts
```typescript
/**
* Prompt构建器
* 负责构建各阶段的System Prompt
*/
export class PromptBuilder {
/**
* 构建系统Prompt
*/
buildSystemPrompt(params: {
basePrompt: string;
stageConfig: StageConfig;
context: Record<string, any>;
toneOfVoice?: string;
}): string {
const { basePrompt, stageConfig, context, toneOfVoice } = params;
return `
# 角色设定
${basePrompt}
${toneOfVoice ? `# 语气风格\n${toneOfVoice}\n` : ''}
# 当前阶段: ${stageConfig.stageName}
${stageConfig.instruction}
# 已收集的研究方案信息
<protocol_context>
${this.formatContext(context)}
</protocol_context>
# 数据提取要求
在回复的最后如果用户提供了新的信息请以XML格式输出提取到的结构化数据
<extracted_data>
${JSON.stringify(stageConfig.extractionSchema.example || {}, null, 2)}
</extracted_data>
# 注意事项
- 如果用户信息不完整,温和地追问补充
- 如果用户表述有歧义,先确认再记录
- 保持专业但不失亲和力的语气
- 不要编造或假设用户未提供的信息
`.trim();
}
/**
* 构建意图识别Prompt
*/
buildQueryAnalysisPrompt(params: {
userMessage: string;
currentStage: string;
contextSummary: string;
}): string {
return `
分析用户消息的意图。
当前阶段: ${params.currentStage}
上下文摘要: ${params.contextSummary}
用户消息: "${params.userMessage}"
请分析并以JSON格式返回:
{
"intent": {
"primary": "provide_info|ask_question|request_change|confirm_complete|navigate_stage|request_tool|chitchat|unclear",
"confidence": 0.0-1.0,
"subIntent": "可选的子意图"
},
"entities": [
{"type": "entity_type", "value": "entity_value", "confidence": 0.0-1.0}
],
"requiresClarification": true|false,
"clarificationQuestion": "如需澄清,提供问题"
}
`.trim();
}
/**
* 构建Reflexion检查Prompt
*/
buildReflexionPrompt(params: {
stageData: Record<string, any>;
stageConfig: StageConfig;
rule: ReflexionRuleConfig;
}): string {
if (params.rule.promptTemplate) {
return this.interpolateTemplate(params.rule.promptTemplate, {
stageData: params.stageData,
stageName: params.stageConfig.stageName
});
}
return `
检查${params.stageConfig.stageName}阶段的数据质量。
当前数据:
${JSON.stringify(params.stageData, null, 2)}
完成标准:
${params.stageConfig.completionCriteria || '无特定标准'}
请检查并以JSON格式返回:
{
"passed": true|false,
"issues": ["问题1", "问题2"],
"suggestions": ["建议1", "建议2"]
}
`.trim();
}
private formatContext(context: Record<string, any>): string {
// 格式化上下文,过滤空值,美化输出
const filtered = Object.entries(context)
.filter(([_, v]) => v != null && Object.keys(v).length > 0)
.reduce((acc, [k, v]) => ({ ...acc, [k]: v }), {});
return JSON.stringify(filtered, null, 2);
}
private interpolateTemplate(template: string, vars: Record<string, any>): string {
return template.replace(/\{\{(\w+(?:\.\w+)*)\}\}/g, (_, path) => {
const value = path.split('.').reduce((obj: any, key: string) => obj?.[key], vars);
return typeof value === 'object' ? JSON.stringify(value) : String(value ?? '');
});
}
}
```
---
## 四、API设计
### 4.1 路由定义
```typescript
// protocolAgent.routes.ts
export async function protocolAgentRoutes(fastify: FastifyInstance) {
// 发送消息核心对话API
fastify.post('/api/aia/protocol-agent/chat', {
schema: {
body: {
type: 'object',
required: ['conversationId', 'message'],
properties: {
conversationId: { type: 'string' },
message: { type: 'string' },
attachments: { type: 'array', items: { type: 'string' } }
}
}
},
handler: protocolAgentController.chat
});
// 确认阶段完成
fastify.post('/api/aia/protocol-agent/stage/complete', {
schema: {
body: {
type: 'object',
required: ['conversationId'],
properties: {
conversationId: { type: 'string' }
}
}
},
handler: protocolAgentController.completeStage
});
// 获取当前Context
fastify.get('/api/aia/protocol-agent/context/:conversationId', {
handler: protocolAgentController.getContext
});
// 更新ContextState Panel编辑
fastify.patch('/api/aia/protocol-agent/context/:conversationId', {
schema: {
body: {
type: 'object',
required: ['field', 'value'],
properties: {
field: { type: 'string' },
value: { type: 'object' }
}
}
},
handler: protocolAgentController.updateContext
});
// Action Card回调
fastify.post('/api/aia/protocol-agent/action-callback', {
schema: {
body: {
type: 'object',
required: ['conversationId', 'cardId', 'result'],
properties: {
conversationId: { type: 'string' },
cardId: { type: 'string' },
result: { type: 'object' }
}
}
},
handler: protocolAgentController.handleActionCallback
});
// 获取追踪日志(调试用)
fastify.get('/api/aia/protocol-agent/trace/:traceId', {
handler: protocolAgentController.getTrace
});
}
```
### 4.2 响应格式
```typescript
// Chat响应
interface ChatResponse {
traceId: string;
message: string;
thinkingContent?: string;
actionCards: ActionCardPayload[];
contextUpdate: {
field: string;
data: any;
confidence: number;
} | null;
currentStage: string;
stageStatus: 'in_progress' | 'completed';
stageProgress: {
current: number;
total: number;
completedStages: string[];
};
}
// Stage Complete响应
interface StageCompleteResponse {
success: boolean;
issues?: string[];
suggestions?: string[];
previousStage: string;
nextStage?: string;
summary?: string;
nextStageActionCards?: ActionCardPayload[];
}
// Context响应
interface ContextResponse {
id: string;
conversationId: string;
currentStage: string;
overallProgress: number;
completedStages: string[];
scientificQuestion: any;
pico: any;
studyDesign: any;
sampleSize: any;
endpoints: any;
updatedAt: string;
}
```
---
## 五、前端组件设计
### 5.1 组件结构
```
apps/web/src/modules/aia/
├── components/
│ ├── ProtocolAgent/
│ │ ├── ProtocolAgentPage.tsx # 主页面
│ │ ├── ProtocolChat.tsx # 聊天区域
│ │ ├── StatePanel/
│ │ │ ├── StatePanel.tsx # 状态面板容器
│ │ │ ├── StageProgress.tsx # 阶段进度
│ │ │ ├── ContextDisplay.tsx # Context展示
│ │ │ └── ContextEditor.tsx # Context编辑
│ │ ├── ActionCard/
│ │ │ ├── ActionCardList.tsx # Action Card列表
│ │ │ ├── ActionCard.tsx # 单个Card
│ │ │ └── DeepLinkModal.tsx # Deep Link弹窗
│ │ └── index.ts
│ └── (existing components)
├── hooks/
│ ├── useProtocolAgent.ts # Protocol Agent Hook
│ ├── useProtocolContext.ts # Context管理Hook
│ └── useActionCard.ts # Action Card Hook
├── stores/
│ └── protocolAgentStore.ts # Zustand Store
└── services/
└── protocolAgentApi.ts # API调用
```
### 5.2 核心Hook
```typescript
// useProtocolAgent.ts
export function useProtocolAgent(conversationId: string) {
const [context, setContext] = useState<ProtocolContext | null>(null);
const [currentStage, setCurrentStage] = useState<string>('scientific_question');
const [actionCards, setActionCards] = useState<ActionCardPayload[]>([]);
const [isLoading, setIsLoading] = useState(false);
// 发送消息
const sendMessage = async (message: string) => {
setIsLoading(true);
try {
const response = await protocolAgentApi.chat(conversationId, message);
// 更新状态
if (response.contextUpdate) {
setContext(prev => ({
...prev,
[response.contextUpdate.field]: response.contextUpdate.data
}));
}
setCurrentStage(response.currentStage);
setActionCards(response.actionCards);
return response;
} finally {
setIsLoading(false);
}
};
// 确认阶段完成
const completeStage = async () => {
const result = await protocolAgentApi.completeStage(conversationId);
if (result.success && result.nextStage) {
setCurrentStage(result.nextStage);
setActionCards(result.nextStageActionCards || []);
}
return result;
};
// 更新Context
const updateContext = async (field: string, value: any) => {
await protocolAgentApi.updateContext(conversationId, field, value);
setContext(prev => ({ ...prev, [field]: value }));
};
// 处理Action Card点击
const handleActionCard = async (card: ActionCardPayload) => {
if (card.actionType === 'deep_link') {
// 打开Deep Link
window.open(card.actionUrl, '_blank');
} else if (card.actionType === 'modal') {
// 打开弹窗
}
};
return {
context,
currentStage,
actionCards,
isLoading,
sendMessage,
completeStage,
updateContext,
handleActionCard
};
}
```
---
## 六、依赖注入设计
```typescript
// 依赖注入容器配置
export function createProtocolAgentDependencies(
prisma: PrismaClient,
llmGateway: LLMGateway
): ProtocolAgentDependencies {
// 基础服务
const traceLogger = new TraceLogger(prisma);
const configLoader = new ConfigLoader(prisma);
const memoryManager = new MemoryManager(prisma);
const promptBuilder = new PromptBuilder();
// Query层
const queryAnalyzer = new QueryAnalyzer(llmGateway, promptBuilder);
// Planner层
const stageManager = new StageManager(configLoader);
const planner = new Planner(stageManager);
// Executor层
const toolRegistry = new ToolRegistry();
const executor = new Executor(llmGateway, toolRegistry, promptBuilder);
// Reflexion层
const reflexionEngine = new ReflexionEngine(llmGateway, promptBuilder);
// Protocol专用
const contextService = new ProtocolContextService(prisma);
const protocolExtractor = new ProtocolExtractor();
return {
traceLogger,
configLoader,
memoryManager,
queryAnalyzer,
planner,
executor,
reflexionEngine,
contextService,
protocolExtractor
};
}
```