手把手教你用通义千问1.8B+WebUI:打造个人专属信息助手
本文介绍了如何在星图GPU平台上自动化部署通义千问1.5-1.8B-Chat-GPTQ-Int4 WebUI镜像,快速搭建个人专属信息助手。该方案结合了轻量化大语言模型与检索增强生成技术,用户可基于自定义知识库进行智能问答,典型应用于从指定信息源(如科技新闻)中获取并总结最新资讯,实现高效、可靠的信息整合与查询。
手把手教你用通义千问1.8B+WebUI:打造个人专属信息助手
你是不是经常觉得,网上信息太多太杂,想找个靠谱的答案得翻半天?或者有些专业问题,通用搜索引擎给的结果要么太浅,要么根本不对路?
我也有过这种困扰。后来我发现,其实有个更聪明的办法:自己搭一个专属的信息助手。它不用很复杂,也不用花很多钱,但能真正理解你的问题,并且只从你信任的信息源里找答案。
今天我就带你一步步实现这个想法。我们用阿里云的通义千问1.8B轻量版模型,加上一个简单的网页界面,再给它配上“外接大脑”——一个你自己定制的知识库。这样组合起来,就是一个既聪明又靠谱的个人信息助手了。
整个方案的核心思路很简单:让AI说“有根据的话”。我们定期从你指定的网站抓取最新内容,存到本地数据库里。当你提问时,系统先从这个数据库里找到最相关的资料,然后把资料和问题一起交给通义千问模型,让它基于这些事实来组织答案。
听起来是不是挺有意思?下面我就带你从零开始,把这个系统搭起来。
1. 准备工作:理解我们要做什么
在开始动手之前,我们先把这个系统的“工作原理”搞清楚。你可以把它想象成一个特别靠谱的私人助理。
这个助理每天会定时去你指定的几个网站(比如你常看的科技博客、行业新闻站)逛一圈,把新文章“读”一遍,然后把核心内容做成一张张小卡片,分门别类存起来。
当你有问题要问它时,比如“最近AI领域有什么新进展?”,它不会随便编个答案。它会先去翻自己的卡片柜,找出所有和“AI”、“新进展”相关的卡片,把上面最相关的几段话拿出来。然后,它看着这些资料和你提的问题,组织语言,给你一个有根有据的回答:“根据A网站昨天的报道,B公司发布了新模型C;另外B博客提到,D团队开源了项目E……”
这就是我们系统的核心流程:“先查资料,再回答问题”。模型本身不需要记住所有知识,它的强项是理解和组织语言。我们通过外接一个实时更新的、高质量的知识库,来弥补模型在事实性和时效性上的不足。
整个系统可以分成三个主要部分:
- 信息采集模块:负责从网上抓取内容,并处理成方便查找的格式
- 问答核心模块:部署通义千问模型,实现“接收问题-查找资料-生成答案”的完整逻辑
- 网页界面:提供一个简洁的网页,让你可以方便地提问和查看答案
接下来,我们就从环境准备开始,一步步把它们构建起来。
2. 环境搭建:把基础工具准备好
工欲善其事,必先利其器。我们首先需要把几个核心的软件环境准备好。这个项目对电脑要求不高,一台普通的云服务器或者性能好一点的个人电脑都能跑起来。
2.1 安装Python和必要库
第一步是准备好Python环境和安装必要的库。我们用conda来管理环境,这样可以避免各种包版本冲突。
# 创建并激活一个新的Python环境
conda create -n my_assistant python=3.10
conda activate my_assistant
# 安装深度学习框架和模型运行库
# 如果你有NVIDIA GPU,可以安装CUDA版本,速度会快很多
pip install torch torchvision torchaudio --index-url https://download.pytorch.org/whl/cu118
# 安装模型相关库
pip install transformers accelerate
# 安装网页界面库
pip install gradio
# 安装向量数据库(用来存我们的知识卡片)
pip install chromadb
# 安装文本处理模型(用来把文字转换成数字向量)
pip install sentence-transformers
# 安装网页抓取工具
pip install requests beautifulsoup4 lxml
这些命令会安装所有需要的软件包。如果网络不太好,可能需要多等一会儿。
2.2 部署通义千问模型
接下来,部署我们今天的主角——通义千问1.5-1.8B-Chat-GPTQ-Int4模型。这个版本是经过特别压缩的,体积小、速度快,在保持不错对话能力的同时,对硬件资源非常友好,特别适合我们这种需要长期运行的服务。
# 创建一个文件叫 model_loader.py,把下面的代码放进去
from transformers import AutoTokenizer, AutoModelForCausalLM
import torch
# 模型在网上的名字
model_name = "Qwen/Qwen1.5-1.8B-Chat-GPTQ-Int4"
print("正在加载分词器...")
# 分词器负责把文字转换成模型能理解的数字
tokenizer = AutoTokenizer.from_pretrained(model_name)
print("正在加载模型...")
# 加载模型本身
model = AutoModelForCausalLM.from_pretrained(
model_name,
torch_dtype=torch.float16, # 用半精度,可以节省显存
device_map="auto", # 自动分配模型到GPU或CPU
trust_remote_code=True # 这个模型需要这个设置
)
print("模型加载完成!")
# 简单测试一下模型能不能正常工作
test_input = "你好,请介绍一下你自己。"
inputs = tokenizer(test_input, return_tensors="pt").to(model.device)
outputs = model.generate(**inputs, max_new_tokens=50)
response = tokenizer.decode(outputs[0], skip_special_tokens=True)
print("模型回复:", response)
运行这个脚本,它会自动从网上下载模型。第一次运行需要一些时间,因为模型有差不多2GB大小。下载完成后,控制台会显示模型的自我介绍,这就说明模型准备就绪了。
2.3 初始化知识库工具
为了让模型能“查阅资料”,我们需要一个高效的检索工具。这里选用 Chroma,它是一个轻量级、易用的向量数据库,非常适合存储和检索文本片段。
# 在另一个Python文件里,比如 init_knowledge_base.py
from sentence_transformers import SentenceTransformer
import chromadb
print("正在加载文本处理模型...")
# 这个模型负责把文字转换成向量(一串数字)
embedding_model = SentenceTransformer('paraphrase-multilingual-MiniLM-L12-v2')
print("正在初始化向量数据库...")
# 创建数据库客户端,数据会保存在本地的 chroma_db 文件夹里
chroma_client = chromadb.PersistentClient(path="./chroma_db")
# 创建一个集合(可以理解成一个文件夹),用来存AI相关的新闻
collection = chroma_client.get_or_create_collection(name="ai_news")
print("知识库工具初始化完成!")
到这里,我们的“私人助理”就有了大脑(通义千问模型)和记忆卡片柜(Chroma向量库)。接下来,我们要开始往卡片柜里存东西了。
3. 构建知识库:让助理有东西可查
知识库是我们系统的基石,质量直接决定最终答案的可靠性。这一部分,我们来实现信息的自动抓取、清洗和入库。
3.1 抓取目标网站内容
我们以“AI新闻”这个领域为例。假设我们选定几个你常看的科技媒体作为信息源。你需要先花点时间看看这些网站的页面结构,找到文章列表页和文章详情页的规律。
下面是一个简单的示例,演示如何抓取一个假设的科技新闻网站:
# crawler.py
import requests
from bs4 import BeautifulSoup
import time
from urllib.parse import urljoin
def fetch_news_list(base_url, max_pages=2):
"""
抓取新闻网站的文章列表
base_url: 网站基础地址
max_pages: 抓取多少页
"""
all_articles = []
# 设置请求头,让网站觉得是正常浏览器在访问
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36'
}
for page in range(1, max_pages + 1):
# 构造列表页的网址
if page == 1:
list_url = base_url # 第一页
else:
list_url = f"{base_url}/page/{page}" # 第二页及以后
try:
print(f"正在抓取:{list_url}")
# 发送请求获取网页内容
resp = requests.get(list_url, headers=headers, timeout=10)
resp.raise_for_status() # 如果请求失败就抛出异常
# 解析网页内容
soup = BeautifulSoup(resp.content, 'html.parser')
# 这里需要根据实际网站调整
# 假设文章链接在 <h2 class="title"> 下的 <a> 标签里
article_links = soup.select('h2.title a')
for link in article_links:
article_url = urljoin(base_url, link['href']) # 补全网址
article_title = link.get_text().strip() # 获取标题
all_articles.append({
'title': article_title,
'url': article_url
})
# 礼貌等待,别把人家网站搞崩了
time.sleep(1)
except Exception as e:
print(f"抓取 {list_url} 时出错:{e}")
continue
return all_articles
# 试试抓取
if __name__ == "__main__":
# 这里换成你实际想抓取的网站
test_url = "https://example-tech-news.com"
articles = fetch_news_list(test_url, max_pages=2)
print(f"共找到 {len(articles)} 篇文章")
for i, art in enumerate(articles[:3]): # 只显示前3篇
print(f"{i+1}. {art['title']}")
print(f" 链接:{art['url']}")
3.2 清洗和整理文章内容
拿到文章链接后,我们需要抓取正文内容,并进行清洗。清洗包括去除无关的HTML标签、广告、导航栏等,只保留核心正文。
# crawler.py 继续添加
def fetch_article_content(article_url):
"""抓取单篇文章的正文内容"""
headers = {'User-Agent': 'Mozilla/5.0 ...'}
try:
resp = requests.get(article_url, headers=headers, timeout=10)
resp.raise_for_status()
soup = BeautifulSoup(resp.content, 'html.parser')
# 1. 移除没用的标签
for tag in soup(["script", "style", "nav", "footer", "aside", "header"]):
tag.decompose()
# 2. 找到文章正文(这需要根据具体网站调整)
# 通常正文在 <article> 或 <div class="content"> 里
content_elem = soup.find('article') or soup.find('div', class_='content')
if not content_elem:
print(f"找不到正文:{article_url}")
return None
# 3. 提取纯文本
raw_text = content_elem.get_text(separator=' ', strip=True)
# 清理多余的空格和换行
cleaned_text = ' '.join(raw_text.split())
return cleaned_text
except Exception as e:
print(f"抓取文章失败 {article_url}:{e}")
return None
def split_into_chunks(text, chunk_size=600, overlap=80):
"""
把长文章切成小段
chunk_size: 每段多少字
overlap: 段与段之间重叠多少字(保持上下文连贯)
"""
chunks = []
start = 0
text_length = len(text)
while start < text_length:
end = start + chunk_size
chunk = text[start:end]
chunks.append(chunk)
start += (chunk_size - overlap) # 移动起始位置
return chunks
# 测试一下
if __name__ == "__main__":
# 假设我们有一篇文章
test_article = {
'title': '测试文章',
'url': 'https://example.com/article'
}
print(f"处理文章:{test_article['title']}")
content = fetch_article_content(test_article['url'])
if content:
print(f"文章长度:{len(content)} 字")
chunks = split_into_chunks(content, chunk_size=600, overlap=80)
print(f"切成了 {len(chunks)} 段")
for i, chunk in enumerate(chunks[:2]): # 显示前两段
print(f"\n--- 第 {i+1} 段(前100字)---")
print(chunk[:100] + "...")
3.3 把内容存到知识库里
清洗切好的文本片段,需要转换成向量才能存到向量数据库里。
# knowledge_base.py
import hashlib
from sentence_transformers import SentenceTransformer
import chromadb
def create_document_id(text):
"""为每段文字生成一个唯一的ID"""
return hashlib.md5(text.encode()).hexdigest()
def add_to_knowledge_base(chunks, metadata_list, collection, embedding_model):
"""
把文本片段添加到知识库
chunks: 文本片段列表
metadata_list: 对应的元数据列表(比如来源信息)
"""
if not chunks:
print("没有内容可添加")
return
print("正在生成文本向量...")
# 把文字转换成向量
embeddings = embedding_model.encode(chunks).tolist()
# 生成ID
ids = [create_document_id(chunk) for chunk in chunks]
print(f"正在保存 {len(chunks)} 个片段...")
# 保存到数据库
collection.add(
embeddings=embeddings, # 向量
documents=chunks, # 原始文本
metadatas=metadata_list, # 元数据
ids=ids # 唯一ID
)
print("保存完成!")
def build_knowledge_base_from_articles(article_list):
"""
完整的建库流程
"""
# 初始化
embed_model = SentenceTransformer('paraphrase-multilingual-MiniLM-L12-v2')
client = chromadb.PersistentClient(path="./chroma_db")
collection = client.get_or_create_collection(name="ai_news")
all_chunks = []
all_metadata = []
print("开始构建知识库...")
for article in article_list[:10]: # 先处理前10篇
print(f"处理:{article['title']}")
content = fetch_article_content(article['url'])
if not content:
continue
# 切分文章
chunks = split_into_chunks(content)
# 为每个片段准备元数据
for chunk in chunks:
all_chunks.append(chunk)
all_metadata.append({
"title": article['title'],
"url": article['url'],
"source": "tech_news"
})
# 保存到知识库
if all_chunks:
add_to_knowledge_base(all_chunks, all_metadata, collection, embed_model)
print(f"知识库构建完成!共添加 {len(all_chunks)} 个文本片段")
else:
print("没有成功处理任何文章")
# 使用示例
if __name__ == "__main__":
# 假设我们已经抓取了一些文章
# articles = fetch_news_list("https://example.com", max_pages=3)
# build_knowledge_base_from_articles(articles)
print("知识库构建模块就绪")
你可以把上面的抓取和建库流程写成脚本,然后用系统的定时任务工具(比如Linux的cron或Windows的“任务计划程序”)定期执行,这样知识库就能自动更新了。
4. 实现智能问答:让助理开始工作
知识库建好了,现在来实现系统的“思考”部分。这个部分负责接收你的问题,从知识库里找到相关资料,然后指挥通义千问模型生成答案。
4.1 从知识库查找相关资料
当您提出一个问题时,我们首先将这个问题转换成向量,然后在向量数据库中进行相似度搜索,找出最相关的几个文本片段。
# assistant_core.py
def search_relevant_docs(question, collection, embedding_model, top_k=4):
"""
根据问题查找相关资料
top_k: 返回最相关的几个片段
"""
# 把问题转换成向量
question_vector = embedding_model.encode([question]).tolist()
# 在知识库里搜索
results = collection.query(
query_embeddings=question_vector,
n_results=top_k,
include=["documents", "metadatas", "distances"]
)
# 提取结果
found_docs = results['documents'][0] if results['documents'] else []
found_meta = results['metadatas'][0] if results['metadatas'] else []
return found_docs, found_meta
# 测试搜索功能
def test_search():
# 初始化
embed_model = SentenceTransformer('paraphrase-multilingual-MiniLM-L12-v2')
client = chromadb.PersistentClient(path="./chroma_db")
collection = client.get_collection(name="ai_news")
# 测试问题
test_question = "深度学习最近有什么新应用?"
print(f"搜索问题:{test_question}")
docs, metas = search_relevant_docs(test_question, collection, embed_model, top_k=2)
if docs:
print(f"找到 {len(docs)} 个相关片段:")
for i, (doc, meta) in enumerate(zip(docs, metas)):
print(f"\n--- 片段 {i+1} ---")
print(f"来自:{meta.get('title', '未知')}")
print(f"内容:{doc[:200]}...") # 只显示前200字
else:
print("没找到相关资料")
if __name__ == "__main__":
test_search()
4.2 让模型基于资料回答问题
找到相关资料后,我们需要设计一个“提问模板”,把问题、找到的资料以及回答要求组合起来,交给通义千问模型。
# assistant_core.py 继续
from transformers import AutoTokenizer, AutoModelForCausalLM
import torch
def create_question_template(question, context_chunks):
"""
创建提问模板
"""
# 把找到的多个片段合并
context = "\n\n".join([f"[资料 {i+1}]: {chunk}" for i, chunk in enumerate(context_chunks)])
# 通义千问专用的对话格式
template = f"""<|im_start|>system
你是一个专业的AI信息助手。请严格根据提供的参考资料来回答问题。
如果资料里没有相关信息,请直接说“根据现有资料,没有找到相关信息”,不要自己编造答案。
参考资料如下:
{context}
<|im_end|>
<|im_start|>user
{question}
<|im_end|>
<|im_start|>assistant
"""
return template
def generate_response(template, model, tokenizer, max_length=500):
"""让模型生成回答"""
inputs = tokenizer(template, return_tensors="pt").to(model.device)
with torch.no_grad():
outputs = model.generate(
**inputs,
max_new_tokens=max_length,
temperature=0.7, # 控制回答的随机性,0.7比较平衡
do_sample=True,
top_p=0.9,
pad_token_id=tokenizer.pad_token_id,
eos_token_id=tokenizer.eos_token_id
)
# 解码结果
full_text = tokenizer.decode(outputs[0], skip_special_tokens=True)
# 提取助手的回答部分
response = full_text.split("<|im_start|>assistant")[-1].strip()
return response
def ask_question(question, model, tokenizer, collection, embedding_model):
"""
完整的问答流程
"""
print(f"问题:{question}")
# 1. 搜索资料
print("正在搜索相关资料...")
relevant_docs, _ = search_relevant_docs(question, collection, embedding_model, top_k=3)
if not relevant_docs:
return "抱歉,在知识库里没找到相关信息。"
# 2. 创建提问模板
template = create_question_template(question, relevant_docs)
# 3. 生成回答
print("正在生成回答...")
answer = generate_response(template, model, tokenizer)
return answer
# 初始化整个系统
def init_assistant_system():
"""初始化所有组件"""
print("正在加载模型...")
tokenizer = AutoTokenizer.from_pretrained("Qwen/Qwen1.5-1.8B-Chat-GPTQ-Int4")
model = AutoModelForCausalLM.from_pretrained(
"Qwen/Qwen1.5-1.8B-Chat-GPTQ-Int4",
torch_dtype=torch.float16,
device_map="auto",
trust_remote_code=True
)
print("正在加载文本处理模型...")
embed_model = SentenceTransformer('paraphrase-multilingual-MiniLM-L12-v2')
print("正在连接知识库...")
client = chromadb.PersistentClient(path="./chroma_db")
collection = client.get_collection(name="ai_news")
print("系统初始化完成!")
return model, tokenizer, collection, embed_model
# 测试问答
if __name__ == "__main__":
print("启动问答系统...")
model, tokenizer, collection, embed_model = init_assistant_system()
test_question = "机器学习在医疗领域有什么新应用?"
answer = ask_question(test_question, model, tokenizer, collection, embed_model)
print("\n" + "="*60)
print("回答:")
print(answer)
print("="*60)
4.3 创建网页界面
最后,我们需要一个友好的界面。用 Gradio 可以快速搭建一个Web界面。
# web_ui.py
import gradio as gr
from assistant_core import init_assistant_system, ask_question
import logging
# 设置日志
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)
# 全局变量,避免重复加载
MODEL = None
TOKENIZER = None
COLLECTION = None
EMBED_MODEL = None
def init_system():
"""初始化系统(只执行一次)"""
global MODEL, TOKENIZER, COLLECTION, EMBED_MODEL
if MODEL is None:
try:
logger.info("正在加载系统,请稍候...")
MODEL, TOKENIZER, COLLECTION, EMBED_MODEL = init_assistant_system()
logger.info("系统加载完成!")
except Exception as e:
logger.error(f"加载失败:{e}")
return False
return True
def handle_question(question, chat_history):
"""处理用户提问"""
if not init_system():
return chat_history, "系统初始化失败,请检查日志。"
if not question.strip():
return chat_history, "请输入问题。"
# 获取回答
answer = ask_question(question, MODEL, TOKENIZER, COLLECTION, EMBED_MODEL)
# 添加到对话历史
chat_history.append((question, answer))
return chat_history, ""
# 创建网页界面
with gr.Blocks(title="个人信息助手", theme=gr.themes.Soft()) as app:
gr.Markdown("# 🎯 个人专属信息助手")
gr.Markdown("基于通义千问1.8B + 自定义知识库")
gr.Markdown("我可以回答AI、科技等相关问题,回答都基于最新的网络资料。")
# 聊天区域
chatbot = gr.Chatbot(label="对话", height=400)
# 输入框
question_input = gr.Textbox(
label="输入问题",
placeholder="例如:最近有什么新的AI技术发布?",
lines=2
)
# 按钮
submit_btn = gr.Button("发送", variant="primary")
clear_btn = gr.Button("清空对话")
# 绑定事件
def respond(message, history):
new_history, _ = handle_question(message, history)
return "", new_history
# 按回车或点按钮都可以发送
question_input.submit(respond, [question_input, chatbot], [question_input, chatbot])
submit_btn.click(respond, [question_input, chatbot], [question_input, chatbot])
# 清空对话
clear_btn.click(lambda: [], None, chatbot)
# 启动服务
if __name__ == "__main__":
# 在本地7860端口启动
app.launch(server_name="0.0.0.0", server_port=7860, share=False)
# 如果要生成公开链接,可以设置 share=True
运行 python web_ui.py,然后在浏览器中打开 http://localhost:7860,你就能看到一个简洁的聊天界面,可以开始向你的个人信息助手提问了。
5. 让系统更好用:优化建议
一个能跑起来的系统只是开始。要让这个系统真正好用、可靠,还需要考虑一些优化点。
知识库质量是关键。爬虫抓取的内容需要仔细清洗,确保没有无关文本(如广告、侧边栏推荐)。选择信息源时,要优先考虑权威性和更新频率。对于抓取到的内容,可以设计一些简单的规则进行过滤,比如过滤掉字数太少、包含大量无关关键词的页面。
搜索效果需要调整。top_k(返回片段数量)是一个重要参数。太少可能信息不全,太多则可能引入噪声并增加模型负担,一般3-5个片段比较合适。文本切割的chunk_size和overlap也需要根据你处理的文章类型调整。科技新闻可能适合500-800字的片段,而技术报告可能需要更长。
提问方式影响回答质量。我们在create_question_template函数中设计的系统指令很关键。你可以调整指令,让模型以更简洁或更详细的方式回答,或者要求它在答案末尾注明参考来源。如果发现模型偶尔还是会“瞎编”,可以加强指令,例如:“你必须且只能根据提供的参考资料回答。资料中没提过的内容,绝对不要猜测或编造。”
性能与资源考虑。通义千问1.5-1.8B-Chat-GPTQ-Int4模型本身资源占用很低。主要的性能瓶颈可能在搜索速度(如果知识库非常大)和模型生成速度上。对于百万级以上的文档,可能需要考虑更专业的向量数据库(如Milvus、Qdrant)和索引算法。定期清理知识库中的过期信息,也能提升搜索效率。
扩展应用场景。这个框架非常灵活。只需更换爬虫的目标网站和关键词,你就可以轻松构建其他领域的助手,比如:
- 科技股资讯:抓取财经科技板块新闻,回答公司动态、股价影响因素
- 开源项目追踪:监控GitHub Trending、特定技术社区,了解最新热门项目
- 行业法规跟踪:针对金融、医疗等行业,抓取官方机构发布的法规文件,提供合规问答
- 内部知识管理:将公司内部的文档、Wiki、会议纪要索引起来,做成一个智能内部知识库
6. 总结
整体搭建和测试下来,这套基于通义千问1.5-1.8B-Chat-GPTQ-Int4和检索增强生成技术的方案,确实能有效构建一个可信赖的个人信息助手。它最大的优势在于平衡了成本、效果和可控性。
模型本身小巧高效,而外接的知识库让你能牢牢把控信息的来源和质量,从根本上减少了模型胡说八道的可能。整个方案对硬件要求不高,大部分消费级显卡都能流畅运行。
实现过程中,最花时间的部分可能在于针对目标网站编写健壮的爬虫,以及调试搜索的相关性。一旦核心流程跑通,剩下的就是持续优化和扩展。
如果你正准备为自己关注的领域打造一个信息利器,不妨就从今天这个原型开始。从抓取几个你信任的网站开始,慢慢完善你的知识库。随着时间推移,你的助手会越来越了解你关心的领域,给出的回答也会越来越精准。
记住,好的工具都是迭代出来的。先让系统跑起来,然后根据实际使用中的反馈,一点点调整和优化。很快你就会发现,有一个专属的信息助手,工作效率和信息获取质量都会提升不少。
获取更多AI镜像
想探索更多AI镜像和应用场景?访问 CSDN星图镜像广场,提供丰富的预置镜像,覆盖大模型推理、图像生成、视频生成、模型微调等多个领域,支持一键部署。
更多推荐



所有评论(0)