Skip to content

Commit 4fc1fa4

Browse files
committed
feat: add context record count configuration to chat
#773
1 parent a3ad51e commit 4fc1fa4

File tree

6 files changed

+115
-44
lines changed

6 files changed

+115
-44
lines changed

backend/apps/chat/task/llm.py

Lines changed: 44 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -54,8 +54,6 @@
5454

5555
warnings.filterwarnings("ignore")
5656

57-
base_message_count_limit = 6
58-
5957
executor = ThreadPoolExecutor(max_workers=200)
6058

6159
dynamic_ds_types = [1, 3]
@@ -95,6 +93,7 @@ class LLMService:
9593
articles_number: int = 4
9694

9795
enable_sql_row_limit: bool = settings.GENERATE_SQL_QUERY_LIMIT_ENABLED
96+
base_message_round_count_limit: int = settings.GENERATE_SQL_QUERY_HISTORY_ROUND_COUNT
9897

9998
def __init__(self, session: Session, current_user: CurrentUser, chat_question: ChatQuestion,
10099
current_assistant: Optional[CurrentAssistant] = None, no_reasoning: bool = False,
@@ -185,6 +184,14 @@ async def create(cls, *args, **kwargs):
185184
instance.enable_sql_row_limit = True
186185
else:
187186
instance.enable_sql_row_limit = False
187+
if config.pkey == 'chat.context_record_count':
188+
count_value = config.pval
189+
if count_value is None:
190+
count_value = settings.GENERATE_SQL_QUERY_HISTORY_ROUND_COUNT
191+
count_value = int(count_value)
192+
if count_value < 0:
193+
count_value = 0
194+
instance.base_message_round_count_limit = count_value
188195
return instance
189196

190197
def is_running(self, timeout=0.5):
@@ -206,22 +213,23 @@ def init_messages(self):
206213
filter(lambda obj: obj.pid == self.chat_question.regenerate_record_id, self.generate_sql_logs), None)
207214
last_sql_messages: List[dict[str, Any]] = _temp_log.messages if _temp_log else []
208215

209-
# todo maybe can configure
210-
count_limit = 0 - base_message_count_limit
216+
count_limit = self.base_message_round_count_limit
211217

212218
self.sql_message = []
213219
# add sys prompt
214220
self.sql_message.append(SystemMessage(
215221
content=self.chat_question.sql_sys_question(self.ds.type, self.enable_sql_row_limit)))
216222
if last_sql_messages is not None and len(last_sql_messages) > 0:
217-
# limit count
218-
for last_sql_message in last_sql_messages[count_limit:]:
223+
# 获取最后3轮对话
224+
last_rounds = get_last_conversation_rounds(last_sql_messages, rounds=count_limit)
225+
226+
for _msg_dict in last_rounds:
219227
_msg: BaseMessage
220-
if last_sql_message['type'] == 'human':
221-
_msg = HumanMessage(content=last_sql_message['content'])
228+
if _msg_dict.get('type') == 'human':
229+
_msg = HumanMessage(content=_msg_dict.get('content'))
222230
self.sql_message.append(_msg)
223-
elif last_sql_message['type'] == 'ai':
224-
_msg = AIMessage(content=last_sql_message['content'])
231+
elif _msg_dict.get('type') == 'ai':
232+
_msg = AIMessage(content=_msg_dict.get('content'))
225233
self.sql_message.append(_msg)
226234

227235
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):
16661674
if normalized.startswith('ko'):
16671675
return '韩语'
16681676
return '简体中文'
1677+
1678+
1679+
def get_last_conversation_rounds(messages, rounds=settings.GENERATE_SQL_QUERY_HISTORY_ROUND_COUNT):
1680+
"""获取最后N轮对话,处理不完整对话的情况"""
1681+
if not messages or rounds <= 0:
1682+
return []
1683+
1684+
# 找到所有用户消息的位置
1685+
human_indices = []
1686+
for index, msg in enumerate(messages):
1687+
if msg.get('type') == 'human':
1688+
human_indices.append(index)
1689+
1690+
# 如果没有用户消息,返回空
1691+
if not human_indices:
1692+
return []
1693+
1694+
# 计算从哪个索引开始
1695+
if len(human_indices) <= rounds:
1696+
# 如果用户消息数少于等于需要的轮数,从第一个用户消息开始
1697+
start_index = human_indices[0]
1698+
else:
1699+
# 否则,从倒数第N个用户消息开始
1700+
start_index = human_indices[-rounds]
1701+
1702+
return messages[start_index:]

backend/common/core/config.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,7 @@ def SQLALCHEMY_DATABASE_URI(self) -> PostgresDsn | str:
109109

110110
# 是否启用SQL查询行数限制,默认值,可被参数配置覆盖
111111
GENERATE_SQL_QUERY_LIMIT_ENABLED: bool = True
112+
GENERATE_SQL_QUERY_HISTORY_ROUND_COUNT: int = 3
112113

113114
PARSE_REASONING_BLOCK_ENABLED: bool = True
114115
DEFAULT_REASONING_CONTENT_START: str = '<think>'

frontend/src/i18n/en.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@
1313
"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.",
1414
"parameter_configuration": "Parameter Config",
1515
"question_count_settings": "Question Count Settings",
16+
"context_record_count": "Context Record Count",
17+
"context_record_count_hint": "Number of user question rounds",
1618
"model_thinking_process": "Expand Model Thinking Process",
1719
"rows_of_data": "Limit 1000 Rows of Data",
1820
"third_party_platform_settings": "Third-Party Platform Settings",

