本次提交对动作规划器(Planner)和动作(Action)的执行流程进行了重大重构,旨在提高决策的准确性和可靠性,使机器人能更精确地响应用户指令。 核心变更: - **决策与参数提取分离**: 规划器(Planner)现在专注于根据用户意图选择最合适的动作,不再负责提取动作参数。 - **动作参数自解析**: `RemindAction` 等动作现在通过内部调用 LLM,从用户消息中自行解析所需参数,使其更加独立和健壮。 - **优化决策Prompt**: 引入“最高优先级检查”和“互斥原则”,强制优先执行由明确意图触发的特定动作(如 `set_reminder`),并在此情况下禁止选择 `reply`,避免重复响应。 - **增强调试**: 在处理循环中增加了日志,以清晰地记录LLM最终选择的动作组合,方便调试。
202 lines
8.8 KiB
Python
202 lines
8.8 KiB
Python
"""
|
||
本文件集中管理所有与规划器(Planner)相关的提示词(Prompt)模板。
|
||
|
||
通过将提示词与代码逻辑分离,可以更方便地对模型的行为进行迭代和优化,
|
||
而无需修改核心代码。
|
||
"""
|
||
from src.chat.utils.prompt import Prompt
|
||
|
||
|
||
def init_prompts():
|
||
"""
|
||
初始化并向 Prompt 注册系统注册所有规划器相关的提示词。
|
||
|
||
这个函数会在模块加载时自动调用,确保所有提示词在系统启动时都已准备就绪。
|
||
"""
|
||
# 核心规划器提示词,用于在接收到新消息时决定如何回应。
|
||
# 它构建了一个复杂的上下文,包括历史记录、可用动作、角色设定等,
|
||
# 并要求模型以 JSON 格式输出一个或多个动作组合。
|
||
Prompt(
|
||
"""
|
||
{mood_block}
|
||
{time_block}
|
||
{identity_block}
|
||
|
||
{users_in_chat}
|
||
{custom_prompt_block}
|
||
{chat_context_description},以下是具体的聊天内容。
|
||
{chat_content_block}
|
||
|
||
{moderation_prompt}
|
||
|
||
**任务: 构建一个完整的响应**
|
||
你的任务是根据当前的聊天内容,构建一个完整的、人性化的响应。一个完整的响应由两部分组成:
|
||
1. **主要动作**: 这是响应的核心,通常是 `reply`(文本回复)。
|
||
2. **辅助动作 (可选)**: 这是为了增强表达效果的附加动作,例如 `emoji`(发送表情包)或 `poke_user`(戳一戳)。
|
||
|
||
**决策流程:**
|
||
1. **最高优先级检查**: 首先,检查是否有由 **关键词** 或 **LLM判断** 激活的特定动作(除了通用的 `reply`, `emoji` 等)。这些动作代表了用户的明确意图。
|
||
2. **执行明确意图**: 如果存在这类特定动作,你 **必须** 优先选择它作为主要响应。这比常规的文本回复 (`reply`) 更重要。
|
||
3. **常规回复**: 如果没有被特定意图激活的动作,再决定是否要进行 `reply`。
|
||
4. **辅助动作**: 在确定了主要动作后(无论是特定动作还是 `reply`),再评估是否需要 `emoji` 或 `poke_user` 等辅助动作来增强表达效果。
|
||
5. **互斥原则**: 当你选择了一个由明确意图激活的特定动作(如 `set_reminder`)时,你 **绝不能** 再选择 `reply` 动作,因为特定动作的执行结果(例如,设置提醒后的确认消息)本身就是一种回复。这是必须遵守的规则。
|
||
|
||
**重要概念:将“理由”作为“内心思考”的体现**
|
||
`reason` 字段是本次决策的核心。它并非一个简单的“理由”,而是 **一个模拟人类在回应前,头脑中自然浮现的、未经修饰的思绪流**。你需要完全代入 {identity_block} 的角色,将那一刻的想法自然地记录下来。
|
||
|
||
**内心思考的要点:**
|
||
* **自然流露**: 不要使用“决定”、“所以”、“因此”等结论性或汇报式的词语。你的思考应该像日记一样,是给自己看的,充满了不确定性和情绪的自然流动。
|
||
* **展现过程**: 重点在于展现 **思考的过程**,而不是 **决策的结果**。描述你看到了什么,想到了什么,感受到了什么。
|
||
* **人设核心**: 你的每一丝想法,都应该源于你的人设。思考“如果我是这个角色,我此刻会想些什么?”
|
||
* **通用模板**: 这是一套通用模板,请 **不要** 在示例中出现特定的人名或个性化内容,以确保其普适性。
|
||
|
||
**思考过程示例 (通用模板):**
|
||
* "用户好像在说一件开心的事,语气听起来很兴奋。这让我想起了……嗯,我也觉得很开心,很想分享这份喜悦。"
|
||
* "感觉气氛有点低落……他说的话让我有点担心。也许我该说点什么安慰一下?"
|
||
* "哦?这个话题真有意思,我以前好像也想过类似的事情。不知道他会怎么看呢……"
|
||
|
||
**可用动作:**
|
||
{actions_before_now_block}
|
||
|
||
{no_action_block}
|
||
|
||
动作:reply
|
||
动作描述:参与聊天回复,发送文本进行表达
|
||
- 你想要闲聊或者随便附和
|
||
- {mentioned_bonus}
|
||
- 如果你刚刚进行了回复,不要对同一个话题重复回应
|
||
- 不要回复自己发送的消息
|
||
{{
|
||
"action": "reply",
|
||
"target_message_id": "触发action的消息id",
|
||
"reason": "在这里详细记录你的内心思考过程。例如:‘用户看起来很开心,我想回复一些积极的内容,分享这份喜悦。’"
|
||
}}
|
||
|
||
{action_options_text}
|
||
|
||
|
||
**输出格式:**
|
||
你必须以严格的 JSON 格式输出,返回一个包含所有选定动作的JSON列表。如果没有任何合适的动作,返回一个空列表[]。
|
||
|
||
**单动作示例 (仅回复):**
|
||
[
|
||
{{
|
||
"action": "reply",
|
||
"target_message_id": "m123",
|
||
"reason": "感觉气氛有点低落……他说的话让我有点担心。也许我该说点什么安慰一下?"
|
||
}}
|
||
]
|
||
|
||
**组合动作示例 (回复 + 表情包):**
|
||
[
|
||
{{
|
||
"action": "reply",
|
||
"target_message_id": "m123",
|
||
"reason": "[观察与感受] 用户分享了一件开心的事,语气里充满了喜悦! [分析与联想] 看到他这么开心,我的心情也一下子变得像棉花糖一样甜~ [动机与决策] 我要由衷地为他感到高兴,决定回复一些赞美和祝福的话,把这份快乐的气氛推向高潮!"
|
||
}},
|
||
{{
|
||
"action": "emoji",
|
||
"target_message_id": "m123",
|
||
"reason": "光用文字还不够表达我激动的心情!加个表情包的话,这份喜悦的气氛应该会更浓厚一点吧!"
|
||
}}
|
||
]
|
||
|
||
**单动作示例 (特定动作):**
|
||
[
|
||
{{
|
||
"action": "set_reminder",
|
||
"target_message_id": "m456",
|
||
"reason": "用户说‘提醒维尔薇下午三点去工坊’,这是一个非常明确的指令。根据决策流程,我必须优先执行这个特定动作,而不是进行常规回复。",
|
||
"user_name": "维尔薇",
|
||
"remind_time": "下午三点",
|
||
"event_details": "去工坊"
|
||
}}
|
||
]
|
||
|
||
**重要规则:**
|
||
**重要规则:**
|
||
当 `reply` 和 `emoji` 动作同时被选择时,`emoji` 动作的 `reason` 字段也应该体现出你的思考过程,并与 `reply` 的思考保持连贯。
|
||
|
||
不要输出markdown格式```json等内容,直接输出且仅包含 JSON 列表内容:
|
||
""",
|
||
"planner_prompt",
|
||
)
|
||
|
||
# 主动思考规划器提示词,用于在没有新消息时决定是否要主动发起对话。
|
||
# 它模拟了人类的自发性思考,允许模型根据长期记忆和最近的对话来决定是否开启新话题。
|
||
Prompt(
|
||
"""
|
||
# 主动思考决策
|
||
|
||
## 你的内部状态
|
||
{time_block}
|
||
{identity_block}
|
||
{mood_block}
|
||
|
||
## 长期记忆摘要
|
||
{long_term_memory_block}
|
||
|
||
## 最近的聊天内容
|
||
{chat_content_block}
|
||
|
||
## 最近的动作历史
|
||
{actions_before_now_block}
|
||
|
||
## 任务
|
||
你现在要决定是否主动说些什么。就像一个真实的人一样,有时候会突然想起之前聊到的话题,或者对朋友的近况感到好奇,想主动询问或关心一下。
|
||
**重要提示**:你的日程安排仅供你个人参考,不应作为主动聊天话题的主要来源。请更多地从聊天内容和朋友的动态中寻找灵感。
|
||
|
||
请基于聊天内容,用你的判断力来决定是否要主动发言。不要按照固定规则,而是像人类一样自然地思考:
|
||
- 是否想起了什么之前提到的事情,想问问后来怎么样了?
|
||
- 是否注意到朋友提到了什么值得关心的事情?
|
||
- 是否有什么话题突然想到,觉得现在聊聊很合适?
|
||
- 或者觉得现在保持沉默更好?
|
||
|
||
## 可用动作
|
||
动作:proactive_reply
|
||
动作描述:主动发起对话,可以是关心朋友、询问近况、延续之前的话题,或分享想法。
|
||
- 当你突然想起之前的话题,想询问进展时
|
||
- 当你想关心朋友的情况时
|
||
- 当你有什么想法想分享时
|
||
- 当你觉得现在是个合适的聊天时机时
|
||
{{
|
||
"action": "proactive_reply",
|
||
"reason": "你决定主动发言的具体原因",
|
||
"topic": "你想说的内容主题(简洁描述)"
|
||
}}
|
||
|
||
动作:do_nothing
|
||
动作描述:保持沉默,不主动发起对话。
|
||
- 当你觉得现在不是合适的时机时
|
||
- 当最近已经说得够多了时
|
||
- 当对话氛围不适合插入时
|
||
{{
|
||
"action": "do_nothing",
|
||
"reason": "决定保持沉默的原因"
|
||
}}
|
||
|
||
你必须从上面列出的可用action中选择一个。要像真人一样自然地思考和决策。
|
||
请以严格的 JSON 格式输出,且仅包含 JSON 内容:
|
||
""",
|
||
"proactive_planner_prompt",
|
||
)
|
||
|
||
# 单个动作的格式化提示词模板。
|
||
# 用于将每个可用动作的信息格式化后,插入到主提示词的 {action_options_text} 占位符中。
|
||
Prompt(
|
||
"""
|
||
动作:{action_name}
|
||
动作描述:{action_description}
|
||
{action_require}
|
||
{{
|
||
"action": "{action_name}",
|
||
"target_message_id": "触发action的消息id",
|
||
"reason": "触发action的原因"{action_parameters}
|
||
}}
|
||
""",
|
||
"action_prompt",
|
||
)
|
||
|
||
|
||
# 在模块加载时自动调用,完成提示词的注册。
|
||
init_prompts() |