Skip to content

Commit aee51e5

Browse files
committed
feat(agent): 增加记忆、文件索引及蒸馏功能支持
- 集成 Qdrant 向量存储与语义模型嵌入,支持长期记忆回溯和保存 - 新增文件索引服务,支持后台自动索引项目文件内容 - 添加记忆蒸馏调度器,定时优化记忆数据 - 扩展内置工具,新增记忆存储、检索、蒸馏及文件搜索工具 - 优化 Agent 消息处理流程,接入记忆调取及原始记忆保存机制 - 增加配置项支持 embedding、qdrant、memory、distillation 及 fileIndex 参数 - 更新配置加载逻辑,支持将 JSON 配置转换为 Agent 所需结构 - 改进上下文构建,加入工具使用指导文档 - 优化日志输出,添加语义模型及记忆系统启动提示 - 修改文件相关工具描述,明确推荐的使用流程 - onebot 通道新增消息撤回及发送图片功能工具 - 升级依赖,新增 DJL 本地语义模型及 Ktor JSON 序列化支持 - 修改启动脚本,增加 JVM 参数支持代理设置环境注入
1 parent 0970497 commit aee51e5

33 files changed

Lines changed: 3858 additions & 121 deletions

build.gradle.kts

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,12 +15,22 @@ repositories {
1515
dependencies {
1616
implementation("com.aallam.openai:openai-client:4.1.0")
1717
implementation("io.ktor:ktor-client-okhttp:3.0.0")
18+
implementation("io.ktor:ktor-client-content-negotiation:3.0.0")
19+
implementation("io.ktor:ktor-serialization-kotlinx-json:3.0.0")
1820
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.10.2")
1921
implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.7.3")
20-
implementation("org.slf4j:slf4j-simple:2.0.13")
22+
implementation("ch.qos.logback:logback-classic:1.5.12")
2123

2224
implementation("top.mrxiaom.mirai:overflow-core:1.1.0")
2325

26+
// 内置语义模型(DJL + HuggingFace sentence-transformers,本地推理)
27+
implementation("ai.djl:api:0.31.1")
28+
implementation("ai.djl.huggingface:tokenizers:0.30.0")
29+
implementation("ai.djl.pytorch:pytorch-engine:0.30.0")
30+
implementation("ai.djl.pytorch:pytorch-model-zoo:0.30.0")
31+
32+
// 向量存储(Qdrant REST API,通过 Ktor HTTP 客户端调用)
33+
2434
testImplementation(kotlin("test"))
2535
}
2636

@@ -48,6 +58,15 @@ tasks.shadowJar {
4858
tasks.matching { it.name in setOf("startShadowScripts", "shadowDistTar", "shadowDistZip") }
4959
.configureEach { enabled = false }
5060

61+
// JDK 17+ 需要显式 --add-opens 才能反射注入进程环境变量
62+
// (BuiltinEmbeddingClient.configureProxy 需要给原生 tokenizer 注入 HTTPS_PROXY)
63+
tasks.withType<JavaExec>().configureEach {
64+
jvmArgs(
65+
"--add-opens=java.base/java.util=ALL-UNNAMED",
66+
"--add-opens=java.base/java.lang=ALL-UNNAMED",
67+
)
68+
}
69+
5170
tasks.build {
5271
dependsOn(tasks.shadowJar)
5372
}

src/main/kotlin/org/example/vicky/agent/Agent.kt

Lines changed: 213 additions & 96 deletions
Large diffs are not rendered by default.

src/main/kotlin/org/example/vicky/agent/AgentConfig.kt

Lines changed: 31 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
package org.example.vicky.agent
1+
package org.example.vicky.agent
22

33
import com.aallam.openai.api.model.ModelId
44

@@ -16,6 +16,7 @@ import com.aallam.openai.api.model.ModelId
1616
* @property agentMd 基础系统提示文本 (人设/指令),直接内联,不再读文件。
1717
* @property debug 打开后输出框架运行日志 (每轮推理 / 工具调用) 及底层 HTTP 日志。
1818
* @property think 打开后把 agent 每轮的中间思考文本 (调用工具前的 content) 打到日志。
19+
* @property embedding 语义模型配置;null = 未启用。内置 / 外置互斥,见 [EmbeddingConfig]。
1920
*/
2021
data class AgentConfig(
2122
val model: ModelId,
@@ -30,4 +31,33 @@ data class AgentConfig(
3031
val debug: Boolean = false,
3132
val think: Boolean = false,
3233
val builtinTools: Boolean = true,
34+
val embedding: EmbeddingConfig? = null,
35+
// Qdrant 配置
36+
val qdrantHost: String? = null,
37+
val qdrantGrpcPort: Int = 6334,
38+
val qdrantHttpPort: Int = 6333,
39+
// 记忆配置
40+
val memoryEnabled: Boolean = false,
41+
val memoryTopK: Int = 5,
42+
val memoryTokenBudget: Int = 800,
43+
val memoryMaxPerUser: Int = 500,
44+
val memoryExpiryDays: Int = 90,
45+
val memoryRawRetentionDays: Int = 30,
46+
val memoryDistilledRetentionDays: Int = 7,
47+
val memoryCollection: String = "vicky_memories",
48+
val memoryRawCollection: String = "vicky_memories_raw",
49+
// 蒸馏配置
50+
val distillationEnabled: Boolean = true,
51+
val distillationSchedule: String = "0 2 * * *",
52+
val distillationMaxConversations: Int = 10,
53+
val distillationTemperature: Double = 0.1,
54+
val distillationMaxTokens: Int = 1000,
55+
// 文件索引配置
56+
val fileIndexEnabled: Boolean = false,
57+
val fileIndexCollection: String = "vicky_files",
58+
val fileIndexChunkSize: Int = 500,
59+
val fileIndexChunkOverlap: Int = 50,
60+
val fileIndexIgnorePatterns: List<String> = listOf(".git", ".gradle", "build", "node_modules"),
61+
val fileIndexPaths: List<String> = emptyList(),
62+
val fileIndexAutoIndexOnStart: Boolean = true,
3363
)
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
package org.example.vicky.agent
2+
3+
/**
4+
* 语义模型(embedding)配置。
5+
*
6+
* 内置([Builtin])与外置([External])二选一,互斥。
7+
* - [Builtin]:进程内本地推理(DJL + HuggingFace sentence-transformers)。
8+
* - [External]:OpenAI 协议兼容的远程 embeddings 端点。
9+
*/
10+
sealed class EmbeddingConfig {
11+
/**
12+
* 内置:本地 Java/Kotlin 模型。
13+
*
14+
* 加载优先级:[modelPath] > [endpoint] > 官方 huggingface.co。
15+
*
16+
* @property model HuggingFace 模型 id,例如 "sentence-transformers/all-MiniLM-L6-v2"。
17+
* @property modelPath 本地模型目录(非空时直接离线加载,不走网络)。
18+
* 目录需含 tokenizer.json + 模型权重(model.safetensors / pytorch_model.bin / traced_model.pt)。
19+
* @property endpoint HuggingFace 镜像端点,如 "https://hf-mirror.com",仅 [modelPath] 为空时生效。
20+
* @property proxy HTTP 代理 URL(如 "http://127.0.0.1:7892"),用于远程下载时穿越网络。
21+
*/
22+
data class Builtin(
23+
val model: String,
24+
val modelPath: String = "",
25+
val endpoint: String = "",
26+
val proxy: String = "",
27+
) : EmbeddingConfig()
28+
29+
/**
30+
* 外置:OpenAI 协议兼容端点。
31+
*
32+
* @property baseUrl 例如 "https://api.openai.com/v1/"。
33+
* @property apiKey API key。
34+
* @property model 模型 id,例如 "text-embedding-3-small"。
35+
*/
36+
data class External(
37+
val baseUrl: String,
38+
val apiKey: String,
39+
val model: String,
40+
) : EmbeddingConfig()
41+
}

0 commit comments

Comments
 (0)