feat(expression_selector): 添加温度采样功能以优化表达选择
feat(official_configs): 新增模型温度配置项以支持表达模型采样 chore(bot_config_template): 更新版本号并添加模型温度说明
This commit is contained in:
@@ -1,5 +1,6 @@
|
|||||||
import asyncio
|
import asyncio
|
||||||
import hashlib
|
import hashlib
|
||||||
|
import math
|
||||||
import random
|
import random
|
||||||
import time
|
import time
|
||||||
from typing import Any
|
from typing import Any
|
||||||
@@ -76,6 +77,45 @@ def weighted_sample(population: list[dict], weights: list[float], k: int) -> lis
|
|||||||
|
|
||||||
|
|
||||||
class ExpressionSelector:
|
class ExpressionSelector:
|
||||||
|
@staticmethod
|
||||||
|
def _sample_with_temperature(
|
||||||
|
candidates: list[tuple[Any, float, float, str]],
|
||||||
|
max_num: int,
|
||||||
|
temperature: float,
|
||||||
|
) -> list[tuple[Any, float, float, str]]:
|
||||||
|
"""
|
||||||
|
对候选表达按温度采样,温度越高越均匀。
|
||||||
|
|
||||||
|
Args:
|
||||||
|
candidates: (expr, similarity, count, best_predicted) 列表
|
||||||
|
max_num: 需要返回的数量
|
||||||
|
temperature: 温度参数,0 表示贪婪选择
|
||||||
|
"""
|
||||||
|
if max_num <= 0 or not candidates:
|
||||||
|
return []
|
||||||
|
|
||||||
|
if temperature <= 0:
|
||||||
|
return candidates[:max_num]
|
||||||
|
|
||||||
|
adjusted_temp = max(temperature, 1e-6)
|
||||||
|
# 使用与排序相同的打分,但通过 softmax/temperature 放大尾部概率
|
||||||
|
scores = [max(c[1] * (c[2] ** 0.5), 1e-8) for c in candidates]
|
||||||
|
max_score = max(scores)
|
||||||
|
weights = [math.exp((s - max_score) / adjusted_temp) for s in scores]
|
||||||
|
|
||||||
|
# 始终保留最高分一个,剩余的按温度采样,避免过度集中
|
||||||
|
best_idx = scores.index(max_score)
|
||||||
|
selected = [candidates[best_idx]]
|
||||||
|
remaining_indices = [i for i in range(len(candidates)) if i != best_idx]
|
||||||
|
|
||||||
|
while remaining_indices and len(selected) < max_num:
|
||||||
|
current_weights = [weights[i] for i in remaining_indices]
|
||||||
|
picked_pos = random.choices(range(len(remaining_indices)), weights=current_weights, k=1)[0]
|
||||||
|
picked_idx = remaining_indices.pop(picked_pos)
|
||||||
|
selected.append(candidates[picked_idx])
|
||||||
|
|
||||||
|
return selected
|
||||||
|
|
||||||
def __init__(self, chat_id: str = ""):
|
def __init__(self, chat_id: str = ""):
|
||||||
self.chat_id = chat_id
|
self.chat_id = chat_id
|
||||||
if model_config is None:
|
if model_config is None:
|
||||||
@@ -517,12 +557,21 @@ class ExpressionSelector:
|
|||||||
)
|
)
|
||||||
return []
|
return []
|
||||||
|
|
||||||
# 按照相似度*count排序,选择最佳匹配
|
# 按照相似度*count排序,并根据温度采样,避免过度集中
|
||||||
matched_expressions.sort(key=lambda x: x[1] * (x[2] ** 0.5), reverse=True)
|
matched_expressions.sort(key=lambda x: x[1] * (x[2] ** 0.5), reverse=True)
|
||||||
expressions_objs = [e[0] for e in matched_expressions[:max_num]]
|
temperature = getattr(global_config.expression, "model_temperature", 0.0)
|
||||||
|
sampled_matches = self._sample_with_temperature(
|
||||||
|
candidates=matched_expressions,
|
||||||
|
max_num=max_num,
|
||||||
|
temperature=temperature,
|
||||||
|
)
|
||||||
|
expressions_objs = [e[0] for e in sampled_matches]
|
||||||
|
|
||||||
# 显示最佳匹配的详细信息
|
# 显示最佳匹配的详细信息
|
||||||
logger.debug(f"模糊匹配成功: 找到 {len(expressions_objs)} 个表达方式")
|
logger.debug(
|
||||||
|
f"模糊匹配成功: 找到 {len(expressions_objs)} 个表达方式 "
|
||||||
|
f"(候选 {len(matched_expressions)},temperature={temperature})"
|
||||||
|
)
|
||||||
|
|
||||||
# 转换为字典格式
|
# 转换为字典格式
|
||||||
expressions = [
|
expressions = [
|
||||||
|
|||||||
@@ -10,11 +10,6 @@ CoreSink 统一管理器
|
|||||||
3. 使用 MessageRuntime 进行消息路由和处理
|
3. 使用 MessageRuntime 进行消息路由和处理
|
||||||
4. 提供统一的消息发送接口
|
4. 提供统一的消息发送接口
|
||||||
|
|
||||||
架构说明(2025-11 重构):
|
|
||||||
- 集成 mofox_wire.MessageRuntime 作为消息路由中心
|
|
||||||
- 使用 @runtime.on_message() 装饰器注册消息处理器
|
|
||||||
- 利用 before_hook/after_hook/error_hook 处理前置/后置/错误逻辑
|
|
||||||
- 简化消息处理链条,提高可扩展性
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|||||||
@@ -213,6 +213,12 @@ class ExpressionConfig(ValidatedConfigBase):
|
|||||||
default="classic",
|
default="classic",
|
||||||
description="表达方式选择模式: classic=经典LLM评估, exp_model=机器学习模型预测"
|
description="表达方式选择模式: classic=经典LLM评估, exp_model=机器学习模型预测"
|
||||||
)
|
)
|
||||||
|
model_temperature: float = Field(
|
||||||
|
default=1.0,
|
||||||
|
ge=0.0,
|
||||||
|
le=5.0,
|
||||||
|
description="表达模型采样温度,0为贪婪,值越大越容易采样到低分表达"
|
||||||
|
)
|
||||||
expiration_days: int = Field(
|
expiration_days: int = Field(
|
||||||
default=90,
|
default=90,
|
||||||
description="表达方式过期天数,超过此天数未激活的表达方式将被清理"
|
description="表达方式过期天数,超过此天数未激活的表达方式将被清理"
|
||||||
@@ -1009,4 +1015,3 @@ class KokoroFlowChatterConfig(ValidatedConfigBase):
|
|||||||
default_factory=KokoroFlowChatterProactiveConfig,
|
default_factory=KokoroFlowChatterProactiveConfig,
|
||||||
description="私聊专属主动思考配置"
|
description="私聊专属主动思考配置"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
[inner]
|
[inner]
|
||||||
version = "7.9.8"
|
version = "7.9.9"
|
||||||
|
|
||||||
#----以下是给开发人员阅读的,如果你只是部署了MoFox-Bot,不需要阅读----
|
#----以下是给开发人员阅读的,如果你只是部署了MoFox-Bot,不需要阅读----
|
||||||
#如果你想要修改配置文件,请递增version的值
|
#如果你想要修改配置文件,请递增version的值
|
||||||
@@ -134,6 +134,8 @@ compress_identity = false # 是否压缩身份,压缩后会精简身份信息
|
|||||||
# - "classic": 经典模式,随机抽样 + LLM选择
|
# - "classic": 经典模式,随机抽样 + LLM选择
|
||||||
# - "exp_model": 表达模型模式,使用机器学习模型预测最合适的表达
|
# - "exp_model": 表达模型模式,使用机器学习模型预测最合适的表达
|
||||||
mode = "classic"
|
mode = "classic"
|
||||||
|
# model_temperature: 机器预测模式下的“温度”,0 为贪婪,越大越爱探索(更容易选到低分表达)
|
||||||
|
model_temperature = 1.0
|
||||||
|
|
||||||
# expiration_days: 表达方式过期天数,超过此天数未激活的表达方式将被清理
|
# expiration_days: 表达方式过期天数,超过此天数未激活的表达方式将被清理
|
||||||
expiration_days = 1
|
expiration_days = 1
|
||||||
|
|||||||
Reference in New Issue
Block a user