小功能添加,模型切换问题修复

This commit is contained in:
2026-04-13 19:34:03 +08:00
parent c435ab15cf
commit f6a43302d2
7 changed files with 259 additions and 36 deletions

View File

@@ -1,13 +1,14 @@
"""Agent Loop 主循环LLM 对话 -> 工具调用 -> 结果回传 -> 继续。"""
import json
import re
import os
from typing import AsyncGenerator, Optional
from openai import AsyncOpenAI
from app.agent.tools import TOOL_DEFINITIONS, execute_tool
from app.config import get_llm_model, get_llm_max_iterations
from app.config import get_llm_model, get_llm_max_iterations, get_image_model_config
from app.services.image_gen import to_data_uri
@@ -44,12 +45,13 @@ SYSTEM_PROMPT = """\
- 尽量详细描述:主体内容、颜色方案、光照、构图、材质等
- 如果用户要求游戏 UI 元素,添加相关关键词如 "game UI", "icon", "button"
- 如果你能直接看到参考图(图片内容),可以在 prompt 中描述参考图的风格特征
- 如果你无法看到参考图(只收到了文字提示说有参考图),参考图会由生图工具的 IP-Adapter 自动处理风格融合。此时你的 prompt 中**绝对不要猜测或指定任何画风/艺术风格关键词**(如 pixel art、watercolor、oil painting 等),只描述画面内容(主体、构图、光照等),把风格完全交给参考图来决定
- 如果你无法看到参考图(只收到了文字提示说有参考图),参考图会由生图工具的 IP-Adapter 自动处理风格融合。此时你不要自行猜测画风/艺术风格关键词(如 pixel art、watercolor、oil painting 等),把风格交给参考图来决定。但如果用户在消息中明确指定了风格(如"赛博朋克风""水彩风"等),应保留并翻译到 prompt 中——尊重用户的主动意图
## 注意事项
- 用中文和用户交流
- 生成图片后简要说明你使用的 prompt 思路
- 主动建议迭代方向
- **禁止模拟工具调用**:生成图片时必须实际调用 generate_image 工具,绝不能用文字描述"已生成"或假装工具已执行。如果需要生成多张图片,每张都必须单独调用工具
"""
@@ -68,8 +70,18 @@ async def run_agent_loop(
- done: 完成
- error: 错误
"""
# 构建消息列表
api_messages = [{"role": "system", "content": SYSTEM_PROMPT}]
# 构建消息列表:将当前生图模型信息注入 system prompt避免 LLM 猜测模型名
model_config = get_image_model_config(image_model)
current_model_name = model_config.get('name', '未知')
current_model_id = model_config.get('id', '未知')
model_hint = (
f"\n\n## 当前生图模型(重要)\n"
f"本次对话用户选择的生图模型是 **{current_model_name}**"
f"model_id: {current_model_id})。\n"
f"**注意**:对话历史中可能包含之前使用其他模型的记录,忽略那些旧模型名。"
f"本次生成使用的是 {current_model_name},在回复中只能使用这个名称。"
)
api_messages = [{"role": "system", "content": SYSTEM_PROMPT + model_hint}]
# 检测当前 LLM 是否支持 vision多模态图片输入
llm_model = get_llm_model().lower()
@@ -96,9 +108,9 @@ async def run_agent_loop(
"【系统提示:用户上传了一张参考图,已自动传递给图片生成工具的 IP-Adapter。"
"IP-Adapter 会从参考图中提取风格并融合到生成结果中。"
"你无法看到这张参考图,因此在生成 prompt 时:\n"
"1. 描述画面内容(主体、构图、光照、材质等)\n"
"2. 不要猜测或添加任何画风/艺术风格关键词(如 pixel art、watercolor、cartoon 等)\n"
"3. 风格完全由参考图通过 IP-Adapter 决定】"
"1. 描述画面内容(主体、构图、光照、材质等)\n"
"2. 不要自行猜测画风/艺术风格——但如果用户明确指定了风格,保留到 prompt 中\n"
"3. 用户未指定风格时,风格完全由参考图通过 IP-Adapter 决定】"
)
api_messages.append({"role": "user", "content": hint})
continue
@@ -150,8 +162,25 @@ async def run_agent_loop(
finish_reason = chunk.choices[0].finish_reason if chunk.choices else None
# 如果没有工具调用,对话结束
# 如果没有工具调用:检测 LLM 是否在用文字模拟生图
if not tool_calls_data:
if _looks_like_fake_generation(collected_text):
# LLM 用文字假装调用了工具,丢弃这段文字,注入纠正消息强制重试
yield {
"type": "text_delta",
"data": {"text": "\n\n[系统:检测到未调用生图工具,正在重试...]\n"},
}
api_messages.append({"role": "assistant", "content": collected_text})
api_messages.append({
"role": "user",
"content": (
"你刚才没有调用 generate_image 工具,只是用文字描述了生成过程。"
"请立即调用 generate_image 工具来实际生成图片。"
"不要解释,直接调用工具。"
f"当前使用的生图模型是 {model_config.get('name', '未知')}"
),
})
continue
yield {"type": "done", "data": {}}
return
@@ -225,3 +254,19 @@ async def run_agent_loop(
# 后续工具调用仍需参考图InstantStyle 等模型必须有 style_image
yield {"type": "done", "data": {}}
# ─── 假生成检测 ──────────────────────────────────────────
_FAKE_GEN_PATTERNS = re.compile(
r"已生成|生成完成|开始生成|正在生成|图片已|prompt.*?设计思路",
re.IGNORECASE,
)
def _looks_like_fake_generation(text: str) -> bool:
"""判断 LLM 的纯文字回复是否在假装已经调用了生图工具。"""
if not text or len(text) < 50:
return False
matches = _FAKE_GEN_PATTERNS.findall(text)
return len(matches) >= 2

View File

@@ -59,7 +59,7 @@ IMAGE_MODELS: dict[str, dict[str, Any]] = {
"id": "sdxl",
"name": "Stable Diffusion XL",
"provider": "replicate",
"model_id": "stability-ai/sdxl",
"model_id": "stability-ai/sdxl:39ed52f2a78e934b3ba6e2a89f5b1c712de7dfea535525255b1aa35c5565e08b",
"description": "经典 SDXL支持 negative prompt",
"supports_ref_image": False,
"num_images_param": "num_outputs",