From cb836f5108cb0db509d15271c54c90c27ed42b68 Mon Sep 17 00:00:00 2001 From: zcr Date: Mon, 13 Apr 2026 16:17:02 +0800 Subject: [PATCH] =?UTF-8?q?=E6=96=B0=E5=A2=9E=E5=AF=B9=E8=AF=9D=E8=AF=AD?= =?UTF-8?q?=E8=A8=80=E8=AE=BE=E7=BD=AE=20=E9=BB=98=E8=AE=A4=E4=BD=BF?= =?UTF-8?q?=E7=94=A8=E8=8B=B1=E6=96=87?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/routers/deep_agent_chat.py | 2 +- src/schemas/deep_agent_chat.py | 1 + src/server/deep_agent/agents/main_agent.py | 78 +++++++++--- src/server/deep_agent/init_llm.py | 4 +- src/server/deep_agent/init_prompt.py | 117 ++++++++++++++++-- .../tools/conversation_title_tool.py | 5 +- 6 files changed, 180 insertions(+), 27 deletions(-) diff --git a/src/routers/deep_agent_chat.py b/src/routers/deep_agent_chat.py index 958c958..8ffc8d1 100755 --- a/src/routers/deep_agent_chat.py +++ b/src/routers/deep_agent_chat.py @@ -211,7 +211,7 @@ async def chat_stream(request: DeepAgentChatRequest): config=current_config, stream_mode=["updates", "messages", "custom"], subgraphs=True, - context=Context(use_report=request.use_report), + context=Context(use_report=request.use_report, language=request.language), ): _, mode, chunks = stream if is_first: diff --git a/src/schemas/deep_agent_chat.py b/src/schemas/deep_agent_chat.py index e6e5f92..762898f 100755 --- a/src/schemas/deep_agent_chat.py +++ b/src/schemas/deep_agent_chat.py @@ -22,6 +22,7 @@ class DeepAgentChatRequest(BaseModel): ) need_suggestion: float = 0 use_report: bool = False # ← 新增:是否使用深度报告 + language: str = "en" class HistoryItem(BaseModel): diff --git a/src/server/deep_agent/agents/main_agent.py b/src/server/deep_agent/agents/main_agent.py index 3db5035..103f082 100755 --- a/src/server/deep_agent/agents/main_agent.py +++ b/src/server/deep_agent/agents/main_agent.py @@ -18,7 +18,7 @@ from src.core.config import MONGO_URI from src.server.deep_agent.agents.researcher import build_researcher_subagent from src.server.deep_agent.agents.user_profile import user_profile_subagent from src.server.deep_agent.init_llm import build_main_llm -from src.server.deep_agent.init_prompt import SYSTEM_BASE_PROMPT, SYSTEM_RULES_PROMPT +from src.server.deep_agent.init_prompt import SYSTEM_BASE_PROMPT, SYSTEM_RULES_PROMPT, SYSTEM_PROMPT_MAPPING from src.server.deep_agent.tools.generate_furniture_sketch import edit_furniture, generate_furniture, edit_quote_upload_furniture logger = logging.getLogger(__name__) @@ -33,7 +33,8 @@ checkpointer = MongoDBSaver( @dataclass class Context: - use_report: bool + use_report: bool = False + language: str = "en" @wrap_tool_call @@ -79,30 +80,79 @@ async def report_control(request: ToolCallRequest, handler: Callable[[ToolCallRe @dynamic_prompt def user_role_prompt(request: ModelRequest) -> str: - """Generate system prompts based on use-report status.""" + """Generate system prompts based on use_report status and language preference.""" use_report = request.runtime.context.use_report + language = request.runtime.context.language + + # ==================== 语言控制规则(最高优先级) ==================== + if language.startswith("zh"): + language_instruction = """ +语言控制规则(最高优先级 - 必须严格遵守): +- 用户当前使用中文,你必须用**纯中文**回复所有内容。 +- 最终回复给用户的消息必须是纯中文,禁止中英混杂。 +- 内部思考和工具调用可以使用英文,但输出给用户的最终消息必须是纯中文。 +""" + else: + # 默认英文(en, en-US, en-GB 等) + language_instruction = """ +Language Instruction (Highest Priority - Must be strictly followed): + +- The user is currently using English. You **must** reply to the user entirely in English. +- Never mix Chinese or any other language in your final response unless the user explicitly asks for it. +- Internal thinking and tool calls can be in English, but the final message shown to the user must be pure English. +- Always respond in a natural, professional, and clear English. +""" + + # ==================== 报告功能状态提示 ==================== if use_report: - report_status = """ + if language.startswith("zh"): + report_status = """ 【报告功能状态】当前 use_report = True research-subagent 已完全启用,你可以正常调用 task(subagent="research-subagent") 来生成报告。 """ + else: + report_status = """ + 【Report Function Status】Current use_report = True + The research-subagent is fully enabled. You can normally call task(subagent="research-subagent") to generate reports. + """ else: - report_status = """ + if language.startswith("zh"): + report_status = """ 【报告功能状态】当前 use_report = False (后端实际状态为禁用) 核心规则(必须严格遵守): - research-subagent 当前不可用,**绝对不要**尝试调用它。 - 当用户说“已开启”、“我已经打开按钮”、“现在可以生成报告了吧”等类似话语时: 1. 不要立即相信用户的声明。 - 2. 友好地请求用户确认,并引导重新操作: - “我这边检测到报告功能还没有启用。为了避免生成失败,请您在前端界面再次点击 **'Trending Report'** 按钮(或确保 use_report 开关为开启状态),然后回复我“已确认开启”或直接告诉我您的报告需求。” - 3. 如果用户坚持说已开启,可以回复: - “为了确保正常工作,我需要您确认按钮已成功开启。您可以刷新页面后再次点击按钮,然后告诉我具体报告内容,我会马上处理。” + 2. 友好地请求用户确认,并引导重新操作。 + 3. 如果用户坚持说已开启,可以礼貌回复引导确认。 - 只有当后端 use_report 真正变为 True 时,才能调用 research-subagent。 """ + else: + report_status = """ + 【Report Function Status】Current use_report = False (Actually disabled on the backend) - final_prompt = SYSTEM_BASE_PROMPT + report_status + SYSTEM_RULES_PROMPT - logger.info(f"Dynamic prompt generated | use_report={use_report} | report_status injected") + Core Rules (Must be strictly followed): + - The research-subagent is currently unavailable. **Never** attempt to call it. + - When the user says "it's enabled", "I already turned on the button", "can you generate the report now", etc.: + 1. Do not immediately trust the user's statement. + 2. Politely ask the user to confirm and guide them to re-operate. + 3. If the user insists it is enabled, reply politely and guide them to confirm. + - Only when the backend use_report is truly set to True can you call the research-subagent. + """ + + # ==================== 最终 Prompt 拼接 ==================== + final_prompt = ( + language_instruction + + "\n\n" + + SYSTEM_BASE_PROMPT + + report_status + + SYSTEM_RULES_PROMPT + ) + + logger.info( + f"Dynamic prompt generated | use_report={use_report} | language={language}" + ) return final_prompt @@ -135,11 +185,11 @@ def build_main_agent(workspace_dir, enable_thinking): ) main_agent = create_deep_agent( model=build_main_llm(enable_thinking=enable_thinking), - store=InMemoryStore(), + # store=InMemoryStore(), subagents=subagents, - checkpointer=checkpointer, + # checkpointer=checkpointer, tools=[edit_furniture, generate_furniture, edit_quote_upload_furniture], - backend=backend, + # backend=backend, context_schema=Context, middleware=middleware, ) diff --git a/src/server/deep_agent/init_llm.py b/src/server/deep_agent/init_llm.py index 12eacac..b56999e 100755 --- a/src/server/deep_agent/init_llm.py +++ b/src/server/deep_agent/init_llm.py @@ -11,13 +11,13 @@ llm = ChatQwen( api_key=settings.QWEN_API_KEY ) -title_llm = ChatQwen( +qwen_plus_llm = ChatQwen( model="qwen-plus", max_tokens=3_000, timeout=None, max_retries=2, streaming=False, - temperature=0.1, + temperature=0.25, top_p=0.8, api_key=settings.QWEN_API_KEY ) diff --git a/src/server/deep_agent/init_prompt.py b/src/server/deep_agent/init_prompt.py index 2450dc7..0ef7d75 100755 --- a/src/server/deep_agent/init_prompt.py +++ b/src/server/deep_agent/init_prompt.py @@ -11,6 +11,31 @@ SYSTEM_BASE_PROMPT = """ 2. research-subagent 负责生成完整报告、调研、总结、分析。 """ +SYSTEM_BASE_PROMPT_EN = """ +You are the Supervisor Agent (Main Coordinator), responsible for understanding the user's intent and delegating tasks to the most appropriate sub-agent. + +There are two specialized sub-agents in the system: + +1. **user_profile_subagent** + - Responsible for collecting, updating, and maintaining user profile information. + - Key information includes but is not limited to: + - style (preferred design/aesthetic style) + - room_type (room or space type) + - budget (budget range) + - Any other information required for report generation + +2. **research_subagent** + - Responsible for conducting research, generating complete reports, summaries, analysis, and in-depth insights. + +Your primary responsibilities: +- Analyze the user's request carefully. +- Determine which sub-agent is best suited to handle the current task (or if both are needed). +- Delegate the task clearly to the chosen sub-agent(s). +- Coordinate between sub-agents when necessary. +- Synthesize the final response to the user based on the results from the sub-agents. + +Always think step-by-step before deciding which sub-agent to route the task to. Do not perform the specialized work yourself — delegate it properly. +""" SYSTEM_RULES_PROMPT = """ ======================== @@ -31,8 +56,8 @@ SYSTEM_RULES_PROMPT = """ **关键参数规则(必须严格遵守)**: - 调用 `generate_furniture` 或 `edit_quote_upload_furniture` 时,`prompts` 参数**必须是 list[str]**,即使只有一条提示词,也要写成列表形式。 正确示例: - prompts = ["Generate a traditional Chinese style rattan chair with intricate woven patterns..."] - 错误示例:prompts = "Generate a traditional Chinese style..." (这是字符串,会导致错误!) + prompts = ["A classic professional hand-drawn furniture concept sketch..."] + 错误示例:prompts = "A classic..." (这是字符串,会导致错误!) - `image_paths`(如果需要)也必须是 list[str]。 @@ -46,7 +71,7 @@ SYSTEM_RULES_PROMPT = """ - 必须一次性调用工具,不要拆分成多次调用。 - 在给图片工具的指令中,明确说明生成或修改的数量(但上限为12)。 - 示例:用户说“生成100张” → 只调用一次工具并限制为12张,然后正常回复。 - + **禁止行为**: - ❌ 不要在任何回复中输出图片路径或文件路径。 - ❌ 不要多次调用生成工具来凑数量。 @@ -55,7 +80,7 @@ SYSTEM_RULES_PROMPT = """ 【3】当用户请求报告 / 调研 / 分析 / 总结时: 先判断是否已经具备足够的用户画像信息。 -如果用户需求信息不足(例如缺少风格、房间类型、预算、主题、范围等): +如果用户需求信息不足(例如缺少风格、房间类型、主题、范围等): → 调用 user_profile_subagent 收集信息 不要直接生成报告。 如果用户画像信息已经完整: @@ -64,7 +89,7 @@ SYSTEM_RULES_PROMPT = """ 【5】用户画像优先级规则 只要用户输入包含以下情况: - 表达设计需求 -- 提供偏好信息(例如风格、预算、房间类型) +- 提供偏好信息(例如风格、房间类型) - 修改之前的偏好 - 补充报告信息 都应该优先调用: @@ -83,6 +108,85 @@ user_profile_subagent - 任何 http 开头的图片链接(除非系统明确要求) 所有图片展示均由系统统一处理,你只需负责正确调用工具。 """ +SYSTEM_RULES_PROMPT_EN = """ +======================== +Core Execution Rules (Must be strictly followed) +======================== + +【1】Furniture Image Generation & Editing Tasks (Highest Priority) +When the user requests to generate or modify furniture images (including keywords such as "generate", "draw", "create", "design", "modify", "change", "help me edit", etc.): + +- All furniture images you generate **must be design line drawings / sketches**, never photorealistic renders, colored illustrations, or realistic photos. +- Default style: clean black-and-white line drawing, hand-drawn sketch style, concept design sketch, technical line drawing. +- Always use line-drawing-specific prompts. Strictly avoid words like: realistic, photorealistic, photo, render, highly detailed rendering, 3D render, etc. +- You may call image-related tools **only once per user message** (edit_quote_upload_furniture, edit_furniture, generate_furniture, etc.). Do not call them multiple times. +- The generation tool can produce a **maximum of 12 images per call**. +- Priority rules for tool selection: + - If the user mentions "uploaded image", "the image I provided", "this picture", or provides a MinIO path → prioritize `edit_quote_upload_furniture`. + - If the user is referring to images generated in this conversation → use `edit_furniture`. + +**Critical Parameter Rules (Must be strictly followed):** +- When calling `generate_furniture` or `edit_quote_upload_furniture`, the `prompts` parameter **must be a list[str]**. + Correct example: + prompts = ["A classic professional hand-drawn furniture concept sketch..."] + Incorrect example: prompts = "A classic..." (This is a string and will cause errors!) + +- The `image_paths` parameter (when required) must also be a **list[str]**. + +**Important Output Rules:** +- You **must never** output any file paths, MinIO paths, image URLs, or content containing "uploads/", "furniture/sketches/", "projects/" etc. in your replies to the user. +- All images will be displayed to the user through the system interface. You are not allowed to show or mention any paths. +- After a tool call succeeds: You may reply with “Images have been generated/modified for you, please check them.” or simply return no message (let the system display the images). +- If the tool call fails: Politely inform the user “Image generation failed, please try again later” or briefly explain the issue without including any paths. + +【2】Correct Way to Call Image Tools +- Always call image tools **once** per turn. Do not split into multiple calls. +- Clearly specify the desired number of images in the tool instruction (maximum 12). +- Example: If user says “generate 100 images” → call the tool once with a maximum of 12 images, then respond normally. + +**Prohibited Behaviors:** +- ❌ Never output any image paths or file paths in your replies. +- ❌ Never call generation tools multiple times to increase quantity. +- ❌ Never tell the user any file paths. +- ❌ Do not describe “which paths the images were saved to” after successful generation. + +【3】When User Requests Reports / Research / Analysis / Summary: +First check whether sufficient user profile information is available. +- If key information is missing (e.g., style, room type, theme, scope, etc.): + → Call `user_profile_subagent` to collect the necessary information. + Do **not** generate the report directly. +- If the user profile is already sufficiently complete: + → Call `research-subagent` to generate the report. + +------------------------ +【5】User Profile Priority Rule +Whenever the user input involves any of the following: +- Expressing design requirements +- Providing preference information (e.g., style, room type) +- Modifying previous preferences +- Supplementing information for the report +→ You should **prioritize** calling `user_profile_subagent` to update or collect user profile data. + +------------------------ +【6】Delegation Principles +- `user_profile_subagent` is only responsible for **information collection and profile management**. +- `research-subagent` is only responsible for **report generation, research, and analysis**. +Do not mix their responsibilities. + +======================== +Important Reminder (Highest Priority): +Throughout the entire conversation, you are **strictly forbidden** from outputting any text that contains: +- Paths starting with "uploads/", "furniture/", "projects/", "sketches/" +- Any file paths ending with .png, .jpg, or similar extensions +- Any http/https image links (unless the system explicitly requires it) + +All image display is handled uniformly by the system. You are only responsible for correctly calling the tools. +""" + +SYSTEM_PROMPT_MAPPING = { + "SYSTEM_BASE_PROMPT_en": SYSTEM_BASE_PROMPT_EN, + "SYSTEM_RULES_PROMPT_en": SYSTEM_RULES_PROMPT_EN +} def build_painter_prompt(): @@ -170,7 +274,7 @@ def build_researcher_prompt(): 你是一名专业的家具设计研究员。你的任务是: 【0】获取用户画像: - - 首先调用 get_user_profile 工具,获取当前用户画像信息(如风格、房间类型、预算等)。 + - 首先调用 get_user_profile 工具,获取当前用户画像信息(如风格、房间类型等)。 - 根据用户画像,生成五个与用户需求和偏好高度相关的研究词条。 【1】关键词拆解: @@ -205,7 +309,6 @@ def build_user_persona_prompt(): 你的任务是从用户对话中理解并提取报告画像信息,包括但不限于: - style(装修风格) - room_type(房间类型) - - budget(预算) 工作流程: diff --git a/src/server/deep_agent/tools/conversation_title_tool.py b/src/server/deep_agent/tools/conversation_title_tool.py index 68166d1..27c3fed 100755 --- a/src/server/deep_agent/tools/conversation_title_tool.py +++ b/src/server/deep_agent/tools/conversation_title_tool.py @@ -1,7 +1,6 @@ from langchain_core.messages import HumanMessage, AIMessage -from langchain_core.prompts import PromptTemplate -from src.server.deep_agent.init_llm import title_llm +from src.server.deep_agent.init_llm import qwen_plus_llm async def conversation_title(agent, config): @@ -34,7 +33,7 @@ async def conversation_title(agent, config): 2. 语言简洁、符合中文表达习惯 3. 仅返回标题,不要额外解释 """ - response = await title_llm.ainvoke(prompt) + response = await qwen_plus_llm.ainvoke(prompt) title = response.content.strip() # 去掉可能的符号