update:1.优化世界观生成提示词 2.修复章节分析页面内容重复问题 3.限制mcp调用最大并发数
This commit is contained in:
@@ -95,15 +95,15 @@ async def world_building_generator(
|
||||
3. 相关领域的专业知识
|
||||
4. 类似作品的设定参考
|
||||
|
||||
请根据题材特点,有针对性地查询2-3个关键问题。"""
|
||||
请查询最关键的1个问题(不要超过1个)。"""
|
||||
|
||||
# 调用MCP增强的AI(非流式,最多2轮工具调用)
|
||||
# 调用MCP增强的AI(非流式,最多1轮工具调用,避免超时)
|
||||
planning_result = await user_ai_service.generate_text_with_mcp(
|
||||
prompt=planning_prompt,
|
||||
user_id=user_id,
|
||||
db_session=db,
|
||||
enable_mcp=True,
|
||||
max_tool_rounds=2,
|
||||
max_tool_rounds=1,
|
||||
tool_choice="auto",
|
||||
provider=None,
|
||||
model=None
|
||||
@@ -365,15 +365,15 @@ async def characters_generator(
|
||||
3. 职业特点和生活方式
|
||||
4. 相关领域的人物原型
|
||||
|
||||
请根据题材特点,有针对性地查询1-2个关键问题。"""
|
||||
请查询最关键的1个问题(不要超过1个)。"""
|
||||
|
||||
# 调用MCP增强的AI(非流式,最多2轮工具调用)
|
||||
# 调用MCP增强的AI(非流式,最多1轮工具调用,避免超时)
|
||||
planning_result = await user_ai_service.generate_text_with_mcp(
|
||||
prompt=planning_prompt,
|
||||
user_id=user_id,
|
||||
db_session=db,
|
||||
enable_mcp=True,
|
||||
max_tool_rounds=2,
|
||||
max_tool_rounds=1, # ✅ 优化: 从2轮减少到1轮
|
||||
tool_choice="auto",
|
||||
provider=None,
|
||||
model=None
|
||||
|
||||
@@ -73,10 +73,10 @@ def _get_or_create_http_client(
|
||||
|
||||
client = httpx.AsyncClient(
|
||||
timeout=httpx.Timeout(
|
||||
connect=60.0, # 连接超时
|
||||
read=180.0, # 读取超时
|
||||
write=60.0, # 写入超时
|
||||
pool=60.0 # 连接池超时
|
||||
connect=90.0, # 连接超时
|
||||
read=300.0, # 读取超时
|
||||
write=90.0, # 写入超时
|
||||
pool=90.0 # 连接池超时
|
||||
),
|
||||
limits=limits,
|
||||
headers={
|
||||
@@ -959,7 +959,7 @@ class AIService:
|
||||
|
||||
else:
|
||||
# 达到最大轮次
|
||||
logger.warning(f"达到MCP最大调用轮次 {max_tool_rounds}")
|
||||
logger.info(f"达到MCP最大调用轮次 {max_tool_rounds}")
|
||||
result["content"] = conversation_history[-1].get("content", "")
|
||||
result["finish_reason"] = "max_rounds"
|
||||
|
||||
|
||||
@@ -291,16 +291,18 @@ class MCPToolService:
|
||||
user_id: str,
|
||||
tool_calls: List[Dict[str, Any]],
|
||||
db_session: AsyncSession,
|
||||
timeout: Optional[float] = None
|
||||
timeout: Optional[float] = None,
|
||||
max_concurrent: int = 2
|
||||
) -> List[Dict[str, Any]]:
|
||||
"""
|
||||
批量执行AI请求的工具调用(并行执行)
|
||||
批量执行AI请求的工具调用(限制并发数,避免超时)
|
||||
|
||||
Args:
|
||||
user_id: 用户ID
|
||||
tool_calls: AI返回的工具调用列表
|
||||
db_session: 数据库会话
|
||||
timeout: 单个工具调用的超时时间(秒,默认使用配置)
|
||||
max_concurrent: 最大并发工具调用数(默认2)
|
||||
|
||||
Returns:
|
||||
工具调用结果列表
|
||||
@@ -311,41 +313,54 @@ class MCPToolService:
|
||||
# 使用配置的默认超时
|
||||
actual_timeout = timeout or mcp_config.TOOL_CALL_TIMEOUT_SECONDS
|
||||
|
||||
logger.info(f"开始执行 {len(tool_calls)} 个工具调用 (超时={actual_timeout}s)")
|
||||
logger.info(f"开始执行 {len(tool_calls)} 个工具调用 (超时={actual_timeout}s, 最大并发={max_concurrent})")
|
||||
|
||||
# 创建异步任务列表
|
||||
tasks = [
|
||||
self._execute_single_tool(
|
||||
user_id=user_id,
|
||||
tool_call=tool_call,
|
||||
db_session=db_session,
|
||||
timeout=actual_timeout
|
||||
)
|
||||
for tool_call in tool_calls
|
||||
]
|
||||
|
||||
# 并行执行所有工具调用
|
||||
results = await asyncio.gather(*tasks, return_exceptions=True)
|
||||
|
||||
# 处理结果
|
||||
formatted_results = []
|
||||
for i, result in enumerate(results):
|
||||
tool_call = tool_calls[i]
|
||||
# ✅ 分批执行,每批最多max_concurrent个
|
||||
all_results = []
|
||||
for i in range(0, len(tool_calls), max_concurrent):
|
||||
batch = tool_calls[i:i+max_concurrent]
|
||||
batch_num = i // max_concurrent + 1
|
||||
total_batches = (len(tool_calls) + max_concurrent - 1) // max_concurrent
|
||||
|
||||
if isinstance(result, Exception):
|
||||
# 工具调用异常
|
||||
formatted_results.append({
|
||||
"tool_call_id": tool_call.get("id", f"call_{i}"),
|
||||
"role": "tool",
|
||||
"name": tool_call["function"]["name"],
|
||||
"content": f"工具调用失败: {str(result)}",
|
||||
"success": False,
|
||||
"error": str(result)
|
||||
})
|
||||
else:
|
||||
formatted_results.append(result)
|
||||
logger.info(f"执行工具批次 {batch_num}/{total_batches}, 数量: {len(batch)}")
|
||||
|
||||
# 创建当前批次的异步任务
|
||||
tasks = [
|
||||
self._execute_single_tool(
|
||||
user_id=user_id,
|
||||
tool_call=tool_call,
|
||||
db_session=db_session,
|
||||
timeout=actual_timeout
|
||||
)
|
||||
for tool_call in batch
|
||||
]
|
||||
|
||||
# 并行执行当前批次
|
||||
batch_results = await asyncio.gather(*tasks, return_exceptions=True)
|
||||
|
||||
# 处理批次结果
|
||||
for j, result in enumerate(batch_results):
|
||||
tool_call = batch[j]
|
||||
|
||||
if isinstance(result, Exception):
|
||||
# 工具调用异常
|
||||
all_results.append({
|
||||
"tool_call_id": tool_call.get("id", f"call_{i+j}"),
|
||||
"role": "tool",
|
||||
"name": tool_call["function"]["name"],
|
||||
"content": f"工具调用失败: {str(result)}",
|
||||
"success": False,
|
||||
"error": str(result)
|
||||
})
|
||||
else:
|
||||
all_results.append(result)
|
||||
|
||||
# 批次间增加短暂延迟,避免API限流
|
||||
if i + max_concurrent < len(tool_calls):
|
||||
await asyncio.sleep(0.5)
|
||||
logger.debug(f"批次间延迟 0.5 秒...")
|
||||
|
||||
return formatted_results
|
||||
return all_results
|
||||
|
||||
async def _execute_single_tool(
|
||||
self,
|
||||
|
||||
@@ -119,27 +119,38 @@ class PromptService:
|
||||
主题:{theme}
|
||||
类型:{genre}
|
||||
|
||||
# 2. 世界构建框架
|
||||
请生成包含以下四个核心板块的世界构建框架。请确保所有板块都围绕【核心概念】展开,并且板块之间【互为因果】。
|
||||
# 2. 核心指令(CRITICAL)
|
||||
* **去标签化**:严禁使用通用的“XX纪元”、“XX时代”、“XX年”作为时间背景的开头或核心描述。请直接描述世界所处的状态、技术水平或生存现状。
|
||||
* **动态演绎**:所有设定必须直接由输入的主题衍生而来。例如,如果是赛博朋克,不要只写“高科技”,要写“义体技术如何导致了贫民窟的特定生活方式”。
|
||||
* **拒绝陈词滥调**:避免使用宏大的空洞词汇,专注于具体的、可感知的细节。
|
||||
|
||||
1. **时间背景 (time_period)**:
|
||||
* 具体的时代设定(例如:星际航行晚期、黑铁时代)。
|
||||
* 重要的【历史转折事件】(是什么导致了当前的世界面貌?)。
|
||||
* 当前的主要【社会矛盾】或【时代议题】。
|
||||
2. **地理/空间 (location)**:
|
||||
* 主要舞台(如城市、星球、位面)的【地理环境特征】。
|
||||
* 这些特征如何影响了【文明】的形态和【资源】分布?
|
||||
* 独特的【空间布局】或【奇观】。
|
||||
3. **氛围基调 (atmosphere)**:
|
||||
* 整体的【情感色彩】(例如:压抑、荒诞、史诗、诡异)。
|
||||
* 【视觉风格】(例如:赛博霓虹、蒸汽朋克、哥特式)。
|
||||
* 普通居民在日常生活中最常【感受】到什么?
|
||||
4. **世界规则 (rules)**:
|
||||
* 【物理法则】或【超自然力量】(如魔法、科技)的【具体运作方式】和【代价】。
|
||||
* 【社会规则】和【权力结构】(谁在统治?基于什么?)。
|
||||
* 最严重的【社会禁忌】是什么?违反了会怎样?
|
||||
# 3. 世界构建框架
|
||||
请生成包含以下四个核心板块的JSON。请确保所有板块互为因果,逻辑严密。
|
||||
|
||||
# 3. 严格格式要求
|
||||
**重要说明:每个字段的value必须是一个完整的文本字符串,将以下所有要点整合成连贯的段落描述,不要使用嵌套的JSON对象或数组。**
|
||||
|
||||
1. **time_period (时间线与文明阶段)**:
|
||||
请将以下内容整合为一段完整的文字描述(300-500字):
|
||||
* 描述当前世界处于什么**发展阶段**(是毁灭边缘、新生萌芽、还是停滞不前?),**不要给这个阶段起名字**,而是描述其**特征**。
|
||||
* **历史转折点**:具体的事件(战争、发明、灾难),它如何直接导致了现在的局面?
|
||||
* **当下的核心矛盾**:时间流逝带来的具体焦虑是什么?(例如:资源枯竭的倒计时、某种信仰的崩塌)。
|
||||
2. **location (空间与生态环境)**:
|
||||
请将以下内容整合为一段完整的文字描述(300-500字):
|
||||
* **舞台特征**:描述主要故事发生的地理或空间环境(如:悬浮的破碎岛屿、被真菌覆盖的地铁网络)。
|
||||
* **环境与生存**:地理环境如何强迫居民改变了生活方式?(例如:因为引力失衡,建筑都是倒挂的)。
|
||||
* **标志性奇观**:一个能代表这个世界独特性的具体场景或建筑。
|
||||
3. **atmosphere (感官体验与基调)**:
|
||||
请将以下内容整合为一段完整的文字描述(300-500字):
|
||||
* **感官细节**:如果站在这个世界的街头,会**闻**到什么?**听**到什么?(不要只写"压抑",要写"空气中弥漫着铁锈和合成营养膏的酸味")。
|
||||
* **视觉美学**:描述具体的色彩倾向和光影质感。
|
||||
* **居民心态**:普通人普遍的心理状态(是麻木、狂热、还是某种特定的恐惧)。
|
||||
4. **rules (运作逻辑与禁忌)**:
|
||||
请将以下内容整合为一段完整的文字描述(300-500字):
|
||||
* **核心法则**:这个世界运行的底层逻辑(物理、魔法或科技)。**重点描述代价**(使用力量需要支付什么?)。
|
||||
* **权力架构**:谁掌握资源?他们通过什么手段维持控制(暴力、技术垄断、宗教洗脑)?
|
||||
* **红线禁忌**:这个社会绝对不能触碰的具体底线,以及违反后的直接后果。
|
||||
|
||||
# 4. 严格格式要求
|
||||
1. **绝对纯净JSON**:你的[唯一]输出必须是一个完整的JSON对象。输出必须以左花括号开始,并以右花括号结束。
|
||||
2. **禁止额外字符**:不要在JSON对象之前或之后包含任何说明文字、Markdown标记(如三个反引号加json)、注释或任何其他非JSON字符。
|
||||
3. **JSON内部文本规则**:在JSON的value字符串内部:
|
||||
@@ -147,13 +158,14 @@ class PromptService:
|
||||
* 所有【专有名词】(如地点、人物、组织)应使用【】包裹。
|
||||
* 所有《作品》或《特殊概念》的标题应使用《》包裹。
|
||||
4. **JSON结构**:严格遵守`"key": "value"`的英文双引号结构,并使用下面指定的key。
|
||||
5. **内容密度**:每个字段的描述都必须【深入且详实】,提供至少5-7个具体的设定点或细节。
|
||||
5. **内容密度**:每个字段的描述都必须【深入且详实】,提供至少5-7个具体的设定点或细节,整合为连贯的段落文本。
|
||||
6. **禁止嵌套结构**:value必须是纯文本字符串,绝对不能是JSON对象或数组,所有信息都要整合在一个字符串中。
|
||||
|
||||
{{
|
||||
"time_period": "(此处填写时间背景的详细描述)",
|
||||
"location": "(此处填写地理/空间的详细描述)",
|
||||
"atmosphere": "(此处填写氛围基调的详细描述)",
|
||||
"rules": "(此处填写世界规则的详细描述)"
|
||||
"time_period": "(此处填写一段完整的文字描述,包含发展阶段特征、历史转折点、核心矛盾等内容,300-500字)",
|
||||
"location": "(此处填写一段完整的文字描述,包含舞台特征、环境与生存、标志性奇观等内容,300-500字)",
|
||||
"atmosphere": "(此处填写一段完整的文字描述,包含感官细节、视觉美学、居民心态等内容,300-500字)",
|
||||
"rules": "(此处填写一段完整的文字描述,包含核心法则、权力架构、红线禁忌等内容,300-500字)"
|
||||
}}"""
|
||||
|
||||
# 批量角色生成提示词
|
||||
|
||||
Reference in New Issue
Block a user