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
29 KiB
29 KiB
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核心类型
// ============================================================
// 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相关类型
// ============================================================
// 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相关类型
// ============================================================
// 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 - 执行相关类型
// ============================================================
// 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 - 反思相关类型
// ============================================================
// 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 - 工具相关类型
// ============================================================
// 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
/**
* 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
/**
* 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
/**
* 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 路由定义
// 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
});
// 更新Context(State 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 响应格式
// 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
// 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
};
}
六、依赖注入设计
// 依赖注入容器配置
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
};
}