Llama 3与Shell结合:打造强大的问答系统系统

云信安装大师
90
AI 质量分
10 5 月, 2025
5 分钟阅读
0 阅读

Llama 3与Shell结合:打造强大的问答系统

引言

在AI技术快速发展的今天,大型语言模型如Llama 3为我们提供了强大的自然语言处理能力。本文将介绍如何将Llama 3与Shell脚本结合,创建一个简单但功能强大的命令行问答系统。这种组合特别适合需要在服务器环境或自动化脚本中使用AI能力的开发者。

准备工作

在开始之前,请确保你已准备好以下环境:

  1. 安装了Python 3.8或更高版本
  2. 有可用的GPU(可选,但能显著提升性能)
  3. 基本的Linux/Unix Shell使用知识
  4. 至少16GB内存(运行Llama 3-8B的最低要求)

步骤1:安装Llama 3

首先我们需要安装Llama 3模型。我们将使用Hugging Face的transformers库来加载模型。

代码片段
# 创建项目目录并进入
mkdir llama3-shell && cd llama3-shell

# 创建Python虚拟环境
python -m venv venv
source venv/bin/activate

# 安装必要的Python包
pip install torch transformers sentencepiece

步骤2:创建Python问答脚本

创建一个名为llama_qa.py的Python脚本:

代码片段
#!/usr/bin/env python3
from transformers import AutoTokenizer, AutoModelForCausalLM
import sys

# 加载Llama 3模型和分词器
model_id = "meta-llama/Meta-Llama-3-8B-Instruct"
tokenizer = AutoTokenizer.from_pretrained(model_id)
model = AutoModelForCausalLM.from_pretrained(model_id)

def get_answer(question):
    # 构建提示词
    prompt = f"""<|begin_of_text|><|start_header_id|>system<|end_header_id|>
    你是一个有帮助的AI助手。<|eot_id|>
    <|start_header_id|>user<|end_header_id|>
    {question}<|eot_id|>
    <|start_header_id|>assistant<|end_header_id|>"""

    # Tokenize输入
    inputs = tokenizer(prompt, return_tensors="pt")

    # 生成回答
    outputs = model.generate(
        inputs["input_ids"],
        max_new_tokens=512,
        do_sample=True,
        temperature=0.7,
        top_p=0.9,
    )

    # Decode并返回回答
    answer = tokenizer.decode(outputs[0], skip_special_tokens=True)

    # 移除提示词部分,只保留回答内容
    return answer.split("<|start_header_id|>assistant<|end_header_id|>")[-1].strip()

if __name__ == "__main__":
    if len(sys.argv) < 2:
        print("请提供一个问题作为参数")
        sys.exit(1)

    question = " ".join(sys.argv[1:])
    print(get_answer(question))

代码解释:

  1. 模型加载:我们使用Hugging Face的AutoTokenizerAutoModelForCausalLM来加载Llama 3-8B-Instruct模型。
  2. 提示词构建:按照Llama 3的特殊格式构建提示词,包含system、user和assistant部分。
  3. 生成参数
    • max_new_tokens:限制生成的最大token数
    • do_sample:启用随机采样而非贪婪解码
    • temperature:控制生成的随机性(0.7是平衡值)
    • top_p:核采样参数,限制候选token的范围

步骤3:创建Shell包装脚本

为了使问答系统更易用,我们创建一个Shell脚本qa.sh

代码片段
#!/bin/bash

