feat(affinity_flow_chatter): 重构计划器以支持多动作并优化思考逻辑
本次提交对亲和流聊天器(AFC)的计划与决策核心进行了重大重构和功能增强,旨在提升其响应的灵活性、鲁棒性和可观测性。
主要变更包括:
1. **多动作支持与解析重构**:
- `PlanFilter` 现在能够正确解析并处理 LLM 返回的动作列表(`"actions": [...]`),而不仅限于单个动作,这使得机器人能够执行更复杂的组合行为。
- 增强了动作解析的鲁棒性,当找不到 `target_message_id` 时会优雅降级(如 `reply` 变为 `no_action`),并会根据当前实际可用的动作列表对 LLM 的选择进行验证。
2. **提示词工程与思考模式优化**:
- 重新设计了核心 Planner 提示词,将 `thinking` 字段定义为“思绪流”,引导 LLM 生成更自然、更符合角色的内心独白,而非简单的决策理由,从而提升决策质量和角色扮演的沉浸感。
- 强制要求 LLM 为需要目标消息的动作提供 `target_message_id`,提高了动作执行的准确性。
3. **上下文构建与鲁棒性增强**:
- 在 `PlanFilter` 中增加了上下文回退机制,当内存中缺少历史消息时(如冷启动),会自动从数据库加载最近的消息记录,确保决策所需上下文的完整性。
- 简化了提供给 LLM 的未读消息格式,移除了兴趣度分数等内部信息,并加入了用户昵称,使其更易于理解和处理。
4. **可观测性与日志改进**:
- 在 AFC 的多个关键节点(消息接收、决策、动作执行)增加了彩色的详细日志,使其决策流程像 HFC 一样清晰可见,极大地方便了调试。
- 将系统中多个模块(视频分析、兴趣度匹配、情绪管理)的常规日志级别从 `INFO` 调整为 `DEBUG`,以减少在生产环境中的日志噪音。
5. **动作描述优化**:
- 优化了 `set_emoji_like` 和 `emoji` 等动作的描述,使其意图更清晰,帮助 LLM 做出更准确的动作选择。
This commit is contained in:
@@ -25,7 +25,7 @@
|
||||
{
|
||||
"type": "action",
|
||||
"name": "set_emoji_like",
|
||||
"description": "为消息设置表情回应"
|
||||
"description": "为某条已经存在的消息添加‘贴表情’回应(类似点赞),而不是发送新消息。当用户明确要求‘贴表情’时使用。"
|
||||
}
|
||||
],
|
||||
"features": [
|
||||
|
||||
@@ -46,7 +46,7 @@ class SetEmojiLikeAction(BaseAction):
|
||||
|
||||
# === 基本信息(必须填写)===
|
||||
action_name = "set_emoji_like"
|
||||
action_description = "为一个已存在的消息添加点赞或表情回应(也叫‘贴表情’)"
|
||||
action_description = "为某条已经存在的消息添加‘贴表情’回应(类似点赞),而不是发送新消息。可以在觉得某条消息非常有趣、值得赞同或者需要特殊情感回应时主动使用。"
|
||||
activation_type = ActionActivationType.ALWAYS # 消息接收时激活(?)
|
||||
chat_type_allow = ChatType.GROUP
|
||||
parallel_action = True
|
||||
|
||||
@@ -464,7 +464,7 @@ class BotInterestManager:
|
||||
low_similarity_count += 1
|
||||
result.add_match(tag.tag_name, enhanced_score, [tag.tag_name])
|
||||
|
||||
logger.info(
|
||||
logger.debug(
|
||||
f"匹配统计: {match_count}/{len(active_tags)} 个标签命中 | "
|
||||
f"高(>{high_threshold}): {high_similarity_count}, "
|
||||
f"中(>{medium_threshold}): {medium_similarity_count}, "
|
||||
@@ -492,9 +492,9 @@ class BotInterestManager:
|
||||
if result.matched_tags:
|
||||
top_tag_name = max(result.match_scores.items(), key=lambda x: x[1])[0]
|
||||
result.top_tag = top_tag_name
|
||||
logger.info(f"最佳匹配: '{top_tag_name}' (分数: {result.match_scores[top_tag_name]:.3f})")
|
||||
logger.debug(f"最佳匹配: '{top_tag_name}' (分数: {result.match_scores[top_tag_name]:.3f})")
|
||||
|
||||
logger.info(
|
||||
logger.debug(
|
||||
f"最终结果: 总分={result.overall_score:.3f}, 置信度={result.confidence:.3f}, 匹配标签数={len(result.matched_tags)}"
|
||||
)
|
||||
return result
|
||||
|
||||
@@ -78,7 +78,7 @@ class VideoAnalyzer:
|
||||
self.video_llm = LLMRequest(
|
||||
model_set=model_config.model_task_config.video_analysis, request_type="video_analysis"
|
||||
)
|
||||
logger.info("✅ 使用video_analysis模型配置")
|
||||
logger.debug("✅ 使用video_analysis模型配置")
|
||||
except (AttributeError, KeyError) as e:
|
||||
# 如果video_analysis不存在,使用vlm配置
|
||||
self.video_llm = LLMRequest(model_set=model_config.model_task_config.vlm, request_type="vlm")
|
||||
@@ -155,14 +155,14 @@ class VideoAnalyzer:
|
||||
self.timeout = 60.0 # 分析超时时间(秒)
|
||||
|
||||
if config:
|
||||
logger.info("✅ 从配置文件读取视频分析参数")
|
||||
logger.debug("✅ 从配置文件读取视频分析参数")
|
||||
else:
|
||||
logger.warning("配置文件中缺少video_analysis配置,使用默认值")
|
||||
|
||||
# 系统提示词
|
||||
self.system_prompt = "你是一个专业的视频内容分析助手。请仔细观察用户提供的视频关键帧,详细描述视频内容。"
|
||||
|
||||
logger.info(f"✅ 视频分析器初始化完成,分析模式: {self.analysis_mode}, 线程池: {self.use_multiprocessing}")
|
||||
logger.debug(f"✅ 视频分析器初始化完成,分析模式: {self.analysis_mode}, 线程池: {self.use_multiprocessing}")
|
||||
|
||||
# 获取Rust模块系统信息
|
||||
self._log_system_info()
|
||||
@@ -175,7 +175,7 @@ class VideoAnalyzer:
|
||||
|
||||
try:
|
||||
system_info = rust_video.get_system_info()
|
||||
logger.info(f"🔧 系统信息: 线程数={system_info.get('threads', '未知')}")
|
||||
logger.debug(f"🔧 系统信息: 线程数={system_info.get('threads', '未知')}")
|
||||
|
||||
# 记录CPU特性
|
||||
features = []
|
||||
@@ -187,11 +187,11 @@ class VideoAnalyzer:
|
||||
features.append("SIMD")
|
||||
|
||||
if features:
|
||||
logger.info(f"🚀 CPU特性: {', '.join(features)}")
|
||||
logger.debug(f"🚀 CPU特性: {', '.join(features)}")
|
||||
else:
|
||||
logger.info("⚠️ 未检测到SIMD支持")
|
||||
logger.debug("⚠️ 未检测到SIMD支持")
|
||||
|
||||
logger.info(f"📦 Rust模块版本: {system_info.get('version', '未知')}")
|
||||
logger.debug(f"📦 Rust模块版本: {system_info.get('version', '未知')}")
|
||||
|
||||
except Exception as e:
|
||||
logger.warning(f"获取系统信息失败: {e}")
|
||||
|
||||
@@ -140,9 +140,9 @@ class ChatMood:
|
||||
prompt=prompt, temperature=0.7
|
||||
)
|
||||
if global_config.debug.show_prompt:
|
||||
logger.info(f"{self.log_prefix} prompt: {prompt}")
|
||||
logger.info(f"{self.log_prefix} response: {response}")
|
||||
logger.info(f"{self.log_prefix} reasoning_content: {reasoning_content}")
|
||||
logger.debug(f"{self.log_prefix} prompt: {prompt}")
|
||||
logger.debug(f"{self.log_prefix} response: {response}")
|
||||
logger.debug(f"{self.log_prefix} reasoning_content: {reasoning_content}")
|
||||
|
||||
logger.info(f"{self.log_prefix} 情绪状态更新为: {response}")
|
||||
|
||||
@@ -190,9 +190,9 @@ class ChatMood:
|
||||
)
|
||||
|
||||
if global_config.debug.show_prompt:
|
||||
logger.info(f"{self.log_prefix} prompt: {prompt}")
|
||||
logger.info(f"{self.log_prefix} response: {response}")
|
||||
logger.info(f"{self.log_prefix} reasoning_content: {reasoning_content}")
|
||||
logger.debug(f"{self.log_prefix} prompt: {prompt}")
|
||||
logger.debug(f"{self.log_prefix} response: {response}")
|
||||
logger.debug(f"{self.log_prefix} reasoning_content: {reasoning_content}")
|
||||
|
||||
logger.info(f"{self.log_prefix} 情绪状态转变为: {response}")
|
||||
|
||||
|
||||
@@ -17,6 +17,10 @@ from src.common.logger import get_logger
|
||||
|
||||
logger = get_logger("affinity_chatter")
|
||||
|
||||
# 定义颜色
|
||||
SOFT_GREEN = "\033[38;5;118m" # 一个更柔和的绿色
|
||||
RESET_COLOR = "\033[0m"
|
||||
|
||||
|
||||
class AffinityChatter(BaseChatter):
|
||||
"""亲和力聊天处理器"""
|
||||
@@ -60,6 +64,10 @@ class AffinityChatter(BaseChatter):
|
||||
try:
|
||||
unread_messages = context.get_unread_messages()
|
||||
|
||||
# 像hfc一样,打印收到的消息
|
||||
for msg in unread_messages:
|
||||
logger.info(f"{SOFT_GREEN}[所见] {msg.user_info.user_nickname}:{msg.processed_plain_text}{RESET_COLOR}")
|
||||
|
||||
# 使用增强版规划器处理消息
|
||||
actions, target_message = await self.planner.plan(context=context)
|
||||
self.stats["plans_created"] += 1
|
||||
|
||||
@@ -15,6 +15,10 @@ from src.config.config import global_config
|
||||
|
||||
logger = get_logger("chatter_interest_scoring")
|
||||
|
||||
# 定义颜色
|
||||
SOFT_BLUE = "\033[38;5;67m"
|
||||
RESET_COLOR = "\033[0m"
|
||||
|
||||
|
||||
class ChatterInterestScoringSystem:
|
||||
"""兴趣度评分系统"""
|
||||
@@ -80,8 +84,8 @@ class ChatterInterestScoringSystem:
|
||||
"mentioned": f"提及: {mentioned_score:.3f}",
|
||||
}
|
||||
|
||||
logger.info(
|
||||
f"消息得分: {total_score:.3f} (匹配: {interest_match_score:.2f}, 关系: {relationship_score:.2f}, 提及: {mentioned_score:.2f})"
|
||||
logger.debug(
|
||||
f"消息得分详情: {total_score:.3f} (匹配: {interest_match_score:.2f}, 关系: {relationship_score:.2f}, 提及: {mentioned_score:.2f})"
|
||||
)
|
||||
|
||||
return InterestScore(
|
||||
@@ -248,7 +252,9 @@ class ChatterInterestScoringSystem:
|
||||
# 做出决策
|
||||
should_reply = score.total_score >= effective_threshold
|
||||
decision = "回复" if should_reply else "不回复"
|
||||
logger.info(f"决策: {decision} (分数: {score.total_score:.3f})")
|
||||
logger.info(
|
||||
f"{SOFT_BLUE}决策: {decision} (兴趣度: {score.total_score:.3f} / 阈值: {effective_threshold:.3f}){RESET_COLOR}"
|
||||
)
|
||||
|
||||
return should_reply, score.total_score
|
||||
|
||||
@@ -264,7 +270,7 @@ class ChatterInterestScoringSystem:
|
||||
|
||||
# 限制最大计数
|
||||
self.no_reply_count = min(self.no_reply_count, self.max_no_reply_count)
|
||||
logger.info(f"{action} | 不回复次数: {old_count} -> {self.no_reply_count}")
|
||||
logger.info(f"动作: {action}, 连续不回复次数: {old_count} -> {self.no_reply_count}")
|
||||
|
||||
def update_user_relationship(self, user_id: str, relationship_change: float):
|
||||
"""更新用户关系"""
|
||||
|
||||
@@ -66,6 +66,10 @@ class ChatterPlanExecutor:
|
||||
logger.info("没有需要执行的动作。")
|
||||
return {"executed_count": 0, "results": []}
|
||||
|
||||
# 像hfc一样,提前打印将要执行的动作
|
||||
action_types = [action.action_type for action in plan.decided_actions]
|
||||
logger.info(f"选择动作: {', '.join(action_types) if action_types else '无'}")
|
||||
|
||||
execution_results = []
|
||||
reply_actions = []
|
||||
other_actions = []
|
||||
|
||||
@@ -27,13 +27,26 @@ from src.schedule.schedule_manager import schedule_manager
|
||||
|
||||
logger = get_logger("plan_filter")
|
||||
|
||||
SAKURA_PINK = "\033[38;5;175m"
|
||||
SKY_BLUE = "\033[38;5;117m"
|
||||
RESET_COLOR = "\033[0m"
|
||||
|
||||
|
||||
class ChatterPlanFilter:
|
||||
"""
|
||||
根据 Plan 中的模式和信息,筛选并决定最终的动作。
|
||||
"""
|
||||
|
||||
def __init__(self):
|
||||
def __init__(self, chat_id: str, available_actions: List[str]):
|
||||
"""
|
||||
初始化动作计划筛选器。
|
||||
|
||||
Args:
|
||||
chat_id (str): 当前聊天的唯一标识符。
|
||||
available_actions (List[str]): 当前可用的动作列表。
|
||||
"""
|
||||
self.chat_id = chat_id
|
||||
self.available_actions = available_actions
|
||||
self.planner_llm = LLMRequest(model_set=model_config.model_task_config.planner, request_type="planner")
|
||||
self.last_obs_time_mark = 0.0
|
||||
|
||||
@@ -110,13 +123,17 @@ class ChatterPlanFilter:
|
||||
final_actions.extend(await self._parse_single_action(item, used_message_id_list, plan))
|
||||
|
||||
if thinking and thinking != "未提供思考过程":
|
||||
logger.info(f"思考: {thinking}")
|
||||
logger.info(f"\n{SAKURA_PINK}思考: {thinking}{RESET_COLOR}\n")
|
||||
plan.decided_actions = self._filter_no_actions(final_actions)
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"筛选 Plan 时出错: {e}\n{traceback.format_exc()}")
|
||||
plan.decided_actions = [ActionPlannerInfo(action_type="no_action", reasoning=f"筛选时出错: {e}")]
|
||||
|
||||
# 在返回最终计划前,打印将要执行的动作
|
||||
action_types = [action.action_type for action in plan.decided_actions]
|
||||
logger.info(f"选择动作: [{SKY_BLUE}{', '.join(action_types) if action_types else '无'}{RESET_COLOR}]")
|
||||
|
||||
return plan
|
||||
|
||||
async def _build_prompt(self, plan: Plan) -> tuple[str, list]:
|
||||
@@ -279,12 +296,24 @@ class ChatterPlanFilter:
|
||||
# 从message_manager获取真实的已读/未读消息
|
||||
from src.chat.message_manager.message_manager import message_manager
|
||||
from src.chat.utils.utils import assign_message_ids
|
||||
from src.chat.utils.chat_message_builder import get_raw_msg_before_timestamp_with_chat
|
||||
|
||||
# 获取聊天流的上下文
|
||||
stream_context = message_manager.stream_contexts.get(plan.chat_id)
|
||||
|
||||
# 获取真正的已读和未读消息
|
||||
read_messages = stream_context.history_messages # 已读消息存储在history_messages中
|
||||
if not read_messages:
|
||||
from src.common.data_models.database_data_model import DatabaseMessages
|
||||
# 如果内存中没有已读消息(比如刚启动),则从数据库加载最近的上下文
|
||||
fallback_messages_dicts = get_raw_msg_before_timestamp_with_chat(
|
||||
chat_id=plan.chat_id,
|
||||
timestamp=time.time(),
|
||||
limit=global_config.chat.max_context_size,
|
||||
)
|
||||
# 将字典转换为DatabaseMessages对象
|
||||
read_messages = [DatabaseMessages(**msg_dict) for msg_dict in fallback_messages_dicts]
|
||||
|
||||
unread_messages = stream_context.get_unread_messages() # 获取未读消息
|
||||
|
||||
# 构建已读历史消息块
|
||||
@@ -316,14 +345,12 @@ class ChatterPlanFilter:
|
||||
synthetic_id = mapped.get("id")
|
||||
original_msg_id = msg.get("message_id") or msg.get("id")
|
||||
msg_time = time.strftime("%H:%M:%S", time.localtime(msg.get("time", time.time())))
|
||||
user_nickname = msg.get("user_nickname", "未知用户")
|
||||
msg_content = msg.get("processed_plain_text", "")
|
||||
|
||||
# 添加兴趣度信息
|
||||
interest_score = interest_scores.get(original_msg_id, 0.0)
|
||||
interest_text = f" [兴趣度: {interest_score:.3f}]" if interest_score > 0 else ""
|
||||
|
||||
# 在未读行中显示合成id,方便 planner 返回时使用
|
||||
unread_lines.append(f"{msg_time} {synthetic_id}: {msg_content}{interest_text}")
|
||||
# 不再显示兴趣度,但保留合成ID供模型内部使用
|
||||
# 同时,为了让模型更好地理解上下文,我们显示用户名
|
||||
unread_lines.append(f"<{synthetic_id}> {msg_time} {user_nickname}: {msg_content}")
|
||||
|
||||
unread_history_block = "\n".join(unread_lines)
|
||||
else:
|
||||
@@ -389,26 +416,22 @@ class ChatterPlanFilter:
|
||||
actions_obj = action_json.get("actions", {})
|
||||
|
||||
# 处理actions字段可能是字典或列表的情况
|
||||
actions_to_process = []
|
||||
if isinstance(actions_obj, dict):
|
||||
action = actions_obj.get("action_type", "no_action")
|
||||
reasoning = actions_obj.get("reason", "未提供原因")
|
||||
# 合并actions_obj中的其他字段作为action_data
|
||||
action_data = {k: v for k, v in actions_obj.items() if k not in ["action_type", "reason"]}
|
||||
elif isinstance(actions_obj, list) and actions_obj:
|
||||
# 如果是列表,取第一个元素
|
||||
first_action = actions_obj[0]
|
||||
if isinstance(first_action, dict):
|
||||
action = first_action.get("action_type", "no_action")
|
||||
reasoning = first_action.get("reason", "未提供原因")
|
||||
action_data = {k: v for k, v in first_action.items() if k not in ["action_type", "reason"]}
|
||||
else:
|
||||
action = "no_action"
|
||||
reasoning = "actions格式错误"
|
||||
action_data = {}
|
||||
else:
|
||||
action = "no_action"
|
||||
reasoning = "actions格式错误"
|
||||
action_data = {}
|
||||
actions_to_process.append(actions_obj)
|
||||
elif isinstance(actions_obj, list):
|
||||
actions_to_process.extend(actions_obj)
|
||||
|
||||
if not actions_to_process:
|
||||
actions_to_process.append({"action_type": "no_action", "reason": "actions格式错误"})
|
||||
|
||||
for single_action_obj in actions_to_process:
|
||||
if not isinstance(single_action_obj, dict):
|
||||
continue
|
||||
|
||||
action = single_action_obj.get("action_type", "no_action")
|
||||
reasoning = single_action_obj.get("reason", "未提供原因")
|
||||
action_data = {k: v for k, v in single_action_obj.items() if k not in ["action_type", "reason"]}
|
||||
|
||||
# 保留原始的thinking字段(如果有)
|
||||
thinking = action_json.get("thinking")
|
||||
@@ -441,10 +464,9 @@ class ChatterPlanFilter:
|
||||
action = "no_action"
|
||||
reasoning = f"找不到目标消息进行回复。原始理由: {reasoning}"
|
||||
|
||||
available_action_names = list(plan.available_actions.keys())
|
||||
if (
|
||||
action not in ["no_action", "no_reply", "reply", "do_nothing", "proactive_reply"]
|
||||
and action not in available_action_names
|
||||
and action not in self.available_actions
|
||||
):
|
||||
reasoning = f"LLM 返回了当前不可用的动作 '{action}'。原始理由: {reasoning}"
|
||||
action = "no_action"
|
||||
|
||||
@@ -50,7 +50,6 @@ class ChatterActionPlanner:
|
||||
self.chat_id = chat_id
|
||||
self.action_manager = action_manager
|
||||
self.generator = ChatterPlanGenerator(chat_id)
|
||||
self.filter = ChatterPlanFilter()
|
||||
self.executor = ChatterPlanExecutor(action_manager)
|
||||
|
||||
# 初始化兴趣度评分系统
|
||||
@@ -96,9 +95,17 @@ class ChatterActionPlanner:
|
||||
async def _enhanced_plan_flow(self, context: "StreamContext") -> Tuple[List[Dict], Optional[Dict]]:
|
||||
"""执行增强版规划流程"""
|
||||
try:
|
||||
# 在规划前,先进行动作修改
|
||||
from src.chat.planner_actions.action_modifier import ActionModifier
|
||||
action_modifier = ActionModifier(self.action_manager, self.chat_id)
|
||||
await action_modifier.modify_actions()
|
||||
|
||||
# 1. 生成初始 Plan
|
||||
initial_plan = await self.generator.generate(context.chat_mode)
|
||||
|
||||
# 确保Plan中包含所有当前可用的动作
|
||||
initial_plan.available_actions = self.action_manager.get_using_actions()
|
||||
|
||||
unread_messages = context.get_unread_messages() if context else []
|
||||
# 2. 兴趣度评分 - 只对未读消息进行评分
|
||||
if unread_messages:
|
||||
@@ -142,7 +149,9 @@ class ChatterActionPlanner:
|
||||
filtered_plan.decided_actions = [no_action]
|
||||
else:
|
||||
# 4. 筛选 Plan
|
||||
filtered_plan = await self.filter.filter(reply_not_available, initial_plan)
|
||||
available_actions = list(initial_plan.available_actions.keys())
|
||||
plan_filter = ChatterPlanFilter(self.chat_id, available_actions)
|
||||
filtered_plan = await plan_filter.filter(reply_not_available, initial_plan)
|
||||
|
||||
# 检查filtered_plan是否有reply动作,以便记录reply action
|
||||
has_reply_action = False
|
||||
|
||||
@@ -56,9 +56,19 @@ def init_prompts():
|
||||
|
||||
**输出格式:**
|
||||
请严格按照以下 JSON 格式输出,包含 `thinking` 和 `actions` 字段:
|
||||
|
||||
**重要概念:将“内心思考”作为思绪流的体现**
|
||||
`thinking` 字段是本次决策的核心。它并非一个简单的“理由”,而是 **一个模拟人类在回应前,头脑中自然浮现的、未经修饰的思绪流**。你需要完全代入 {identity_block} 的角色,将那一刻的想法自然地记录下来。
|
||||
|
||||
**内心思考的要点:**
|
||||
* **自然流露**: 不要使用“决定”、“所以”、“因此”等结论性或汇报式的词语。你的思考应该像日记一样,是给自己看的,充满了不确定性和情绪的自然流动。
|
||||
* **展现过程**: 重点在于展现 **思考的过程**,而不是 **决策的结果**。描述你看到了什么,想到了什么,感受到了什么。
|
||||
* **使用昵称**: 在你的思绪流中,请直接使用用户的昵称来指代他们,而不是`<m1>`, `<m2>`这样的消息ID。
|
||||
* **严禁技术术语**: 严禁在思考中提及任何数字化的度量(如兴趣度、分数)或内部技术术语。请完全使用角色自身的感受和语言来描述思考过程。
|
||||
|
||||
```json
|
||||
{{
|
||||
"thinking": "你的内心思考,简要描述你选择动作时的心路历程",
|
||||
"thinking": "在这里写下你的思绪流...",
|
||||
"actions": [
|
||||
{{
|
||||
"action_type": "动作类型(如:reply, emoji等)",
|
||||
@@ -72,6 +82,9 @@ def init_prompts():
|
||||
}}
|
||||
```
|
||||
|
||||
**强制规则**:
|
||||
- 对于每一个需要目标消息的动作(如`reply`, `poke_user`, `set_emoji_like`),你 **必须** 在`action_data`中提供准确的`target_message_id`,这个ID来源于`## 未读历史消息`中消息前的`<m...>`标签。
|
||||
|
||||
如果没有合适的回复对象或不需要回复,输出空的 actions 数组:
|
||||
```json
|
||||
{{
|
||||
|
||||
@@ -27,7 +27,7 @@
|
||||
{
|
||||
"type": "action",
|
||||
"name": "emoji",
|
||||
"description": "发送表情包辅助表达情绪"
|
||||
"description": "作为一条全新的消息,发送一个符合当前情景的表情包来生动地表达情绪。"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
@@ -33,7 +33,7 @@ class EmojiAction(BaseAction):
|
||||
|
||||
# 动作基本信息
|
||||
action_name = "emoji"
|
||||
action_description = "发送表情包辅助表达情绪"
|
||||
action_description = "作为一条全新的消息,发送一个符合当前情景的表情包来生动地表达情绪。"
|
||||
|
||||
# LLM判断提示词
|
||||
llm_judge_prompt = """
|
||||
|
||||
Reference in New Issue
Block a user