From 4d39cdf464c214c87967858cbd915377e65d5e82 Mon Sep 17 00:00:00 2001 From: Timebomb2018 <18868801967@163.com> Date: Thu, 26 Mar 2026 18:28:19 +0800 Subject: [PATCH] fix(app): The opening remarks and the referenced documents have been saved in the history. --- api/app/services/app_chat_service.py | 69 +++++++++++++++++------ api/app/services/draft_run_service.py | 81 ++++++++++++++++++--------- 2 files changed, 107 insertions(+), 43 deletions(-) diff --git a/api/app/services/app_chat_service.py b/api/app/services/app_chat_service.py index 3dda6fc0..90474428 100644 --- a/api/app/services/app_chat_service.py +++ b/api/app/services/app_chat_service.py @@ -82,12 +82,6 @@ class AppChatService: ) system_prompt = system_prompt_rendered.get_text_content() or system_prompt - # opening_statement:首轮对话注入开场白 - is_new_conversation = not self.conversation_service.get_messages(conversation_id, limit=1) - system_prompt = self.agent_service._inject_opening_statement( - features_config, system_prompt, is_new_conversation - ) - # 准备工具列表 tools = [] @@ -135,7 +129,7 @@ class AppChatService: model_type=ModelType.LLM ) - # 加载历史消息 + # 加载历史消息(包含开场白) history = await self.conversation_service.get_conversation_history( conversation_id=conversation_id, max_history=10, @@ -143,6 +137,25 @@ class AppChatService: current_is_omni=api_key_obj.is_omni ) + # 如果是新会话且有开场白,作为第一条 assistant 消息写入数据库 + is_new_conversation = len(history) == 0 + if is_new_conversation: + opening = self.agent_service._get_opening_statement(features_config, True, variables) + if opening: + self.conversation_service.add_message( + conversation_id=conversation_id, + role="assistant", + content=opening, + meta_data={} + ) + # 重新加载历史(包含刚写入的开场白) + history = await self.conversation_service.get_conversation_history( + conversation_id=conversation_id, + max_history=10, + current_provider=api_key_obj.provider, + current_is_omni=api_key_obj.is_omni + ) + # 处理多模态文件 processed_files = None if files: @@ -184,6 +197,9 @@ class AppChatService: tenant_id=tenant_id, workspace_id=workspace_id ) + # 过滤 citations(只调用一次) + filtered_citations = self.agent_service._filter_citations(features_config, citations_collector) + # 构建用户消息内容(含多模态文件) human_meta = { "files": [], @@ -192,7 +208,8 @@ class AppChatService: assistant_meta = { "model": api_key_obj.model_name, "usage": result.get("usage", {"prompt_tokens": 0, "completion_tokens": 0, "total_tokens": 0}), - "audio_url": None + "audio_url": None, + "citations": filtered_citations } if files: for f in files: @@ -237,7 +254,7 @@ class AppChatService: }), "elapsed_time": elapsed_time, "suggested_questions": suggested_questions, - "citations": self.agent_service._filter_citations(features_config, citations_collector), + "citations": filtered_citations, "audio_url": audio_url, "audio_status": "pending" } @@ -290,12 +307,6 @@ class AppChatService: ) system_prompt = system_prompt_rendered.get_text_content() or system_prompt - # opening_statement:首轮对话注入开场白 - is_new_conversation = not self.conversation_service.get_messages(conversation_id, limit=1) - system_prompt = self.agent_service._inject_opening_statement( - features_config, system_prompt, is_new_conversation - ) - # 准备工具列表 tools = [] @@ -345,7 +356,7 @@ class AppChatService: model_type=ModelType.LLM ) - # 加载历史消息 + # 加载历史消息(包含开场白) history = await self.conversation_service.get_conversation_history( conversation_id=conversation_id, max_history=10, @@ -353,6 +364,25 @@ class AppChatService: current_is_omni=api_key_obj.is_omni ) + # 如果是新会话且有开场白,作为第一条 assistant 消息写入数据库 + is_new_conversation = len(history) == 0 + if is_new_conversation: + opening = self.agent_service._get_opening_statement(features_config, True, variables) + if opening: + self.conversation_service.add_message( + conversation_id=conversation_id, + role="assistant", + content=opening, + meta_data={} + ) + # 重新加载历史(包含刚写入的开场白) + history = await self.conversation_service.get_conversation_history( + conversation_id=conversation_id, + max_history=10, + current_provider=api_key_obj.provider, + current_is_omni=api_key_obj.is_omni + ) + # 处理多模态文件 processed_files = None if files: @@ -423,7 +453,9 @@ class AppChatService: logger.warning(f"TTS任务异常: {e}") audio_status = "failed" end_data["audio_status"] = audio_status if stream_audio_url else None - end_data["citations"] = self.agent_service._filter_citations(features_config, citations_collector) + # 过滤 citations(只调用一次) + filtered_citations = self.agent_service._filter_citations(features_config, citations_collector) + end_data["citations"] = filtered_citations # 保存消息 human_meta = { @@ -433,7 +465,8 @@ class AppChatService: assistant_meta = { "model": api_key_obj.model_name, "usage": {"prompt_tokens": 0, "completion_tokens": 0, "total_tokens": total_tokens}, - "audio_url": None + "audio_url": None, + "citations": filtered_citations } if files: diff --git a/api/app/services/draft_run_service.py b/api/app/services/draft_run_service.py index ac34b4de..e188872f 100644 --- a/api/app/services/draft_run_service.py +++ b/api/app/services/draft_run_service.py @@ -445,19 +445,27 @@ class AgentRunService: ) @staticmethod - def _inject_opening_statement( + def _get_opening_statement( features_config: Dict[str, Any], - system_prompt: str, - is_new_conversation: bool - ) -> str: - """首轮对话时将开场白注入 system_prompt""" + is_new_conversation: bool, + variables: Optional[Dict[str, Any]] = None + ) -> Optional[str]: + """首轮对话时返回开场白文本(支持变量替换),否则返回 None""" if not is_new_conversation: - return system_prompt + return None opening = features_config.get("opening_statement", {}) if not (isinstance(opening, dict) and opening.get("enabled") and opening.get("statement")): - return system_prompt + return None + statement = opening["statement"] - return f"{system_prompt}\n\n[对话开场白]\n{statement}" + + # 如果有变量,进行替换(仅支持 {{var_name}} 格式) + if variables: + for var_name, var_value in variables.items(): + placeholder = f"{{{{{var_name}}}}}" + statement = statement.replace(placeholder, str(var_value)) + + return statement @staticmethod def _filter_citations( @@ -555,10 +563,6 @@ class AgentRunService: # 3. 处理系统提示词(支持变量替换) system_prompt = system_prompt.get_text_content() or "你是一个专业的AI助手" - # opening_statement:首轮对话注入开场白 - is_new_conversation = not conversation_id - system_prompt = self._inject_opening_statement(features_config, system_prompt, is_new_conversation) - # 4. 准备工具列表 tools = [] @@ -593,12 +597,15 @@ class AgentRunService: tools=tools, ) - # 5. 处理会话ID(创建或验证) + # 5. 处理会话ID(创建或验证),新会话时写入开场白 + is_new_conversation = not conversation_id + opening = self._get_opening_statement(features_config, is_new_conversation, variables) conversation_id = await self._ensure_conversation( conversation_id=conversation_id, app_id=agent_config.app_id, workspace_id=workspace_id, - user_id=user_id + user_id=user_id, + opening_statement=opening ) model_info = ModelInfo( @@ -611,7 +618,7 @@ class AgentRunService: model_type=model_config.type ) - # 6. 加载历史消息 + # 6. 加载历史消息(包含开场白) history = await self._load_conversation_history( conversation_id=conversation_id, max_history=10, @@ -668,6 +675,9 @@ class AgentRunService: tenant_id=tenant_id, workspace_id=workspace_id ) if not sub_agent else None + # 过滤 citations(只调用一次) + filtered_citations = self._filter_citations(features_config, citations_collector) + # 10. 保存会话消息 if not sub_agent: await self._save_conversation_message( @@ -686,6 +696,7 @@ class AgentRunService: files=files, processed_files=processed_files, audio_url=audio_url, + citations=filtered_citations, provider=api_key_config.get("provider"), is_omni=api_key_config.get("is_omni", False) ) @@ -702,7 +713,7 @@ class AgentRunService: "suggested_questions": await self._generate_suggested_questions( features_config, result["content"], api_key_config, effective_params ) if not sub_agent else [], - "citations": self._filter_citations(features_config, citations_collector), + "citations": filtered_citations, "audio_url": audio_url, "audio_status": "pending" } @@ -797,10 +808,6 @@ class AgentRunService: # 3. 处理系统提示词(支持变量替换) system_prompt = system_prompt.get_text_content() or "你是一个专业的AI助手" - # opening_statement:首轮对话注入开场白 - is_new_conversation = not conversation_id - system_prompt = self._inject_opening_statement(features_config, system_prompt, is_new_conversation) - # 4. 准备工具列表 tools = [] @@ -836,13 +843,16 @@ class AgentRunService: streaming=True ) - # 5. 处理会话ID(创建或验证) + # 5. 处理会话ID(创建或验证),新会话时写入开场白 + is_new_conversation = not conversation_id + opening = self._get_opening_statement(features_config, is_new_conversation, variables) conversation_id = await self._ensure_conversation( conversation_id=conversation_id, app_id=agent_config.app_id, workspace_id=workspace_id, user_id=user_id, - sub_agent=sub_agent + sub_agent=sub_agent, + opening_statement=opening ) model_info = ModelInfo( @@ -926,6 +936,9 @@ class AgentRunService: if sub_agent: yield self._format_sse_event("sub_usage", {"total_tokens": total_tokens}) + # 过滤 citations(只调用一次) + filtered_citations = self._filter_citations(features_config, citations_collector) + # 11. 保存会话消息 if not sub_agent: await self._save_conversation_message( @@ -940,6 +953,7 @@ class AgentRunService: files=files, processed_files=processed_files, audio_url=stream_audio_url, + citations=filtered_citations, provider=api_key_config.get("provider"), is_omni=api_key_config.get("is_omni", False) ) @@ -966,7 +980,7 @@ class AgentRunService: logger.warning(f"TTS任务异常: {e}") audio_status = "failed" end_data["audio_status"] = audio_status if stream_audio_url else None - end_data["citations"] = self._filter_citations(features_config, citations_collector) + end_data["citations"] = filtered_citations yield self._format_sse_event("end", end_data) logger.info( @@ -1046,7 +1060,8 @@ class AgentRunService: app_id: uuid.UUID, workspace_id: uuid.UUID, user_id: Optional[str], - sub_agent: bool = False + sub_agent: bool = False, + opening_statement: Optional[str] = None ) -> str: """确保会话存在(创建或验证) @@ -1055,6 +1070,8 @@ class AgentRunService: app_id: 应用ID workspace_id: 工作空间ID(必须) user_id: 用户ID + sub_agent: 是否为子代理 + opening_statement: 开场白(新会话时作为第一条消息写入) Returns: str: 会话ID @@ -1092,6 +1109,16 @@ class AgentRunService: self.db.commit() self.db.refresh(new_conversation) + # 如果有开场白,作为第一条 assistant 消息写入数据库 + if opening_statement: + conversation_service.add_message( + conversation_id=uuid.UUID(new_conv_id), + role="assistant", + content=opening_statement, + meta_data={} + ) + logger.debug(f"已保存开场白到会话 {new_conv_id}") + logger.info( "创建草稿会话成功", extra={ @@ -1215,6 +1242,7 @@ class AgentRunService: files: Optional[List[FileInput]] = None, processed_files: Optional[List[Dict[str, Any]]] = None, audio_url: Optional[str] = None, + citations: Optional[List[Any]] = None, provider: Optional[str] = None, is_omni: Optional[bool] = None ) -> None: @@ -1230,6 +1258,7 @@ class AgentRunService: files: 原始文件输入 processed_files: 处理后的文件 audio_url: 音频URL + citations: 引用来源列表 provider: 模型供应商 is_omni: 是否为全模态模型 """ @@ -1266,9 +1295,11 @@ class AgentRunService: content=user_message, meta_data=human_meta ) - # 保存助手消息(含 audio_url) + # 保存助手消息(含 audio_url 和 citations) if audio_url: meta_data["audio_url"] = audio_url + if citations: + meta_data["citations"] = citations conversation_service.add_message( conversation_id=conv_uuid, role="assistant",