diff --git a/backend/src/core/agent/crewai/template_loader.py b/backend/src/core/agent/crewai/template_loader.py index 89a230d..d91f552 100644 --- a/backend/src/core/agent/crewai/template_loader.py +++ b/backend/src/core/agent/crewai/template_loader.py @@ -12,12 +12,11 @@ class CrewAITemplate: agents: dict[str, Any] tasks: dict[str, Any] workflow: dict[str, Any] - prompts: dict[str, str] tools_whitelist: set[str] def _default_static_root() -> Path: - return Path(__file__).resolve().parents[3] / "config" / "static" / "agent" + return Path(__file__).resolve().parents[3] / "config" / "static" / "crewai" def _read_yaml(file_path: Path) -> dict[str, Any]: @@ -30,12 +29,6 @@ def _read_yaml(file_path: Path) -> dict[str, Any]: return loaded -def _read_prompt(file_path: Path) -> str: - if not file_path.is_file(): - raise FileNotFoundError(f"Required prompt file not found: {file_path}") - return file_path.read_text(encoding="utf-8").strip() - - def validate_workflow_stages(stages: list[str]) -> None: expected = ["intent", "execution", "organization"] if stages != expected: @@ -56,27 +49,19 @@ def load_tools_whitelist(static_root: Path | None = None) -> set[str]: def load_crewai_template(static_root: Path | None = None) -> CrewAITemplate: root = static_root or _default_static_root() - crewai_root = root / "crewai" - agents = _read_yaml(crewai_root / "agents.yaml") - tasks = _read_yaml(crewai_root / "tasks.yaml") - workflow = _read_yaml(crewai_root / "workflow.yaml") + agents = _read_yaml(root / "agents.yaml") + tasks = _read_yaml(root / "tasks.yaml") + workflow = _read_yaml(root / "workflow.yaml") stages = workflow.get("stages") if not isinstance(stages, list): raise ValueError("workflow.yaml field 'stages' must be a list") validate_workflow_stages([str(stage) for stage in stages]) - prompts = { - "intent": _read_prompt(crewai_root / "prompts" / "intent.md"), - "execution": _read_prompt(crewai_root / "prompts" / "execution.md"), - "organization": _read_prompt(crewai_root / "prompts" / "organization.md"), - } - return CrewAITemplate( agents=agents, tasks=tasks, workflow=workflow, - prompts=prompts, tools_whitelist=load_tools_whitelist(root), ) diff --git a/backend/src/core/initialization/init_data.py b/backend/src/core/config/initial/init_data.py similarity index 95% rename from backend/src/core/initialization/init_data.py rename to backend/src/core/config/initial/init_data.py index c066f96..bc87829 100644 --- a/backend/src/core/initialization/init_data.py +++ b/backend/src/core/config/initial/init_data.py @@ -14,7 +14,7 @@ from core.logging import get_logger from models.llm import Llm from models.llm_factory import LlmFactory -logger = get_logger("core.initialization.init_data") +logger = get_logger("core.config.initial.init_data") class LlmFactorySeed(BaseModel): @@ -35,11 +35,7 @@ class LlmCatalogSeed(BaseModel): def _default_catalog_path() -> Path: return ( - Path(__file__).resolve().parents[1] - / "config" - / "static" - / "agent" - / "llm_catalog.yaml" + Path(__file__).resolve().parents[1] / "static" / "database" / "llm_catalog.yaml" ) diff --git a/backend/src/core/config/static/agent/crewai/agents.yaml b/backend/src/core/config/static/agent/crewai/agents.yaml deleted file mode 100644 index 74f611f..0000000 --- a/backend/src/core/config/static/agent/crewai/agents.yaml +++ /dev/null @@ -1,9 +0,0 @@ -intent: - role: Intent Agent - goal: Classify user intent and decide execution strategy -execution: - role: Execution Agent - goal: Execute tasks with available tools -organization: - role: Organization Agent - goal: Organize output for user-friendly response diff --git a/backend/src/core/config/static/agent/crewai/prompts/execution.md b/backend/src/core/config/static/agent/crewai/prompts/execution.md deleted file mode 100644 index ed0546b..0000000 --- a/backend/src/core/config/static/agent/crewai/prompts/execution.md +++ /dev/null @@ -1,2 +0,0 @@ -你是任务执行代理。 -基于输入意图与上下文调用可用工具,并生成可验证执行结果。 diff --git a/backend/src/core/config/static/agent/crewai/prompts/intent.md b/backend/src/core/config/static/agent/crewai/prompts/intent.md deleted file mode 100644 index 5e7dd3b..0000000 --- a/backend/src/core/config/static/agent/crewai/prompts/intent.md +++ /dev/null @@ -1,2 +0,0 @@ -你是意图识别代理。 -你的任务是识别用户输入的意图类型,并返回结构化意图标签。 diff --git a/backend/src/core/config/static/agent/crewai/prompts/organization.md b/backend/src/core/config/static/agent/crewai/prompts/organization.md deleted file mode 100644 index 4e0268f..0000000 --- a/backend/src/core/config/static/agent/crewai/prompts/organization.md +++ /dev/null @@ -1,2 +0,0 @@ -你是结果整理代理。 -将执行结果组织为面向用户的清晰回复,保留关键信息与必要引用。 diff --git a/backend/src/core/config/static/agent/crewai/tasks.yaml b/backend/src/core/config/static/agent/crewai/tasks.yaml deleted file mode 100644 index 43a1f9f..0000000 --- a/backend/src/core/config/static/agent/crewai/tasks.yaml +++ /dev/null @@ -1,6 +0,0 @@ -intent: - description: Identify user intent and required capabilities -execution: - description: Execute intent with tools and model calls -organization: - description: Format final response and references diff --git a/backend/src/core/config/static/crewai/agents.yaml b/backend/src/core/config/static/crewai/agents.yaml new file mode 100644 index 0000000..3076346 --- /dev/null +++ b/backend/src/core/config/static/crewai/agents.yaml @@ -0,0 +1,22 @@ +intent: + role: Intent Agent + goal: Classify user intent and decide execution strategy + backstory: > + You are an expert intent classifier with deep understanding + of user query patterns and dialogue acts. Your role is to + analyze user input and determine the appropriate action. + +execution: + role: Execution Agent + goal: Execute tasks with available tools + backstory: > + You are a skilled task executor with expertise in tool calling, + API interactions, and result verification. You work systematically + to complete user requests. + +organization: + role: Organization Agent + goal: Organize output for user-friendly response + backstory: > + You specialize in presenting results in a clear, user-friendly manner. + You ensure responses are well-structured and actionable. diff --git a/backend/src/core/config/static/crewai/tasks.yaml b/backend/src/core/config/static/crewai/tasks.yaml new file mode 100644 index 0000000..bc652dd --- /dev/null +++ b/backend/src/core/config/static/crewai/tasks.yaml @@ -0,0 +1,16 @@ +intent: + description: Identify user intent and required capabilities + expected_output: > + Structured intent classification with intent type, confidence score, + and recommended action plan + +execution: + description: Execute intent with tools and model calls + expected_output: > + Verified execution results with tool outputs, status, and any errors + +organization: + description: Format final response and references + expected_output: > + User-friendly response with structured output, citations, and + clear next steps if applicable diff --git a/backend/src/core/config/static/agent/tools.yaml b/backend/src/core/config/static/crewai/tools.yaml similarity index 100% rename from backend/src/core/config/static/agent/tools.yaml rename to backend/src/core/config/static/crewai/tools.yaml diff --git a/backend/src/core/config/static/agent/crewai/workflow.yaml b/backend/src/core/config/static/crewai/workflow.yaml similarity index 100% rename from backend/src/core/config/static/agent/crewai/workflow.yaml rename to backend/src/core/config/static/crewai/workflow.yaml diff --git a/backend/src/core/config/static/agent/llm_catalog.yaml b/backend/src/core/config/static/database/llm_catalog.yaml similarity index 100% rename from backend/src/core/config/static/agent/llm_catalog.yaml rename to backend/src/core/config/static/database/llm_catalog.yaml diff --git a/backend/src/core/config/static/database/user_agent_catalog.yaml b/backend/src/core/config/static/database/user_agent_catalog.yaml new file mode 100644 index 0000000..8428f80 --- /dev/null +++ b/backend/src/core/config/static/database/user_agent_catalog.yaml @@ -0,0 +1 @@ +agents: [] diff --git a/backend/src/core/runtime/cli.py b/backend/src/core/runtime/cli.py index e8cfcc4..d12e039 100644 --- a/backend/src/core/runtime/cli.py +++ b/backend/src/core/runtime/cli.py @@ -5,7 +5,7 @@ import subprocess import sys from pathlib import Path -from core.initialization.init_data import initialize_data +from core.config.initial.init_data import initialize_data from core.logging import get_logger logger = get_logger("core.runtime.cli") diff --git a/backend/tests/unit/core/config/test_crewai_template_loader.py b/backend/tests/unit/core/config/test_crewai_template_loader.py index 6287a1b..88c4870 100644 --- a/backend/tests/unit/core/config/test_crewai_template_loader.py +++ b/backend/tests/unit/core/config/test_crewai_template_loader.py @@ -18,7 +18,7 @@ def _write(path: Path, content: str) -> None: def _prepare_static_root(root: Path) -> Path: _write( - root / "crewai" / "agents.yaml", + root / "agents.yaml", """ intent: role: Intent Agent @@ -29,7 +29,7 @@ organization: """.strip(), ) _write( - root / "crewai" / "tasks.yaml", + root / "tasks.yaml", """ intent: description: classify @@ -40,7 +40,7 @@ organization: """.strip(), ) _write( - root / "crewai" / "workflow.yaml", + root / "workflow.yaml", """ stages: - intent @@ -48,9 +48,6 @@ stages: - organization """.strip(), ) - _write(root / "crewai" / "prompts" / "intent.md", "intent prompt") - _write(root / "crewai" / "prompts" / "execution.md", "execution prompt") - _write(root / "crewai" / "prompts" / "organization.md", "organization prompt") _write( root / "tools.yaml", """ @@ -63,24 +60,21 @@ tools: def test_load_crewai_template_success_when_all_files_valid(tmp_path: Path) -> None: - static_root = _prepare_static_root(tmp_path / "agent") + static_root = _prepare_static_root(tmp_path) template = load_crewai_template(static_root) assert set(template.agents.keys()) == {"intent", "execution", "organization"} assert set(template.tasks.keys()) == {"intent", "execution", "organization"} assert template.workflow["stages"] == ["intent", "execution", "organization"] - assert template.prompts["intent"] == "intent prompt" - assert template.prompts["execution"] == "execution prompt" - assert template.prompts["organization"] == "organization prompt" assert template.tools_whitelist == {"asr_fun_asr", "doc_extract"} def test_load_crewai_template_raises_file_not_found_when_required_file_missing( tmp_path: Path, ) -> None: - static_root = _prepare_static_root(tmp_path / "agent") - (static_root / "crewai" / "tasks.yaml").unlink() + static_root = _prepare_static_root(tmp_path) + (static_root / "tasks.yaml").unlink() with pytest.raises(FileNotFoundError): load_crewai_template(static_root) @@ -89,9 +83,9 @@ def test_load_crewai_template_raises_file_not_found_when_required_file_missing( def test_load_crewai_template_raises_value_error_when_workflow_stages_invalid( tmp_path: Path, ) -> None: - static_root = _prepare_static_root(tmp_path / "agent") + static_root = _prepare_static_root(tmp_path) _write( - static_root / "crewai" / "workflow.yaml", + static_root / "workflow.yaml", """ stages: - execution @@ -105,7 +99,7 @@ stages: def test_load_tools_whitelist_from_tools_yaml(tmp_path: Path) -> None: - static_root = _prepare_static_root(tmp_path / "agent") + static_root = _prepare_static_root(tmp_path) whitelist = load_tools_whitelist(static_root) @@ -124,7 +118,7 @@ def test_validate_workflow_stages_rejects_extra_or_missing_stage() -> None: def test_load_tools_whitelist_rejects_non_string_item(tmp_path: Path) -> None: - static_root = _prepare_static_root(tmp_path / "agent") + static_root = _prepare_static_root(tmp_path) _write( static_root / "tools.yaml", """ diff --git a/backend/tests/unit/core/test_agent_init_data.py b/backend/tests/unit/core/test_agent_init_data.py index 9d85e95..cbd1359 100644 --- a/backend/tests/unit/core/test_agent_init_data.py +++ b/backend/tests/unit/core/test_agent_init_data.py @@ -7,7 +7,7 @@ from sqlalchemy import Column, String, Table, func, select from sqlalchemy.ext.asyncio import AsyncSession, async_sessionmaker, create_async_engine from core.db.base import Base -from core.initialization import init_data +from core.config.initial import init_data from models.llm import Llm from models.llm_factory import LlmFactory @@ -19,7 +19,7 @@ def test_llm_catalog_file_exists_and_has_required_fields() -> None: / "core" / "config" / "static" - / "agent" + / "database" / "llm_catalog.yaml" ) diff --git a/docs/plans/2026-03-02-config-restructuring-plan.md b/docs/plans/2026-03-02-config-restructuring-plan.md new file mode 100644 index 0000000..0eefbe4 --- /dev/null +++ b/docs/plans/2026-03-02-config-restructuring-plan.md @@ -0,0 +1,184 @@ +# Config 目录重构计划 + +**日期**: 2026-03-02 +**目标**: 重新整理 backend/src/core/config 下的配置文件,按领域分类 + +--- + +## 1. 需求背景 + +当前 `backend/src/core/config` 结构存在以下问题: + +1. **职责不清**: `initialization` 模块放在 `core/` 根目录,但实际是配置初始化,应归属 `config/` +2. **分类粗放**: `static/agent/` 混入了不同领域的配置(LLM 目录、工具白名单、Agent 模板) +3. **配置不符规范**: CrewAI 模板缺少必要字段(backstory、expected_output),且 prompts 目录是冗余的 + +--- + +## 2. 目标结构 + +``` +backend/src/core/ +├── config/ +│ ├── settings.py # 运行时配置(不变) +│ ├── initial/ +│ │ └── init_data.py # 种子数据初始化(移动) +│ └── static/ +│ ├── database/ +│ │ ├── llm_catalog.yaml # LLM 目录(移动) +│ │ └── user_agent_catalog.yaml # 用户 Agent 种子(新增,置空) +│ └── crewai/ +│ ├── agents.yaml # Agent 定义(移动 + 补充字段) +│ ├── tasks.yaml # Task 定义(移动 + 补充 expected_output) +│ ├── workflow.yaml # 工作流(移动) +│ └── tools.yaml # 工具白名单(移动) +└── agent/ # 代码实现(不变) + └── crewai/ + └── template_loader.py # 需更新路径引用 +``` + +--- + +## 3. 涉及代码清单 + +### 3.1 需要移动/删除的文件 + +| 操作 | 源路径 | 目标路径 | +|------|--------|----------| +| 移动 | `core/initialization/init_data.py` | `core/config/initial/init_data.py` | +| 移动 | `core/config/static/agent/llm_catalog.yaml` | `core/config/static/database/llm_catalog.yaml` | +| 新建 | - | `core/config/static/database/user_agent_catalog.yaml` | +| 移动 | `core/config/static/agent/crewai/agents.yaml` | `core/config/static/crewai/agents.yaml` | +| 移动 | `core/config/static/agent/crewai/tasks.yaml` | `core/config/static/crewai/tasks.yaml` | +| 移动 | `core/config/static/agent/crewai/workflow.yaml` | `core/config/static/crewai/workflow.yaml` | +| 移动 | `core/config/static/agent/tools.yaml` | `core/config/static/crewai/tools.yaml` | +| 删除 | `core/config/static/agent/crewai/prompts/` | - | + +### 3.2 需要修改的代码文件 + +| 文件 | 修改内容 | +|------|----------| +| `core/config/initial/init_data.py` | 更新 `_default_catalog_path()` 指向 `static/database/` | +| `core/agent/crewai/template_loader.py` | 1. 更新 `_default_static_root()` 指向 `static/crewai/`
2. 移除 `CrewAITemplate.prompts` 字段
3. 移除 `_read_prompt()` 和 prompts 加载逻辑 | +| `core/runtime/cli.py` | 更新 import 路径 | +| `tests/unit/core/test_agent_init_data.py` | 更新 import 路径和路径断言 | +| `tests/unit/core/config/test_crewai_template_loader.py` | 1. 更新路径构造
2. 移除 prompts 目录创建
3. 移除 prompts 相关断言 | + +### 3.3 需要更新的配置文件内容 + +#### agents.yaml - 补充 backstory + +```yaml +intent: + role: Intent Agent + goal: Classify user intent and decide execution strategy + backstory: > + You are an expert intent classifier with deep understanding + of user query patterns and dialogue acts. Your role is to + analyze user input and determine the appropriate action. + +execution: + role: Execution Agent + goal: Execute tasks with available tools + backstory: > + You are a skilled task executor with expertise in tool calling, + API interactions, and result verification. You work systematically + to complete user requests. + +organization: + role: Organization Agent + goal: Format final response and references + backstory: > + You specialize in presenting results in a clear, user-friendly manner. + You ensure responses are well-structured and actionable. +``` + +#### tasks.yaml - 补充 expected_output + +```yaml +intent: + description: Identify user intent and required capabilities + expected_output: > + Structured intent classification with intent type, confidence score, + and recommended action plan + +execution: + description: Execute intent with tools and model calls + expected_output: > + Verified execution results with tool outputs, status, and any errors + +organization: + description: Format final response and references + expected_output: > + User-friendly response with structured output, citations, and + clear next steps if applicable +``` + +#### user_agent_catalog.yaml - 置空 + +```yaml +agents: [] +``` + +--- + +## 4. 实施步骤 + +### Phase 1: 移动配置文件 + +1. 创建 `core/config/static/database/` 目录 +2. 创建 `core/config/static/crewai/` 目录 +3. 移动并合并 LLM 目录配置 +4. 创建空的 user_agent_catalog.yaml + +### Phase 2: 更新代码引用 + +1. 移动 `initialization/init_data.py` → `config/initial/init_data.py` +2. 更新 `init_data.py` 中的路径函数 `_default_catalog_path()` → `static/database/` +3. 更新 `template_loader.py`: + - 路径函数 `_default_static_root()` → `static/crewai/` + - 移除 `_read_prompt()` 函数 + - 移除 `CrewAITemplate.prompts` 字段 + - 移除 prompts 加载逻辑 +4. 更新 `cli.py` 的 import 路径 +5. 删除旧的 `core/initialization/` 目录(如为空) + +### Phase 4: 更新测试 + +1. 更新 `test_agent_init_data.py`: + - import 路径: `core.initialization` → `core.config.initial` + - 路径断言: `static/agent/` → `static/database/` +2. 更新 `test_crewai_template_loader.py`: + - 路径构造: `agent/` → `crewai/` + - 移除 prompts 目录创建代码 + - 移除 `template.prompts` 相关断言 +3. 运行测试验证 + +--- + +## 5. 风险与回滚 + +### 风险 + +- 路径变更可能导致运行时找不到配置文件 +- 测试路径断言需要同步更新 + +### 回滚方案 + +- 保留 git 分支,验证通过后再合并 +- 如有问题,可通过 git revert 快速回滚 + +--- + +## 6. 验证方式 + +```bash +# 1. 运行单元测试 +cd backend && uv run pytest tests/unit/core/test_agent_init_data.py tests/unit/core/config/test_crewai_template_loader.py -v + +# 2. 运行 lint +cd backend && uv run ruff check src/core/config/ src/core/agent/crewai/ src/core/runtime/cli.py + +# 3. 运行 typecheck +cd backend && uv run basedpyright src/core/config/ src/core/agent/crewai/ src/core/runtime/cli.py +```