frontend/src/i18n/ko-KR.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@
1313
"memo": "메모 업데이트 규칙: 테이블 이름과 필드 이름이 일치하는지 확인합니다. 일치하는 항목이 있으면 테이블 메모와 필드 메모를 업데이트하고, 그렇지 않으면 메모를 변경하지 않고 그대로 둡니다.",
1414
"parameter_configuration": "매개변수 구성",
1515
"question_count_settings": "질문 수 설정",
16+
"context_record_count": "컨텍스트 기록 수",
17+
"context_record_count_hint": "사용자 질문 라운드 수",
1618
"model_thinking_process": "모델 사고 프로세스 확장",
1719
"rows_of_data": "데이터 1,000행 제한",
1820
"third_party_platform_settings": "타사 플랫폼 설정",

frontend/src/i18n/zh-CN.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@
1313
"memo": "备注更新规则:根据表名和字段名匹配,如果匹配则更新表备注和字段备注;如果匹配不上,备注保持不变。",
1414
"parameter_configuration": "参数配置",
1515
"question_count_settings": "问数设置",
16+
"context_record_count": "上下文记录数",
17+
"context_record_count_hint": "用户提问轮数",
1618
"model_thinking_process": "展开模型思考过程",
1719
"rows_of_data": "限制 1000 行数据",
1820
"third_party_platform_settings": "第三方平台设置",

frontend/src/views/system/parameter/index.vue

Lines changed: 64 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,13 @@ const loadData = () => {
3131
})
3232
}
3333
34+
const onContextRecordCountChange = (count: number) => {
35+
if (count < 0) {
36+
state.parameterForm['chat.context_record_count'] = 0
37+
}
38+
state.parameterForm['chat.context_record_count'] = Math.floor(count)
39+
}
40+
3441
const beforeChange = (): Promise<boolean> => {
3542
return new Promise((resolve) => {
3643
if (!state.parameterForm['chat.rows_of_data']) {
@@ -88,41 +95,66 @@ onMounted(() => {
8895
<div class="card-title">
8996
{{ t('parameter.question_count_settings') }}
9097
</div>
91-
<div class="card-item">
92-
<div class="label">
93-
{{ t('parameter.model_thinking_process') }}
98+
<el-row>
99+
<div class="card-item">
100+
<div class="label">
101+
{{ t('parameter.model_thinking_process') }}
94102

95-
<el-tooltip effect="dark" :content="t('parameter.closed_by_default')" placement="top">
96-
<el-icon size="16">
97-
<icon_info_outlined_1></icon_info_outlined_1>
98-
</el-icon>
99-
</el-tooltip>
103+
<el-tooltip effect="dark" :content="t('parameter.closed_by_default')" placement="top">
104+
<el-icon size="16">
105+
<icon_info_outlined_1></icon_info_outlined_1>
106+
</el-icon>
107+
</el-tooltip>
108+
</div>
109+
<div class="value">
110+
<el-switch v-model="state.parameterForm['chat.expand_thinking_block']" />
111+
</div>
100112
</div>
101-
<div class="value">
102-
<el-switch v-model="state.parameterForm['chat.expand_thinking_block']" />
113+
<div class="card-item" style="margin-left: 16px">
114+
<div class="label">
115+
{{ t('parameter.rows_of_data') }}
116+
<el-tooltip
117+
effect="dark"
118+
:content="t('parameter.excessive_data_volume')"
119+
placement="top"
120+
>
121+
<el-icon size="16">
122+
<icon_info_outlined_1></icon_info_outlined_1>
123+
</el-icon>
124+
</el-tooltip>
125+
</div>
126+
<div class="value">
127+
<el-switch
128+
v-model="state.parameterForm['chat.limit_rows']"
129+
:before-change="beforeChange"
130+
/>
131+
</div>
103132
</div>
104-
</div>
105-
106-
<div class="card-item" style="margin-left: 16px">
107-
<div class="label">
108-
{{ t('parameter.rows_of_data') }}
109-
<el-tooltip
110-
effect="dark"
111-
:content="t('parameter.excessive_data_volume')"
112-
placement="top"
113-
>
114-
<el-icon size="16">
115-
<icon_info_outlined_1></icon_info_outlined_1>
116-
</el-icon>
117-
</el-tooltip>
118-
</div>
119-
<div class="value">
120-
<el-switch
121-
v-model="state.parameterForm['chat.limit_rows']"
122-
:before-change="beforeChange"
123-
/>
133+
</el-row>
134+
<el-row>
135+
<div class="card-item">
136+
<div class="label">
137+
{{ t('parameter.context_record_count') }}
138+
<el-tooltip
139+
effect="dark"
140+
:content="t('parameter.context_record_count_hint')"
141+
placement="top"
142+
>
143+
<el-icon size="16">
144+
<icon_info_outlined_1></icon_info_outlined_1>
145+
</el-icon>
146+
</el-tooltip>
147+
</div>
148+
<div class="value">
149+
<el-input-number
150+
v-model.number="state.parameterForm['chat.context_record_count']"
151+
min="0"
152+
step="1"
153+
@change="onContextRecordCountChange"
154+
/>
155+
</div>
124156
</div>
125-
</div>
157+
</el-row>
126158
</div>
127159

128160
<platform-param />
@@ -152,7 +184,6 @@ onMounted(() => {
152184
}
153185
.title {
154186
font-weight: 500;
155-
font-style: Medium;
156187
font-size: 20px;
157188
line-height: 28px;
158189
margin-bottom: 16px;
@@ -164,12 +195,11 @@ onMounted(() => {
164195
padding: 16px;
165196
border: 1px solid #dee0e3;
166197
display: flex;
167-
flex-wrap: wrap;
198+
flex-direction: column;
168199
margin-top: 16px;
169200
170201
.card-title {
171202
font-weight: 500;
172-
font-style: Medium;
173203
font-size: 16px;
174204
line-height: 24px;
175205
width: 100%;

0 commit comments

Comments
 (0)