mirror of
https://github.com/jie65535/JChatGPT.git
synced 2026-09-15 02:56:10 +08:00
profile: return complete query results
This commit is contained in:
@@ -246,7 +246,7 @@ searchHistoryMaxRecords: 5000
|
|||||||
|
|
||||||
下一次正常群聊会自动携带触发者和最近发言者的认识。现有好感度、Bot 代号、标签和主观印象会与证据驱动的
|
下一次正常群聊会自动携带触发者和最近发言者的认识。现有好感度、Bot 代号、标签和主观印象会与证据驱动的
|
||||||
长期画像按同一个人合并渲染,并明确给出长期画像条目数;私聊也会携带对方的可靠画像摘要和条目数。
|
长期画像按同一个人合并渲染,并明确给出长期画像条目数;私聊也会携带对方的可靠画像摘要和条目数。
|
||||||
模型需要完整细节时可主动调用 `queryUserProfile`,按 QQ 号、群名片、昵称或好友备注读取画像。两套画像数据
|
模型需要完整细节时可主动调用 `queryUserProfile`,按 QQ 号、群名片、昵称或好友备注读取完整画像。两套画像数据
|
||||||
仍独立保存,自动画像不会修改好感度。
|
仍独立保存,自动画像不会修改好感度。
|
||||||
|
|
||||||
`queryUserProfile` 解析出唯一联系人后才按需调用一次 `queryProfile()`,并在内存中缓存 10 分钟;周期联系人
|
`queryUserProfile` 解析出唯一联系人后才按需调用一次 `queryProfile()`,并在内存中缓存 10 分钟;周期联系人
|
||||||
@@ -486,7 +486,7 @@ JChatGPT 维护对每位用户的画像,由好感度、Bot 自定义代号、
|
|||||||
### 注入到上下文
|
### 注入到上下文
|
||||||
- 群聊:合并列出当前相关群友的关系状态,以及可靠长期画像的摘要和条目数
|
- 群聊:合并列出当前相关群友的关系状态,以及可靠长期画像的摘要和条目数
|
||||||
- 私聊:合并注入对方的关系状态,以及可靠长期画像的摘要和条目数
|
- 私聊:合并注入对方的关系状态,以及可靠长期画像的摘要和条目数
|
||||||
- 模型需要画像明细时主动调用 `queryUserProfile`,不必把全部条目常驻在上下文中
|
- 模型需要画像明细时主动调用 `queryUserProfile`,查询始终返回完整条目,不必把全部条目常驻在上下文中
|
||||||
- 只有好感度数值、其它关系字段和可靠长期画像均为空的用户不会被列出,避免提示词噪声
|
- 只有好感度数值、其它关系字段和可靠长期画像均为空的用户不会被列出,避免提示词噪声
|
||||||
|
|
||||||
### 配置选项
|
### 配置选项
|
||||||
|
|||||||
@@ -5,7 +5,6 @@ import com.aallam.openai.api.core.Parameters
|
|||||||
import kotlinx.serialization.json.JsonObject
|
import kotlinx.serialization.json.JsonObject
|
||||||
import kotlinx.serialization.json.booleanOrNull
|
import kotlinx.serialization.json.booleanOrNull
|
||||||
import kotlinx.serialization.json.contentOrNull
|
import kotlinx.serialization.json.contentOrNull
|
||||||
import kotlinx.serialization.json.intOrNull
|
|
||||||
import kotlinx.serialization.json.jsonPrimitive
|
import kotlinx.serialization.json.jsonPrimitive
|
||||||
import kotlinx.serialization.json.longOrNull
|
import kotlinx.serialization.json.longOrNull
|
||||||
import kotlinx.serialization.json.put
|
import kotlinx.serialization.json.put
|
||||||
@@ -50,10 +49,6 @@ class QueryUserProfileAgent : BaseAgent(
|
|||||||
put("type", "boolean")
|
put("type", "boolean")
|
||||||
put("description", "是否返回画像条目明细,默认true")
|
put("description", "是否返回画像条目明细,默认true")
|
||||||
}
|
}
|
||||||
putJsonObject("limit") {
|
|
||||||
put("type", "integer")
|
|
||||||
put("description", "最多返回多少条画像条目,默认20,最大50")
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
@@ -73,10 +68,9 @@ class QueryUserProfileAgent : BaseAgent(
|
|||||||
if (profile == null && publicProfile == null) return "用户 $userId 尚无画像,当前联系人也没有可读取的公开资料卡。"
|
if (profile == null && publicProfile == null) return "用户 $userId 尚无画像,当前联系人也没有可读取的公开资料卡。"
|
||||||
|
|
||||||
val includeItems = args?.get("includeItems")?.jsonPrimitive?.booleanOrNull ?: true
|
val includeItems = args?.get("includeItems")?.jsonPrimitive?.booleanOrNull ?: true
|
||||||
val limit = args?.get("limit")?.jsonPrimitive?.intOrNull?.coerceIn(1, 50) ?: 20
|
|
||||||
val displayName = resolveDisplayName(userId, event)
|
val displayName = resolveDisplayName(userId, event)
|
||||||
|
|
||||||
return formatProfile(userId, profile, publicProfile, displayName, includeItems, limit)
|
return formatProfile(userId, profile, publicProfile, displayName, includeItems)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun resolveUserId(args: JsonObject?, event: MessageEvent): Long? {
|
private fun resolveUserId(args: JsonObject?, event: MessageEvent): Long? {
|
||||||
@@ -148,7 +142,6 @@ class QueryUserProfileAgent : BaseAgent(
|
|||||||
publicProfile: UserProfile?,
|
publicProfile: UserProfile?,
|
||||||
displayName: String,
|
displayName: String,
|
||||||
includeItems: Boolean,
|
includeItems: Boolean,
|
||||||
limit: Int,
|
|
||||||
): String = buildString {
|
): String = buildString {
|
||||||
appendLine("用户画像:$displayName($userId)")
|
appendLine("用户画像:$displayName($userId)")
|
||||||
if (profile != null) {
|
if (profile != null) {
|
||||||
@@ -163,9 +156,7 @@ class QueryUserProfileAgent : BaseAgent(
|
|||||||
publicProfile?.let { appendPublicProfile(it) }
|
publicProfile?.let { appendPublicProfile(it) }
|
||||||
if (includeItems && profile?.items?.isNotEmpty() == true) {
|
if (includeItems && profile?.items?.isNotEmpty() == true) {
|
||||||
appendLine("条目:")
|
appendLine("条目:")
|
||||||
profile.items
|
selectProfileItems(profile.items)
|
||||||
.sortedWith(compareBy<UserProfileItem>({ it.category.ordinal }, { it.firstSeenAt }, { it.id }))
|
|
||||||
.take(limit)
|
|
||||||
.forEach { item ->
|
.forEach { item ->
|
||||||
append("- ")
|
append("- ")
|
||||||
append(item.category.label()).append('/').append(item.confidence.name.lowercase())
|
append(item.category.label()).append('/').append(item.confidence.name.lowercase())
|
||||||
@@ -180,9 +171,6 @@ class QueryUserProfileAgent : BaseAgent(
|
|||||||
relationship = item.category == ProfileCategory.RELATIONSHIP_NOTE,
|
relationship = item.category == ProfileCategory.RELATIONSHIP_NOTE,
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
if (profile.items.size > limit) {
|
|
||||||
appendLine("其余 ${profile.items.size - limit} 条已省略,可提高 limit 继续查询。")
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}.trim()
|
}.trim()
|
||||||
|
|
||||||
@@ -252,3 +240,9 @@ class QueryUserProfileAgent : BaseAgent(
|
|||||||
|
|
||||||
private fun String.normalized(): String = trim().replace(Regex("\\s+"), " ")
|
private fun String.normalized(): String = trim().replace(Regex("\\s+"), " ")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
internal fun selectProfileItems(
|
||||||
|
items: List<UserProfileItem>,
|
||||||
|
): List<UserProfileItem> = items.sortedWith(
|
||||||
|
compareBy<UserProfileItem>({ it.category.ordinal }, { it.firstSeenAt }, { it.id })
|
||||||
|
)
|
||||||
|
|||||||
@@ -0,0 +1,32 @@
|
|||||||
|
package top.jie65535.mirai.tools
|
||||||
|
|
||||||
|
import top.jie65535.mirai.profile.ProfileCategory
|
||||||
|
import top.jie65535.mirai.profile.ProfileConfidence
|
||||||
|
import top.jie65535.mirai.profile.UserProfileItem
|
||||||
|
import kotlin.test.Test
|
||||||
|
import kotlin.test.assertEquals
|
||||||
|
|
||||||
|
class QueryUserProfileAgentTest {
|
||||||
|
@Test
|
||||||
|
fun returnsAllItemsInStableOrder() {
|
||||||
|
val items = listOf(
|
||||||
|
item("later", firstSeenAt = 300),
|
||||||
|
item("earlier", firstSeenAt = 100),
|
||||||
|
item("middle", firstSeenAt = 200),
|
||||||
|
)
|
||||||
|
|
||||||
|
assertEquals(
|
||||||
|
listOf("earlier", "middle", "later"),
|
||||||
|
selectProfileItems(items).map(UserProfileItem::content),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun item(content: String, firstSeenAt: Int) = UserProfileItem(
|
||||||
|
id = content,
|
||||||
|
category = ProfileCategory.NOTABLE_FACT,
|
||||||
|
content = content,
|
||||||
|
confidence = ProfileConfidence.MEDIUM,
|
||||||
|
firstSeenAt = firstSeenAt,
|
||||||
|
lastConfirmedAt = firstSeenAt,
|
||||||
|
)
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user