feat(lightrag): 添加LightRAG知识库的语言选择和LLM模型选择功能

- 支持在创建LightRAG知识库时选择语言和LLM模型
- 修复知识图谱加载按钮在没有文件时仍可点击的问题
- 更新README中的分支说明
- 简化chroma和milvus的集合命名方式
- 修复知识库创建失败的情况
This commit is contained in:
Wenjie Zhang 2025-08-16 20:07:12 +08:00
parent 9e4402aa60
commit e6145657c5
12 changed files with 110 additions and 36 deletions

View File

@ -37,10 +37,10 @@ https://github.com/user-attachments/assets/15f7f315-003d-4e41-a260-739c2529f824
1. **克隆项目**
```bash
git clone -b stable https://github.com/xerrors/Yuxi-Know.git
git clone -b 0.2.0.preview https://github.com/xerrors/Yuxi-Know.git
cd Yuxi-Know
```
如果想要使用 v0.2 预览版,可以使用分支:`0.2.0.preview`
如果想要使用之前的稳定版,可以使用分支:`stable` 分支,`main` 分支是最新的开发版本。
2. **配置 API 密钥**

View File

@ -19,7 +19,8 @@
- [x] 切换知识库之后,检索结果没有刷新
- [x] 文件上传模块 UI的边距、配色有问题
- [x] 知识图谱页面的节点数量统计方法 #236
- [ ] 当没有手动添加节点的时候,尝试检索,会出现为创建索引的情况 #236
- [x] 当没有手动添加节点的时候,尝试检索,会出现为创建索引的情况 #236
- [ ] 删除知识库的时候,没有正常将数据从 Neo4j / Milvus 数据库中删除(需要添加检测脚本)
# 💯 More:

View File

@ -33,10 +33,11 @@ async def create_database(
embed_model_name: str = Body(...),
kb_type: str = Body("lightrag"),
additional_params: dict = Body({}),
llm_info: dict = Body(None),
current_user: User = Depends(get_admin_user)
):
"""创建知识库"""
logger.debug(f"Create database {database_name} with kb_type {kb_type}, additional_params {additional_params}")
logger.debug(f"Create database {database_name} with kb_type {kb_type}, additional_params {additional_params}, llm_info {llm_info}")
try:
embed_info = config.embed_model_names[embed_model_name]
database_info = await knowledge_base.create_database(
@ -44,6 +45,7 @@ async def create_database(
description,
kb_type=kb_type,
embed_info=embed_info,
llm_info=llm_info,
**additional_params
)

View File

@ -64,7 +64,7 @@ class ChromaKB(KnowledgeBase):
embedding_function = self._get_embedding_function(embed_info)
# 创建或获取集合
collection_name = f"kb_{db_id}"
collection_name = db_id
try:
# 尝试获取现有集合

View File

@ -85,7 +85,7 @@ class KnowledgeBase(ABC):
pass
def create_database(self, database_name: str, description: str,
embed_info: dict | None = None, **kwargs) -> dict:
embed_info: dict | None = None, llm_info: dict | None = None, **kwargs) -> dict:
"""
创建数据库
@ -108,6 +108,7 @@ class KnowledgeBase(ABC):
"description": description,
"kb_type": self.kb_type,
"embed_info": embed_info,
"llm_info": llm_info,
"metadata": kwargs,
"created_at": datetime.now().isoformat()
}
@ -187,7 +188,6 @@ class KnowledgeBase(ABC):
"""
pass
@abstractmethod
async def export_data(self, db_id: str, format: str = 'zip', **kwargs) -> str:
pass

View File

