feat: add context record count configuration to chat

#773
This commit is contained in:
ulleo
2026-01-26 17:21:56 +08:00
committed by ulleo
parent a3ad51e9b7
commit 5cdfc07169
6 changed files with 115 additions and 44 deletions
+44 -10
View File
@@ -54,8 +54,6 @@ from common.utils.utils import SQLBotLogUtil, extract_nested_json, prepare_for_o
warnings.filterwarnings("ignore")
base_message_count_limit = 6
executor = ThreadPoolExecutor(max_workers=200)
dynamic_ds_types = [1, 3]
@@ -95,6 +93,7 @@ class LLMService:
articles_number: int = 4
enable_sql_row_limit: bool = settings.GENERATE_SQL_QUERY_LIMIT_ENABLED
base_message_round_count_limit: int = settings.GENERATE_SQL_QUERY_HISTORY_ROUND_COUNT
def __init__(self, session: Session, current_user: CurrentUser, chat_question: ChatQuestion,
current_assistant: Optional[CurrentAssistant] = None, no_reasoning: bool = False,
@@ -185,6 +184,14 @@ class LLMService:
instance.enable_sql_row_limit = True
else:
instance.enable_sql_row_limit = False
if config.pkey == 'chat.context_record_count':
count_value = config.pval
if count_value is None:
count_value = settings.GENERATE_SQL_QUERY_HISTORY_ROUND_COUNT
count_value = int(count_value)
if count_value < 0:
count_value = 0
instance.base_message_round_count_limit = count_value
return instance
def is_running(self, timeout=0.5):
@@ -206,22 +213,23 @@ class LLMService:
filter(lambda obj: obj.pid == self.chat_question.regenerate_record_id, self.generate_sql_logs), None)
last_sql_messages: List[dict[str, Any]] = _temp_log.messages if _temp_log else []
# todo maybe can configure
count_limit = 0 - base_message_count_limit
count_limit = self.base_message_round_count_limit
self.sql_message = []
# add sys prompt
self.sql_message.append(SystemMessage(
content=self.chat_question.sql_sys_question(self.ds.type, self.enable_sql_row_limit)))
if last_sql_messages is not None and len(last_sql_messages) > 0:
# limit count
for last_sql_message in last_sql_messages[count_limit:]:
# 获取最后3轮对话
last_rounds = get_last_conversation_rounds(last_sql_messages, rounds=count_limit)
for _msg_dict in last_rounds:
_msg: BaseMessage
if last_sql_message['type'] == 'human':
_msg = HumanMessage(content=last_sql_message['content'])
if _msg_dict.get('type') == 'human':
_msg = HumanMessage(content=_msg_dict.get('content'))
self.sql_message.append(_msg)
elif last_sql_message['type'] == 'ai':
_msg = AIMessage(content=last_sql_message['content'])
elif _msg_dict.get('type') == 'ai':
_msg = AIMessage(content=_msg_dict.get('content'))
self.sql_message.append(_msg)
last_chart_messages: List[dict[str, Any]] = self.generate_chart_logs[-1].messages if len(
@@ -1666,3 +1674,29 @@ def get_lang_name(lang: str):
if normalized.startswith('ko'):
return '韩语'
return '简体中文'
def get_last_conversation_rounds(messages, rounds=settings.GENERATE_SQL_QUERY_HISTORY_ROUND_COUNT):
"""获取最后N轮对话,处理不完整对话的情况"""
if not messages or rounds <= 0:
return []
# 找到所有用户消息的位置
human_indices = []
for index, msg in enumerate(messages):
if msg.get('type') == 'human':
human_indices.append(index)
# 如果没有用户消息,返回空
if not human_indices:
return []
# 计算从哪个索引开始
if len(human_indices) <= rounds:
# 如果用户消息数少于等于需要的轮数,从第一个用户消息开始
start_index = human_indices[0]
else:
# 否则,从倒数第N个用户消息开始
start_index = human_indices[-rounds]
return messages[start_index:]
+1
View File
@@ -109,6 +109,7 @@ class Settings(BaseSettings):
# 是否启用SQL查询行数限制,默认值,可被参数配置覆盖
GENERATE_SQL_QUERY_LIMIT_ENABLED: bool = True
GENERATE_SQL_QUERY_HISTORY_ROUND_COUNT: int = 3
PARSE_REASONING_BLOCK_ENABLED: bool = True
DEFAULT_REASONING_CONTENT_START: str = '<think>'
+2
View File
@@ -13,6 +13,8 @@
"memo": "Memo update rules: Match table name and field name. If a match is found, update the table memo and field memo; otherwise, leave the memo unchanged.",
"parameter_configuration": "Parameter Config",
"question_count_settings": "Question Count Settings",
"context_record_count": "Context Record Count",
"context_record_count_hint": "Number of user question rounds",
"model_thinking_process": "Expand Model Thinking Process",
"rows_of_data": "Limit 1000 Rows of Data",
"third_party_platform_settings": "Third-Party Platform Settings",
+2
View File
@@ -13,6 +13,8 @@
"memo": "메모 업데이트 규칙: 테이블 이름과 필드 이름이 일치하는지 확인합니다. 일치하는 항목이 있으면 테이블 메모와 필드 메모를 업데이트하고, 그렇지 않으면 메모를 변경하지 않고 그대로 둡니다.",
"parameter_configuration": "매개변수 구성",
"question_count_settings": "질문 수 설정",
"context_record_count": "컨텍스트 기록 수",
"context_record_count_hint": "사용자 질문 라운드 수",
"model_thinking_process": "모델 사고 프로세스 확장",
"rows_of_data": "데이터 1,000행 제한",
"third_party_platform_settings": "타사 플랫폼 설정",
+2
View File
@@ -13,6 +13,8 @@
"memo": "备注更新规则:根据表名和字段名匹配,如果匹配则更新表备注和字段备注;如果匹配不上,备注保持不变。",
"parameter_configuration": "参数配置",
"question_count_settings": "问数设置",
"context_record_count": "上下文记录数",
"context_record_count_hint": "用户提问轮数",
"model_thinking_process": "展开模型思考过程",
"rows_of_data": "限制 1000 行数据",
"third_party_platform_settings": "第三方平台设置",
+64 -34
View File
@@ -31,6 +31,13 @@ const loadData = () => {
})
}
const onContextRecordCountChange = (count: number) => {
if (count < 0) {
state.parameterForm['chat.context_record_count'] = 0
}
state.parameterForm['chat.context_record_count'] = Math.floor(count)
}
const beforeChange = (): Promise<boolean> => {
return new Promise((resolve) => {
if (!state.parameterForm['chat.rows_of_data']) {
@@ -88,41 +95,66 @@ onMounted(() => {
<div class="card-title">
{{ t('parameter.question_count_settings') }}
</div>
<div class="card-item">
<div class="label">
{{ t('parameter.model_thinking_process') }}
<el-row>
<div class="card-item">
<div class="label">
{{ t('parameter.model_thinking_process') }}
<el-tooltip effect="dark" :content="t('parameter.closed_by_default')" placement="top">
<el-icon size="16">
<icon_info_outlined_1></icon_info_outlined_1>
</el-icon>
</el-tooltip>
<el-tooltip effect="dark" :content="t('parameter.closed_by_default')" placement="top">
<el-icon size="16">
<icon_info_outlined_1></icon_info_outlined_1>
</el-icon>
</el-tooltip>
</div>
<div class="value">
<el-switch v-model="state.parameterForm['chat.expand_thinking_block']" />
</div>
</div>
<div class="value">
<el-switch v-model="state.parameterForm['chat.expand_thinking_block']" />
<div class="card-item" style="margin-left: 16px">
<div class="label">
{{ t('parameter.rows_of_data') }}
<el-tooltip
effect="dark"
:content="t('parameter.excessive_data_volume')"
placement="top"
>
<el-icon size="16">
<icon_info_outlined_1></icon_info_outlined_1>
</el-icon>
</el-tooltip>
</div>
<div class="value">
<el-switch
v-model="state.parameterForm['chat.limit_rows']"
:before-change="beforeChange"
/>
</div>
</div>
</div>
<div class="card-item" style="margin-left: 16px">
<div class="label">
{{ t('parameter.rows_of_data') }}
<el-tooltip
effect="dark"
:content="t('parameter.excessive_data_volume')"
placement="top"
>
<el-icon size="16">
<icon_info_outlined_1></icon_info_outlined_1>
</el-icon>
</el-tooltip>
</el-row>
<el-row>
<div class="card-item">
<div class="label">
{{ t('parameter.context_record_count') }}
<el-tooltip
effect="dark"
:content="t('parameter.context_record_count_hint')"
placement="top"
>
<el-icon size="16">
<icon_info_outlined_1></icon_info_outlined_1>
</el-icon>
</el-tooltip>
</div>
<div class="value">
<el-input-number
v-model.number="state.parameterForm['chat.context_record_count']"
min="0"
step="1"
@change="onContextRecordCountChange"
/>
</div>
</div>
<div class="value">
<el-switch
v-model="state.parameterForm['chat.limit_rows']"
:before-change="beforeChange"
/>
</div>
</div>
</el-row>
</div>
<platform-param />
@@ -152,7 +184,6 @@ onMounted(() => {
}
.title {
font-weight: 500;
font-style: Medium;
font-size: 20px;
line-height: 28px;
margin-bottom: 16px;
@@ -164,12 +195,11 @@ onMounted(() => {
padding: 16px;
border: 1px solid #dee0e3;
display: flex;
flex-wrap: wrap;
flex-direction: column;
margin-top: 16px;
.card-title {
font-weight: 500;
font-style: Medium;
font-size: 16px;
line-height: 24px;
width: 100%;