793 lines
23 KiB
Markdown
793 lines
23 KiB
Markdown
# 意图驱动话术流程 - 设计文档
|
||
|
||
## 1. 架构概览
|
||
|
||
### 1.1 系统架构图
|
||
|
||
```
|
||
┌─────────────────────────────────────────────────────────────┐
|
||
│ 前端配置界面 │
|
||
│ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │
|
||
│ │ 模式选择器 │ │ 意图配置表单 │ │ 约束管理器 │ │
|
||
│ └──────────────┘ └──────────────┘ └──────────────┘ │
|
||
└─────────────────────────────────────────────────────────────┘
|
||
│ HTTP API
|
||
▼
|
||
┌─────────────────────────────────────────────────────────────┐
|
||
│ 后端 API 层 │
|
||
│ ┌──────────────────────────────────────────────────────┐ │
|
||
│ │ ScriptFlowService (CRUD) │ │
|
||
│ └──────────────────────────────────────────────────────┘ │
|
||
└─────────────────────────────────────────────────────────────┘
|
||
│
|
||
▼
|
||
┌─────────────────────────────────────────────────────────────┐
|
||
│ FlowEngine (执行引擎) │
|
||
│ ┌──────────────────────────────────────────────────────┐ │
|
||
│ │ start() / advance() │ │
|
||
│ │ ↓ │ │
|
||
│ │ _generate_step_content() ← 核心扩展点 │ │
|
||
│ │ ├─ fixed: 返回 content │ │
|
||
│ │ ├─ flexible: 调用 ScriptGenerator │ │
|
||
│ │ └─ template: 调用 TemplateEngine │ │
|
||
│ └──────────────────────────────────────────────────────┘ │
|
||
└─────────────────────────────────────────────────────────────┘
|
||
│
|
||
┌───────────────┼───────────────┐
|
||
▼ ▼ ▼
|
||
┌──────────────┐ ┌──────────────┐ ┌──────────────┐
|
||
│ScriptGenerator│ │TemplateEngine│ │ Orchestrator │
|
||
│ (新增) │ │ (新增) │ │ (LLM调用) │
|
||
└──────────────┘ └──────────────┘ └──────────────┘
|
||
```
|
||
|
||
### 1.2 数据流图
|
||
|
||
```
|
||
用户配置流程
|
||
│
|
||
├─ 选择 script_mode
|
||
│ ├─ fixed: 配置 content
|
||
│ ├─ flexible: 配置 intent + constraints
|
||
│ └─ template: 配置 content (模板)
|
||
│
|
||
▼
|
||
保存到数据库 (ScriptFlow.steps JSON)
|
||
│
|
||
▼
|
||
执行时加载流程
|
||
│
|
||
├─ FlowEngine.start() / advance()
|
||
│ │
|
||
│ ├─ 获取当前步骤配置
|
||
│ │
|
||
│ ├─ 调用 _generate_step_content()
|
||
│ │ │
|
||
│ │ ├─ fixed: 直接返回 content
|
||
│ │ │
|
||
│ │ ├─ flexible:
|
||
│ │ │ ├─ 构建 Prompt (intent + constraints + history)
|
||
│ │ │ ├─ 调用 LLM 生成话术
|
||
│ │ │ └─ 失败时返回 fallback (content)
|
||
│ │ │
|
||
│ │ └─ template:
|
||
│ │ ├─ 解析模板变量
|
||
│ │ ├─ 调用 LLM 生成变量值
|
||
│ │ └─ 替换模板占位符
|
||
│ │
|
||
│ └─ 返回生成的话术
|
||
│
|
||
▼
|
||
返回给用户
|
||
```
|
||
|
||
---
|
||
|
||
## 2. 核心模块设计
|
||
|
||
### 2.1 后端:话术生成引擎
|
||
|
||
#### 2.1.1 FlowEngine 扩展
|
||
|
||
**文件位置**: `ai-service/app/services/flow/engine.py`
|
||
|
||
**新增方法**:
|
||
|
||
```python
|
||
async def _generate_step_content(
|
||
self,
|
||
step: dict,
|
||
context: dict,
|
||
history: list[dict]
|
||
) -> str:
|
||
"""
|
||
[AC-IDS-03] 根据步骤配置生成话术内容
|
||
|
||
Args:
|
||
step: 步骤配置 (包含 script_mode, intent, constraints 等)
|
||
context: 会话上下文 (从 FlowInstance.context 获取)
|
||
history: 对话历史 (最近 N 轮)
|
||
|
||
Returns:
|
||
生成的话术文本
|
||
"""
|
||
script_mode = step.get("script_mode", "fixed")
|
||
|
||
if script_mode == "fixed":
|
||
return step.get("content", "")
|
||
|
||
elif script_mode == "flexible":
|
||
return await self._generate_flexible_script(step, context, history)
|
||
|
||
elif script_mode == "template":
|
||
return await self._generate_template_script(step, context, history)
|
||
|
||
else:
|
||
logger.warning(f"Unknown script_mode: {script_mode}, fallback to fixed")
|
||
return step.get("content", "")
|
||
```
|
||
|
||
**修改方法**:
|
||
|
||
```python
|
||
async def start(
|
||
self,
|
||
tenant_id: str,
|
||
session_id: str,
|
||
flow_id: uuid.UUID,
|
||
) -> tuple[FlowInstance | None, str | None]:
|
||
"""
|
||
[AC-IDS-05] 修改:启动流程时生成首步话术
|
||
"""
|
||
# ... 现有逻辑 ...
|
||
|
||
first_step = flow.steps[0]
|
||
|
||
# 修改:调用话术生成引擎
|
||
history = await self._get_conversation_history(tenant_id, session_id, limit=3)
|
||
first_content = await self._generate_step_content(
|
||
first_step,
|
||
instance.context,
|
||
history
|
||
)
|
||
|
||
return instance, first_content
|
||
```
|
||
|
||
#### 2.1.2 ScriptGenerator (新增模块)
|
||
|
||
**文件位置**: `ai-service/app/services/flow/script_generator.py`
|
||
|
||
**职责**: 灵活模式的话术生成逻辑
|
||
|
||
```python
|
||
class ScriptGenerator:
|
||
"""
|
||
[AC-IDS-04] 灵活模式话术生成器
|
||
"""
|
||
|
||
def __init__(self, orchestrator):
|
||
self._orchestrator = orchestrator
|
||
|
||
async def generate(
|
||
self,
|
||
intent: str,
|
||
intent_description: str | None,
|
||
constraints: list[str],
|
||
context: dict,
|
||
history: list[dict],
|
||
fallback: str
|
||
) -> str:
|
||
"""
|
||
生成灵活话术
|
||
|
||
Args:
|
||
intent: 步骤意图
|
||
intent_description: 意图详细说明
|
||
constraints: 话术约束条件
|
||
context: 会话上下文
|
||
history: 对话历史
|
||
fallback: 失败时的 fallback 话术
|
||
|
||
Returns:
|
||
生成的话术文本
|
||
"""
|
||
try:
|
||
prompt = self._build_prompt(
|
||
intent, intent_description, constraints, context, history
|
||
)
|
||
|
||
# 调用 LLM,设置 2 秒超时
|
||
response = await asyncio.wait_for(
|
||
self._orchestrator.generate(prompt),
|
||
timeout=2.0
|
||
)
|
||
|
||
return response.strip()
|
||
|
||
except asyncio.TimeoutError:
|
||
logger.warning(f"[AC-IDS-05] Script generation timeout, use fallback")
|
||
return fallback
|
||
|
||
except Exception as e:
|
||
logger.error(f"[AC-IDS-05] Script generation failed: {e}, use fallback")
|
||
return fallback
|
||
|
||
def _build_prompt(
|
||
self,
|
||
intent: str,
|
||
intent_description: str | None,
|
||
constraints: list[str],
|
||
context: dict,
|
||
history: list[dict]
|
||
) -> str:
|
||
"""
|
||
[AC-IDS-04] 构建 LLM Prompt
|
||
"""
|
||
prompt_parts = [
|
||
"你是一个客服对话系统,当前需要执行以下步骤:",
|
||
"",
|
||
f"【步骤目标】{intent}"
|
||
]
|
||
|
||
if intent_description:
|
||
prompt_parts.append(f"【详细说明】{intent_description}")
|
||
|
||
if constraints:
|
||
prompt_parts.append("【约束条件】")
|
||
for c in constraints:
|
||
prompt_parts.append(f"- {c}")
|
||
|
||
if history:
|
||
prompt_parts.append("")
|
||
prompt_parts.append("【对话历史】")
|
||
for msg in history[-3:]: # 最近 3 轮
|
||
role = "用户" if msg["role"] == "user" else "客服"
|
||
prompt_parts.append(f"{role}: {msg['content']}")
|
||
|
||
if context.get("inputs"):
|
||
prompt_parts.append("")
|
||
prompt_parts.append("【已收集信息】")
|
||
for inp in context["inputs"]:
|
||
prompt_parts.append(f"- {inp}")
|
||
|
||
prompt_parts.extend([
|
||
"",
|
||
"请生成一句符合目标和约束的话术(不超过50字)。",
|
||
"只返回话术内容,不要解释。"
|
||
])
|
||
|
||
return "\n".join(prompt_parts)
|
||
```
|
||
|
||
#### 2.1.3 TemplateEngine (新增模块)
|
||
|
||
**文件位置**: `ai-service/app/services/flow/template_engine.py`
|
||
|
||
**职责**: 模板模式的变量填充逻辑
|
||
|
||
```python
|
||
import re
|
||
|
||
class TemplateEngine:
|
||
"""
|
||
[AC-IDS-06] 模板话术引擎
|
||
"""
|
||
|
||
VARIABLE_PATTERN = re.compile(r'\{(\w+)\}')
|
||
|
||
def __init__(self, orchestrator):
|
||
self._orchestrator = orchestrator
|
||
|
||
async def fill_template(
|
||
self,
|
||
template: str,
|
||
context: dict,
|
||
history: list[dict]
|
||
) -> str:
|
||
"""
|
||
填充模板变量
|
||
|
||
Args:
|
||
template: 话术模板(包含 {变量名} 占位符)
|
||
context: 会话上下文
|
||
history: 对话历史
|
||
|
||
Returns:
|
||
填充后的话术
|
||
"""
|
||
# 提取模板中的变量
|
||
variables = self.VARIABLE_PATTERN.findall(template)
|
||
|
||
if not variables:
|
||
return template
|
||
|
||
# 为每个变量生成值
|
||
variable_values = {}
|
||
for var in variables:
|
||
value = await self._generate_variable_value(var, context, history)
|
||
variable_values[var] = value
|
||
|
||
# 替换模板中的占位符
|
||
result = template
|
||
for var, value in variable_values.items():
|
||
result = result.replace(f"{{{var}}}", value)
|
||
|
||
return result
|
||
|
||
async def _generate_variable_value(
|
||
self,
|
||
variable_name: str,
|
||
context: dict,
|
||
history: list[dict]
|
||
) -> str:
|
||
"""
|
||
为单个变量生成值
|
||
"""
|
||
# 先尝试从上下文中获取
|
||
if variable_name in context:
|
||
return str(context[variable_name])
|
||
|
||
# 否则调用 LLM 生成
|
||
prompt = f"""
|
||
根据对话历史,为变量 "{variable_name}" 生成合适的值。
|
||
|
||
对话历史:
|
||
{self._format_history(history[-3:])}
|
||
|
||
只返回变量值,不要解释。
|
||
"""
|
||
|
||
try:
|
||
response = await asyncio.wait_for(
|
||
self._orchestrator.generate(prompt),
|
||
timeout=1.0
|
||
)
|
||
return response.strip()
|
||
except:
|
||
return f"[{variable_name}]" # fallback
|
||
```
|
||
|
||
---
|
||
|
||
### 2.2 前端:配置界面设计
|
||
|
||
#### 2.2.1 类型定义扩展
|
||
|
||
**文件位置**: `ai-service-admin/src/types/script-flow.ts`
|
||
|
||
```typescript
|
||
export type ScriptMode = 'fixed' | 'flexible' | 'template'
|
||
|
||
export interface FlowStep {
|
||
step_id: string
|
||
step_no: number
|
||
|
||
// 原有字段
|
||
content: string
|
||
wait_input: boolean
|
||
timeout_seconds?: number
|
||
timeout_action?: 'repeat' | 'skip' | 'transfer'
|
||
next_conditions?: NextCondition[]
|
||
|
||
// 新增字段
|
||
script_mode?: ScriptMode
|
||
intent?: string
|
||
intent_description?: string
|
||
script_constraints?: string[]
|
||
expected_variables?: string[]
|
||
}
|
||
|
||
export const SCRIPT_MODE_OPTIONS = [
|
||
{ value: 'fixed', label: '固定话术', description: '话术内容固定不变' },
|
||
{ value: 'flexible', label: '灵活话术', description: 'AI根据意图和上下文生成' },
|
||
{ value: 'template', label: '模板话术', description: 'AI填充模板中的变量' }
|
||
]
|
||
```
|
||
|
||
#### 2.2.2 配置表单组件
|
||
|
||
**文件位置**: `ai-service-admin/src/views/admin/script-flow/index.vue`
|
||
|
||
**UI 结构**:
|
||
|
||
```vue
|
||
<template>
|
||
<el-form-item label="话术模式">
|
||
<el-radio-group v-model="currentStep.script_mode">
|
||
<el-radio-button
|
||
v-for="option in SCRIPT_MODE_OPTIONS"
|
||
:key="option.value"
|
||
:label="option.value"
|
||
>
|
||
{{ option.label }}
|
||
<el-tooltip :content="option.description">
|
||
<el-icon><QuestionFilled /></el-icon>
|
||
</el-tooltip>
|
||
</el-radio-button>
|
||
</el-radio-group>
|
||
</el-form-item>
|
||
|
||
<!-- 固定模式 -->
|
||
<template v-if="currentStep.script_mode === 'fixed'">
|
||
<el-form-item label="话术内容" required>
|
||
<el-input
|
||
v-model="currentStep.content"
|
||
type="textarea"
|
||
:rows="3"
|
||
placeholder="输入固定话术内容"
|
||
/>
|
||
</el-form-item>
|
||
</template>
|
||
|
||
<!-- 灵活模式 -->
|
||
<template v-if="currentStep.script_mode === 'flexible'">
|
||
<el-form-item label="步骤意图" required>
|
||
<el-input
|
||
v-model="currentStep.intent"
|
||
placeholder="例如:获取用户姓名"
|
||
/>
|
||
</el-form-item>
|
||
|
||
<el-form-item label="意图说明">
|
||
<el-input
|
||
v-model="currentStep.intent_description"
|
||
type="textarea"
|
||
:rows="2"
|
||
placeholder="详细描述这一步的目的和期望效果"
|
||
/>
|
||
</el-form-item>
|
||
|
||
<el-form-item label="话术约束">
|
||
<ConstraintManager v-model="currentStep.script_constraints" />
|
||
</el-form-item>
|
||
|
||
<el-form-item label="Fallback话术" required>
|
||
<el-input
|
||
v-model="currentStep.content"
|
||
type="textarea"
|
||
:rows="2"
|
||
placeholder="AI生成失败时使用的备用话术"
|
||
/>
|
||
</el-form-item>
|
||
</template>
|
||
|
||
<!-- 模板模式 -->
|
||
<template v-if="currentStep.script_mode === 'template'">
|
||
<el-form-item label="话术模板" required>
|
||
<el-input
|
||
v-model="currentStep.content"
|
||
type="textarea"
|
||
:rows="3"
|
||
placeholder="使用 {变量名} 标记可变部分,例如:您好{user_name},请问您{inquiry_style}?"
|
||
/>
|
||
<div class="template-hint">
|
||
提示:使用 {变量名} 标记需要AI填充的部分
|
||
</div>
|
||
</el-form-item>
|
||
</template>
|
||
</template>
|
||
```
|
||
|
||
#### 2.2.3 约束管理组件
|
||
|
||
**文件位置**: `ai-service-admin/src/views/admin/script-flow/components/ConstraintManager.vue`
|
||
|
||
```vue
|
||
<template>
|
||
<div class="constraint-manager">
|
||
<div class="constraint-tags">
|
||
<el-tag
|
||
v-for="(constraint, index) in modelValue"
|
||
:key="index"
|
||
closable
|
||
@close="removeConstraint(index)"
|
||
>
|
||
{{ constraint }}
|
||
</el-tag>
|
||
</div>
|
||
|
||
<el-input
|
||
v-model="newConstraint"
|
||
placeholder="输入约束条件后按回车添加"
|
||
@keyup.enter="addConstraint"
|
||
class="constraint-input"
|
||
>
|
||
<template #append>
|
||
<el-button @click="addConstraint">添加</el-button>
|
||
</template>
|
||
</el-input>
|
||
|
||
<div class="constraint-presets">
|
||
<span class="preset-label">常用约束:</span>
|
||
<el-button
|
||
v-for="preset in PRESET_CONSTRAINTS"
|
||
:key="preset"
|
||
size="small"
|
||
@click="addPreset(preset)"
|
||
>
|
||
{{ preset }}
|
||
</el-button>
|
||
</div>
|
||
</div>
|
||
</template>
|
||
|
||
<script setup lang="ts">
|
||
const PRESET_CONSTRAINTS = [
|
||
'必须礼貌',
|
||
'语气自然',
|
||
'简洁明了',
|
||
'不要生硬',
|
||
'不要重复'
|
||
]
|
||
|
||
const addConstraint = () => {
|
||
if (newConstraint.value.trim()) {
|
||
emit('update:modelValue', [...modelValue.value, newConstraint.value.trim()])
|
||
newConstraint.value = ''
|
||
}
|
||
}
|
||
</script>
|
||
```
|
||
|
||
---
|
||
|
||
## 3. 数据模型设计
|
||
|
||
### 3.1 数据库 Schema
|
||
|
||
**无需修改表结构**,因为 `script_flows.steps` 已经是 JSON 类型。
|
||
|
||
**现有结构**:
|
||
```sql
|
||
CREATE TABLE script_flows (
|
||
id UUID PRIMARY KEY,
|
||
tenant_id VARCHAR NOT NULL,
|
||
name VARCHAR NOT NULL,
|
||
description TEXT,
|
||
steps JSONB NOT NULL, -- 直接扩展此字段
|
||
is_enabled BOOLEAN DEFAULT TRUE,
|
||
created_at TIMESTAMP DEFAULT NOW(),
|
||
updated_at TIMESTAMP DEFAULT NOW()
|
||
);
|
||
```
|
||
|
||
**扩展后的 steps JSON 示例**:
|
||
```json
|
||
[
|
||
{
|
||
"step_no": 1,
|
||
"script_mode": "flexible",
|
||
"intent": "获取用户姓名",
|
||
"intent_description": "礼貌询问用户姓名",
|
||
"script_constraints": ["必须礼貌", "语气自然"],
|
||
"content": "请问怎么称呼您?",
|
||
"wait_input": true,
|
||
"timeout_seconds": 60
|
||
}
|
||
]
|
||
```
|
||
|
||
### 3.2 向后兼容策略
|
||
|
||
**读取时**:
|
||
```python
|
||
def _normalize_step(step: dict) -> dict:
|
||
"""确保步骤配置包含所有必需字段"""
|
||
return {
|
||
"script_mode": step.get("script_mode", "fixed"),
|
||
"intent": step.get("intent"),
|
||
"intent_description": step.get("intent_description"),
|
||
"script_constraints": step.get("script_constraints", []),
|
||
"expected_variables": step.get("expected_variables", []),
|
||
**step # 保留其他字段
|
||
}
|
||
```
|
||
|
||
**写入时**:
|
||
- 前端默认 `script_mode = 'fixed'`
|
||
- 后端不做强制校验,允许字段缺失
|
||
|
||
---
|
||
|
||
## 4. 技术决策
|
||
|
||
### 4.1 为什么选择 JSON 扩展而不是新表?
|
||
|
||
**决策**: 在现有的 `steps` JSON 字段中扩展,而不是创建新表
|
||
|
||
**理由**:
|
||
1. **简化数据模型**: 步骤配置是流程的一部分,不需要独立管理
|
||
2. **避免数据迁移**: 无需修改表结构,现有数据自动兼容
|
||
3. **灵活性**: JSON 字段易于扩展,未来可以继续添加新字段
|
||
4. **性能**: 步骤数量通常不多(<20),JSON 查询性能足够
|
||
|
||
**权衡**: 无法对意图字段建立索引,但实际场景中不需要按意图查询流程
|
||
|
||
### 4.2 为什么设置 2 秒超时?
|
||
|
||
**决策**: LLM 调用超时设置为 2 秒
|
||
|
||
**理由**:
|
||
1. **用户体验**: 对话系统需要快速响应,2 秒是可接受的上限
|
||
2. **Fallback 保障**: 超时后立即返回 fallback 话术,不影响流程执行
|
||
3. **成本控制**: 避免长时间等待消耗资源
|
||
|
||
**权衡**: 可能导致部分复杂话术生成失败,但有 fallback 保障
|
||
|
||
### 4.3 为什么对话历史只取最近 3 轮?
|
||
|
||
**决策**: 传递给 LLM 的对话历史限制为最近 3 轮
|
||
|
||
**理由**:
|
||
1. **Token 成本**: 减少 Prompt 长度,降低成本
|
||
2. **相关性**: 最近 3 轮对话最相关,更早的对话影响较小
|
||
3. **性能**: 减少数据库查询和网络传输
|
||
|
||
**权衡**: 可能丢失更早的上下文信息,但实际影响有限
|
||
|
||
### 4.4 为什么不缓存生成的话术?
|
||
|
||
**决策**: 不对生成的话术进行缓存
|
||
|
||
**理由**:
|
||
1. **灵活性优先**: 每次生成都考虑最新的上下文,更符合"灵活话术"的定位
|
||
2. **缓存复杂度**: 需要考虑缓存失效策略(上下文变化、配置变化)
|
||
3. **实际收益有限**: 同一步骤在同一会话中通常只执行一次
|
||
|
||
**未来优化**: 如果性能成为瓶颈,可以考虑基于上下文哈希的缓存
|
||
|
||
---
|
||
|
||
## 5. 错误处理与降级策略
|
||
|
||
### 5.1 话术生成失败
|
||
|
||
**场景**: LLM 调用超时或返回错误
|
||
|
||
**处理**:
|
||
1. 记录错误日志(包含 tenant_id, session_id, flow_id, step_no)
|
||
2. 返回 `step.content` 作为 fallback
|
||
3. 在 ChatMessage 中标记 `is_error=False`(因为有 fallback,不算错误)
|
||
|
||
### 5.2 配置错误
|
||
|
||
**场景**: flexible 模式但 intent 为空
|
||
|
||
**处理**:
|
||
1. 前端校验:提交时检查必填字段
|
||
2. 后端容错:如果 intent 为空,降级为 fixed 模式
|
||
|
||
### 5.3 模板解析错误
|
||
|
||
**场景**: 模板语法错误(如 `{unclosed`)
|
||
|
||
**处理**:
|
||
1. 捕获正则匹配异常
|
||
2. 返回原始模板(不做替换)
|
||
3. 记录警告日志
|
||
|
||
---
|
||
|
||
## 6. 性能考虑
|
||
|
||
### 6.1 预期性能指标
|
||
|
||
| 指标 | 目标值 | 说明 |
|
||
|------|--------|------|
|
||
| 话术生成延迟 (P95) | < 2s | LLM 调用时间 |
|
||
| API 响应时间增加 | < 10% | 相比固定模式 |
|
||
| 数据库查询增加 | +1 次 | 获取对话历史 |
|
||
|
||
### 6.2 优化策略
|
||
|
||
1. **并行查询**: 获取对话历史和流程配置可以并行
|
||
2. **限制历史长度**: 只查询最近 3 轮对话
|
||
3. **超时控制**: 严格的 2 秒超时,避免长时间等待
|
||
|
||
---
|
||
|
||
## 7. 测试策略
|
||
|
||
### 7.1 单元测试
|
||
|
||
**测试文件**: `ai-service/tests/services/flow/test_script_generator.py`
|
||
|
||
**测试用例**:
|
||
- 固定模式:直接返回 content
|
||
- 灵活模式:正常生成、超时 fallback、异常 fallback
|
||
- 模板模式:变量替换、变量缺失、模板语法错误
|
||
|
||
### 7.2 集成测试
|
||
|
||
**测试文件**: `ai-service/tests/api/test_script_flow_intent_driven.py`
|
||
|
||
**测试场景**:
|
||
1. 创建灵活模式流程
|
||
2. 启动流程,验证首步话术生成
|
||
3. 推进流程,验证后续步骤话术生成
|
||
4. 验证对话历史正确传递
|
||
|
||
### 7.3 端到端测试
|
||
|
||
**测试场景**:
|
||
1. 前端配置灵活模式流程
|
||
2. 保存并启用流程
|
||
3. 通过 Provider API 触发流程
|
||
4. 验证生成的话术符合意图和约束
|
||
|
||
---
|
||
|
||
## 8. 部署与发布
|
||
|
||
### 8.1 发布顺序
|
||
|
||
1. **Phase 1**: 后端数据模型和 API 扩展
|
||
- 部署后端代码
|
||
- 验证 API 向后兼容性
|
||
|
||
2. **Phase 2**: 后端话术生成引擎
|
||
- 部署话术生成逻辑
|
||
- 验证 fallback 机制
|
||
|
||
3. **Phase 3**: 前端配置界面
|
||
- 部署前端代码
|
||
- 验证配置保存和加载
|
||
|
||
4. **Phase 4**: 灰度发布
|
||
- 选择部分租户启用灵活模式
|
||
- 监控性能和错误率
|
||
- 全量发布
|
||
|
||
### 8.2 回滚策略
|
||
|
||
**如果出现问题**:
|
||
1. 前端回滚:恢复旧版本,用户无法配置灵活模式
|
||
2. 后端回滚:恢复旧版本,灵活模式降级为固定模式
|
||
3. 数据无需回滚:JSON 字段扩展,旧版本可以忽略新字段
|
||
|
||
---
|
||
|
||
## 9. 监控与告警
|
||
|
||
### 9.1 关键指标
|
||
|
||
| 指标 | 说明 | 告警阈值 |
|
||
|------|------|---------|
|
||
| script_generation_latency | 话术生成延迟 | P95 > 2.5s |
|
||
| script_generation_timeout_rate | 超时率 | > 5% |
|
||
| script_generation_error_rate | 错误率 | > 1% |
|
||
| fallback_usage_rate | Fallback 使用率 | > 10% |
|
||
|
||
### 9.2 日志记录
|
||
|
||
**关键日志**:
|
||
```python
|
||
logger.info(
|
||
f"[AC-IDS-03] Generated script: tenant={tenant_id}, "
|
||
f"session={session_id}, flow={flow_id}, step={step_no}, "
|
||
f"mode={script_mode}, latency={latency_ms}ms"
|
||
)
|
||
|
||
logger.warning(
|
||
f"[AC-IDS-05] Script generation timeout, use fallback: "
|
||
f"tenant={tenant_id}, session={session_id}, step={step_no}"
|
||
)
|
||
```
|
||
|
||
---
|
||
|
||
## 10. 未来扩展
|
||
|
||
### 10.1 短期优化(v1.1)
|
||
|
||
- 话术生成缓存(基于上下文哈希)
|
||
- 更丰富的约束条件预设
|
||
- 话术效果评估(用户满意度)
|
||
|
||
### 10.2 长期规划(v2.0)
|
||
|
||
- 多轮对话规划(提前生成后续步骤话术)
|
||
- 话术 A/B 测试
|
||
- 基于历史数据的话术优化建议
|