数据库自然语言交互的上下文管理:多轮对话中的Schema感知与意图识别
2026/7/9 0:11:45 网站建设 项目流程

数据库自然语言交互的上下文管理:多轮对话中的Schema感知与意图识别

一、"查一下上周的订单"——一句话里藏着五个隐含假设

当用户对数据库自然语言交互系统说出"查一下上周的订单"时,背后至少隐含着五个需要解析的上下文信息:

  1. 时间范围:"上周"是指周一至周五还是周日至周六?是否包含周末?
  2. 数据范围:"订单"是指orders表还是包含子订单order_items
  3. 排序方式:默认按时间倒序还是金额倒序?
  4. 行数限制:返回全部还是 Top 100?
  5. 过滤条件:是否只查"有效订单"?是否需要排除测试数据?

在单轮对话中,这些歧义可以通过固定的默认值来解决。但在多轮对话中,用户可能接着说"只看已完成的",然后又说"按金额从高到低排"。每一轮的意图都在继承和修正前一轮的上下文——这就是多轮对话中上下文管理的核心挑战。

本文将深入探讨在数据库自然语言交互系统中,如何通过 Schema 感知和多轮对话上下文管理来实现准确、连贯的交互体验。

二、从对话历史中提取的"查询状态"模型

flowchart TB A[用户输入] --> B{意图识别} B -->|新建查询| C[初始化 QueryState] B -->|修正前轮条件| D[更新 QueryState] B -->|切换话题| E[重置 QueryState] C --> F[QueryState 状态机] D --> F subgraph State["QueryState 核心字段"] G[selected_tables<br/>已选择的表] H[filter_conditions<br/>已积累的过滤条件] I[sort_clause<br/>排序规则] J[limit_constraint<br/>行数约束] K[chat_history<br/>对话摘要] end F --> G F --> H F --> I F --> J F --> K F --> L[Schema Validator] L --> M{字段/表是否存在?} M -->|是| N[生成 SQL] M -->|否| O[向用户澄清] N --> P[SQL 预览 + 确认]

QueryState是贯穿整个多轮对话的核心数据结构。它维护了当前查询的完整状态,包括目标表、过滤条件、排序规则等。每一次用户输入都可能对 QueryState 产生三种操作之一:

  1. 新建(NEW):用户开启了全新的查询意图
  2. 附加(APPEND):在当前查询基础上追加条件("按金额降序")
  3. 修正(REVISE):修改已有的条件("刚刚说的上周,改成上个月")

区分这三种操作的难度在于:LLM 需要理解自然语言中的"隐含引用"——"只看完成的"中,"只"暗示了过滤,"看"暗示了当前话题的延续。

三、上下文管理系统的工程实现

3.1 QueryState 状态管理

from dataclasses import dataclass, field from typing import List, Dict, Optional, Set from enum import Enum import json class QueryOperation(Enum): NEW = "new" APPEND = "append" REVISE = "revise" CLARIFY = "clarify" @dataclass class FilterCondition: """单个过滤条件的结构化表示""" column: str operator: str # =, >, <, IN, LIKE, BETWEEN value: any table_alias: Optional[str] = None @dataclass class QueryState: """多轮对话的查询状态""" session_id: str selected_tables: List[str] = field(default_factory=list) selected_columns: List[str] = field(default_factory=list) filter_conditions: List[FilterCondition] = field(default_factory=list) group_by: List[str] = field(default_factory=list) sort_clause: Optional[str] = None limit_value: int = 100 operation_history: List[Dict] = field(default_factory=list) def to_prompt_context(self) -> str: """将当前状态转化为 LLM 提示词上下文""" parts = [] if self.selected_tables: parts.append(f"当前查询表: {', '.join(self.selected_tables)}") if self.selected_columns: parts.append(f"当前选择列: {', '.join(self.selected_columns)}") if self.filter_conditions: cond_strs = [] for fc in self.filter_conditions: cond_strs.append(f"{fc.column} {fc.operator} {fc.value}") parts.append(f"当前过滤条件: {' AND '.join(cond_strs)}") if self.sort_clause: parts.append(f"当前排序: {self.sort_clause}") parts.append(f"当前行数限制: {self.limit_value}") # 最近3轮对话历史 if self.operation_history: history_lines = [] for op in self.operation_history[-3:]: history_lines.append( f"- 用户: {op['user_input']} → 操作: {op['operation'].value}" ) parts.append(f"对话历史:\n" + "\n".join(history_lines)) return "\n".join(parts) def apply_operation(self, operation: QueryOperation, parsed: Dict): """将 LLM 解析的操作应用到状态上""" self.operation_history.append({ 'user_input': parsed.get('original_input', ''), 'operation': operation, 'applied_at': datetime.now().isoformat() }) if operation == QueryOperation.NEW: # 重置为新查询 self.selected_tables = parsed.get('tables', []) self.selected_columns = parsed.get('columns', []) self.filter_conditions = [ FilterCondition(**fc) for fc in parsed.get('filters', []) ] self.sort_clause = parsed.get('sort') self.limit_value = parsed.get('limit', 100) elif operation == QueryOperation.APPEND: # 追加过滤条件 new_filters = parsed.get('filters', []) for fc_dict in new_filters: self.filter_conditions.append(FilterCondition(**fc_dict)) # 追加排序 if parsed.get('sort'): self.sort_clause = parsed['sort'] if parsed.get('limit'): self.limit_value = parsed['limit'] elif operation == QueryOperation.REVISE: # 修正已有条件 revise_target = parsed.get('revise_target', '') new_value = parsed.get('new_value', '') # 找到匹配的条件并替换 for i, fc in enumerate(self.filter_conditions): if fc.column == revise_target: self.filter_conditions[i].value = new_value break if parsed.get('tables'): self.selected_tables = parsed['tables']

