RAG工厂制度问答 - 源码
from dotenv import load_dotenv
from openai import OpenAI
from pdfminer.high_level import extract_pages
from pdfminer.layout import LTTextContainer
import chromadb
import os
def sliding_window_chunks(text, chunk_size, stride):
return [text[i:i + chunk_size] for i in range(0, len(text), stride)]
def extract_text_from_pdf(filename, page_numbers=None):
'''从 PDF 文件中(按指定页码)提取文字'''
full_text = ''
for i, page_layout in enumerate(extract_pages(filename)):
if page_numbers is not None and i not in page_numbers:
continue
for element in page_layout:
if isinstance(element, LTTextContainer):
full_text += element.get_text().replace("\n", "").replace(" ", "")
text_chunks = sliding_window_chunks(full_text, 250, 100)
return text_chunks
class MyVectorDBConnector:
def __init__(self, collection_name):
chroma_client = chromadb.Client()
self.collection = chroma_client.get_or_create_collection(
name=collection_name,
metadata={'hnsw:space': 'cosine'}
)
def get_embeddings(self, texts, model="text-embedding-v2", batch_size=20):
'''封装 qwen 的 Embedding 模型接口'''
all_embeddings = []
for i in range(0, len(texts), batch_size):
batch = texts[i:i + batch_size]
data = client.embeddings.create(input=batch, model=model).data
all_embeddings.extend([x.embedding for x in data])
return all_embeddings
def add_documents(self, instructions):
'''向 collection 中添加文档与向量'''
embeddings = self.get_embeddings(instructions)
self.collection.add(
embeddings=embeddings,
documents=instructions,
ids=[f"id{i}" for i in range(len(instructions))]
)
def search(self, query, n_results):
'''检索向量数据库'''
results = self.collection.query(
query_embeddings=self.get_embeddings([query]),
n_results=n_results,
)
return results
class RAG_Bot:
def __init__(self, vector_db, n_results=2):
self.vector_db = vector_db
self.n_results = n_results
def get_completion(self, prompt, model="qwen3.8-27b"):
'''封装 千问 接口'''
messages = [{"role": "user", "content": prompt}]
response = client.chat.completions.create(
model=model,
messages=messages,
temperature=0,
)
return response.choices[0].message.content
def chat(self, user_query):
search_res = self.vector_db.search(user_query, self.n_results)
print(search_res)
prompt = prompt_template.replace('__INFO__', ','.join(search_res['documents'][0])).replace('__QUERY__', user_query)
res = self.get_completion(prompt)
print('用户问题:', user_query)
print('大模型回复:', res)
if __name__ == '__main__':
load_dotenv()
client = OpenAI(api_key=os.getenv("DASHSCOPE_API_KEY"), base_url=os.getenv("DASHSCOPE_BASE_URL"))
prompt_template = """
你是一个问答机器人。
你的任务是根据下述给定的已知信息回答用户问题。
确保你的回复完全依据下述已知信息。不要编造答案。
如果下述已知信息不足以回答用户的问题,请直接回复"我无法回答您的问题"。
已知信息:
__INFO__
用户问:
__QUERY__
请用中文回答用户问题。
"""
docx_file = '工厂员工手册.pdf'
paragraphs = extract_text_from_pdf(docx_file)
vector_db = MyVectorDBConnector('test1')
vector_db.add_documents(paragraphs)
bot = RAG_Bot(vector_db, 5)
user_query = "录用员工必须签订合同么?"
response = bot.chat(user_query)