@ -55,6 +55,16 @@ class LightRagKB(KnowledgeBase):
llm_info = self.databases_meta[db_id].get("llm_info", {})
embed_info = self.databases_meta[db_id].get("embed_info", {})
# 读取在创建数据库时透传的附加参数(包括语言)
metadata = self.databases_meta[db_id].get("metadata", {}) or {}
addon_params = {}
if isinstance(metadata.get("addon_params"), dict):
addon_params.update(metadata.get("addon_params", {}))
# 兼容直接放在 metadata 下的 language
if isinstance(metadata.get("language"), str) and metadata.get("language"):
addon_params.setdefault("language", metadata.get("language"))
# 默认语言从环境变量读取,默认 English
addon_params.setdefault("language", os.getenv("SUMMARY_LANGUAGE", "English"))
# 创建工作目录
working_dir = os.path.join(self.work_dir, db_id)
@ -71,6 +81,7 @@ class LightRagKB(KnowledgeBase):
graph_storage="Neo4JStorage",
doc_status_storage="JsonDocStatusStorage",
log_file_path=os.path.join(working_dir, "lightrag.log"),
addon_params=addon_params,
)
return rag
@ -107,7 +118,18 @@ class LightRagKB(KnowledgeBase):
def _get_llm_func(self, llm_info: dict):
"""获取 LLM 函数"""
from src.models import select_model
model = select_model(LIGHTRAG_LLM_PROVIDER, LIGHTRAG_LLM_NAME)
# 如果用户选择了LLM使用用户选择的否则使用环境变量默认值
if llm_info and llm_info.get("provider") and llm_info.get("model_name"):
provider = llm_info["provider"]
model_name = llm_info["model_name"]
logger.info(f"Using user-selected LLM: {provider}/{model_name}")
else:
provider = LIGHTRAG_LLM_PROVIDER
model_name = LIGHTRAG_LLM_NAME
logger.info(f"Using default LLM from environment: {provider}/{model_name}")
model = select_model(provider, model_name)
async def llm_model_func(prompt, system_prompt=None, history_messages=[], **kwargs):
return await openai_complete_if_cache(

View File

@ -101,7 +101,7 @@ class MilvusKB(KnowledgeBase):
raise ValueError(f"Database {db_id} not found")
embed_info = self.databases_meta[db_id].get("embed_info", {})
collection_name = f"kb_{db_id}"
collection_name = db_id
try:
# 检查集合是否存在
@ -256,7 +256,7 @@ class MilvusKB(KnowledgeBase):
self._save_metadata()
file_record["file_id"] = file_id
# 添加到处理队列
self._add_to_processing_queue(file_id)

View File

@ -0,0 +1 @@
《红楼梦》是中国古典四大名著之一,由曹雪芹创作

View File

@ -370,10 +370,7 @@ const printDatabaseInfo = async () => {
if (!checkAdminPermission()) return;
try {
console.log('=== 知识库信息 ===');
// API
await databaseStore.refreshDatabase();
console.log('知识库信息', databaseStore.database);
} catch (error) {
console.error('获取知识库信息失败:', error);

View File

@ -15,6 +15,7 @@
size="small"
@click="loadGraph"
:disabled="!isGraphSupported"
:icon='h(ReloadOutlined)'
>
加载图谱
</a-button>
@ -153,7 +154,6 @@
import { ref, computed, watch } from 'vue';
import { useDatabaseStore } from '@/stores/database';
import { useUserStore } from '@/stores/user';
import { getKbTypeLabel } from '@/utils/kb_utils';
import { ReloadOutlined, DeleteOutlined, ExpandOutlined, UpOutlined, DownOutlined, SettingOutlined } from '@ant-design/icons-vue';
import { message } from 'ant-design-vue';
import KnowledgeGraphViewer from '@/components/KnowledgeGraphViewer.vue';
@ -208,6 +208,9 @@ const toggleVisible = () => {
};
const loadGraph = () => {
if (!(Object.keys(store.database?.files).length > 0)) {
return;
}
if (graphViewerRef.value && typeof graphViewerRef.value.loadFullGraph === 'function') {
graphViewerRef.value.loadFullGraph();
}

View File

@ -241,17 +241,17 @@ export const useDatabaseStore = defineStore('database', () => {
try {
const response = await queryApi.getKnowledgeBaseQueryParams(db_id);
queryParams.value = response.params?.options || [];
// Create a set of currently supported parameter keys
const supportedParamKeys = new Set(queryParams.value.map(param => param.key));
// Remove unsupported parameters from meta
for (const key in meta) {
if (key !== 'db_id' && !supportedParamKeys.has(key)) {
delete meta[key];
}
}
// Add default values for supported parameters that are not in meta
queryParams.value.forEach(param => {
if (!(param.key in meta)) {
@ -291,16 +291,16 @@ export const useDatabaseStore = defineStore('database', () => {
stopAutoRefresh();
}
}
function selectAllFailedFiles() {
const files = Object.values(database.value.files || {});
const failedFiles = files
.filter(file => file.status === 'failed')
.map(file => file.file_id);
const newSelectedKeys = [...new Set([...selectedRowKeys.value, ...failedFiles])];
selectedRowKeys.value = newSelectedKeys;
if (failedFiles.length > 0) {
message.success(`已选择 ${failedFiles.length} 个失败的文件`);
} else {

View File

@ -47,18 +47,26 @@
<h3>嵌入模型</h3>
<a-select v-model:value="newDatabase.embed_model_name" :options="embedModelOptions" style="width: 100%;" size="large" />
<!-- 根据类型显示不同配置 -->
<!-- <div v-if="newDatabase.kb_type === 'chroma' || newDatabase.kb_type === 'milvus'" class="storage-config">
<h3>存储配置</h3>
<div class="param-row">
<label>存储方式</label>
<a-select v-model:value="newDatabase.storage" style="width: 200px;">
<a-select-option value="DemoA">DemoA</a-select-option>
<a-select-option value="DemoB">DemoB</a-select-option>
</a-select>
<span class="param-hint">存储方式配置功能预留</span>
</div>
</div> -->
<!-- 仅对 LightRAG 提供语言选择和LLM选择 -->
<div v-if="newDatabase.kb_type === 'lightrag'">
<h3 style="margin-top: 20px;">语言</h3>
<a-select
v-model:value="newDatabase.language"
:options="languageOptions"
style="width: 100%;"
size="large"
:dropdown-match-select-width="false"
/>
<h3 style="margin-top: 20px;">语言模型 (LLM)</h3>
<p style="color: var(--gray-700); font-size: 14px;">可以在设置中配置语言模型</p>
<ModelSelectorComponent
:model_name="newDatabase.llm_info.model_name || '请选择模型'"
:model_provider="newDatabase.llm_info.provider || ''"
@select-model="handleLLMSelect"
style="width: 100%; height: 60px;"
/>
</div>
<h3 style="margin-top: 20px;">知识库描述</h3>
<p style="color: var(--gray-700); font-size: 14px;">在智能体流程中这里的描述会作为工具的描述智能体会根据知识库的标题和描述来选择合适的工具所以这里描述的越详细智能体越容易选择到合适的工具</p>
@ -72,13 +80,13 @@
<a-button key="submit" type="primary" :loading="state.creating" @click="createDatabase">创建</a-button>
</template>
</a-modal>
<!-- 加载状态 -->
<div v-if="state.loading" class="loading-container">
<a-spin size="large" />
<p>正在加载知识库...</p>
</div>
<!-- 数据库列表 -->
<div v-else class="databases">
<div class="new-database dbcard" @click="state.openNewDatabaseModel=true">
@ -115,7 +123,7 @@
<p class="description">{{ database.description || '暂无描述' }}</p>
<div class="tags">
<a-tag color="blue" v-if="database.embed_info?.name">{{ database.embed_info.name }}</a-tag>
<a-tag color="green" v-if="database.embed_info?.dimension">{{ database.embed_info.dimension }}</a-tag>
<!-- <a-tag color="green" v-if="database.embed_info?.dimension">{{ database.embed_info.dimension }}</a-tag> -->
<a-tag
:color="getKbTypeColor(database.kb_type || 'lightrag')"
class="kb-type-tag"
@ -139,6 +147,7 @@ import { message } from 'ant-design-vue'
import { BookPlus, Database, Zap, FileDigit, Waypoints, Building2 } from 'lucide-vue-next';
import { databaseApi, typeApi } from '@/apis/knowledge_api';
import HeaderComponent from '@/components/HeaderComponent.vue';
import ModelSelectorComponent from '@/components/ModelSelectorComponent.vue';
const route = useRoute()
const router = useRouter()
@ -158,6 +167,21 @@ const embedModelOptions = computed(() => {
}))
})
// 使/LightRAG 便
const languageOptions = [
{ label: '英语 English', value: 'English' },
{ label: '中文 Chinese', value: 'Chinese' },
{ label: '日语 Japanese', value: 'Japanese' },
{ label: '韩语 Korean', value: 'Korean' },
{ label: '德语 German', value: 'German' },
{ label: '法语 French', value: 'French' },
{ label: '西班牙语 Spanish', value: 'Spanish' },
{ label: '葡萄牙语 Portuguese', value: 'Portuguese' },
{ label: '俄语 Russian', value: 'Russian' },
{ label: '阿拉伯语 Arabic', value: 'Arabic' },
{ label: '印地语 Hindi', value: 'Hindi' },
]
const emptyEmbedInfo = {
name: '',
description: '',
@ -165,6 +189,12 @@ const emptyEmbedInfo = {
kb_type: 'chroma', // Milvus
// Vector
storage: '', //
// LightRAG
language: 'English',
llm_info: {
provider: '',
model_name: ''
},
}
const newDatabase = reactive({
@ -312,6 +342,13 @@ const handleKbTypeChange = (type) => {
newDatabase.kb_type = type
}
// LLM
const handleLLMSelect = (selection) => {
console.log('LLM选择:', selection)
newDatabase.llm_info.provider = selection.provider
newDatabase.llm_info.model_name = selection.name
}
const createDatabase = () => {
if (!newDatabase.name?.trim()) {
message.error('数据库名称不能为空')
@ -338,6 +375,17 @@ const createDatabase = () => {
requestData.additional_params.storage = newDatabase.storage || 'DemoA'
}
if (newDatabase.kb_type === 'lightrag') {
requestData.additional_params.language = newDatabase.language || 'English'
// LLM
if (newDatabase.llm_info.provider && newDatabase.llm_info.model_name) {
requestData.llm_info = {
provider: newDatabase.llm_info.provider,
model_name: newDatabase.llm_info.model_name
}
}
}
databaseApi.createDatabase(requestData)
.then(data => {
console.log('创建成功:', data)