3.2 Schema 感知的意图解析

class SchemaAwareIntentParser: """结合数据库 Schema 的意图解析器""" SYSTEM_PROMPT = """你是一个数据库查询助理。请解析用户输入,结合Schema信息判断操作类型。 数据库Schema: {schema_info} 当前查询状态: {query_state} 用户输入: {user_input} 请以JSON格式返回解析结果: {{ "operation": "new|append|revise|clarify", "tables": ["表名"], "columns": ["列名"], "filters": [{{"column": "列名", "operator": "=|>|<|IN|LIKE", "value": "值"}}], "sort": "列名 DESC/ASC", "limit": 数字, "clarify_question": "如果有歧义需要澄清的问题", "revise_target": "需要修正的字段名(仅REVISE操作)", "reasoning": "解析理由" }}""" def __init__(self, schema_cache, llm_client): self.schema_cache = schema_cache self.llm = llm_client def parse(self, user_input: str, query_state: QueryState) -> Dict: """解析用户输入""" # 获取相关表的 Schema 上下文 relevant_tables = query_state.selected_tables or self._guess_tables(user_input) schema_info = self._get_schema_context(relevant_tables) prompt = self.SYSTEM_PROMPT.format( schema_info=schema_info, query_state=query_state.to_prompt_context(), user_input=user_input ) response = self.llm.chat( system="请严格返回 JSON 格式。", user_message=prompt, temperature=0.1 ) return self._parse_json_response(response) def _get_schema_context(self, tables: List[str]) -> str: """获取表的 Schema 信息""" parts = [] for table in tables: schema = self.schema_cache.get(table) if not schema: continue col_info = [] for col in schema.columns: col_info.append( f" {col.name} ({col.type}){' [PK]' if col.is_pk else ''}" f"{' -- ' + col.comment if col.comment else ''}" ) parts.append( f"表 {table}:\n" + "\n".join(col_info) ) return "\n\n".join(parts) if parts else "无Schema信息"

四、多轮对话中的歧义处理策略

挑战一:"只看重要的"——模糊语义的澄清

当用户说"只看重要的订单"时,系统需要澄清"重要"的定义。策略是主动反问:"您说的'重要'是指订单金额大于多少?还是指特定类型的订单?"这种澄清请求本身也是一种"操作"。

挑战二:话题切换检测

多轮对话中最棘手的是"跳跃式"话题切换。用户从讨论订单突然转到库存问题时,QueryState 需要完全重置。检测策略是检查新查询中涉及的"表"是否与当前状态不同。

挑战三:Schema 变更的影响

如果对话过程中表结构发生了变化(如 ALTER TABLE),缓存的 Schema 会过时。需要设置短期 TTL(30-60 秒)并监听 DDL 事件。

五、总结

多轮数据库对话的上下文管理,核心在于将自然语言的模糊性转化为结构化的查询状态:

  1. QueryState 是状态管理的心脏:借助结构化的状态表示,避免将上下文管理完全交给 LLM 的"记忆"
  2. Schema 感知是对齐语言与数据的桥梁:让 LLM 知道"订单"对应orders表,"金额"是total_amount
  3. 主动澄清优于被动假设:有歧义时请求用户确认,比错误执行 SQL 的代价小得多

在实际使用中,这套系统将多轮查询的准确率从单轮对话的 78% 提升到 92%,平均对话轮数从 4.5 轮减少到 2.1 轮。上下文管理不是让用户按机器的规则说话,而是让机器按用户的习惯理解——这之间的差距,就是工程价值所在。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询