Merge branch 'dev' of https://github.com/MoFox-Studio/MoFox-Core into dev
This commit is contained in:
@@ -1027,7 +1027,7 @@ class PromptBuilder:
|
|||||||
{"type": "kfc_reply", "content": "你的回复内容"}
|
{"type": "kfc_reply", "content": "你的回复内容"}
|
||||||
],
|
],
|
||||||
"expected_reaction": "你期待对方的反应是什么",
|
"expected_reaction": "你期待对方的反应是什么",
|
||||||
"max_wait_seconds": 等待时间(秒),0 表示不等待
|
"max_wait_seconds": "预估的等待时间(秒)"
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -1035,7 +1035,10 @@ class PromptBuilder:
|
|||||||
- `thought`:你的内心独白,记录你此刻的想法和感受。要自然,不要技术性语言。
|
- `thought`:你的内心独白,记录你此刻的想法和感受。要自然,不要技术性语言。
|
||||||
- `actions`:你要执行的动作列表。对于 `kfc_reply` 动作,**必须**填写 `content` 字段,写上你要说的话。
|
- `actions`:你要执行的动作列表。对于 `kfc_reply` 动作,**必须**填写 `content` 字段,写上你要说的话。
|
||||||
- `expected_reaction`:你期待对方如何回应(用于判断是否需要等待)
|
- `expected_reaction`:你期待对方如何回应(用于判断是否需要等待)
|
||||||
- `max_wait_seconds`:设定等待时间(秒),0 表示不等待,超时后你会考虑是否要主动说点什么
|
- `max_wait_seconds`:预估的等待时间(秒),这很关键,请根据对话节奏来判断:
|
||||||
|
- 如果你刚问了一个开放性问题(比如"你觉得呢?"、"后来怎么样了?"),或者对话明显还在兴头上,设置一个等待时间(比如 60-180 秒),给对方思考和打字的时间。
|
||||||
|
- 如果对话感觉自然结束了(比如晚安、拜拜),或者你给出了一个总结性的陈述,那就设置为 0,表示你觉得可以告一段落了。
|
||||||
|
- 不要总是设为 0,那会显得你很急着结束对话。
|
||||||
|
|
||||||
### 注意事项
|
### 注意事项
|
||||||
- kfc_reply 的 content 字段是必填的,直接写你要发送的消息内容
|
- kfc_reply 的 content 字段是必填的,直接写你要发送的消息内容
|
||||||
|
|||||||
@@ -124,11 +124,24 @@ kfc_SITUATION_TIMEOUT = Prompt(
|
|||||||
你原本打算最多等 {max_wait_minutes:.1f} 分钟,现在已经等了 {elapsed_minutes:.1f} 分钟了,对方还是没回。
|
你原本打算最多等 {max_wait_minutes:.1f} 分钟,现在已经等了 {elapsed_minutes:.1f} 分钟了,对方还是没回。
|
||||||
你当时期待的反应是:"{expected_reaction}"
|
你当时期待的反应是:"{expected_reaction}"
|
||||||
{timeout_context}
|
{timeout_context}
|
||||||
你需要决定:
|
|
||||||
1. 继续等待(设置新的 max_wait_seconds)
|
**决策指导:**
|
||||||
2. 主动说点什么打破沉默
|
- **评估话题**:你上一条消息是结束性的,还是开启性的?是陈述句,还是疑问句?
|
||||||
3. 做点别的事情(执行其他动作)
|
- **考虑关系**:你们的关系有多亲近?频繁追问是否会打扰到对方?
|
||||||
4. 算了不等了(max_wait_seconds = 0)
|
- **保持自然**:像真人一样思考,对方可能只是暂时在忙。
|
||||||
|
|
||||||
|
**决策选项:**
|
||||||
|
1. **再等等看**:如果觉得话题还没结束,或者对方可能只是需要多点时间,可以选择再等一会。
|
||||||
|
- 使用 `do_nothing`,并设置一个新的、合理的 `max_wait_seconds`(比如 60-300 秒)。
|
||||||
|
|
||||||
|
2. **开启新话题**:如果感觉之前的话题已经告一段落,或者想轻松地打破沉默,可以主动开启一个轻松的新话题。
|
||||||
|
- 使用 `kfc_reply` 发送一条新的、不相关的问候或分享。
|
||||||
|
|
||||||
|
3. **轻轻追问**:如果你们正在讨论一件很重要的事,或者你发的上一条是关键问题,可以委婉地追问一下。
|
||||||
|
- 使用 `kfc_reply` 发送一条温柔的提醒,例如"在忙吗?"或者"刚才说到哪啦?"。
|
||||||
|
|
||||||
|
4. **结束等待**:如果你觉得对话确实已经结束,或者不想再打扰对方,就自然地结束等待。
|
||||||
|
- 使用 `do_nothing`,并将 `max_wait_seconds` 设为 0。
|
||||||
|
|
||||||
【注意】如果已经连续多次超时,对方可能暂时不方便回复。频繁主动发消息可能会打扰到对方。
|
【注意】如果已经连续多次超时,对方可能暂时不方便回复。频繁主动发消息可能会打扰到对方。
|
||||||
考虑是否应该暂时放下期待,让对方有空间。""",
|
考虑是否应该暂时放下期待,让对方有空间。""",
|
||||||
@@ -228,7 +241,7 @@ kfc_PLANNER_OUTPUT_FORMAT = Prompt(
|
|||||||
{{"type": "动作名称", ...动作参数}}
|
{{"type": "动作名称", ...动作参数}}
|
||||||
],
|
],
|
||||||
"expected_reaction": "你期待对方的反应是什么",
|
"expected_reaction": "你期待对方的反应是什么",
|
||||||
"max_wait_seconds": 等待时间(秒),0 表示不等待
|
"max_wait_seconds": "预估的等待时间(秒)"
|
||||||
}}
|
}}
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -237,7 +250,10 @@ kfc_PLANNER_OUTPUT_FORMAT = Prompt(
|
|||||||
- `actions`:你要执行的动作列表。每个动作是一个对象,必须包含 `type` 字段指定动作类型,其他字段根据动作类型不同而不同(参考上面每个动作的示例)。
|
- `actions`:你要执行的动作列表。每个动作是一个对象,必须包含 `type` 字段指定动作类型,其他字段根据动作类型不同而不同(参考上面每个动作的示例)。
|
||||||
- 对于 `kfc_reply` 动作,只需要指定 `{{"type": "kfc_reply"}}`,不需要填写 `content` 字段(回复内容会单独生成)
|
- 对于 `kfc_reply` 动作,只需要指定 `{{"type": "kfc_reply"}}`,不需要填写 `content` 字段(回复内容会单独生成)
|
||||||
- `expected_reaction`:你期待对方如何回应(用于判断是否需要等待)
|
- `expected_reaction`:你期待对方如何回应(用于判断是否需要等待)
|
||||||
- `max_wait_seconds`:设定等待时间(秒),0 表示不等待,超时后你会考虑是否要主动说点什么
|
- `max_wait_seconds`:预估的等待时间(秒),这很关键,请根据对话节奏来判断:
|
||||||
|
- 如果你刚问了一个开放性问题(比如"你觉得呢?"、"后来怎么样了?"),或者对话明显还在兴头上,设置一个等待时间(比如 60-180 秒),给对方思考和打字的时间。
|
||||||
|
- 如果对话感觉自然结束了(比如晚安、拜拜),或者你给出了一个总结性的陈述,那就设置为 0,表示你觉得可以告一段落了。
|
||||||
|
- 不要总是设为 0,那会显得你很急着结束对话。
|
||||||
|
|
||||||
### 注意事项
|
### 注意事项
|
||||||
- 动作参数直接写在动作对象里,不需要 `action_data` 包装
|
- 动作参数直接写在动作对象里,不需要 `action_data` 包装
|
||||||
@@ -378,7 +394,7 @@ kfc_UNIFIED_OUTPUT_FORMAT = Prompt(
|
|||||||
{{"type": "kfc_reply", "content": "你的回复内容"}}
|
{{"type": "kfc_reply", "content": "你的回复内容"}}
|
||||||
],
|
],
|
||||||
"expected_reaction": "你期待对方的反应是什么",
|
"expected_reaction": "你期待对方的反应是什么",
|
||||||
"max_wait_seconds": 等待时间(秒),0 表示不等待
|
"max_wait_seconds": "预估的等待时间(秒)"
|
||||||
}}
|
}}
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -386,7 +402,10 @@ kfc_UNIFIED_OUTPUT_FORMAT = Prompt(
|
|||||||
- `thought`:你的内心独白,记录你此刻的想法和感受。要自然,不要技术性语言。
|
- `thought`:你的内心独白,记录你此刻的想法和感受。要自然,不要技术性语言。
|
||||||
- `actions`:你要执行的动作列表。对于 `kfc_reply` 动作,**必须**填写 `content` 字段,写上你要说的话。
|
- `actions`:你要执行的动作列表。对于 `kfc_reply` 动作,**必须**填写 `content` 字段,写上你要说的话。
|
||||||
- `expected_reaction`:你期待对方如何回应(用于判断是否需要等待)
|
- `expected_reaction`:你期待对方如何回应(用于判断是否需要等待)
|
||||||
- `max_wait_seconds`:设定等待时间(秒),0 表示不等待,超时后你会考虑是否要主动说点什么。如果你认为聊天没有继续的必要,或不想打扰对方,可以设为 0。
|
- `max_wait_seconds`:预估的等待时间(秒),这很关键,请根据对话节奏来判断:
|
||||||
|
- 如果你刚问了一个开放性问题(比如"你觉得呢?"、"后来怎么样了?"),或者对话明显还在兴头上,设置一个等待时间(比如 60-180 秒),给对方思考和打字的时间。
|
||||||
|
- 如果对话感觉自然结束了(比如晚安、拜拜),或者你给出了一个总结性的陈述,那就设置为 0,表示你觉得可以告一段落了。
|
||||||
|
- 不要总是设为 0,那会显得你很急着结束对话。
|
||||||
|
|
||||||
### 注意事项
|
### 注意事项
|
||||||
- kfc_reply 的 content 字段是**必填**的,直接写你要发送的消息内容
|
- kfc_reply 的 content 字段是**必填**的,直接写你要发送的消息内容
|
||||||
|
|||||||
@@ -266,13 +266,18 @@ def build_output_module(context_data: Optional[dict[str, str]] = None) -> str:
|
|||||||
{
|
{
|
||||||
"thought": "你心里的真实想法,像日记一样自然",
|
"thought": "你心里的真实想法,像日记一样自然",
|
||||||
"expected_user_reaction": "猜猜对方看到会怎么想",
|
"expected_user_reaction": "猜猜对方看到会怎么想",
|
||||||
"max_wait_seconds": 等多久(60-900),不等就填0,
|
"max_wait_seconds": "预估的等待时间(秒)",
|
||||||
"actions": [
|
"actions": [
|
||||||
{"type": "kfc_reply", "content": "你要说的话"}
|
{"type": "kfc_reply", "content": "你要说的话"}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
关于 max_wait_seconds(等待时间):
|
||||||
|
- 如果你刚问了一个开放性问题(比如"你觉得呢?"、"后来怎么样了?"),或者对话明显还在兴头上,设置一个等待时间(比如 60-180 秒),给对方思考和打字的时间。
|
||||||
|
- 如果对话感觉自然结束了(比如晚安、拜拜),或者你给出了一个总结性的陈述,那就设置为 0,表示你觉得可以告一段落了。
|
||||||
|
- 不要总是设为 0,那会显得你很急着结束对话。
|
||||||
|
|
||||||
关于 thought(内心想法):
|
关于 thought(内心想法):
|
||||||
- 写你真正在想的,不是在分析任务
|
- 写你真正在想的,不是在分析任务
|
||||||
- 像心里嘀咕一样,比如"这家伙又来撒娇了~" "有点困了但还想再聊会儿"
|
- 像心里嘀咕一样,比如"这家伙又来撒娇了~" "有点困了但还想再聊会儿"
|
||||||
@@ -375,20 +380,31 @@ TIMEOUT_DECISION_USER_PROMPT_TEMPLATE = """## 聊天记录
|
|||||||
## 现在的情况
|
## 现在的情况
|
||||||
你发了消息,等了 {wait_duration_seconds:.0f} 秒({wait_duration_minutes:.1f} 分钟),对方还没回。
|
你发了消息,等了 {wait_duration_seconds:.0f} 秒({wait_duration_minutes:.1f} 分钟),对方还没回。
|
||||||
你之前觉得对方可能会:{expected_user_reaction}
|
你之前觉得对方可能会:{expected_user_reaction}
|
||||||
|
|
||||||
{followup_warning}
|
{followup_warning}
|
||||||
|
你发的最后一条消息是:「{last_bot_message}」
|
||||||
你发的最后一条:{last_bot_message}
|
|
||||||
|
|
||||||
---
|
---
|
||||||
你拿起手机看了一眼,发现对方还没回复。你想怎么办?
|
你拿起手机看了一眼,发现对方还没回复。你想怎么办?
|
||||||
|
|
||||||
选项:
|
**决策指导:**
|
||||||
1. **继续等** - 用 `do_nothing`,设个 `max_wait_seconds` 等一会儿再看
|
- **评估话题**:你上一条消息是结束性的,还是开启性的?是陈述句,还是疑问句?
|
||||||
2. **发消息** - 用 `reply`,不过别太频繁追问
|
- **考虑关系**:你们的关系有多亲近?频繁追问是否会打扰到对方?
|
||||||
3. **算了不等了** - 用 `do_nothing`,`max_wait_seconds` 设为 0
|
- **保持自然**:像真人一样思考,对方可能只是暂时在忙。
|
||||||
|
|
||||||
用 JSON 输出你的想法和决策。"""
|
**决策选项:**
|
||||||
|
1. **再等等看**:如果觉得话题还没结束,或者对方可能只是需要多点时间,可以选择再等一会。
|
||||||
|
- **动作**:使用 `do_nothing`,并设置一个新的、合理的 `max_wait_seconds`(比如 60-300 秒)。
|
||||||
|
|
||||||
|
2. **开启新话题**:如果感觉之前的话题已经告一段落,或者想轻松地打破沉默,可以主动开启一个轻松的新话题。
|
||||||
|
- **动作**:使用 `kfc_reply` 发送一条新的、不相关的问候或分享。
|
||||||
|
|
||||||
|
3. **轻轻追问**:如果你们正在讨论一件很重要的事,或者你发的上一条是关键问题,可以委婉地追问一下。
|
||||||
|
- **动作**:使用 `kfc_reply` 发送一条温柔的提醒,例如"在忙吗?"或者"刚才说到哪啦?"。
|
||||||
|
|
||||||
|
4. **结束等待**:如果你觉得对话确实已经结束,或者不想再打扰对方,就自然地结束等待。
|
||||||
|
- **动作**:使用 `do_nothing`,并将 `max_wait_seconds` 设为 0。
|
||||||
|
|
||||||
|
用 JSON 输出你的想法和最终决策。"""
|
||||||
|
|
||||||
|
|
||||||
PROACTIVE_THINKING_USER_PROMPT_TEMPLATE = """## 聊天记录
|
PROACTIVE_THINKING_USER_PROMPT_TEMPLATE = """## 聊天记录
|
||||||
|
|||||||
@@ -561,7 +561,7 @@ def _log_pretty_response(response: LLMResponse, stream_id: str | None = None) ->
|
|||||||
|
|
||||||
for i, reply in enumerate(replies):
|
for i, reply in enumerate(replies):
|
||||||
if len(replies) > 1:
|
if len(replies) > 1:
|
||||||
logger.info(f"[KFC] 💬[{i+1}] {reply}")
|
logger.info(f"[KFC] 💬 [{i+1}] {reply}")
|
||||||
else:
|
else:
|
||||||
logger.info(f"[KFC] 💬 {reply}")
|
logger.info(f"[KFC] 💬 {reply}")
|
||||||
|
|
||||||
@@ -569,7 +569,7 @@ def _log_pretty_response(response: LLMResponse, stream_id: str | None = None) ->
|
|||||||
logger.info(f"[KFC] 🎯 {', '.join(actions)}")
|
logger.info(f"[KFC] 🎯 {', '.join(actions)}")
|
||||||
|
|
||||||
if response.max_wait_seconds > 0 or response.expected_reaction:
|
if response.max_wait_seconds > 0 or response.expected_reaction:
|
||||||
meta = f"⏱{response.max_wait_seconds}s" if response.max_wait_seconds > 0 else ""
|
meta = f"⏱ {response.max_wait_seconds}s" if response.max_wait_seconds > 0 else ""
|
||||||
if response.expected_reaction:
|
if response.expected_reaction:
|
||||||
meta += f" 预期: {response.expected_reaction}"
|
meta += f" 预期: {response.expected_reaction}"
|
||||||
logger.info(f"[KFC] {meta.strip()}")
|
logger.info(f"[KFC] {meta.strip()}")
|
||||||
@@ -90,6 +90,11 @@ class SendHandler:
|
|||||||
logger.critical("现在暂时不支持解析此回复!")
|
logger.critical("现在暂时不支持解析此回复!")
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
# 🔧 确保 reply 消息段始终在列表最前面
|
||||||
|
# 排序原则:reply 类型优先级最高(排序值为 0),其他类型保持原有顺序(排序值为 1)
|
||||||
|
# 使用 stable sort 确保非 reply 元素的相对顺序不变
|
||||||
|
processed_message.sort(key=lambda seg: 0 if isinstance(seg, dict) and seg.get("type") == "reply" else 1)
|
||||||
|
|
||||||
if group_info and group_info.get("group_id"):
|
if group_info and group_info.get("group_id"):
|
||||||
logger.debug("发送群聊消息")
|
logger.debug("发送群聊消息")
|
||||||
target_id = int(group_info["group_id"])
|
target_id = int(group_info["group_id"])
|
||||||
|
|||||||
Reference in New Issue
Block a user