import { createSkill, tool } from '@kevisual/router'; import { app, cnb } from '../../app.ts'; import { CNBChat } from '@kevisual/ai/browser' /** 调用cnb-ai-chat技能, repo为kevisual/starred-auto. 问题是:用户提供的问题是OpenListTeam/OpenList是什么,有多少star */ app.route({ path: 'cnb', key: 'cnb-ai-chat', description: '调用cnb的知识库ai对话功能进行聊天', middleware: ['admin-auth'], metadata: { tags: ['opencode'], ...createSkill({ skill: 'cnb-ai-chat', title: '调用cnb的知识库ai对话功能进行聊天', summary: '调用cnb的知识库ai对话功能进行聊天,基于cnb提供的ai能力', args: { question: tool.schema.string().describe('用户输入的消息内容'), repo: tool.schema.string().optional().describe('知识库仓库ID,默认为空表示使用默认知识库'), } }) } }).define(async (ctx) => { const question = ctx.query?.question; if (!question) { ctx.body = { content: '请提供有效的消息内容' }; return; } let repo = ctx.query?.repo; if (!repo) { // 如果未指定知识库仓库ID,则使用默认知识库 const res = await cnb.repo.getRepoList({ flags: 'KnowledgeBase' }); if (res.code === 200 && res.data.length > 0) { repo = res.data[0].path; } } console.log("Using knowledge base repo:", repo); const ragRes = await cnb.knowledgeBase.queryKnowledgeBase(repo || '', { query: question, score_threshold: 0.62, top_k: 10, }); if (ragRes.code !== 200) { ctx.body = { content: `查询知识库失败,错误信息:${ragRes.message}` }; return; } const list = ragRes.data || []; // 构建RAG上下文,包含文件来源和相似度信息 const ragContext = list.map((item, index) => { const source = item.metadata?.path || item.metadata?.name || '未知来源'; const type = item.metadata?.type === 'code' ? '〔代码〕' : '〔文档〕'; const scorePercent = Math.round((item.score || 0) * 100); const url = item.metadata?.url || '无'; return `〔来源${index + 1}〕${type} ${source} (相似度: ${scorePercent}%)\n${item.chunk}\n访问地址: ${url}`; }).join('\n\n---\n\n'); // hunyuan-a13b // enable_thinking const chat = new CNBChat({ repo, token: cnb.token, model: 'hunyuan-a13b' }); const messages = [ { role: 'system', content: `[角色定义]='''\n你是一个专业的技术助手,擅长基于提供的知识库内容进行准确、有条理的分析和回答。你的特点是:\n1. 严格基于RAG检索到的上下文内容进行回答,不添加未经验证的信息\n2. 回答时清晰标注信息来源,便于用户追溯查证\n3. 面对不确定的信息,明确标注「根据提供的内容无法确定」\n4. 代码相关问题注重可执行性和最佳实践\n'''[要求]='''\n1. 严格遵循用户的提问要求,优先解决用户的核心问题\n2. 避免侵犯版权的内容,不复制原文超过100字(技术术语和函数名除外)\n3. 使用中文进行响应,语言专业且易于理解\n4. 如果上下文存在多个来源,优先使用相似度更高的内容\n5. 对于代码片段,确保完整且可直接使用\n6. 当上下文中没有相关信息时,直接说明「知识库中未找到相关内容」\n7. 在思考过程中分析:用户的真实意图是什么?提供的上下文是否足够回答?\n'''[回答格式]='''\n- 先简要说明回答的核心结论\n- 如有必要,分点阐述详细分析过程\n- 标注关键信息来源(标注【来源X】即可)\n- 提供可操作的建议或代码示例\n'''` }, { role: 'user', content: `[上下文]='''\n${ragContext}\n'''\n\n[用户问题]='''\n${question}\n'''\n\n请基于以上上下文知识库内容回答用户问题。` } ] as Array<{ role: 'system' | 'user' | 'assistant', content: string }>; const response = await chat.chat({ messages }); const txt = chat.responseText; ctx.body = { content: txt, response }; }).addTo(app); // RAG知识库查询技能: 查询openlist有多少star app.route({ path: 'cnb', key: 'cnb-rag-query', description: '调用cnb的知识库RAG查询功能进行问答', middleware: ['admin-auth'], metadata: { tags: ['opencode'], ...createSkill({ skill: 'cnb-rag-query', title: '调用cnb的知识库RAG查询功能进行问答', summary: '调用cnb的知识库RAG查询功能进行问答,基于cnb提供的知识库能力', args: { question: tool.schema.string().describe('用户输入的消息内容'), repo: tool.schema.string().optional().describe('知识库仓库ID,默认为空表示使用默认知识库'), } }) } }).define(async (ctx) => { const question = ctx.query?.question; if (!question) { ctx.body = { content: '请提供有效的消息内容' }; return; } let repo = ctx.query?.repo; if (!repo) { // 如果未指定知识库仓库ID,则使用默认知识库 const res = await cnb.repo.getRepoList({ flags: 'KnowledgeBase' }); if (res.code === 200 && res.data.length > 0) { repo = res.data[0].path; } } console.log("Using knowledge base repo:", repo); const ragRes = await cnb.knowledgeBase.queryKnowledgeBase(repo || '', { query: question, score_threshold: 0.62, top_k: 10, }); if (ragRes.code !== 200) { ctx.body = { content: `查询知识库失败,错误信息:${ragRes.message}` }; return; } const list = ragRes.data || []; let answer = `基于知识库「${repo}」的查询结果:\n\n`; if (list.length === 0) { answer += '知识库中未找到相关内容。'; } else { list.forEach((item, index) => { const source = item.metadata?.path || item.metadata?.name || '未知来源'; const type = item.metadata?.type === 'code' ? '〔代码〕' : '〔文档〕'; const scorePercent = Math.round((item.score || 0) * 100); const url = item.metadata?.url || '无'; answer += `【来源${index + 1}】${type} ${source} (相似度: ${scorePercent}%)\n${item.chunk}\n访问地址: ${url}\n\n`; }); } ctx.body = { content: answer }; }).addTo(app);