# 检查是否提供了问题参数
if [ $# -eq 0 ]; then
    echo "使用方法: ./qa.sh '你的问题'"
    exit 1
fi

# Python脚本路径(假设在同一目录下)
PY_SCRIPT="./llama_qa.py"

# 检查Python脚本是否存在
if [ ! -f "$PY_SCRIPT" ]; then
    echo "错误: $PY_SCRIPT不存在"
    exit 1
fi

# 执行Python脚本并显示结果(带格式化)
echo "问题: $@"
echo "----------------------------------------"
python "$PY_SCRIPT" "$@"
echo "----------------------------------------"

给脚本添加执行权限:

代码片段
chmod +x qa.sh chmod +x llama_qa.py 

步骤4:测试问答系统

现在你可以通过以下方式测试你的问答系统:

代码片段
./qa.sh "如何用Python读取文件?"
./qa.sh "解释一下量子计算的基本原理"
./qa.sh "写一个快速排序的Java实现"

(可选)步骤5:性能优化建议

如果你的系统资源有限,可以考虑以下优化:

  1. 量化模型
代码片段
model = AutoModelForCausalLM.from_pretrained(model_id, load_in_8bit=True)
  1. 使用更小的模型
代码片段
model_id = "meta-llama/Meta-Llama-3-8B-Instruct" 
# Llama也提供70B、13B和更小的版本可选 
  1. 缓存模型
    第一次运行后,模型会被缓存到~/.cache/huggingface/hub/目录下,后续运行会更快。

(可选)步骤6:添加对话历史功能

修改Python脚本以支持多轮对话:

代码片段
conversation_history = []

def get_answer(question):
    global conversation_history

    # 添加新问题到对话历史中 
    conversation_history.append(f"用户: {question}")

    # 构建完整的对话上下文 
    context = "\n".join(conversation_history)

    prompt = f"""<|begin_of_text|><|start_header_id|>system<|end_header_id|>
    你是一个有帮助的AI助手。请基于以下对话历史回答问题:

    对话历史:
{context}<|eot_id|<|start_header_id|>assistant<|end_header_id|>"""

    inputs = tokenizer(prompt, return_tensors="pt")

    outputs = model.generate(
        inputs["input_ids"],
        max_new_tokens=512,
        do_sample=True,
        temperature=0.7,
        top_p=0.9,
    )

    answer = tokenizer.decode(outputs[0], skip_special_tokens=True)

    提取回答部分 
response_part = answer.split("<|start_header_id|>assistant<|end_header_id|>")[-1].strip()
conversation_history.append(f"助手: {response_part}")
return response_part 

(可选)步骤7:添加交互模式

修改Shell脚本以支持交互式会话:

代码片段
#!/bin/bash 

PY_SCRIPT="./llama_qa.py"

echo "Llama问答系统 (输入'exit'退出)"
echo "----------------------------------------"

while true; do 
read -p "你的问题: " question

if [[ "$question" == "exit" ]]; then 
break 
fi

echo "----------------------------------------"
python "$PY_SCRIPT" "$question"
echo "----------------------------------------"
done 

echo ""
echo "感谢使用Llama问答系统!"

(可选)步骤8:部署为系统命令

如果你想在任何地方都能使用这个问答工具:

代码片段
sudo ln -s $(pwd)/qa.sh /usr/local/bin/llama-qa 

然后就可以在任何地方使用:
llama-qa "你的问题" 

或者进入交互模式:
llama-qa --interactive 

(可选)步骤9:添加日志记录功能

修改Shell脚本以记录问题和答案:

代码片段
LOG_FILE="qa_log.txt"

log_message() {
timestamp=$(date "+%Y-%m-%d %H:%M:%S")
echo "[$timestamp] $@" | tee -a "$LOG_FILE"
}

log_message "问题: $@"
response=$(python "$PY_SCRIPT" "$@")
log_message "回答: $response"

echo "$response" 

这样所有问题和答案都会被记录到 qa_log.txt文件中。

(可选)步骤10:添加Markdown格式输出

如果你希望输出更适合阅读的格式:

修改Python脚本中的输出部分:

代码片段
def format_markdown(text):
import re 
text = re.sub(r'^\*\*(.*?)\*\*', r'\n### \1\n', text, flags=re.MULTILINE)
text = re.sub(r'\*(.*?)\*', r'**\1**', text)
text = re.sub(r'^\s*-\s*(.*)', r'- \1', text, flags=re.MULTILINE)
return text 

print(format_markdown(get_answer(question)))

这样代码块、列表和标题会以Markdown格式显示。

(可选)步骤11:添加流式输出

对于长回答,可以逐字显示结果以获得更好的用户体验:

修改Python脚本:

代码片段
from transformers import TextStreamer 

def get_answer_streaming(question):
prompt = f"""...""" # same as before 

inputs = tokenizer(prompt, return_tensors="pt") 

streamer = TextStreamer(tokenizer) 

outputs = model.generate(
inputs["input_ids"], 
max_new_tokens=512,
do_sample=True,
temperature=0.7,
top_p=0.9,
streamer=streamer )

answer_token_ids = outputs[0][len(inputs["input_ids"][0]):]
return tokenizer.decode(answer_token_ids, skip_special_tokens=True) 

然后在主函数中调用get_answer_streaming而不是get_answer。

(可选)步骤12:添加API服务模式

如果你想将问答系统作为HTTP服务:

创建api_server.py:

代码片段
from flask import Flask, request, jsonify 
from llama_qa import get_answer 

app Flask(__name__)

@app.route('/ask', methods=['POST']) def ask():
data request.get_json() question data.get('question', '') if not question:
return jsonify({'error': 'No question provided'}),400 answer get_answer(question) return jsonify({'answer': answer}) if __name__ '__main__':
app.run(host='0.0.0.0', port=5000)

然后可以通过curl或任何HTTP客户端发送请求:

curl -X POST http://localhost:5000/ask \
-H Content-Type application/json \
-d ‘{“question”:”如何学习编程?”}’

这将返回JSON格式的回答。

代码片段

## (可选)步骤13:添加RAG功能 (检索增强生成)  

要结合外部知识库增强回答质量:

首先安装必要的包:

pip install langchain faiss-cpu sentence-transformers  

然后修改get_answer函数:

```python  
from langchain.document_loaders import DirectoryLoader from langchain.text_splitter RecursiveCharacterTextSplitter from langchain.embeddings HuggingFaceEmbeddings from langchain.vectorstores FAISS  

def load_knowledge_base(): loader DirectoryLoader('./knowledge_base/', glob="*.txt") documents loader.load() text_splitter RecursiveCharacterTextSplitter(chunk_size100 chunk_overlap20) texts text_splitter.split_documents(documents) embeddings HuggingFaceEmbeddings(model_name"sentence-transformers/all-mpnet-base-v2") db FAISS.from_documents(texts embeddings) return db  

db load_knowledge_base()  

def get_answer_with_rag(question): docs db.similarity_search(question k2) context "\n".join([doc.page_content for doc docs]) prompt f"""基于以下上下文回答问题:\n{context}\n\n问题:{question}\n\n回答:""" ... rest same as before  

这样回答会先检索相关知识库中最相关的文档片段作为上下文。

代码片段
现在你需要创建一个knowledge_base目录并放入一些文本文件作为知识来源。

mkdir knowledge_base echo这是一个示例知识文件 > knowledge_base/doc1.txt

每次提问时系统会先查找相关知识片段再生成回答。

这显著提高了回答的专业性和准确性特别是在特定领域问题上。

注意知识库文件应该是纯文本格式(.txt)。

代码片段
为了保持知识库更新你可以添加一个自动更新机制例如定期从某个URL下载最新资料解压到knowledge_base目录中。

下面是一个自动更新知识库的Shell函数可以添加到你的qa.sh中:

updateknowledge() {
KNOWLEDGE
URL=”https://example.com/knowledgebase.zip” TEMPZIP=”/tmp/knowledge_update.zip”

echo正在更新知识库…
wget -O $TEMPZIP $KNOWLEDGEURL unzip -o $TEMPZIP -d ./knowledgebase/ rm $TEMP_ZIP echo知识库更新完成 }

然后在主菜单中添加一个选项来触发更新。这需要你有一个定期更新的知识库压缩包托管在某个URL上。

对于企业环境你可以设置一个cron作业定期自动更新知识库而不需要手动干预。

代码片段
最后为了确保所有组件正常工作我们可以编写一个简单的测试用例:

test_qa_system() {
echo测试简单问题...
./qa.sh你好吗 > /dev/null && echo测试通过 || echo测试失败 echo测试长问题...
./qa.sh请详细解释人工智能的历史发展 > /dev/null && echo测试通过 || echo测试失败 echo测试RAG功能...
./qa.sh根据知识库内容我们的主要产品是什么 > /dev/null && echo测试通过 || echo测试失败 }

将上述函数添加到你的Shell脚本中然后可以通过运行test_qa_system来验证核心功能是否正常。

这有助于在部署后快速验证系统的健康状况特别是在自动更新或配置变更后。

为了进一步改进这个系统以下是几个高级扩展方向:

代码片段
多语言支持通过检测输入语言自动切换响应语言风格。可以使用langdetect包实现简单的语言检测。

情感分析在回答问题前先分析用户问题的情感倾向调整回答语气。可以使用VADER等情感分析工具。

权限控制对不同用户设置不同的访问权限和知识范围例如普通用户和管理员看到不同的答案版本。

审计日志记录所有用户问题和系统答案用于后续分析和改进特别是对错误答案的分析非常有价值。

缓存机制对常见问题缓存答案减少模型计算开销提高响应速度特别是对于频繁出现的类似问题。

这些高级功能可以根据实际需求逐步添加到系统中而不会影响核心功能的稳定性。

最后为了帮助其他开发者理解和使用这个项目建议创建一个详细的README.md文件包含:

代码片段
项目简介和主要功能特点快速开始指南包括安装和基本使用方法配置选项说明包括各种参数的调整方法API文档如果实现了HTTP服务接口贡献指南如何参与项目开发路线图计划中的未来功能变更日志各版本的更新内容常见问题解答特别是安装和使用中的典型问题解决方案许可证信息明确使用限制和授权方式这将使你的项目更加完整和专业便于团队协作和开源共享。

记住在实际部署时需要考虑的几个重要因素:
“`
安全性特别是如果开放为网络服务需要添加适当的认证和授权隐私保护确保不记录敏感信息性能优化根据硬件资源调整模型大小和参数可扩展性设计良好的架构以便未来轻松升级模型版本监控告警实施系统健康检查和异常通知维护计划制定定期的模型更新和数据清理策略这些工程化考虑将使你的问答系统更加健壮可靠适合生产环境使用而不仅仅是技术演示。

原创 高质量