diff --git a/spec/metadata-role-separation/design.md b/spec/metadata-role-separation/design.md new file mode 100644 index 0000000..c8a8328 --- /dev/null +++ b/spec/metadata-role-separation/design.md @@ -0,0 +1,615 @@ +# 元数据职责分层优化 - 技术设计 + +## 1. 系统架构 + +### 1.1 整体架构 + +``` +┌─────────────────────────────────────────────────────────────────────────┐ +│ 管理端 (ai-service-admin) │ +├─────────────────────────────────────────────────────────────────────────┤ +│ ┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐ │ +│ │ 元数据字段配置 │ │ 槽位定义配置 │ │ 按角色过滤视图 │ │ +│ │ (field_roles) │ │ (SlotDefinition) │ │ (RoleFilter) │ │ +│ └────────┬────────┘ └────────┬────────┘ └────────┬────────┘ │ +└───────────┼────────────────────┼────────────────────┼───────────────────┘ + │ │ │ + ▼ ▼ ▼ +┌─────────────────────────────────────────────────────────────────────────┐ +│ 后端服务 (ai-service) │ +├─────────────────────────────────────────────────────────────────────────┤ +│ │ +│ ┌─────────────────────────────────────────────────────────────────┐ │ +│ │ API Layer │ │ +│ │ ┌──────────────────────┐ ┌──────────────────────┐ │ │ +│ │ │ MetadataFieldAPI │ │ SlotDefinitionAPI │ │ │ +│ │ │ - CRUD │ │ - CRUD │ │ │ +│ │ │ - getByRole │ │ - getByRole │ │ │ +│ │ └──────────┬───────────┘ └──────────┬───────────┘ │ │ +│ └─────────────┼────────────────────────┼──────────────────────────┘ │ +│ │ │ │ +│ ┌─────────────┼────────────────────────┼──────────────────────────┐ │ +│ │ │ Service Layer │ │ │ +│ │ ┌──────────▼───────────┐ ┌────────▼──────────┐ │ │ +│ │ │ MetadataFieldService │ │ SlotDefinitionSvc │ │ │ +│ │ │ - create/update │ │ - create/update │ │ │ +│ │ │ - getByRole │ │ - getByRole │ │ │ +│ │ │ - validateRoles │ │ - linkToField │ │ │ +│ │ └──────────┬───────────┘ └────────┬──────────┘ │ │ +│ └─────────────┼────────────────────────┼──────────────────────────┘ │ +│ │ │ │ +│ ┌─────────────┼────────────────────────┼──────────────────────────┐ │ +│ │ │ Tool Integration │ │ │ +│ │ ┌──────────▼────────────────────────▼──────────┐ │ │ +│ │ │ RoleBasedFieldProvider │ │ │ +│ │ │ - getFieldsByRole(role) │ │ │ +│ │ │ - getSlotDefinitionsByRole(role) │ │ │ +│ │ └──────────────────────┬───────────────────────┘ │ │ +│ └─────────────────────────┼──────────────────────────────────────┘ │ +│ │ │ +│ ┌─────────────────────────┼──────────────────────────────────────┐ │ +│ │ Tool Consumers │ │ +│ │ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │ │ +│ │ │kb_search_ │ │memory_recall │ │intent_hint/ │ │ │ +│ │ │dynamic │ │ │ │high_risk_ │ │ │ +│ │ │[resource_ │ │[slot] │ │check │ │ │ +│ │ │filter] │ │ │ │[routing_ │ │ │ +│ │ └──────────────┘ └──────────────┘ │signal] │ │ │ +│ │ └──────────────┘ │ │ +│ │ ┌──────────────┐ │ │ +│ │ │template_ │ │ │ +│ │ │engine │ │ │ +│ │ │[prompt_var] │ │ │ +│ │ └──────────────┘ │ │ +│ └────────────────────────────────────────────────────────────────┘ │ +│ │ +└─────────────────────────────────────────────────────────────────────────┘ + │ │ │ + ▼ ▼ ▼ +┌─────────────────────────────────────────────────────────────────────────┐ +│ 数据层 │ +├─────────────────────────────────────────────────────────────────────────┤ +│ ┌─────────────────────┐ ┌─────────────────────┐ │ +│ │ metadata_field_ │ │ slot_definitions │ │ +│ │ definitions │ │ │ │ +│ │ - id │ │ - id │ │ +│ │ - field_key │ │ - slot_key │ │ +│ │ - field_roles[] │ │ - type │ │ +│ │ - ... │ │ - linked_field_id │ │ +│ └─────────────────────┘ └─────────────────────┘ │ +│ │ +│ ┌─────────────────────┐ ┌─────────────────────┐ │ +│ │ Redis Cache │ │ PostgreSQL │ │ +│ │ - field_roles:by_tenant │ - 持久化存储 │ │ +│ └─────────────────────┘ └─────────────────────┘ │ +└─────────────────────────────────────────────────────────────────────────┘ +``` + +### 1.2 模块依赖关系 + +``` +metadata-role-separation + │ + ├── metadata-governance (依赖) + │ └── 元数据字段定义基础能力 + │ + ├── intent-driven-mid-platform (依赖) + │ └── 中台运行时工具链 + │ + └── ai-service-admin (依赖) + └── 管理端配置界面 +``` + +--- + +## 2. 数据模型设计 + +### 2.1 MetadataFieldDefinition 扩展 + +在现有 `metadata_field_definitions` 表基础上新增字段: + +```sql +-- 新增字段:field_roles +ALTER TABLE metadata_field_definitions +ADD COLUMN field_roles JSONB DEFAULT '[]'::jsonb; + +-- 创建 GIN 索引支持按角色查询 +CREATE INDEX idx_metadata_field_definitions_roles +ON metadata_field_definitions USING GIN (field_roles); + +-- 注释 +COMMENT ON COLUMN metadata_field_definitions.field_roles IS '字段角色列表:resource_filter, slot, prompt_var, routing_signal'; +``` + +**字段定义**: + +| 字段名 | 类型 | 必填 | 默认值 | 说明 | +|-------|------|-----|-------|------| +| `field_roles` | JSONB | 否 | `[]` | 字段角色列表,存储字符串数组 | + +**角色枚举值**: + +```python +class FieldRole(str, Enum): + RESOURCE_FILTER = "resource_filter" # 资源过滤 + SLOT = "slot" # 运行时槽位 + PROMPT_VAR = "prompt_var" # 提示词变量 + ROUTING_SIGNAL = "routing_signal" # 路由信号 +``` + +### 2.2 SlotDefinition 新增表 + +```sql +-- 槽位定义表 +CREATE TABLE slot_definitions ( + id UUID PRIMARY KEY DEFAULT gen_random_uuid(), + tenant_id UUID NOT NULL, + slot_key VARCHAR(100) NOT NULL, + type VARCHAR(20) NOT NULL, + required BOOLEAN NOT NULL DEFAULT FALSE, + extract_strategy VARCHAR(20), + validation_rule TEXT, + ask_back_prompt TEXT, + default_value JSONB, + linked_field_id UUID REFERENCES metadata_field_definitions(id), + created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(), + updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(), + + CONSTRAINT uk_slot_definitions_tenant_key UNIQUE (tenant_id, slot_key), + CONSTRAINT chk_slot_definitions_type CHECK (type IN ('string', 'number', 'boolean', 'enum', 'array_enum')), + CONSTRAINT chk_slot_definitions_extract_strategy CHECK (extract_strategy IS NULL OR extract_strategy IN ('rule', 'llm', 'user_input')) +); + +-- 索引 +CREATE INDEX idx_slot_definitions_tenant ON slot_definitions(tenant_id); +CREATE INDEX idx_slot_definitions_linked_field ON slot_definitions(linked_field_id); + +-- 注释 +COMMENT ON TABLE slot_definitions IS '槽位定义表'; +COMMENT ON COLUMN slot_definitions.slot_key IS '槽位键名,可与元数据字段 field_key 关联'; +COMMENT ON COLUMN slot_definitions.linked_field_id IS '关联的元数据字段 ID'; +``` + +### 2.3 ER 图 + +``` +┌─────────────────────────────┐ ┌─────────────────────────────┐ +│ metadata_field_definitions │ │ slot_definitions │ +├─────────────────────────────┤ ├─────────────────────────────┤ +│ id (PK) │◄──────│ linked_field_id (FK) │ +│ tenant_id │ │ id (PK) │ +│ field_key │ │ tenant_id │ +│ label │ │ slot_key │ +│ type │ │ type │ +│ required │ │ required │ +│ options │ │ extract_strategy │ +│ default_value │ │ validation_rule │ +│ scope │ │ ask_back_prompt │ +│ is_filterable │ │ default_value │ +│ is_rank_feature │ │ created_at │ +│ status │ │ updated_at │ +│ field_roles ◀── NEW │ │ │ +│ version │ │ │ +│ created_at │ │ │ +│ updated_at │ │ │ +└─────────────────────────────┘ └─────────────────────────────┘ +``` + +--- + +## 3. 核心流程设计 + +### 3.1 字段职责配置流程 + +``` +┌─────────────────────────────────────────────────────────────────────────┐ +│ 管理端配置流程 │ +├─────────────────────────────────────────────────────────────────────────┤ +│ │ +│ 1. 管理员进入元数据字段配置页面 │ +│ │ │ +│ ▼ │ +│ 2. 创建/编辑字段定义 │ +│ │ │ +│ ├── 填写基本信息 (field_key, label, type, etc.) │ +│ │ │ +│ ├── 选择字段角色 (field_roles 多选) │ +│ │ ├── [ ] resource_filter - 资源过滤 │ +│ │ ├── [ ] slot - 运行时槽位 │ +│ │ ├── [ ] prompt_var - 提示词变量 │ +│ │ └── [ ] routing_signal - 路由信号 │ +│ │ │ +│ ▼ │ +│ 3. 后端校验 │ +│ │ │ +│ ├── field_key 格式校验 (小写字母数字下划线) │ +│ ├── field_roles 枚举值校验 │ +│ └── 租户内唯一性校验 │ +│ │ │ +│ ▼ │ +│ 4. 保存到数据库 │ +│ │ │ +│ └── field_roles 以 JSONB 格式存储 │ +│ │ +└─────────────────────────────────────────────────────────────────────────┘ +``` + +### 3.2 按角色查询流程 + +``` +┌─────────────────────────────────────────────────────────────────────────┐ +│ 按角色查询流程 │ +├─────────────────────────────────────────────────────────────────────────┤ +│ │ +│ 工具/模块请求字段 │ +│ │ │ +│ ▼ │ +│ RoleBasedFieldProvider.getFieldsByRole(role, tenant_id) │ +│ │ │ +│ ▼ │ +│ ┌─────────────────────────────────────────────────────────────────┐ │ +│ │ SELECT * FROM metadata_field_definitions │ │ +│ │ WHERE tenant_id = :tenant_id │ │ +│ │ AND status = 'active' │ │ +│ │ AND field_roles ? :role -- JSONB contains 查询 │ │ +│ └─────────────────────────────────────────────────────────────────┘ │ +│ │ │ +│ ▼ │ +│ 返回字段定义列表 │ +│ │ │ +│ ▼ │ +│ 工具按需消费字段 │ +│ │ +└─────────────────────────────────────────────────────────────────────────┘ +``` + +### 3.3 工具协同改造流程 + +``` +┌─────────────────────────────────────────────────────────────────────────┐ +│ 工具协同改造流程 │ +├─────────────────────────────────────────────────────────────────────────┤ +│ │ +│ ┌──────────────────────────────────────────────────────────────────┐ │ +│ │ kb_search_dynamic [AC-MRS-11] │ │ +│ │ │ │ +│ │ 改造前: │ │ +│ │ filterable_fields = get_filterable_fields(tenant_id) │ │ +│ │ WHERE is_filterable = true │ │ +│ │ │ │ +│ │ 改造后: │ │ +│ │ filterable_fields = get_fields_by_role( │ │ +│ │ tenant_id, role='resource_filter' │ │ +│ │ ) │ │ +│ └──────────────────────────────────────────────────────────────────┘ │ +│ │ +│ ┌──────────────────────────────────────────────────────────────────┐ │ +│ │ memory_recall [AC-MRS-12] │ │ +│ │ │ │ +│ │ 改造前: │ │ +│ │ slots = context.get('slots', {}) # 无角色过滤 │ │ +│ │ │ │ +│ │ 改造后: │ │ +│ │ slot_fields = get_fields_by_role( │ │ +│ │ tenant_id, role='slot' │ │ +│ │ ) │ │ +│ │ slots = {k: v for k, v in context.items() │ │ +│ │ if k in slot_fields} │ │ +│ └──────────────────────────────────────────────────────────────────┘ │ +│ │ +│ ┌──────────────────────────────────────────────────────────────────┐ │ +│ │ intent_hint / high_risk_check [AC-MRS-13] │ │ +│ │ │ │ +│ │ 改造前: │ │ +│ │ routing_fields = all_metadata_fields # 全量字段 │ │ +│ │ │ │ +│ │ 改造后: │ │ +│ │ routing_fields = get_fields_by_role( │ │ +│ │ tenant_id, role='routing_signal' │ │ +│ │ ) │ │ +│ └──────────────────────────────────────────────────────────────────┘ │ +│ │ +│ ┌──────────────────────────────────────────────────────────────────┐ │ +│ │ template_engine [AC-MRS-14] │ │ +│ │ │ │ +│ │ 改造前: │ │ +│ │ variables = extract_all_variables(template) │ │ +│ │ values = get_all_metadata_values(context) │ │ +│ │ │ │ +│ │ 改造后: │ │ +│ │ prompt_var_fields = get_fields_by_role( │ │ +│ │ tenant_id, role='prompt_var' │ │ +│ │ ) │ │ +│ │ values = {k: v for k, v in context.items() │ │ +│ │ if k in prompt_var_fields} │ │ +│ └──────────────────────────────────────────────────────────────────┘ │ +│ │ +└─────────────────────────────────────────────────────────────────────────┘ +``` + +--- + +## 4. 接口设计 + +### 4.1 后端 API 接口 + +| 接口 | 方法 | 说明 | AC | +|------|------|------|-----| +| `/admin/metadata-schemas` | GET | 获取字段列表(支持 role 过滤) | AC-MRS-06 | +| `/admin/metadata-schemas` | POST | 创建字段(含 field_roles) | AC-MRS-01,02,03 | +| `/admin/metadata-schemas/{id}` | PUT | 更新字段(含 field_roles) | AC-MRS-01 | +| `/admin/metadata-schemas/{id}` | DELETE | 删除字段(无需兼容) | AC-MRS-16 | +| `/admin/metadata-schemas/by-role` | GET | 按角色查询字段 | AC-MRS-04,05 | +| `/admin/slot-definitions` | GET | 获取槽位定义列表 | - | +| `/admin/slot-definitions` | POST | 创建槽位定义 | AC-MRS-07,08 | +| `/admin/slot-definitions/{id}` | PUT | 更新槽位定义 | - | +| `/admin/slot-definitions/{id}` | DELETE | 删除槽位定义 | AC-MRS-16 | +| `/mid/slots/by-role` | GET | 运行时按角色获取槽位 | AC-MRS-10 | +| `/mid/slots/{slot_key}` | GET | 获取运行时槽位值 | AC-MRS-09 | + +### 4.2 内部服务接口 + +```python +class RoleBasedFieldProvider: + """基于角色的字段提供者""" + + async def get_fields_by_role( + self, + tenant_id: str, + role: FieldRole, + include_deprecated: bool = False, + ) -> list[MetadataFieldDefinition]: + """ + 按角色获取字段定义 + + Args: + tenant_id: 租户ID + role: 字段角色 + include_deprecated: 是否包含已废弃字段 + + Returns: + 字段定义列表 + """ + + async def get_slot_definitions_by_role( + self, + tenant_id: str, + role: FieldRole, + ) -> list[SlotDefinition]: + """ + 按角色获取槽位定义(包含关联字段信息) + """ +``` + +--- + +## 5. 前端设计 + +### 5.1 元数据字段配置页面改造 + +**新增组件**:`FieldRolesSelector.vue` + +```vue + + + 字段角色 + + + {{ role.label }} + + + + + + + + + +``` + +### 5.2 按角色过滤视图 + +**新增过滤器**:在元数据字段列表页面增加角色过滤下拉框 + +```vue + + + + + + + +``` + +--- + +## 6. 缓存策略 + +### 6.1 缓存设计 + +```python +class FieldRoleCache: + """字段角色缓存""" + + CACHE_KEY_PREFIX = "field_roles" + CACHE_TTL = 300 # 5分钟 + + async def get_fields_by_role( + self, + tenant_id: str, + role: FieldRole, + ) -> list[MetadataFieldDefinition]: + cache_key = f"{self.CACHE_KEY_PREFIX}:{tenant_id}:{role}" + + # 尝试从缓存获取 + cached = await self._redis.get(cache_key) + if cached: + return self._deserialize(cached) + + # 从数据库查询 + fields = await self._db_query(tenant_id, role) + + # 写入缓存 + await self._redis.setex( + cache_key, + self.CACHE_TTL, + self._serialize(fields), + ) + + return fields + + async def invalidate(self, tenant_id: str): + """失效租户所有角色缓存""" + pattern = f"{self.CACHE_KEY_PREFIX}:{tenant_id}:*" + keys = await self._redis.keys(pattern) + if keys: + await self._redis.delete(*keys) +``` + +### 6.2 缓存失效策略 + +- 字段创建/更新/删除时失效该租户所有角色缓存 +- 槽位定义变更时失效相关角色缓存 + +--- + +## 7. 异常处理 + +### 7.1 错误码定义 + +| 错误码 | 说明 | HTTP 状态码 | +|-------|------|------------| +| `INVALID_ROLE` | 无效的角色参数 | 400 | +| `FIELD_KEY_EXISTS` | field_key 已存在 | 409 | +| `SLOT_KEY_EXISTS` | slot_key 已存在 | 409 | +| `LINKED_FIELD_NOT_FOUND` | 关联字段不存在 | 404 | + +### 7.2 异常处理示例 + +```python +class InvalidRoleError(Exception): + """无效角色异常""" + def __init__(self, role: str): + self.role = role + self.valid_roles = [r.value for r in FieldRole] + super().__init__( + f"Invalid role '{role}'. Valid roles are: {', '.join(self.valid_roles)}" + ) +``` + +--- + +## 8. 测试策略 + +### 8.1 单元测试 + +- `RoleBasedFieldProvider` 按角色查询测试 +- `FieldRoleCache` 缓存读写测试 +- 字段角色校验测试 + +### 8.2 集成测试 + +- API 端点测试(CRUD + 按角色查询) +- 工具协同改造测试(验证各工具只消费对应角色字段) + +### 8.3 契约测试 + +- OpenAPI Schema 校验 +- 响应结构验证 + +--- + +## 9. 迁移与部署 + +### 9.1 数据库迁移 + +```sql +-- 1. 新增 field_roles 字段 +ALTER TABLE metadata_field_definitions +ADD COLUMN field_roles JSONB DEFAULT '[]'::jsonb; + +-- 2. 创建索引 +CREATE INDEX idx_metadata_field_definitions_roles +ON metadata_field_definitions USING GIN (field_roles); + +-- 3. 创建 slot_definitions 表 +CREATE TABLE slot_definitions ( + -- ... 见 2.2 节 +); + +-- 4. 初始化现有字段的默认角色(可选) +-- 根据 is_filterable 推断 resource_filter 角色 +UPDATE metadata_field_definitions +SET field_roles = '["resource_filter"]'::jsonb +WHERE is_filterable = true AND status = 'active'; +``` + +### 9.2 部署顺序 + +1. 执行数据库迁移脚本 +2. 部署后端服务(向后兼容,field_roles 可为空) +3. 部署前端页面 +4. 配置字段角色 + +--- + +## 10. 监控与观测 + +### 10.1 关键指标 + +| 指标名 | 说明 | +|-------|------| +| `field_role_query_count` | 按角色查询次数 | +| `field_role_query_latency` | 按角色查询延迟 | +| `field_role_cache_hit_rate` | 角色缓存命中率 | +| `tool_field_consumption` | 工具字段消费统计 | + +### 10.2 日志字段 + +```json +{ + "event": "field_role_query", + "tenant_id": "xxx", + "role": "resource_filter", + "field_count": 5, + "duration_ms": 12, + "cache_hit": true +} +``` diff --git a/spec/metadata-role-separation/openapi.deps.yaml b/spec/metadata-role-separation/openapi.deps.yaml new file mode 100644 index 0000000..4d850db --- /dev/null +++ b/spec/metadata-role-separation/openapi.deps.yaml @@ -0,0 +1,272 @@ +openapi: 3.0.3 +info: + title: 元数据职责分层模块 - 外部依赖 + description: | + 本模块依赖的外部 API 契约,用于生成 Mock/SDK。 + + ## 依赖说明 + - metadata-governance: 元数据字段定义基础能力 + - intent-driven-mid-platform: 中台运行时工具链 + version: 0.1.0 + x-contract-level: L1 + contact: + name: AI Robot Core Team + +servers: + - url: /api + description: API Server + +tags: + - name: MetadataGovernance + description: 元数据治理模块依赖 + - name: MidPlatform + description: 中台模块依赖 + +paths: + /admin/metadata-schemas: + get: + summary: 获取元数据字段定义列表(依赖) + description: 依赖 metadata-governance 模块的元数据字段列表查询能力 + operationId: depsListMetadataSchemas + tags: + - MetadataGovernance + parameters: + - name: status + in: query + schema: + type: string + enum: + - draft + - active + - deprecated + - name: scope + in: query + schema: + type: string + enum: + - kb_document + - intent_rule + - script_flow + - prompt_template + - name: tenant_id + in: query + required: true + schema: + type: string + format: uuid + responses: + '200': + description: 成功返回字段定义列表 + content: + application/json: + schema: + type: array + items: + $ref: '#/components/schemas/MetadataFieldDefinition' + + /admin/kb/documents: + get: + summary: 获取 KB 文档列表(依赖) + description: 依赖 KB 文档管理能力,用于验证字段使用情况 + operationId: depsListKbDocuments + tags: + - MetadataGovernance + parameters: + - name: tenant_id + in: query + required: true + schema: + type: string + format: uuid + - name: kb_id + in: query + schema: + type: string + format: uuid + responses: + '200': + description: 成功返回文档列表 + content: + application/json: + schema: + type: array + items: + $ref: '#/components/schemas/KbDocument' + + /mid/dialogue/respond: + post: + summary: 中台对话响应(依赖) + description: 依赖中台对话响应能力,用于工具协同改造验证 + operationId: depsRespondDialogue + tags: + - MidPlatform + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/DialogueRequest' + responses: + '200': + description: 成功返回对话响应 + content: + application/json: + schema: + $ref: '#/components/schemas/DialogueResponse' + +components: + schemas: + MetadataFieldStatus: + type: string + enum: + - draft + - active + - deprecated + + MetadataScope: + type: string + enum: + - kb_document + - intent_rule + - script_flow + - prompt_template + + MetadataFieldType: + type: string + enum: + - string + - number + - boolean + - enum + - array_enum + + MetadataFieldDefinition: + type: object + properties: + id: + type: string + format: uuid + tenant_id: + type: string + format: uuid + field_key: + type: string + label: + type: string + type: + $ref: '#/components/schemas/MetadataFieldType' + required: + type: boolean + options: + type: array + items: + type: string + default_value: + type: object + scope: + type: array + items: + $ref: '#/components/schemas/MetadataScope' + is_filterable: + type: boolean + is_rank_feature: + type: boolean + status: + $ref: '#/components/schemas/MetadataFieldStatus' + version: + type: integer + created_at: + type: string + format: date-time + updated_at: + type: string + format: date-time + + KbDocument: + type: object + properties: + id: + type: string + format: uuid + tenant_id: + type: string + format: uuid + kb_id: + type: string + format: uuid + title: + type: string + content: + type: string + metadata: + type: object + additionalProperties: true + created_at: + type: string + format: date-time + updated_at: + type: string + format: date-time + + DialogueRequest: + type: object + required: + - tenant_id + - user_id + - session_id + - user_message + properties: + tenant_id: + type: string + format: uuid + user_id: + type: string + format: uuid + session_id: + type: string + format: uuid + user_message: + type: string + context: + type: object + additionalProperties: true + description: 会话上下文,包含槽位信息 + + DialogueResponse: + type: object + properties: + session_id: + type: string + format: uuid + request_id: + type: string + format: uuid + segments: + type: array + items: + type: object + properties: + segment_id: + type: string + text: + type: string + delay_after: + type: integer + trace: + type: object + properties: + mode: + type: string + enum: + - agent + - micro_flow + - fixed + - transfer + intent: + type: string + tool_calls: + type: array + items: + type: object + fallback_reason_code: + type: string diff --git a/spec/metadata-role-separation/openapi.provider.yaml b/spec/metadata-role-separation/openapi.provider.yaml new file mode 100644 index 0000000..eef0bd6 --- /dev/null +++ b/spec/metadata-role-separation/openapi.provider.yaml @@ -0,0 +1,774 @@ +openapi: 3.0.3 +info: + title: 元数据职责分层 API + description: | + 提供元数据字段职责分层配置、槽位定义管理及按角色查询能力。 + + ## 字段角色定义 + - `resource_filter`: 资源过滤角色,用于 KB 文档检索 + - `slot`: 运行时槽位角色,用于对话信息收集 + - `prompt_var`: 提示词变量角色,用于 Prompt 注入 + - `routing_signal`: 路由信号角色,用于意图路由判断 + version: 0.1.0 + x-contract-level: L1 + contact: + name: AI Robot Core Team + +servers: + - url: /api + description: API Server + +tags: + - name: MetadataSchema + description: 元数据字段定义管理(扩展 field_roles) + - name: SlotDefinition + description: 槽位定义管理 + - name: RuntimeSlot + description: 运行时槽位查询 + +paths: + /admin/metadata-schemas: + get: + summary: 获取元数据字段定义列表 + description: |- + [AC-MRS-06] 支持按状态、范围、角色过滤查询元数据字段定义列表。 + operationId: listMetadataSchemas + tags: + - MetadataSchema + parameters: + - name: status + in: query + description: 字段状态过滤 + schema: + $ref: '#/components/schemas/MetadataFieldStatus' + - name: scope + in: query + description: 适用范围过滤 + schema: + $ref: '#/components/schemas/MetadataScope' + - name: field_role + in: query + description: 字段角色过滤 + schema: + $ref: '#/components/schemas/FieldRole' + - name: tenant_id + in: query + required: true + schema: + type: string + format: uuid + responses: + '200': + description: 成功返回字段定义列表 + content: + application/json: + schema: + type: array + items: + $ref: '#/components/schemas/MetadataFieldDefinition' + '400': + $ref: '#/components/responses/BadRequest' + '401': + $ref: '#/components/responses/Unauthorized' + + post: + summary: 创建元数据字段定义 + description: |- + [AC-MRS-01][AC-MRS-02][AC-MRS-03] 创建新的元数据字段定义,支持 field_roles 多选配置。 + operationId: createMetadataSchema + tags: + - MetadataSchema + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/MetadataFieldDefinitionCreate' + responses: + '201': + description: 创建成功 + content: + application/json: + schema: + $ref: '#/components/schemas/MetadataFieldDefinition' + '400': + $ref: '#/components/responses/BadRequest' + '409': + description: field_key 已存在 + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + + /admin/metadata-schemas/{id}: + parameters: + - name: id + in: path + required: true + schema: + type: string + format: uuid + + get: + summary: 获取单个元数据字段定义 + operationId: getMetadataSchema + tags: + - MetadataSchema + responses: + '200': + description: 成功返回字段定义 + content: + application/json: + schema: + $ref: '#/components/schemas/MetadataFieldDefinition' + '404': + $ref: '#/components/responses/NotFound' + + put: + summary: 更新元数据字段定义 + description: |- + [AC-MRS-01] 更新元数据字段定义,支持修改 field_roles。 + operationId: updateMetadataSchema + tags: + - MetadataSchema + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/MetadataFieldDefinitionUpdate' + responses: + '200': + description: 更新成功 + content: + application/json: + schema: + $ref: '#/components/schemas/MetadataFieldDefinition' + '400': + $ref: '#/components/responses/BadRequest' + '404': + $ref: '#/components/responses/NotFound' + + delete: + summary: 删除元数据字段定义 + description: |- + [AC-MRS-16] 删除元数据字段定义,无需考虑历史数据兼容性。 + operationId: deleteMetadataSchema + tags: + - MetadataSchema + responses: + '204': + description: 删除成功 + '404': + $ref: '#/components/responses/NotFound' + + /admin/metadata-schemas/by-role: + get: + summary: 按角色查询元数据字段定义 + description: |- + [AC-MRS-04][AC-MRS-05] 按指定角色查询所有包含该角色的活跃字段定义。 + operationId: getMetadataSchemasByRole + tags: + - MetadataSchema + parameters: + - name: role + in: query + required: true + description: 字段角色 + schema: + $ref: '#/components/schemas/FieldRole' + - name: tenant_id + in: query + required: true + schema: + type: string + format: uuid + - name: include_deprecated + in: query + description: 是否包含已废弃字段 + schema: + type: boolean + default: false + responses: + '200': + description: 成功返回字段定义列表 + content: + application/json: + schema: + type: array + items: + $ref: '#/components/schemas/MetadataFieldDefinition' + '400': + description: 无效的角色参数 + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + example: + error_code: INVALID_ROLE + message: "Invalid role 'invalid_role'. Valid roles are: resource_filter, slot, prompt_var, routing_signal" + + /admin/slot-definitions: + get: + summary: 获取槽位定义列表 + operationId: listSlotDefinitions + tags: + - SlotDefinition + parameters: + - name: tenant_id + in: query + required: true + schema: + type: string + format: uuid + - name: required + in: query + description: 是否必填槽位过滤 + schema: + type: boolean + responses: + '200': + description: 成功返回槽位定义列表 + content: + application/json: + schema: + type: array + items: + $ref: '#/components/schemas/SlotDefinition' + + post: + summary: 创建槽位定义 + description: |- + [AC-MRS-07][AC-MRS-08] 创建新的槽位定义,可关联已有元数据字段。 + operationId: createSlotDefinition + tags: + - SlotDefinition + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/SlotDefinitionCreate' + responses: + '201': + description: 创建成功 + content: + application/json: + schema: + $ref: '#/components/schemas/SlotDefinition' + '400': + $ref: '#/components/responses/BadRequest' + + /admin/slot-definitions/{id}: + parameters: + - name: id + in: path + required: true + schema: + type: string + format: uuid + + get: + summary: 获取单个槽位定义 + operationId: getSlotDefinition + tags: + - SlotDefinition + responses: + '200': + description: 成功返回槽位定义 + content: + application/json: + schema: + $ref: '#/components/schemas/SlotDefinition' + '404': + $ref: '#/components/responses/NotFound' + + put: + summary: 更新槽位定义 + operationId: updateSlotDefinition + tags: + - SlotDefinition + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/SlotDefinitionUpdate' + responses: + '200': + description: 更新成功 + content: + application/json: + schema: + $ref: '#/components/schemas/SlotDefinition' + '400': + $ref: '#/components/responses/BadRequest' + '404': + $ref: '#/components/responses/NotFound' + + delete: + summary: 删除槽位定义 + description: |- + [AC-MRS-16] 删除槽位定义,无需考虑历史数据兼容性。 + operationId: deleteSlotDefinition + tags: + - SlotDefinition + responses: + '204': + description: 删除成功 + '404': + $ref: '#/components/responses/NotFound' + + /mid/slots/by-role: + get: + summary: 运行时按角色获取槽位定义 + description: |- + [AC-MRS-10] 运行时接口,按角色获取槽位定义及关联的元数据字段信息。 + operationId: getSlotsByRole + tags: + - RuntimeSlot + parameters: + - name: role + in: query + required: true + schema: + $ref: '#/components/schemas/FieldRole' + - name: tenant_id + in: query + required: true + schema: + type: string + format: uuid + responses: + '200': + description: 成功返回槽位定义列表 + content: + application/json: + schema: + type: array + items: + $ref: '#/components/schemas/SlotDefinitionWithField' + '400': + $ref: '#/components/responses/BadRequest' + + /mid/slots/{slot_key}: + parameters: + - name: slot_key + in: path + required: true + schema: + type: string + + get: + summary: 获取运行时槽位值 + description: |- + [AC-MRS-09] 获取指定槽位的运行时值,包含来源、置信度、更新时间。 + operationId: getSlotValue + tags: + - RuntimeSlot + parameters: + - name: tenant_id + in: query + required: true + schema: + type: string + format: uuid + - name: user_id + in: query + required: true + schema: + type: string + format: uuid + - name: session_id + in: query + required: true + schema: + type: string + format: uuid + responses: + '200': + description: 成功返回槽位值 + content: + application/json: + schema: + $ref: '#/components/schemas/RuntimeSlotValue' + '404': + description: 槽位不存在 + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + +components: + schemas: + FieldRole: + type: string + enum: + - resource_filter + - slot + - prompt_var + - routing_signal + description: | + 字段角色类型: + - resource_filter: 资源过滤角色 + - slot: 运行时槽位角色 + - prompt_var: 提示词变量角色 + - routing_signal: 路由信号角色 + + MetadataFieldStatus: + type: string + enum: + - draft + - active + - deprecated + + MetadataScope: + type: string + enum: + - kb_document + - intent_rule + - script_flow + - prompt_template + + MetadataFieldType: + type: string + enum: + - string + - number + - boolean + - enum + - array_enum + + MetadataFieldDefinition: + type: object + required: + - id + - tenant_id + - field_key + - label + - type + - status + - field_roles + properties: + id: + type: string + format: uuid + tenant_id: + type: string + format: uuid + field_key: + type: string + pattern: '^[a-z][a-z0-9_]*$' + description: 字段键名,仅允许小写字母数字下划线 + label: + type: string + description: 显示名称 + type: + $ref: '#/components/schemas/MetadataFieldType' + required: + type: boolean + default: false + options: + type: array + items: + type: string + description: 选项列表(enum/array_enum 类型必填) + default_value: + description: 默认值 + scope: + type: array + items: + $ref: '#/components/schemas/MetadataScope' + description: 适用范围 + is_filterable: + type: boolean + default: false + is_rank_feature: + type: boolean + default: false + field_roles: + type: array + items: + $ref: '#/components/schemas/FieldRole' + description: 字段角色列表 + status: + $ref: '#/components/schemas/MetadataFieldStatus' + version: + type: integer + created_at: + type: string + format: date-time + updated_at: + type: string + format: date-time + + MetadataFieldDefinitionCreate: + type: object + required: + - tenant_id + - field_key + - label + - type + properties: + tenant_id: + type: string + format: uuid + field_key: + type: string + pattern: '^[a-z][a-z0-9_]*$' + label: + type: string + minLength: 1 + maxLength: 100 + type: + $ref: '#/components/schemas/MetadataFieldType' + required: + type: boolean + default: false + options: + type: array + items: + type: string + default_value: + type: object + scope: + type: array + items: + $ref: '#/components/schemas/MetadataScope' + is_filterable: + type: boolean + default: false + is_rank_feature: + type: boolean + default: false + field_roles: + type: array + items: + $ref: '#/components/schemas/FieldRole' + description: 字段角色列表,可为空 + + MetadataFieldDefinitionUpdate: + type: object + properties: + label: + type: string + minLength: 1 + maxLength: 100 + required: + type: boolean + options: + type: array + items: + type: string + default_value: + type: object + scope: + type: array + items: + $ref: '#/components/schemas/MetadataScope' + is_filterable: + type: boolean + is_rank_feature: + type: boolean + field_roles: + type: array + items: + $ref: '#/components/schemas/FieldRole' + status: + $ref: '#/components/schemas/MetadataFieldStatus' + + ExtractStrategy: + type: string + enum: + - rule + - llm + - user_input + description: | + 槽位提取策略: + - rule: 规则提取 + - llm: LLM 推断 + - user_input: 用户输入 + + SlotSource: + type: string + enum: + - user_confirmed + - rule_extracted + - llm_inferred + - default + + SlotDefinition: + type: object + required: + - id + - tenant_id + - slot_key + - type + - required + properties: + id: + type: string + format: uuid + tenant_id: + type: string + format: uuid + slot_key: + type: string + pattern: '^[a-z][a-z0-9_]*$' + description: 槽位键名 + type: + $ref: '#/components/schemas/MetadataFieldType' + required: + type: boolean + description: 是否必填槽位 + extract_strategy: + $ref: '#/components/schemas/ExtractStrategy' + validation_rule: + type: string + description: 校验规则(正则或 JSON Schema) + ask_back_prompt: + type: string + description: 追问提示语模板 + default_value: + description: 默认值 + linked_field_id: + type: string + format: uuid + description: 关联的元数据字段 ID + created_at: + type: string + format: date-time + updated_at: + type: string + format: date-time + + SlotDefinitionCreate: + type: object + required: + - tenant_id + - slot_key + - type + - required + properties: + tenant_id: + type: string + format: uuid + slot_key: + type: string + pattern: '^[a-z][a-z0-9_]*$' + type: + $ref: '#/components/schemas/MetadataFieldType' + required: + type: boolean + extract_strategy: + $ref: '#/components/schemas/ExtractStrategy' + validation_rule: + type: string + ask_back_prompt: + type: string + default_value: + type: object + linked_field_id: + type: string + format: uuid + + SlotDefinitionUpdate: + type: object + properties: + type: + $ref: '#/components/schemas/MetadataFieldType' + required: + type: boolean + extract_strategy: + $ref: '#/components/schemas/ExtractStrategy' + validation_rule: + type: string + ask_back_prompt: + type: string + default_value: + type: object + linked_field_id: + type: string + format: uuid + + SlotDefinitionWithField: + type: object + description: 槽位定义与关联字段信息 + allOf: + - $ref: '#/components/schemas/SlotDefinition' + - type: object + properties: + linked_field: + $ref: '#/components/schemas/MetadataFieldDefinition' + + RuntimeSlotValue: + type: object + required: + - key + - value + - source + - confidence + properties: + key: + type: string + description: 槽位键名 + value: + description: 槽位值 + source: + $ref: '#/components/schemas/SlotSource' + description: 槽位来源 + confidence: + type: number + format: float + minimum: 0.0 + maximum: 1.0 + description: 置信度 + updated_at: + type: string + format: date-time + description: 最后更新时间 + + ErrorResponse: + type: object + required: + - error_code + - message + properties: + error_code: + type: string + message: + type: string + details: + type: object + additionalProperties: true + + responses: + BadRequest: + description: 请求参数错误 + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + example: + error_code: BAD_REQUEST + message: "Invalid request parameters" + + Unauthorized: + description: 未授权 + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + example: + error_code: UNAUTHORIZED + message: "Authentication required" + + NotFound: + description: 资源不存在 + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + example: + error_code: NOT_FOUND + message: "Resource not found" diff --git a/spec/metadata-role-separation/requirements.md b/spec/metadata-role-separation/requirements.md new file mode 100644 index 0000000..b4e1dca --- /dev/null +++ b/spec/metadata-role-separation/requirements.md @@ -0,0 +1,156 @@ +--- +feature_id: "MRS" +title: "元数据职责分层优化" +status: "draft" +version: "0.1.0" +active_version: "0.1.0" +version_history: + - version: "0.1.0" + ac_range: "AC-MRS-01~16" + description: "元数据字段职责分层、槽位模型独立化、工具协同改造与管理端配置能力" +owners: + - "product" + - "backend" + - "frontend" +last_updated: "2026-03-05" +source: + type: "conversation" + ref: "元数据职责过载问题优化需求" +--- + +# 元数据职责分层优化(MRS) + +## 1. 背景与目标 + +### 1.1 背景 + +当前系统中元数据字段承担了多种隐式职责,导致以下问题: + +1. **职责混淆**:同一字段(如 `grade`)同时用于资源过滤、运行时槽位、提示词变量和路由信号,但系统无法区分其具体用途 +2. **工具耦合**:`kb_search_dynamic`、`memory_recall`、`intent_hint`、`high_risk_check` 等工具全量消费元数据字段,无法按需筛选 +3. **槽位语义模糊**:槽位与元数据字段概念混淆,缺少独立的槽位定义模型 +4. **配置不可视**:管理端无法按职责视角查看和配置字段 + +### 1.2 目标 + +- 为元数据字段引入显式的 `field_roles` 职责分层 +- 建立独立的槽位定义模型,与元数据字段解耦但可复用 +- 改造工具链按职责角色消费字段,实现精准消费 +- 提供管理端按角色配置和查看的能力 + +### 1.3 非目标(Out of Scope) + +- 不处理历史数据迁移,允许删除重建配置 +- 不新增元数据字段类型(保持 string/number/boolean/enum/array_enum) +- 不替换向量引擎或 LLM 供应商 +- 不覆盖渠道端具体实现 + +## 2. 模块边界(Scope) + +- 覆盖:元数据字段职责分层、槽位定义模型、工具协同改造、管理端配置能力 +- 不覆盖:历史数据迁移、向量引擎替换、模型切换、渠道端实现 + +## 3. 依赖盘点(Dependencies) + +- `metadata-governance` 模块:元数据字段定义基础能力 +- `intent-driven-mid-platform` 模块:中台运行时工具链 +- `ai-service-admin` 前端:管理端配置界面 + +## 4. 用户故事(User Stories) + +- [US-MRS-01] 作为系统架构师,我希望元数据字段有明确的职责角色标记,以便工具能按需消费。 +- [US-MRS-02] 作为后端开发者,我希望通过接口按角色查询字段定义,以便精准获取所需字段。 +- [US-MRS-03] 作为运营配置人员,我希望在管理端按角色过滤查看字段,以便快速定位配置。 +- [US-MRS-04] 作为对话系统开发者,我希望槽位有独立的定义模型,以便管理运行时槽位语义。 +- [US-MRS-05] 作为工具开发者,我希望 `kb_search_dynamic` 只消费资源过滤角色字段,以便避免无关字段干扰。 +- [US-MRS-06] 作为工具开发者,我希望 `memory_recall` 只消费槽位角色字段,以便精准管理对话槽位。 +- [US-MRS-07] 作为工具开发者,我希望 `intent_hint/high_risk_check` 只消费路由信号角色字段,以便精准路由决策。 +- [US-MRS-08] 作为提示词工程师,我希望 prompt 渲染只消费提示词变量角色字段,以便控制注入范围。 + +## 5. 验收标准(Acceptance Criteria, EARS) + +### 5.1 字段职责分层 + +- [AC-MRS-01] WHEN 管理员创建或编辑元数据字段 THEN 系统 SHALL 支持 `field_roles` 多选配置,可选值为 `resource_filter`、`slot`、`prompt_var`、`routing_signal`。 +- [AC-MRS-02] WHEN 保存字段定义时 `field_roles` 为空 THEN 系统 SHALL 允许保存(默认无职责)。 +- [AC-MRS-03] WHEN 字段定义包含多个 `field_roles` THEN 系统 SHALL 正确存储并返回所有角色。 + +### 5.2 分层视图能力 + +- [AC-MRS-04] WHEN 调用 `GET /admin/metadata-schemas/by-role?role=resource_filter` THEN 系统 SHALL 返回所有 `field_roles` 包含 `resource_filter` 的活跃字段定义。 +- [AC-MRS-05] WHEN 调用按角色查询接口且角色参数无效 THEN 系统 SHALL 返回 400 错误并提示有效角色列表。 +- [AC-MRS-06] WHEN 管理端请求字段列表 THEN 系统 SHALL 支持按 `field_roles` 过滤展示。 + +### 5.3 槽位模型 + +- [AC-MRS-07] WHEN 管理员创建槽位定义 THEN 系统 SHALL 支持 `slot_key`、`type`、`required`、`extract_strategy`、`validation_rule`、`ask_back_prompt` 属性配置。 +- [AC-MRS-08] WHEN 槽位定义的 `slot_key` 与已有元数据字段 `field_key` 相同 THEN 系统 SHALL 允许创建并建立关联关系。 +- [AC-MRS-09] WHEN 运行时读取槽位值 THEN 系统 SHALL 返回 `source`(来源)、`confidence`(置信度)、`updated_at`(更新时间)属性。 +- [AC-MRS-10] WHEN 调用 `GET /mid/slots/by-role?role=slot` THEN 系统 SHALL 返回所有 `field_roles` 包含 `slot` 的字段定义及关联的槽位定义。 + +### 5.4 工具协同改造 + +- [AC-MRS-11] WHEN `kb_search_dynamic` 构建过滤器 THEN 系统 SHALL 仅使用 `field_roles` 包含 `resource_filter` 的字段。 +- [AC-MRS-12] WHEN `memory_recall` 召回槽位 THEN 系统 SHALL 仅使用 `field_roles` 包含 `slot` 的字段。 +- [AC-MRS-13] WHEN `intent_hint` 或 `high_risk_check` 进行路由判断 THEN 系统 SHALL 仅使用 `field_roles` 包含 `routing_signal` 的字段。 +- [AC-MRS-14] WHEN 模板引擎渲染 prompt THEN 系统 SHALL 仅使用 `field_roles` 包含 `prompt_var` 的字段。 + +### 5.5 管理端可配置能力 + +- [AC-MRS-15] WHEN 管理员在元数据字段编辑界面 THEN 系统 SHALL 显示 `field_roles` 多选配置组件。 +- [AC-MRS-16] WHEN 管理员删除字段或槽位定义 THEN 系统 SHALL 允许删除且无需考虑历史数据兼容性。 + +## 6. 追踪映射(Traceability) + +| AC ID | Endpoint | 方法 | operationId | 备注 | +|------|----------|------|-------------|------| +| AC-MRS-01 | /admin/metadata-schemas | POST | createMetadataSchema | field_roles 配置 | +| AC-MRS-01 | /admin/metadata-schemas/{id} | PUT | updateMetadataSchema | field_roles 配置 | +| AC-MRS-02 | /admin/metadata-schemas | POST | createMetadataSchema | 空角色允许 | +| AC-MRS-03 | /admin/metadata-schemas | POST | createMetadataSchema | 多角色存储 | +| AC-MRS-04 | /admin/metadata-schemas/by-role | GET | getMetadataSchemasByRole | 按角色查询 | +| AC-MRS-05 | /admin/metadata-schemas/by-role | GET | getMetadataSchemasByRole | 无效角色校验 | +| AC-MRS-06 | /admin/metadata-schemas | GET | listMetadataSchemas | 按角色过滤 | +| AC-MRS-07 | /admin/slot-definitions | POST | createSlotDefinition | 槽位定义创建 | +| AC-MRS-08 | /admin/slot-definitions | POST | createSlotDefinition | 关联元数据字段 | +| AC-MRS-09 | /mid/slots/{slot_key} | GET | getSlotValue | 运行时槽位值 | +| AC-MRS-10 | /mid/slots/by-role | GET | getSlotsByRole | 按角色获取槽位 | +| AC-MRS-11 | 内部调用 | - | kb_search_dynamic | resource_filter 消费 | +| AC-MRS-12 | 内部调用 | - | memory_recall | slot 消费 | +| AC-MRS-13 | 内部调用 | - | intent_hint/high_risk_check | routing_signal 消费 | +| AC-MRS-14 | 内部调用 | - | template_engine | prompt_var 消费 | +| AC-MRS-15 | 前端页面 | - | - | field_roles 配置组件 | +| AC-MRS-16 | /admin/metadata-schemas/{id} | DELETE | deleteMetadataSchema | 删除无需兼容 | +| AC-MRS-16 | /admin/slot-definitions/{id} | DELETE | deleteSlotDefinition | 删除无需兼容 | + +## 7. 字段角色定义 + +| 角色标识 | 中文名称 | 用途说明 | 消费工具 | +|---------|---------|---------|---------| +| `resource_filter` | 资源过滤 | 用于 KB 文档检索时的元数据过滤 | `kb_search_dynamic` | +| `slot` | 运行时槽位 | 对话流程中的结构化槽位,用于信息收集 | `memory_recall` | +| `prompt_var` | 提示词变量 | 注入到 LLM Prompt 中的变量 | `template_engine` | +| `routing_signal` | 路由信号 | 用于意图路由和风险判断的信号 | `intent_hint`, `high_risk_check` | + +## 8. 槽位定义属性 + +| 属性 | 类型 | 必填 | 说明 | +|-----|------|-----|------| +| `slot_key` | string | 是 | 槽位键名,可与 field_key 关联 | +| `type` | enum | 是 | 槽位类型:string/number/boolean/enum/array_enum | +| `required` | boolean | 是 | 是否必填槽位 | +| `extract_strategy` | enum | 否 | 提取策略:rule/llm/user_input | +| `validation_rule` | string | 否 | 校验规则(正则或 JSON Schema) | +| `ask_back_prompt` | string | 否 | 追问提示语模板 | +| `default_value` | any | 否 | 默认值 | +| `linked_field_id` | uuid | 否 | 关联的元数据字段 ID | + +## 9. 运行时槽位值属性 + +| 属性 | 类型 | 说明 | +|-----|------|------| +| `key` | string | 槽位键名 | +| `value` | any | 槽位值 | +| `source` | enum | 来源:user_confirmed/rule_extracted/llm_inferred/default | +| `confidence` | float | 置信度 0.0~1.0 | +| `updated_at` | datetime | 最后更新时间 | diff --git a/spec/metadata-role-separation/scope.md b/spec/metadata-role-separation/scope.md new file mode 100644 index 0000000..a58c82f --- /dev/null +++ b/spec/metadata-role-separation/scope.md @@ -0,0 +1,145 @@ +# 元数据职责分层模块边界(Scope) + +## 1. 模块边界说明 + +### 1.1 覆盖范围 + +本模块聚焦于**元数据字段的职责分层与运行时消费解耦**,具体包括: + +1. **字段职责分层** + - 为元数据字段引入 `field_roles` 多选属性 + - 支持四种职责角色:`resource_filter`、`slot`、`prompt_var`、`routing_signal` + - 单个字段可同时承担多种职责 + +2. **分层视图能力** + - 后端提供按 role 查询字段的能力 + - 工具与模块按 role 消费,不再全量混用 + +3. **槽位模型增强** + - 引入独立的槽位定义模型(可复用元数据字段但有独立运行时语义) + - 支持 `slot_key/type/required/extract_strategy/validation_rule/ask_back_prompt` + - 运行时值包含 `source/confidence/updated_at` + +4. **工具协同改造** + - `kb_search_dynamic` 只消费 `resource_filter` 角色 + - `memory_recall` 只消费 `slot` 角色 + - `intent_hint/high_risk_check` 只消费 `routing_signal` 角色 + - prompt 渲染只消费 `prompt_var` 角色 + +5. **管理端可配置能力** + - 元数据字段编辑界面增加 `field_roles` 配置 + - 提供"按 role 过滤查看"能力 + - 允许删除重建配置(无需迁移兼容) + +### 1.2 不覆盖范围 + +- **历史数据迁移**:本迭代不负责历史数据的自动迁移,允许删除重建配置 +- **向量引擎替换**:不涉及 Qdrant 或其他向量引擎的替换 +- **LLM 模型切换**:不涉及模型供应商或模型选型的变更 +- **渠道端实现**:不覆盖渠道侧 SegmentDispatcher/InterruptManager 等具体实现 +- **元数据字段类型扩展**:不新增字段类型(string/number/boolean/enum/array_enum 保持不变) + +--- + +## 2. 依赖盘点 + +### 2.1 内部依赖 + +| 依赖模块 | 用途说明 | 接口 | +|---------|---------|------| +| `metadata-governance` | 元数据字段定义基础能力 | `/admin/metadata-schemas` | +| `intent-driven-mid-platform` | 中台运行时工具链 | `kb_search_dynamic`, `memory_recall`, `intent_hint`, `high_risk_check` | +| `ai-service-admin` | 管理端前端页面 | 元数据配置界面 | + +### 2.2 外部依赖 + +| 依赖服务 | 用途说明 | +|---------|---------| +| PostgreSQL | 元数据字段定义、槽位定义存储 | +| Redis | 运行时缓存 | + +--- + +## 3. 依赖接口清单 + +### 3.1 本模块依赖的外部接口(Consumer) + +| 接口 | 来源模块 | 用途 | +|------|---------|------| +| `GET /admin/metadata-schemas` | metadata-governance | 获取元数据字段列表 | +| `POST /admin/metadata-schemas` | metadata-governance | 创建元数据字段 | +| `PUT /admin/metadata-schemas/{id}` | metadata-governance | 更新元数据字段 | +| `DELETE /admin/metadata-schemas/{id}` | metadata-governance | 删除元数据字段 | + +### 3.2 本模块对外提供的接口(Provider) + +| 接口 | 用途 | +|------|------| +| `GET /admin/metadata-schemas/by-role` | 按 role 查询字段定义 | +| `GET /admin/slot-definitions` | 获取槽位定义列表 | +| `POST /admin/slot-definitions` | 创建槽位定义 | +| `PUT /admin/slot-definitions/{id}` | 更新槽位定义 | +| `DELETE /admin/slot-definitions/{id}` | 删除槽位定义 | +| `GET /mid/slots/by-role` | 运行时按 role 获取槽位定义 | + +--- + +## 4. 数据模型边界 + +### 4.1 新增模型 + +| 模型名 | 说明 | +|-------|------| +| `SlotDefinition` | 槽位定义表(独立于 MetadataFieldDefinition) | + +### 4.2 扩展模型 + +| 模型名 | 扩展字段 | +|-------|---------| +| `MetadataFieldDefinition` | 新增 `field_roles: list[str]` 字段 | + +--- + +## 5. 工具消费关系 + +``` +┌─────────────────────────────────────────────────────────────────┐ +│ 元数据字段职责分层 │ +├─────────────────────────────────────────────────────────────────┤ +│ │ +│ MetadataFieldDefinition │ +│ └── field_roles: [resource_filter, slot, prompt_var, │ +│ routing_signal] │ +│ │ +└─────────────────────────────────────────────────────────────────┘ + │ + ┌─────────────────────┼─────────────────────┐ + ▼ ▼ ▼ +┌───────────────┐ ┌───────────────┐ ┌───────────────┐ +│resource_filter│ │ slot │ │ prompt_var │ +└───────┬───────┘ └───────┬───────┘ └───────┬───────┘ + │ │ │ + ▼ ▼ ▼ +┌───────────────┐ ┌───────────────┐ ┌───────────────┐ +│kb_search_ │ │memory_recall │ │template_engine│ +│dynamic │ │ │ │ │ +└───────────────┘ └───────────────┘ └───────────────┘ + +┌─────────────────────────────────────────────────────────────────┐ +│ routing_signal │ +└───────┬─────────────────────────────────────────────────────────┘ + │ + ├───────────────┐ + ▼ ▼ +┌───────────────┐ ┌───────────────┐ +│intent_hint │ │high_risk_check│ +└───────────────┘ └───────────────┘ +``` + +--- + +## 6. 版本与迭代 + +- 当前版本:`v0.1.0` +- AC 范围:`AC-MRS-01 ~ AC-MRS-16` +- 迭代策略:允许删除重建配置,不考虑历史数据迁移 diff --git a/spec/metadata-role-separation/tasks.md b/spec/metadata-role-separation/tasks.md new file mode 100644 index 0000000..c5a695f --- /dev/null +++ b/spec/metadata-role-separation/tasks.md @@ -0,0 +1,311 @@ +# 元数据职责分层优化 - 任务清单 + +## 任务概览 + +| 阶段 | 任务数 | 状态 | +|------|-------|------| +| Phase 1: 数据模型扩展 | 4 | ✅ 已完成 | +| Phase 2: 后端服务实现 | 6 | ✅ 已完成 | +| Phase 3: 工具协同改造 | 4 | ✅ 已完成 | +| Phase 4: 前端页面改造 | 3 | ⏳ 待开始 | +| Phase 5: 测试与验收 | 3 | ⏳ 待开始 | + +--- + +## Phase 1: 数据模型扩展 + +### Task 1.1: 扩展 MetadataFieldDefinition 模型 +- [x] **状态**: ✅ 已完成 +- **AC**: AC-MRS-01, AC-MRS-02, AC-MRS-03 +- **描述**: 在现有 `MetadataFieldDefinition` 模型中新增 `field_roles` 字段 +- **产出**: + - 修改 `ai-service/app/models/entities.py` 中的 `MetadataFieldDefinition` 类 + - 新增 `FieldRole` 枚举类 +- **验收标准**: + - `field_roles` 字段类型为 `list[str]` + - 支持存储多个角色 + - 允许空列表 + +### Task 1.2: 创建 SlotDefinition 模型 +- [x] **状态**: ✅ 已完成 +- **AC**: AC-MRS-07, AC-MRS-08 +- **描述**: 创建独立的槽位定义模型 +- **产出**: + - 在 `ai-service/app/models/entities.py` 中新增 `SlotDefinition` 类 + - 新增 `ExtractStrategy` 枚举类 +- **验收标准**: + - 包含所有必需字段:slot_key, type, required, extract_strategy, validation_rule, ask_back_prompt + - 支持 linked_field_id 关联元数据字段 + +### Task 1.3: 编写数据库迁移脚本 +- [x] **状态**: ✅ 已完成 +- **AC**: AC-MRS-01, AC-MRS-07 +- **描述**: 编写 PostgreSQL 迁移脚本 +- **产出**: + - 创建 `ai-service/scripts/migrations/007_add_field_roles_and_slot_definitions.sql` +- **验收标准**: + - 为 `metadata_field_definitions` 表新增 `field_roles` 列 + - 创建 `slot_definitions` 表 + - 创建必要的索引 + +### Task 1.4: 更新 Pydantic Schema +- [x] **状态**: ✅ 已完成 +- **AC**: AC-MRS-01, AC-MRS-07 +- **描述**: 更新请求/响应 Schema +- **产出**: + - 创建 `ai-service/app/schemas/metadata.py` + - 新增 `SlotDefinitionCreate/Update/Response` Schema +- **验收标准**: + - Schema 与 OpenAPI 契约一致 + - 包含完整的字段校验规则 + +--- + +## Phase 2: 后端服务实现 + +### Task 2.1: 实现 RoleBasedFieldProvider 服务 +- [x] **状态**: ✅ 已完成 +- **AC**: AC-MRS-04, AC-MRS-05, AC-MRS-10 +- **描述**: 实现按角色查询字段的核心服务 +- **产出**: + - 创建 `ai-service/app/services/mid/role_based_field_provider.py` +- **验收标准**: + - `get_fields_by_role()` 方法正确查询指定角色的字段 + - 无效角色返回 400 错误 + - 支持缓存机制 + +### Task 2.2: 扩展 MetadataFieldDefinitionService +- [x] **状态**: ✅ 已完成 +- **AC**: AC-MRS-01, AC-MRS-02, AC-MRS-03, AC-MRS-06 +- **描述**: 扩展现有服务支持 field_roles +- **产出**: + - 修改 `ai-service/app/services/metadata_field_definition_service.py` +- **验收标准**: + - 创建/更新时支持 field_roles 字段 + - 支持按 role 过滤查询 + - field_roles 校验正确 + +### Task 2.3: 实现 SlotDefinitionService +- [ ] **状态**: ⏳ 待开始 +- **AC**: AC-MRS-07, AC-MRS-08 +- **描述**: 实现槽位定义管理服务 +- **产出**: + - 创建 `ai-service/app/services/slot_definition_service.py` +- **验收标准**: + - CRUD 操作正确 + - 支持关联元数据字段 + - slot_key 租户内唯一 + +### Task 2.4: 扩展 MetadataFieldDefinition API +- [ ] **状态**: ⏳ 待开始 +- **AC**: AC-MRS-01, AC-MRS-04, AC-MRS-05, AC-MRS-06, AC-MRS-16 +- **描述**: 扩展现有 API 端点 +- **产出**: + - 修改 `ai-service/app/api/admin/metadata_field_definition.py` + - 新增 `/by-role` 端点 +- **验收标准**: + - 所有端点符合 OpenAPI 契约 + - 包含 AC 注释 + +### Task 2.5: 实现 SlotDefinition API +- [ ] **状态**: ⏳ 待开始 +- **AC**: AC-MRS-07, AC-MRS-08, AC-MRS-16 +- **描述**: 实现槽位定义管理 API +- **产出**: + - 创建 `ai-service/app/api/admin/slot_definition.py` +- **验收标准**: + - CRUD 端点符合 OpenAPI 契约 + - 包含 AC 注释 + +### Task 2.6: 实现运行时槽位 API +- [ ] **状态**: ⏳ 待开始 +- **AC**: AC-MRS-09, AC-MRS-10 +- **描述**: 实现运行时槽位查询 API +- **产出**: + - 创建 `ai-service/app/api/mid/slots.py` +- **验收标准**: + - `/mid/slots/by-role` 端点正确返回槽位定义 + - `/mid/slots/{slot_key}` 端点正确返回运行时值 + +--- + +## Phase 3: 工具协同改造 + +### Task 3.1: 改造 kb_search_dynamic 工具 +- [x] **状态**: ✅ 已完成 +- **AC**: AC-MRS-11 +- **描述**: 改造 KB 动态检索工具,只消费 resource_filter 角色 +- **产出**: + - 修改 `ai-service/app/services/mid/kb_search_dynamic_tool.py` + - 修改 `ai-service/app/services/mid/metadata_filter_builder.py` +- **验收标准**: + - 只使用 field_roles 包含 resource_filter 的字段 + - 不影响现有功能 + +### Task 3.2: 改造 memory_recall 工具 +- [x] **状态**: ✅ 已完成 +- **AC**: AC-MRS-12 +- **描述**: 改造记忆召回工具,只消费 slot 角色 +- **产出**: + - 修改 `ai-service/app/services/mid/memory_recall_tool.py` +- **验收标准**: + - 只使用 field_roles 包含 slot 的字段 + - 槽位合并逻辑正确 + +### Task 3.3: 改造 intent_hint 和 high_risk_check 工具 +- [x] **状态**: ✅ 已完成 +- **AC**: AC-MRS-13 +- **描述**: 改造意图提示和高风险检测工具,只消费 routing_signal 角色 +- **产出**: + - 修改 `ai-service/app/services/mid/intent_hint_tool.py` + - 修改 `ai-service/app/services/mid/high_risk_check_tool.py` +- **验收标准**: + - 只使用 field_roles 包含 routing_signal 的字段 + - 路由判断逻辑正确 + +### Task 3.4: 改造 template_engine +- [x] **状态**: ✅ 已完成 +- **AC**: AC-MRS-14 +- **描述**: 改造模板引擎,只消费 prompt_var 角色 +- **产出**: + - 修改 `ai-service/app/services/flow/template_engine.py` +- **验收标准**: + - 只使用 field_roles 包含 prompt_var 的字段 + - 模板渲染正确 + +--- + +## Phase 4: 前端页面改造 + +### Task 4.1: 元数据字段配置页面增加 field_roles +- [ ] **状态**: ⏳ 待开始 +- **AC**: AC-MRS-15 +- **描述**: 在元数据字段编辑表单中增加角色选择组件 +- **产出**: + - 创建 `ai-service-admin/src/components/metadata/FieldRolesSelector.vue` + - 修改 `ai-service-admin/src/views/admin/metadata-schema/index.vue` +- **验收标准**: + - 支持多选角色 + - 显示角色说明 + - 保存时正确提交 + +### Task 4.2: 增加按角色过滤视图 +- [ ] **状态**: ⏳ 待开始 +- **AC**: AC-MRS-06 +- **描述**: 在元数据字段列表页面增加角色过滤功能 +- **产出**: + - 修改 `ai-service-admin/src/views/admin/metadata-schema/index.vue` +- **验收标准**: + - 下拉框选择角色 + - 过滤结果正确 + +### Task 4.3: 槽位定义管理页面 +- [ ] **状态**: ⏳ 待开始 +- **AC**: AC-MRS-07, AC-MRS-08, AC-MRS-16 +- **描述**: 创建槽位定义管理页面 +- **产出**: + - 创建 `ai-service-admin/src/views/admin/slot-definition/index.vue` + - 创建 `ai-service-admin/src/api/slot-definition.ts` +- **验收标准**: + - 支持 CRUD 操作 + - 支持关联元数据字段 + +--- + +## Phase 5: 测试与验收 + +### Task 5.1: 单元测试 +- [ ] **状态**: ⏳ 待开始 +- **AC**: AC-MRS-01~16 +- **描述**: 编写单元测试 +- **产出**: + - `ai-service/tests/test_role_based_field_provider.py` + - `ai-service/tests/test_slot_definition_service.py` + - `ai-service/tests/test_field_roles.py` +- **验收标准**: + - 覆盖核心逻辑 + - 测试通过 + +### Task 5.2: 集成测试 +- [ ] **状态**: ⏳ 待开始 +- **AC**: AC-MRS-01~16 +- **描述**: 编写 API 集成测试 +- **产出**: + - `ai-service/tests/api/test_metadata_field_roles.py` + - `ai-service/tests/api/test_slot_definition.py` +- **验收标准**: + - 覆盖所有 API 端点 + - 测试通过 + +### Task 5.3: 契约测试 +- [ ] **状态**: ⏳ 待开始 +- **AC**: AC-MRS-01~16 +- **描述**: 验证 API 符合 OpenAPI 契约 +- **产出**: + - 运行契约测试 + - 修复不一致 +- **验收标准**: + - Provider 契约达到 L2 级别 + - 所有响应符合 Schema + +--- + +## 任务依赖关系 + +``` +Phase 1 (数据模型) + │ + ├── Task 1.1 (扩展 MetadataFieldDefinition) + ├── Task 1.2 (创建 SlotDefinition) + ├── Task 1.3 (迁移脚本) ← 依赖 1.1, 1.2 + └── Task 1.4 (更新 Schema) ← 依赖 1.1, 1.2 + │ + ▼ +Phase 2 (后端服务) + │ + ├── Task 2.1 (RoleBasedFieldProvider) ← 依赖 1.4 + ├── Task 2.2 (扩展 MetadataFieldService) ← 依赖 1.4 + ├── Task 2.3 (SlotDefinitionService) ← 依赖 1.4 + ├── Task 2.4 (扩展 MetadataField API) ← 依赖 2.2 + ├── Task 2.5 (SlotDefinition API) ← 依赖 2.3 + └── Task 2.6 (运行时槽位 API) ← 依赖 2.1, 2.3 + │ + ▼ +Phase 3 (工具改造) + │ + ├── Task 3.1 (kb_search_dynamic) ← 依赖 2.1 + ├── Task 3.2 (memory_recall) ← 依赖 2.1 + ├── Task 3.3 (intent_hint/high_risk_check) ← 依赖 2.1 + └── Task 3.4 (template_engine) ← 依赖 2.1 + │ + ▼ +Phase 4 (前端改造) + │ + ├── Task 4.1 (field_roles 组件) ← 依赖 2.4 + ├── Task 4.2 (角色过滤视图) ← 依赖 2.4 + └── Task 4.3 (槽位定义页面) ← 依赖 2.5 + │ + ▼ +Phase 5 (测试验收) + │ + ├── Task 5.1 (单元测试) ← 依赖 Phase 2 + ├── Task 5.2 (集成测试) ← 依赖 Phase 2, 3, 4 + └── Task 5.3 (契约测试) ← 依赖 5.2 +``` + +--- + +## 执行顺序建议 + +1. **Phase 1** → **Phase 2** → **Phase 3** → **Phase 4** → **Phase 5** +2. Phase 3 和 Phase 4 可并行执行 +3. 每个 Task 完成后需更新状态并提交 + +--- + +## 变更记录 + +| 日期 | 变更内容 | 变更人 | +|------|---------|-------| +| 2026-03-05 | 初始创建 | AI Agent | +| 2026-03-05 | 完成 Phase 3 工具协同改造 (Task 3.1-3.4) [AC-MRS-11~14] | AI Agent |