第一步:创建一个知识库类(KB
) 目标 :将长文档分块并生成嵌入向量,便于后续检索。
1.1 定义 KB
类及初始化方法 1 2 3 4 5 6 7 8 9 10 11 12 13 class KB : """ 知识库类,用于管理文档分块和生成嵌入向量。 """ def __init__ (self, filepath ): try : with open (filepath, 'r' , encoding='UTF-8' ) as f: content = f.read() except FileNotFoundError: raise ValueError(f"File {filepath} not found." ) self .docs = list (self .split_content(content)) self .embeds = self .encode(self .docs)
1.2 文本分块方法 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 @staticmethod def split_content (content, max_length=128 ): """ 将文档按标点符号分块,块大小不超过 max_length。 """ sentences = re.split(r'(?<=[.!?。,!])\s+' , content) current_chunk = [] current_length = 0 for sentence in sentences: sentence_length = len (sentence) if current_length + sentence_length <= max_length: current_chunk.append(sentence) current_length += sentence_length else : yield ' ' .join(current_chunk).strip() current_chunk = [sentence] current_length = sentence_length if current_chunk: yield ' ' .join(current_chunk).strip()
1.3 嵌入向量生成方法 1 2 3 4 5 6 7 8 9 10 11 12 13 14 @staticmethod def encode (texts ): """ Encode a list of texts into embeddings. """ embeds = [] for text in texts: try : response = ollama.embeddings(model='nomic-embed-text' , prompt=text) embeds.append(response['embedding' ]) except Exception as e: print (f"Error encoding text: {text[:30 ]} ... -> {e} " ) return np.array(embeds)
第二步:实现检索功能 目标 :通过余弦相似度,从知识库中找到与输入文本最相关的文档块。
2.1 定义相似度计算方法 1 2 3 4 5 6 7 8 @staticmethod def similarity (vec1, vec2 ): """ 计算余弦相似度 """ dot_product = np.dot(vec1, vec2) norm1, norm2 = np.linalg.norm(vec1), np.linalg.norm(vec2) return dot_product / (norm1 * norm2)
2.2 实现检索逻辑 1 2 3 4 5 6 7 8 9 10 def search (self, text ): """ 根据输入文本匹配知识库中相似度最高的片段 """ query_embed = self .encode([text])[0 ] similarities = np.dot(self .embeds, query_embed) / ( np.linalg.norm(self .embeds, axis=1 ) * np.linalg.norm(query_embed) ) max_index = np.argmax(similarities) return self .docs[max_index]
第三步:构建 RAG 问答类 目标 :结合知识库和生成模型,生成基于上下文的回答。
3.1 定义 Rag
类及初始化方法 1 2 3 4 5 6 7 8 9 10 11 12 13 14 class Rag : """ 用于结合知识库和语言模型的检索增强生成(RAG)类。 """ def __init__ (self, model, kb: KB ): self .model = model self .kb = kb self .prompt_template = """ 任务描述:使用中文回答用户的问题,请根据提供的上下文信息生成精准回答。 检索上下文:{retrieved_context} 问题:{user_query} 请基于检索上下文和问题生成答案。如果检索上下文中没有明确的信息,请礼貌地告诉用户无法回答。 """
3.2 实现生成回答方法 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 def chat (self, text ): """ 根据检索到的上下文和输入问题创建响应 """ context = self .kb.search(text) prompt = self .prompt_template.format (retrieved_context=context, user_query=text) print (f"Generated Prompt:\n{prompt} " ) try : response = ollama.chat(self .model, [ollama.Message(role='user' , content=prompt), ollama.Message(role='system' , content='你是怀光长纵的智能助理' )]) return response['message' ] except Exception as e: print (f"Error during chat generation: {e} " ) return {"content" : "抱歉,我无法生成答案。" }
第四步:整合并运行 4.1 主程序逻辑 1 2 3 4 5 6 7 8 9 10 if __name__ == '__main__' : try : kb = KB('../file/test.txt' ) rag = Rag('qwen2.5:0.5b-instruct' , kb) question = '明吉集团是怎么创办的' result = rag.chat(question) print ("回答:" , result.get('content' , '未生成答案。' )) except ValueError as e: print (e)
测试与输出 问题 :明吉集团是怎么创办的?
控制台日志 :
1 2 3 4 5 6 7 生成的提示语: 根据以下提供的内容回答问题: 内容:明吉集团成立于2001年,致力于科技创新。 问题:明吉集团是怎么创办的 回答需简洁明了。 回答: 明吉集团成立于2001年,致力于科技创新。
实现过程:
构建知识库并生成嵌入向量。
实现基于余弦相似度的检索功能。
将检索结果结合语言模型生成答案。
可扩展方向:
多文档支持 :支持从多个知识库中检索答案。
模型优化 :使用更强大的语言模型。
性能改进 :通过向量索引(如 FAISS)加速检索。