feat: Day 10-11 - Agent Configuration System completed

Backend:
- Create agents.yaml config file with 12 agents definition
- Create Prompt templates for topic-evaluation agent
- Implement agentService.ts for loading and managing agent configs
- Create agentController.ts with CRUD operations
- Create agent routes (GET /agents, /agents/:id, etc.)
- Register agent routes in main server

Frontend:
- Create agentApi.ts service module
- Update AgentChatPage to dynamically load agent config from API
- Add loading state and error handling
- Display agent details (description, category, model)

Build: Both frontend and backend build successfully
This commit is contained in:
AI Clinical Dev Team
2025-10-10 20:13:08 +08:00
parent 59522eaab7
commit 864a0b1906
13 changed files with 1077 additions and 13 deletions

View File

@@ -0,0 +1,212 @@
import fs from 'fs';
import path from 'path';
import yaml from 'js-yaml';
import { fileURLToPath } from 'url';
const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);
// 智能体配置接口
export interface AgentConfig {
id: string;
name: string;
nameEn: string;
description: string;
category: string;
icon: string;
enabled: boolean;
systemPromptFile: string;
userPromptTemplateFile: string;
models: {
[modelName: string]: {
temperature: number;
maxTokens: number;
topP?: number;
};
};
ragEnabled: boolean;
requiresProject: boolean;
outputFormat: 'text' | 'structured' | 'document';
tags: string[];
}
// 配置文件根结构
interface AgentsConfigFile {
agents: AgentConfig[];
}
class AgentService {
private agents: Map<string, AgentConfig> = new Map();
private prompts: Map<string, string> = new Map();
private configPath: string;
private promptsPath: string;
constructor() {
// 配置文件路径
this.configPath = path.resolve(__dirname, '../../config/agents.yaml');
this.promptsPath = path.resolve(__dirname, '../../prompts');
// 初始化加载配置
this.loadAgents();
}
// 加载智能体配置
private loadAgents() {
try {
const fileContents = fs.readFileSync(this.configPath, 'utf8');
const config = yaml.load(fileContents) as AgentsConfigFile;
if (!config || !config.agents) {
throw new Error('Invalid agents configuration file');
}
// 存储到Map中
config.agents.forEach((agent) => {
this.agents.set(agent.id, agent);
});
console.log(`✅ Loaded ${this.agents.size} agent configurations`);
} catch (error) {
console.error('❌ Failed to load agent configurations:', error);
throw error;
}
}
// 加载Prompt模板
private loadPrompt(filename: string): string {
const cacheKey = filename;
// 检查缓存
if (this.prompts.has(cacheKey)) {
return this.prompts.get(cacheKey)!;
}
try {
const promptPath = path.join(this.promptsPath, filename);
const content = fs.readFileSync(promptPath, 'utf8');
// 缓存到内存
this.prompts.set(cacheKey, content);
return content;
} catch (error) {
console.error(`❌ Failed to load prompt file: ${filename}`, error);
throw new Error(`Prompt file not found: ${filename}`);
}
}
// 获取所有智能体列表
getAllAgents(): AgentConfig[] {
return Array.from(this.agents.values());
}
// 获取启用的智能体列表
getEnabledAgents(): AgentConfig[] {
return Array.from(this.agents.values()).filter((agent) => agent.enabled);
}
// 根据ID获取智能体配置
getAgentById(agentId: string): AgentConfig | null {
return this.agents.get(agentId) || null;
}
// 根据分类获取智能体列表
getAgentsByCategory(category: string): AgentConfig[] {
return Array.from(this.agents.values()).filter(
(agent) => agent.category === category
);
}
// 获取智能体的系统Prompt
getSystemPrompt(agentId: string): string {
const agent = this.getAgentById(agentId);
if (!agent) {
throw new Error(`Agent not found: ${agentId}`);
}
return this.loadPrompt(agent.systemPromptFile);
}
// 获取智能体的用户Prompt模板
getUserPromptTemplate(agentId: string): string {
const agent = this.getAgentById(agentId);
if (!agent) {
throw new Error(`Agent not found: ${agentId}`);
}
return this.loadPrompt(agent.userPromptTemplateFile);
}
// 渲染用户Prompt替换模板变量
renderUserPrompt(
agentId: string,
variables: {
projectBackground?: string;
userInput: string;
knowledgeBaseContext?: string;
}
): string {
const template = this.getUserPromptTemplate(agentId);
let rendered = template;
// 替换变量
rendered = rendered.replace(/\{\{projectBackground\}\}/g, variables.projectBackground || '未提供项目背景');
rendered = rendered.replace(/\{\{userInput\}\}/g, variables.userInput);
// 处理条件块(知识库上下文)
if (variables.knowledgeBaseContext) {
rendered = rendered.replace(
/\{\{#if knowledgeBaseContext\}\}([\s\S]*?)\{\{\/if\}\}/g,
'$1'
);
rendered = rendered.replace(/\{\{knowledgeBaseContext\}\}/g, variables.knowledgeBaseContext);
} else {
// 移除条件块
rendered = rendered.replace(
/\{\{#if knowledgeBaseContext\}\}[\s\S]*?\{\{\/if\}\}/g,
''
);
}
return rendered.trim();
}
// 检查智能体是否存在
agentExists(agentId: string): boolean {
return this.agents.has(agentId);
}
// 检查智能体是否启用
isAgentEnabled(agentId: string): boolean {
const agent = this.getAgentById(agentId);
return agent ? agent.enabled : false;
}
// 获取智能体的模型配置
getModelConfig(agentId: string, modelName: string) {
const agent = this.getAgentById(agentId);
if (!agent) {
throw new Error(`Agent not found: ${agentId}`);
}
const modelConfig = agent.models[modelName];
if (!modelConfig) {
throw new Error(`Model ${modelName} not configured for agent ${agentId}`);
}
return modelConfig;
}
// 重新加载配置(热更新)
reloadConfig() {
this.agents.clear();
this.prompts.clear();
this.loadAgents();
console.log('✅ Agent configurations reloaded');
}
}
// 导出单例
export const agentService = new AgentService();