大厂闭源模型越来越贵?这个开源项目让你免费玩转生成式AI,还能本地部署隐私无忧

大厂闭源模型越来越贵?这个开源项目让你免费玩转生成式AI,还能本地部署隐私无忧

大厂闭源模型越来越贵?这个开源项目让你免费玩转生成式AI,还能本地部署隐私无忧

前言

在AI浪潮席卷全球的今天,生成式AI已经成为技术圈最炙手可热的话题。从ChatGPT到Claude,从Midjourney到Stable Diffusion,每一次技术突破都在刷新我们对人工智能的认知。然而,随之而来的不仅是技术的革新,还有令人望而却步的使用成本。API调用费用按token计费,GPT-4的调用成本屡创新高,对于个人开发者和小型团队来说,动辄几百美元的月账单已经成为不可承受之重。

就在这样的背景下,一个名为 Open-Generative-AI 的开源项目悄然崛起。这个由社区驱动的项目致力于打造一个免费、开源、本地化的生成式AI解决方案,让每一个对AI感兴趣的开发者都能零门槛地进入这个领域。无论你是想快速验证想法的创业者,还是希望保护数据隐私的企业开发者,亦或是想要深入学习AI原理的学生,这个项目都能满足你的需求。

本文将带你深入了解这个项目的每一个细节,从环境搭建到高级应用,从基础功能到最佳实践,用最详细的步骤和最丰富的代码示例,帮你真正掌握这个强大的开源工具。


第一部分:为什么值得关注

1.1 解决痛点:让AI不再高高在上

在深入了解这个项目之前,我们先来思考一个根本性的问题:为什么我们需要关注又一个开源的生成式AI项目?

答案很简单,因为现有的解决方案都存在明显的局限性。商业闭源模型虽然效果出色,但存在三个核心问题:首先是成本高昂,以OpenAI的GPT-4为例,1000个输入token就要花费0.03美元,生成式AI应用往往需要频繁调用,成本会迅速失控;其次是数据隐私,当你把用户数据发送给第三方API服务器时,就意味着这些数据不再完全受你控制,这对于处理敏感信息的企业来说是不可接受的;最后是可用性问题,网络延迟、服务中断、地区限制等因素都会影响应用的稳定性。

而传统的开源方案虽然免费且可本地部署,但往往存在配置复杂、性能有限、文档缺失等问题,让很多初学者望而却步。Open-Generative-AI项目正是针对这些痛点而设计的,它在保证功能完整性的同时,特别注重用户体验和文档建设,让零基础的用户也能快速上手。

1.2 项目的核心优势

经过深入研究,我们发现这个项目具备以下几个显著优势:

完全开源透明:整个项目采用MIT许可证开源,你可以自由地查看、修改、部署每一个组件。更重要的是,开源意味着你可以完全理解系统的运作原理,不会被黑盒模型所困扰。这种透明性对于需要审计和合规的企业应用来说尤为重要。

本地部署能力:项目支持完整的本地部署方案,你可以在自己的服务器甚至个人电脑上运行模型。这意味着你的数据永远不会离开你的设备,真正实现了数据主权。对于医疗、金融、法律等对数据安全要求极高的行业,这是一个不可替代的优势。

统一的API接口:项目提供了一致的API接口设计,与主流商业API(如OpenAI的API)高度兼容。这意味着你可以几乎不修改代码,就在开源方案和商业方案之间切换,大大降低了迁移成本和供应商锁定风险。

活跃的社区生态:项目拥有一个活跃的开发者社区,持续贡献新的模型、优化性能和丰富文档。你可以在这里找到大量的使用案例、教程和解决方案,遇到问题时也能得到社区的帮助。

1.3 适用人群分析

这个项目特别适合以下几类用户:

个人开发者和独立创作者:你可能有一个绝妙的AI应用创意,但预算有限。通过这个项目,你可以零成本地开始开发和测试你的想法,等产品成熟后再考虑是否需要升级到商业方案。

学生和教育工作者:学习AI最好的方式就是动手实践,而不是只阅读理论。这个项目提供了丰富的实践机会,你可以在本地环境中尝试各种模型,理解它们的工作原理,为未来的深入研究打下坚实基础。

中小型企业:对于不需要处理超大规模请求的企业来说,本地部署的开源方案可能比购买商业API更加经济实惠。而且完整的数据控制能力对于满足合规要求至关重要。

AI研究者:开源项目是学术研究的重要基础。你可以自由地修改模型、尝试新的训练方法、与其他研究者分享成果,推动整个领域的发展。


第二部分:环境搭建

2.1 系统要求

在开始安装之前,我们需要确保你的系统满足基本要求。这个项目主要使用Python开发,兼容Python 3.8到3.11版本。对于不同的使用场景,硬件配置建议如下:

轻量级使用场景(模型调用、API服务、小规模实验):推荐至少8GB内存,建议16GB;需要至少10GB的可用磁盘空间用于存储模型文件;显卡可选,但如果要运行本地模型推理,建议有NVIDIA显卡以提升性能。

生产环境部署:推荐至少16GB内存,建议32GB或以上;SSD存储至少100GB,用于存储多个模型和缓存数据;强烈建议配置NVIDIA显卡,显存至少8GB,运行量化模型可以在一定程度上降低要求。

GPU加速配置(可选但推荐):需要NVIDIA显卡,计算能力3.5及以上;需要安装CUDA 11.7或更高版本;需要安装cuDNN 8.x或更高版本。

2.2 基础环境安装

让我们从最基础的Python环境开始。假设你的系统还没有配置Python开发环境,我们将一步步引导你完成所有准备工作。

首先,你需要安装Python。推荐使用Anaconda或Miniconda来管理Python环境,这样可以避免系统Python的版本冲突问题。访问 https://docs.conda.io/en/main/miniconda.html 下载适合你操作系统的安装包。安装完成后,打开终端(Windows用户使用Anaconda Prompt),执行以下命令创建一个新的虚拟环境:

# 创建一个名为openai的虚拟环境,指定Python版本为3.10
conda create -n openai python=3.10

# 激活这个虚拟环境
conda activate openai

如果你更习惯使用venv,这也是一个不错的选择:

# 创建虚拟环境
python -m venv openai_env

# 激活虚拟环境
# Windows系统
openai_env\Scripts\activate
# Linux或macOS系统
source openai_env/bin/activate

环境创建完成后,我们来安装项目的依赖包。首先克隆项目仓库:

# 克隆项目仓库
git clone https://github.com/Anil-matcha/Open-Generative-AI.git

# 进入项目目录
cd Open-Generative-AI

然后查看项目的依赖文件,通常是requirements.txt或pyproject.toml:

# 如果使用requirements.txt
pip install -r requirements.txt

# 或者如果使用pyproject.toml和poetry
pip install poetry
poetry install

2.3 显卡驱动和CUDA配置

如果你计划运行本地模型推理,显卡加速是必不可少的。让我详细讲解如何配置GPU环境。

检查显卡驱动:首先确认你的NVIDIA显卡驱动已经正确安装。打开终端,执行以下命令:

nvidia-smi

如果安装成功,你应该能看到类似以下输出,显示你的显卡型号、驱动版本和CUDA版本。如果命令不存在或报错,说明驱动未正确安装。

安装CUDA Toolkit:访问NVIDIA官网 https://developer.nvidia.com/cuda-downloads 下载适合你操作系统的CUDA Toolkit。建议安装CUDA 11.7或11.8版本,这些版本有较好的兼容性。

# 下载CUDA安装包(以Ubuntu为例)
wget https://developer.download.nvidia.com/compute/cuda/repos/ubuntu2204/x86_64/cuda-ubuntu2204.pin
sudo mv cuda-ubuntu2204.pin /etc/apt/preferences.d/cuda-repository-pin-600
wget https://developer.download.nvidia.com/compute/cuda/11.8.0/local_installers/cuda-repo-ubuntu2204-11-8-local_11.8.0-520.61.05-1_amd64.deb
sudo dpkg -i cuda-repo-ubuntu2204-11-8-local_11.8.0-520.61.05-1_amd64.deb
sudo apt-get update
sudo apt-get install cuda

安装完成后,需要将CUDA添加到PATH环境变量:

# 临时添加到当前会话的PATH
export PATH=/usr/local/cuda-11.8/bin:$PATH
export LD_LIBRARY_PATH=/usr/local/cuda-11.8/lib64:$LD_LIBRARY_PATH

# 或者永久添加到~/.bashrc
echo 'export PATH=/usr/local/cuda-11.8/bin:$PATH' >> ~/.bashrc
echo 'export LD_LIBRARY_PATH=/usr/local/cuda-11.8/lib64:$LD_LIBRARY_PATH' >> ~/.bashrc
source ~/.bashrc

安装cuDNN:cuDNN是CUDA的深度神经网络库加速包,很多模型都需要它。从NVIDIA官网注册并下载cuDNN安装包后,按照以下步骤安装:

# 解压cuDNN包
tar -xf cudnn-linux-x86_64-8.x.x.x_cuda11.y-archive.tar.xz

# 复制文件到CUDA目录
sudo cp cuda/include/cudnn*.h /usr/local/cuda/include/
sudo cp cuda/lib64/libcudnn* /usr/local/cuda/lib64/
sudo chmod a+r /usr/local/cuda/include/cudnn*.h /usr/local/cuda/lib64/libcudnn*

2.4 验证安装

安装完成后,我们需要验证所有组件是否正确安装。创建一个验证脚本:

# 验证Python环境和基础依赖
import sys
print(f"Python版本: {sys.version}")
print(f"Python路径: {sys.executable}")

# 验证PyTorch安装
try:
    import torch
    print(f"\nPyTorch版本: {torch.__version__}")
    print(f"CUDA是否可用: {torch.cuda.is_available()}")
    if torch.cuda.is_available():
        print(f"CUDA版本: {torch.version.cuda}")
        print(f"GPU数量: {torch.cuda.device_count()}")
        print(f"GPU名称: {torch.cuda.get_device_name(0)}")
except ImportError:
    print("PyTorch未安装")

# 验证transformers库
try:
    import transformers
    print(f"\nTransformers版本: {transformers.__version__}")
except ImportError:
    print("Transformers未安装")

# 验证项目核心模块
try:
    import open_generative_ai
    print(f"\nOpen-Generative-AI已正确安装")
    print(f"版本: {open_generative_ai.__version__}")
except ImportError as e:
    print(f"\nOpen-Generative-AI导入失败: {e}")

运行这个验证脚本:

python verify_installation.py

如果所有组件都正确安装,你应该能看到完整的版本信息和配置状态。任何缺失或错误都会被清晰地报告出来。


第三部分:核心功能详解

3.1 项目架构概览

在深入使用之前,理解项目的整体架构非常重要。Open-Generative-AI项目采用了模块化的设计思想,主要由以下几个核心组件构成:

核心引擎层(Core Engine):这是整个项目的心脏,负责模型加载、推理执行和结果处理。它封装了底层的复杂逻辑,提供简洁统一的接口给上层调用。

API适配层(API Adapter):这一层实现了与OpenAI API完全兼容的接口定义,包括Chat completions、Completions、Embeddings等主要端点。这意味着你可以把项目中生成的代码无缝迁移到其他支持OpenAI接口的服务商,反之亦然。

模型管理层(Model Manager):负责模型的下载、缓存、版本管理和多模型协调。你可以轻松地在不同模型之间切换,或者同时运行多个模型实例。

工具扩展层(Tool Extensions):提供了丰富的扩展能力,包括函数调用(Function Calling)、插件系统、提示词模板管理等高级功能。

存储后端(Storage Backend):支持多种存储选项,包括本地文件系统、云存储服务等,方便管理和备份模型文件及配置。

3.2 文本生成功能

文本生成是最基础也是最核心的功能。项目支持多种文本生成模式,从简单的单轮问答到复杂的多轮对话,都能轻松实现。

基础文本补全:这是最直接的用法,给定一段文本开头,让模型续写后面的内容。这在写作辅助、代码补全、创意发想等场景非常有用。

# 首先导入核心模块
from open_generative_ai import OpenAIClient

# 初始化客户端
client = OpenAIClient(
    model="gpt-3.5-turbo",  # 可以指定任意支持的模型
    api_base="http://localhost:8000"  # 本地部署的地址
)

# 简单的文本补全
prompt = "在一个遥远的星系中,有一艘宇宙飞船正在穿越虫洞"
response = client.completions.create(
    prompt=prompt,
    max_tokens=200,  # 生成的最大token数
    temperature=0.7,  # 控制随机性,0-2之间,越高越随机
    top_p=0.9  # 核采样参数
)

print("生成的文本:")
print(response.choices[0].text)

聊天补全:现代AI助手主要使用聊天模式,它支持多轮对话上下文,能够进行更自然的人机交互。

# 使用聊天补全接口
messages = [
    {"role": "system", "content": "你是一位博学多才的历史老师,擅长用生动的故事讲解历史事件。"},
    {"role": "user", "content": "请给我讲讲秦始皇统一六国的故事。"},
    {"role": "assistant", "content": "好的,让我来为你讲述这个精彩的历史故事..."},
    {"role": "user", "content": "那他又为什么要焚书坑儒呢?"}
]

response = client.chat.completions.create(
    model="gpt-3.5-turbo",
    messages=messages,
    max_tokens=500,
    temperature=0.8
)

print("助手的回复:")
print(response.choices[0].message.content)

3.3 Embeddings向量化功能

文本向量化是现代AI应用的基础技术之一。它将文本转换为稠密的向量表示,使得计算机能够理解和比较文本的语义内容。这个功能在语义搜索、推荐系统、文本分类、聚类分析等场景中都有广泛应用。

from open_generative_ai import OpenAIClient
import numpy as np

# 初始化客户端
client = OpenAIClient(
    model="text-embedding-ada-002",  # 使用专门的嵌入模型
    api_base="http://localhost:8000"
)

# 获取单个文本的嵌入向量
text = "人工智能正在改变我们的生活方式和工作模式"
embedding = client.embeddings.create(
    input=text,
    model="text-embedding-ada-002"
)

# 提取向量结果
vector = embedding.data[0].embedding
print(f"嵌入向量维度: {len(vector)}")
print(f"向量前5个值: {vector[:5]}")

# 批量获取嵌入向量
texts = [
    "机器学习是人工智能的核心技术",
    "深度学习在图像识别领域取得了突破",
    "自然语言处理让人机交互更加自然",
    "计算机视觉使机器能够看懂世界"
]

embeddings = client.embeddings.create(
    input=texts,
    model="text-embedding-ada-002"
)

# 处理批量结果
for i, embedding_data in enumerate(embeddings.data):
    print(f"文本{i+1}的嵌入向量前5个值: {embedding_data.embedding[:5]}")

# 计算文本相似度(余弦相似度)
def cosine_similarity(vec1, vec2):
    """计算两个向量的余弦相似度"""
    vec1 = np.array(vec1)
    vec2 = np.array(vec2)
    return np.dot(vec1, vec2) / (np.linalg.norm(vec1) * np.linalg.norm(vec2))

# 比较前两个文本的相似度
similarity = cosine_similarity(
    embeddings.data[0].embedding,
    embeddings.data[1].embedding
)
print(f"\n文本1和文本2的余弦相似度: {similarity:.4f}")

3.4 函数调用(Function Calling)

函数调用是GPT系列模型的重要特性,它允许模型在生成回复时主动调用预定义的函数。这使得AI能够执行实际操作,如查询数据库、调用API、控制外部设备等,大大扩展了AI的应用范围。

from open_generative_ai import OpenAIClient
import json

# 定义可用的函数
functions = [
    {
        "name": "get_weather",
        "description": "获取指定城市的天气信息",
        "parameters": {
            "type": "object",
            "properties": {
                "city": {
                    "type": "string",
                    "description": "城市名称,如北京、上海、东京"
                },
                "unit": {
                    "type": "string",
                    "enum": ["celsius", "fahrenheit"],
                    "description": "温度单位"
                }
            },
            "required": ["city"]
        }
    },
    {
        "name": "search_hotels",
        "description": "搜索符合条件的酒店",
        "parameters": {
            "type": "object",
            "properties": {
                "city": {
                    "type": "string",
                    "description": "城市名称"
                },
                "min_price": {
                    "type": "number",
                    "description": "最低价格(元)"
                },
                "max_price": {
                    "type": "number",
                    "description": "最高价格(元)"
                }
            },
            "required": ["city"]
        }
    }
]

client = OpenAIClient(api_base="http://localhost:8000")

messages = [
    {"role": "user", "content": "我想去北京玩,帮我查一下那边酒店的價格,在300到800元之间的有哪些?"}
]

response = client.chat.completions.create(
    model="gpt-3.5-turbo",
    messages=messages,
    functions=functions,
    function_call="auto"  # 自动决定是否调用函数
)

# 检查是否有函数调用
message = response.choices[0].message

if message.function_call:
    # 解析函数调用
    function_name = message.function_call.name
    arguments = json.loads(message.function_call.arguments)

    print(f"模型决定调用函数: {function_name}")
    print(f"传入参数: {arguments}")

    # 这里模拟函数执行结果
    # 实际应用中,你需要实现真正的函数逻辑
    if function_name == "search_hotels":
        hotel_results = [
            {"name": "北京饭店", "price": 580, "rating": 4.5},
            {"name": "王府半岛酒店", "price": 750, "rating": 4.8},
            {"name": "北京希尔顿", "price": 620, "rating": 4.6}
        ]

        # 将函数结果返回给模型
        messages.append(message)  # 添加助手的函数调用消息

        # 模拟函数执行结果
        function_result_message = {
            "role": "function",
            "name": function_name,
            "content": json.dumps(hotel_results)
        }

        # 再次调用模型,让它根据函数结果生成回复
        messages.append(function_result_message)

        final_response = client.chat.completions.create(
            model="gpt-3.5-turbo",
            messages=messages
        )

        print("\n最终回复:")
        print(final_response.choices[0].message.content)
else:
    print("模型回复:")
    print(message.content)

3.5 流式输出(Streaming)

对于需要实时反馈的应用场景,如聊天机器人、内容生成工具等,流式输出可以显著提升用户体验。用户不需要等待整个响应生成完成,就能逐步看到AI的回复,这种即时反馈对于长文本生成尤为重要。

from open_generative_ai import OpenAIClient

client = OpenAIClient(api_base="http://localhost:8000")

# 启用流式输出
stream = client.chat.completions.create(
    model="gpt-3.5-turbo",
    messages=[
        {"role": "user", "content": "用三段话介绍一下人工智能的发展历史"}
    ],
    max_tokens=500,
    stream=True  # 启用流式输出
)

print("AI正在生成回复(流式输出):\n")

# 逐步接收并显示内容
full_response = ""
for chunk in stream:
    if chunk.choices and chunk.choices[0].delta.content:
        content = chunk.choices[0].delta.content
        full_response += content
        print(content, end="", flush=True)  # 实时打印,不换行

print("\n\n流式输出完成!")
print(f"总字数: {len(full_response)}")

3.6 多模态支持

随着技术的发展,单一模态已经不能满足日益增长的需求。这个项目还提供了多模态支持的能力,使得AI不仅能理解和生成文本,还能处理图像、音频等多种数据类型。

# 图像理解功能
from open_generative_ai import OpenAIClient
import base64

# 读取本地图片并转换为base64
def encode_image(image_path):
    with open(image_path, "rb") as image_file:
        return base64.b64encode(image_file.read()).decode('utf-8')

client = OpenAIClient(api_base="http://localhost:8000")

# 如果模型支持视觉功能,可以使用图片进行对话
try:
    image_base64 = encode_image("example_image.jpg")

    messages = [
        {
            "role": "user",
            "content": [
                {
                    "type": "text",
                    "text": "请描述这张图片的内容"
                },
                {
                    "type": "image_url",
                    "image_url": {
                        "url": f"data:image/jpeg;base64,{image_base64}"
                    }
                }
            ]
        }
    ]

    response = client.chat.completions.create(
        model="gpt-4-vision-preview",  # 需要支持视觉的模型
        messages=messages,
        max_tokens=300
    )

    print("图片描述:")
    print(response.choices[0].message.content)

except Exception as e:
    print(f"图像处理功能暂不可用: {e}")
    print("可能原因:1. 当前模型不支持视觉功能 2. 需要更新到支持多模态的模型版本")

第四部分:实战教程

4.1 教程一:构建本地文档问答系统

在这个实战教程中,我们将构建一个本地文档问答系统。这个系统可以让你上传自己的文档,然后针对这些文档提出问题,AI会基于文档内容给出准确的答案。这个系统在企业知识库、个人笔记管理、技术文档查询等场景都非常有用。

第一步:准备文档处理模块

# document_processor.py
# 文档处理模块,负责文档的加载、分割和向量化

import os
import json
from typing import List, Dict, Tuple
from pathlib import Path

class DocumentProcessor:
    """文档处理器,用于加载、分割和向量化文档"""

    def __init__(self, client, chunk_size: int = 500, chunk_overlap: int = 50):
        """
        初始化文档处理器

        Args:
            client: OpenAIClient实例
            chunk_size: 每个文本块的最大字符数
            chunk_overlap: 相邻文本块之间的重叠字符数
        """
        self.client = client
        self.chunk_size = chunk_size
        self.chunk_overlap = chunk_overlap
        self.documents = []
        self.chunks = []
        self.embeddings = []

    def load_text_file(self, file_path: str) -> str:
        """加载文本文件"""
        with open(file_path, 'r', encoding='utf-8') as f:
            return f.read()

    def load_markdown_file(self, file_path: str) -> str:
        """加载Markdown文件"""
        with open(file_path, 'r', encoding='utf-8') as f:
            return f.read()

    def load_pdf_file(self, file_path: str) -> str:
        """
        加载PDF文件
        注意:需要安装PyPDF2或pdfplumber库
        """
        try:
            import PyPDF2
            text = ""
            with open(file_path, 'rb') as f:
                reader = PyPDF2.PdfReader(f)
                for page in reader.pages:
                    text += page.extract_text() + "\n"
            return text
        except ImportError:
            print("请安装PyPDF2: pip install PyPDF2")
            raise

    def load_document(self, file_path: str) -> str:
        """根据文件扩展名自动选择加载方法"""
        path = Path(file_path)
        extension = path.suffix.lower()

        loaders = {
            '.txt': self.load_text_file,
            '.md': self.load_markdown_file,
            '.markdown': self.load_markdown_file,
            '.pdf': self.load_pdf_file
        }

        if extension not in loaders:
            raise ValueError(f"不支持的文件类型: {extension}")

        return loaders[extension](file_path)

    def split_text(self, text: str) -> List[str]:
        """将长文本分割成小块"""
        chunks = []
        start = 0

        while start < len(text):
            # 计算当前块的结束位置
            end = start + self.chunk_size

            # 如果不是最后一块,尝试在句子边界处分割
            if end < len(text):
                # 寻找最近的句子结束符
                for sep in ['。', '!', '?', '.', '!', '?', '\n']:
                    last_sep = text.rfind(sep, start, end)
                    if last_sep > start:
                        end = last_sep + 1
                        break

            # 提取文本块
            chunk = text[start:end].strip()
            if chunk:
                chunks.append(chunk)

            # 移动到下一个块(包含重叠部分)
            start = end - self.chunk_overlap

        return chunks

    def process_document(self, file_path: str, metadata: Dict = None) -> List[Dict]:
        """
        处理单个文档

        Args:
            file_path: 文档路径
            metadata: 文档的元数据信息

        Returns:
            处理后的文本块列表,每个块包含文本和元数据
        """
        print(f"正在加载文档: {file_path}")
        text = self.load_document(file_path)

        print("正在分割文档...")
        chunks = self.split_text(text)
        print(f"分割完成,共{len(chunks)}个文本块")

        # 为每个块添加元数据
        processed_chunks = []
        for i, chunk in enumerate(chunks):
            chunk_data = {
                "text": chunk,
                "metadata": metadata or {},
                "metadata"]["file_path"] = file_path,
                "metadata"]["chunk_index"] = i
            }
            processed_chunks.append(chunk_data)

        self.chunks.extend(processed_chunks)
        return processed_chunks

    def process_documents(self, file_paths: List[str]) -> List[Dict]:
        """批量处理多个文档"""
        all_chunks = []
        for path in file_paths:
            chunks = self.process_document(path)
            all_chunks.extend(chunks)
        return all_chunks

    def create_embeddings(self, show_progress: bool = True) -> List[List[float]]:
        """
        为所有文本块创建嵌入向量

        Returns:
            嵌入向量列表
        """
        print("正在创建嵌入向量...")

        all_embeddings = []
        total = len(self.chunks)

        # 批量处理以提高效率
        batch_size = 20

        for i in range(0, total, batch_size):
            batch = self.chunks[i:i+batch_size]
            texts = [chunk["text"] for chunk in batch]

            # 调用API获取嵌入向量
            response = self.client.embeddings.create(
                input=texts,
                model="text-embedding-ada-002"
            )

            for data in response.data:
                all_embeddings.append(data.embedding)

            if show_progress:
                progress = min(i + batch_size, total)
                print(f"进度: {progress}/{total}")

        self.embeddings = all_embeddings
        print(f"嵌入向量创建完成,共{len(all_embeddings)}个")

        return all_embeddings

    def save_index(self, file_path: str):
        """保存索引数据到文件"""
        index_data = {
            "chunks": self.chunks,
            "embeddings": self.embeddings
        }
        with open(file_path, 'w', encoding='utf-8') as f:
            json.dump(index_data, f, ensure_ascii=False)
        print(f"索引已保存到: {file_path}")

    def load_index(self, file_path: str):
        """从文件加载索引数据"""
        with open(file_path, 'r', encoding='utf-8') as f:
            index_data = json.load(f)
        self.chunks = index_data["chunks"]
        self.embeddings = index_data["embeddings"]
        print(f"索引已加载,共{len(self.chunks)}个文本块")

第二步:构建问答检索模块

# retrieval.py
# 问答检索模块,负责在文档中检索相关内容

import numpy as np
from typing import List, Dict, Tuple, Optional

class RetrievalEngine:
    """检索引擎,用于在文档中查找相关内容"""

    def __init__(self, chunks: List[Dict], embeddings: List[List[float]]):
        """
        初始化检索引擎

        Args:
            chunks: 文本块列表
            embeddings: 对应的嵌入向量列表
        """
        self.chunks = chunks
        self.embeddings = np.array(embeddings)
        self.dimension = self.embeddings.shape[1]

    def cosine_similarity(self, vec1: np.ndarray, vec2: np.ndarray) -> float:
        """计算两个向量的余弦相似度"""
        dot_product = np.dot(vec1, vec2)
        norm_product = np.linalg.norm(vec1) * np.linalg.norm(vec2)
        return dot_product / (norm_product + 1e-10)  # 防止除零

    def find_similar_chunks(
        self, 
        query: str, 
        query_embedding: List[float],
        top_k: int = 5,
        threshold: float = 0.0
    ) -> List[Tuple[Dict, float]]:
        """
        查找与查询最相似的文本块

        Args:
            query: 查询文本
            query_embedding: 查询的嵌入向量
            top_k: 返回的最相似块数量
            threshold: 相似度阈值,低于此值的块将被过滤

        Returns:
            (文本块, 相似度)元组列表,按相似度降序排列
        """
        query_vec = np.array(query_embedding)
        similarities = []

        for i, embedding in enumerate(self.embeddings):
            sim = self.cosine_similarity(query_vec, embedding)
            if sim >= threshold:
                similarities.append((self.chunks[i], sim))

        # 按相似度降序排序
        similarities.sort(key=lambda x: x[1], reverse=True)

        return similarities[:top_k]

    def batch_find_similar(
        self,
        queries: List[str],
        query_embeddings: List[List[float]],
        top_k: int = 5
    ) -> List[List[Tuple[Dict, float]]]:
        """批量查询"""
        results = []
        for query, embedding in zip(queries, query_embeddings):
            similar = self.find_similar_chunks(query, embedding, top_k)
            results.append(similar)
        return results


class QAEngine:
    """问答引擎,结合检索和生成进行问答"""

    def __init__(self, retrieval_engine: RetrievalEngine, client):
        """
        初始化问答引擎

        Args:
            retrieval_engine: 检索引擎实例
            client: OpenAIClient实例
        """
        self.retrieval = retrieval_engine
        self.client = client

    def get_query_embedding(self, query: str) -> List[float]:
        """获取查询的嵌入向量"""
        response = self.client.embeddings.create(
            input=query,
            model="text-embedding-ada-002"
        )
        return response.data[0].embedding

    def build_context(self, similar_chunks: List[Tuple[Dict, float]]) -> str:
        """根据相似块构建上下文"""
        context_parts = []

        for i, (chunk, similarity) in enumerate(similar_chunks, 1):
            source = chunk["metadata"].get("file_path", "未知来源")
            chunk_index = chunk["metadata"].get("chunk_index", 0)

            part = f"[文档{i}] 来源: {source} (相似度: {similarity:.4f})\n{chunk['text']}\n"
            context_parts.append(part)

        return "\n---\n".join(context_parts)

    def ask(
        self, 
        question: str, 
        top_k: int = 5,
        threshold: float = 0.5,
        max_context_tokens: int = 3000
    ) -> Dict:
        """
        提问并获取答案

        Args:
            question: 问题
            top_k: 参考的文档块数量
            threshold: 相似度阈值
            max_context_tokens: 最大上下文token数(约等于字符数/2)

        Returns:
            包含答案和参考信息的字典
        """
        # 1. 获取问题的嵌入向量
        print("正在分析问题...")
        query_embedding = self.get_query_embedding(question)

        # 2. 检索相关文档
        print("正在检索相关文档...")
        similar_chunks = self.retrieval.find_similar_chunks(
            question, 
            query_embedding, 
            top_k=top_k,
            threshold=threshold
        )

        if not similar_chunks:
            return {
                "question": question,
                "answer": "抱歉,我在文档库中没有找到与您问题相关的内容。",
                "sources": [],
                "similarities": []
            }

        # 3. 构建上下文
        print(f"找到{len(similar_chunks)}个相关文档块")
        context = self.build_context(similar_chunks)

        # 如果上下文太长,截断
        if len(context) > max_context_tokens * 2:
            context = context[:max_context_tokens * 2]

        # 4. 构建提示词
        system_prompt = """你是一个专业的文档问答助手。你的任务是根据提供的文档内容回答用户的问题。

重要规则:
1. 只根据文档内容回答,不要编造信息
2. 如果文档中没有提到相关信息,明确指出这一点
3. 回答要清晰、有条理
4. 可以引用文档中的具体内容来支持你的回答
5. 如果多个文档的内容有冲突,请指出来源差异"""

        user_prompt = f"""## 文档内容:

{context}

## 用户问题:

{question}

## 要求:
请根据上述文档内容回答用户的问题。"""

        # 5. 调用语言模型生成答案
        print("正在生成答案...")
        response = self.client.chat.completions.create(
            model="gpt-3.5-turbo",
            messages=[
                {"role": "system", "content": system_prompt},
                {"role": "user", "content": user_prompt}
            ],
            max_tokens=1000,
            temperature=0.3  # 较低的随机性,保持回答的准确性
        )

        answer = response.choices[0].message.content

        # 6. 整理结果
        sources = []
        similarities = []
        for chunk, sim in similar_chunks:
            sources.append(chunk["metadata"].get("file_path", "未知来源"))
            similarities.append(sim)

        return {
            "question": question,
            "answer": answer,
            "sources": sources,
            "similarities": similarities
        }

第三步:构建完整的问答系统

# document_qa_system.py
# 完整的文档问答系统

import os
import argparse
from pathlib import Path

from open_generative_ai import OpenAIClient
from document_processor import DocumentProcessor
from retrieval import RetrievalEngine, QAEngine

class DocumentQASystem:
    """文档问答系统主类"""

    def __init__(self, api_base: str = "http://localhost:8000"):
        """初始化系统"""
        self.client = OpenAIClient(api_base=api_base)
        self.processor = None
        self.retrieval = None
        self.qa_engine = None

    def build_index(
        self, 
        documents: List[str], 
        index_path: str = "document_index.json",
        chunk_size: int = 500
    ):
        """
        构建文档索引

        Args:
            documents: 文档路径列表
            index_path: 索引文件保存路径
            chunk_size: 文本块大小
        """
        print("=" * 50)
        print("开始构建文档索引")
        print("=" * 50)

        # 初始化处理器
        self.processor = DocumentProcessor(
            client=self.client,
            chunk_size=chunk_size
        )

        # 处理文档
        for doc_path in documents:
            metadata = {
                "file_name": os.path.basename(doc_path),
                "file_size": os.path.getsize(doc_path)
            }
            self.processor.process_document(doc_path, metadata)

        # 创建嵌入向量
        self.processor.create_embeddings()

        # 保存索引
        self.processor.save_index(index_path)

        # 初始化检索引擎
        self.retrieval = RetrievalEngine(
            chunks=self.processor.chunks,
            embeddings=self.processor.embeddings
        )

        # 初始化问答引擎
        self.qa_engine = QAEngine(self.retrieval, self.client)

        print("索引构建完成!")

    def load_index(self, index_path: str):
        """加载已有索引"""
        print(f"正在加载索引: {index_path}")
        self.processor = DocumentProcessor(client=self.client)
        self.processor.load_index(index_path)

        self.retrieval = RetrievalEngine(
            chunks=self.processor.chunks,
            embeddings=self.processor.embeddings
        )

        self.qa_engine = QAEngine(self.retrieval, self.client)
        print("索引加载完成!")

    def ask(self, question: str, top_k: int = 5):
        """
        提问

        Args:
            question: 问题
            top_k: 参考的文档块数量
        """
        if not self.qa_engine:
            raise ValueError("请先构建或加载索引")

        result = self.qa_engine.ask(question, top_k=top_k)

        print("\n" + "=" * 50)
        print("问题:", result["question"])
        print("=" * 50)
        print("\n答案:")
        print(result["answer"])
        print("\n" + "-" * 50)
        print("参考来源:")
        for i, (source, similarity) in enumerate(
            zip(result["sources"], result["similarities"]), 1
        ):
            print(f"  {i}. {source} (相似度: {similarity:.4f})")

        return result


# 主程序入口
def main():
    parser = argparse.ArgumentParser(description="文档问答系统")
    parser.add_argument("--api-base", default="http://localhost:8000", 
                        help="API服务地址")
    parser.add_argument("--documents", nargs="+", 
                        help="要处理的文档路径")
    parser.add_argument("--index", default="document_index.json",
                        help="索引文件路径")
    parser.add_argument("--chunk-size", type=int, default=500,
                        help="文本块大小")
    parser.add_argument("--interactive", action="store_true",
                        help="交互模式")

    args = parser.parse_args()

    # 初始化系统
    system = DocumentQASystem(api_base=args.api_base)

    # 如果指定了文档,构建索引
    if args.documents:
        system.build_index(
            documents=args.documents,
            index_path=args.index,
            chunk_size=args.chunk_size
        )
    # 否则尝试加载已有索引
    elif os.path.exists(args.index):
        system.load_index(args.index)
    else:
        print("错误: 请指定要处理的文档,或确保索引文件存在")
        return

    # 交互模式
    if args.interactive:
        print("\n" + "=" * 50)
        print("文档问答系统 - 交互模式")
        print("输入问题进行查询,输入'quit'退出")
        print("=" * 50 + "\n")

        while True:
            question = input("你: ").strip()
            if question.lower() in ['quit', 'exit', '退出']:
                print("再见!")
                break
            if not question:
                continue
            system.ask(question)
            print()


if __name__ == "__main__":
    main()

使用示例

# 构建索引
python document_qa_system.py \
    --api-base http://localhost:8000 \
    --documents ./docs/faq.md ./docs/guide.txt \
    --index my_index.json \
    --chunk-size 500

# 交互式问答
python document_qa_system.py \
    --api-base http://localhost:8000 \
    --index my_index.json \
    --interactive

4.2 教程二:构建智能客服机器人

在这个教程中,我们将构建一个智能客服机器人,它可以理解用户的问题,从知识库中检索答案,还能处理复杂的多轮对话场景。

第一步:构建对话管理模块

# conversation_manager.py
# 对话管理模块,处理多轮对话上下文

import json
from datetime import datetime
from typing import List, Dict, Optional, Callable
from dataclasses import dataclass, field, asdict

@dataclass
class Message:
    """消息类"""
    role: str  # "user", "assistant", "system"
    content: str
    timestamp: str = field(default_factory=lambda: datetime.now().isoformat())
    metadata: Dict = field(default_factory=dict)

@dataclass
class Conversation:
    """会话类"""
    id: str
    messages: List[Message] = field(default_factory=list)
    created_at: str = field(default_factory=lambda: datetime.now().isoformat())
    updated_at: str = field(default_factory=lambda: datetime.now().isoformat())
    metadata: Dict = field(default_factory=dict)

class ConversationManager:
    """对话管理器"""

    MAX_HISTORY_LENGTH = 20  # 最大历史消息数
    SYSTEM_PROMPT = """你是一个专业、友好的客服助手。请根据以下知识库内容回答用户的问题。

回答原则:
1. 首先向用户问好,了解用户的需求
2. 根据知识库内容准确回答用户的问题
3. 如果知识库中没有相关信息,诚实地告知用户
4. 保持友好、耐心的态度
5. 如果用户问题不清晰,适当追问
6. 在回答结束时,询问用户是否还有其他问题

当前时间: {current_time}"""

    def __init__(self, knowledge_base: Optional[List[Dict]] = None):
        """
        初始化对话管理器

        Args:
            knowledge_base: 知识库列表,每个条目包含question和answer
        """
        self.conversations: Dict[str, Conversation] = {}
        self.knowledge_base = knowledge_base or []
        self.current_time = datetime.now().strftime("%Y年%m月%d日 %H:%M")

    def create_conversation(self, user_id: str, metadata: Dict = None) -> str:
        """创建新会话"""
        conversation_id = f"{user_id}_{datetime.now().strftime('%Y%m%d%H%M%S')}"

        conversation = Conversation(
            id=conversation_id,
            metadata=metadata or {}
        )

        # 添加系统提示
        system_message = Message(
            role="system",
            content=self.SYSTEM_PROMPT.format(current_time=self.current_time)
        )
        conversation.messages.append(system_message)

        self.conversations[conversation_id] = conversation
        return conversation_id

    def get_conversation(self, conversation_id: str) -> Optional[Conversation]:
        """获取会话"""
        return self.conversations.get(conversation_id)

    def add_message(
        self, 
        conversation_id: str, 
        role: str, 
        content: str,
        metadata: Dict = None
    ) -> bool:
        """添加消息"""
        conversation = self.get_conversation(conversation_id)
        if not conversation:
            return False

        message = Message(
            role=role,
            content=content,
            metadata=metadata or {}
        )

        conversation.messages.append(message)

        # 限制历史消息长度
        if len(conversation.messages) > self.MAX_HISTORY_LENGTH:
            # 保留系统提示和最近的对话
            system_msg = conversation.messages[0]
            conversation.messages = [system_msg] + conversation.messages[-(self.MAX_HISTORY_LENGTH-1):]

        # 更新会话时间
        conversation.updated_at = datetime.now().isoformat()

        return True

    def get_messages(self, conversation_id: str) -> List[Dict]:
        """获取会话消息列表"""
        conversation = self.get_conversation(conversation_id)
        if not conversation:
            return []
        return [asdict(msg) for msg in conversation.messages]

    def format_messages_for_api(
        self, 
        conversation_id: str,
        include_knowledge: bool = True
    ) -> List[Dict]:
        """
        将消息格式化为API调用格式

        Args:
            conversation_id: 会话ID
            include_knowledge: 是否在系统提示中包含知识库
        """
        messages = self.get_messages(conversation_id)
        formatted = []

        for msg in messages:
            if msg["role"] == "system":
                # 在系统提示中添加知识库
                content = msg["content"]
                if include_knowledge and self.knowledge_base:
                    kb_text = self._format_knowledge_base()
                    content += "\n\n## 知识库内容:\n" + kb_text

                formatted.append({
                    "role": "system",
                    "content": content
                })
            else:
                formatted.append({
                    "role": msg["role"],
                    "content": msg["content"]
                })

        return formatted

    def _format_knowledge_base(self) -> str:
        """格式化知识库"""
        if not self.knowledge_base:
            return "(暂无知识库内容)"

        kb_parts = []
        for i, item in enumerate(self.knowledge_base, 1):
            q = item.get("question", "")
            a = item.get("answer", "")
            kb_parts.append(f"Q{i}: {q}\nA{i}: {a}")

        return "\n\n".join(kb_parts)

    def clear_conversation(self, conversation_id: str) -> bool:
        """清除会话历史"""
        conversation = self.get_conversation(conversation_id)
        if not conversation:
            return False

        # 保留系统提示
        system_msg = conversation.messages[0] if conversation.messages else None
        conversation.messages = []
        if system_msg:
            conversation.messages.append(system_msg)

        return True


class CustomerServiceBot:
    """客服机器人主类"""

    def __init__(
        self, 
        client,
        knowledge_base: List[Dict],
        max_response_tokens: int = 500
    ):
        """
        初始化客服机器人

        Args:
            client: OpenAIClient实例
            knowledge_base: 知识库列表
            max_response_tokens: 最大回复token数
        """
        self.client = client
        self.conversation_manager = ConversationManager(knowledge_base)
        self.max_response_tokens = max_response_tokens

    def start_conversation(self, user_id: str, metadata: Dict = None) -> str:
        """开始新会话"""
        return self.conversation_manager.create_conversation(user_id, metadata)

    def chat(
        self, 
        conversation_id: str, 
        user_message: str,
        temperature: float = 0.7
    ) -> Dict:
        """
        处理用户消息并生成回复

        Args:
            conversation_id: 会话ID
            user_message: 用户消息
            temperature: 生成随机性

        Returns:
            包含回复和元数据的字典
        """
        # 添加用户消息
        self.conversation_manager.add_message(
            conversation_id, 
            "user", 
            user_message
        )

        # 准备API调用
        messages = self.conversation_manager.format_messages_for_api(
            conversation_id
        )

        # 调用API
        try:
            response = self.client.chat.completions.create(
                model="gpt-3.5-turbo",
                messages=messages,
                max_tokens=self.max_response_tokens,
                temperature=temperature
            )

            assistant_message = response.choices[0].message.content

        except Exception as e:
            assistant_message = f"抱歉,系统遇到了问题: {str(e)}"

        # 添加助手回复
        self.conversation_manager.add_message(
            conversation_id,
            "assistant",
            assistant_message
        )

        return {
            "conversation_id": conversation_id,
            "user_message": user_message,
            "assistant_message": assistant_message,
            "timestamp": datetime.now().isoformat()
        }

    def get_conversation_history(self, conversation_id: str) -> List[Dict]:
        """获取会话历史"""
        return self.conversation_manager.get_messages(conversation_id)

    def clear_conversation(self, conversation_id: str):
        """清除会话"""
        self.conversation_manager.clear_conversation(conversation_id)

第二步:创建知识库并启动服务

# customer_service_demo.py
# 客服机器人演示程序

from open_generative_ai import OpenAIClient
from conversation_manager import CustomerServiceBot

# 定义知识库
KNOWLEDGE_BASE = [
    {
        "question": "你们的工作时间是几点?",
        "answer": "我们的工作时间是为周一到周五的上午9点到下午6点,节假日除外。"
    },
    {
        "question": "如何重置密码?",
        "answer": "您可以通过以下步骤重置密码:1. 点击登录页面的'忘记密码'链接 2. 输入您注册的邮箱地址 3. 查收邮件并点击重置链接 4. 设置新密码。如果有任何问题,可以联系我们的客服。"
    },
    {
        "question": "如何联系人工客服?",
        "answer": "您可以通过以下方式联系人工客服:1. 拨打客服热线:400-123-4567 2. 发送邮件到 support@example.com 3. 在APP内点击'在线客服'按钮。我们的客服人员会在工作时间内尽快回复您。"
    },
    {
        "question": "产品支持哪些支付方式?",
        "answer": "我们支持多种支付方式,包括:1. 微信支付 2. 支付宝 3. 银行卡支付 4. Apple Pay(仅限iOS用户)。所有支付都经过加密处理,保障您的资金安全。"
    },
    {
        "question": "退款政策是什么?",
        "answer": "我们的退款政策如下:1. 购买后7天内,如对产品不满意,可以申请全额退款 2. 购买后7-30天,可以申请部分退款(扣除已使用天数费用)3. 超过30天后,不接受退款申请,但可以申请换货。退款将在1-3个工作日内原路返回。"
    },
    {
        "question": "会员有哪些等级?",
        "answer": "我们的会员分为四个等级:1. 免费会员:基础功能 2. 银卡会员:月费29元,享受9折优惠 3. 金卡会员:月费59元,享受8折优惠和专属客服 4. 钻石会员:月费99元,享受7折优惠,专属客服和优先体验新功能。"
    }
]

def run_demo():
    """运行演示"""
    print("=" * 60)
    print("智能客服机器人演示")
    print("=" * 60)

    # 初始化
    client = OpenAIClient(api_base="http://localhost:8000")
    bot = CustomerServiceBot(
        client=client,
        knowledge_base=KNOWLEDGE_BASE,
        max_response_tokens=500
    )

    # 开始会话
    user_id = "demo_user_001"
    conversation_id = bot.start_conversation(
        user_id=user_id,
        metadata={"source": "demo", "version": "1.0"}
    )

    print(f"\n会话已创建,会话ID: {conversation_id}")
    print("\n提示: 输入'quit'退出,输入'clear'清空对话历史\n")

    # 欢迎消息
    welcome = bot.chat(conversation_id, "你好,我想了解一下你们的服务")
    print(f"\n客服: {welcome['assistant_message']}\n")

    # 对话循环
    while True:
        try:
            user_input = input("用户: ").strip()
        except (KeyboardInterrupt, EOFError):
            print("\n\n再见!")
            break

        if user_input.lower() in ['quit', 'exit', '退出']:
            print("\n感谢您的咨询,再见!")
            break

        if user_input.lower() == 'clear':
            bot.clear_conversation(conversation_id)
            print("对话历史已清空\n")
            continue

        if not user_input:
            continue

        # 获取回复
        response = bot.chat(conversation_id, user_input)
        print(f"\n客服: {response['assistant_message']}\n")


if __name__ == "__main__":
    run_demo()

4.3 教程三:构建AI写作助手

AI写作助手是一个非常实用的工具,可以帮助用户进行各种写作任务,如文章创作、文案撰写、内容润色等。在这个教程中,我们将构建一个功能丰富的写作助手。

# writing_assistant.py
# AI写作助手

import re
from typing import List, Dict, Optional, Tuple
from enum import Enum
from dataclasses import dataclass

class WritingStyle(Enum):
    """写作风格枚举"""
    FORMAL = "formal"           # 正式
    CASUAL = "casual"           # 随意
    PROFESSIONAL = "professional"  # 专业
    CREATIVE = "creative"       # 创意
    ACADEMIC = "academic"       # 学术
    NEWS = "news"               # 新闻

class WritingLength(Enum):
    """写作长度枚举"""
    SHORT = "short"      # 短(100-200字)
    MEDIUM = "medium"    # 中(300-500字)
    LONG = "long"        # 长(800-1000字)

@dataclass
class WritingRequest:
    """写作请求"""
    task: str                    # 写作任务
    topic: str                   # 主题
    style: WritingStyle          # 风格
    length: WritingLength        # 长度
    keywords: List[str]         # 关键词
    audience: str               # 目标受众
    tone: str                   # 语气
    include_outline: bool        # 是否包含大纲
    language: str               # 语言

class WritingAssistant:
    """写作助手类"""

    def __init__(self, client):
        """
        初始化写作助手

        Args:
            client: OpenAIClient实例
        """
        self.client = client

    def generate_system_prompt(self, request: WritingRequest) -> str:
        """生成系统提示词"""
        style_descriptions = {
            WritingStyle.FORMAL: "正式、严谨的语言风格",
            WritingStyle.CASUAL: "轻松、亲切的语言风格",
            WritingStyle.PROFESSIONAL: "专业、权威的语言风格",
            WritingStyle.CREATIVE: "富有创意、想象力丰富的语言风格",
            WritingStyle.ACADEMIC: "学术、客观的语言风格",
            WritingStyle.NEWS: "新闻报道式的语言风格"
        }

        length_descriptions = {
            WritingLength.SHORT: "简短精炼(100-200字)",
            WritingLength.MEDIUM: "适中(300-500字)",
            WritingLength.LONG: "详细深入(800-1000字)"
        }

        prompt = f"""你是一位专业的内容创作专家,擅长各类写作任务。

## 写作任务
{request.task}

## 主题
{request.topic}

## 写作风格
{style_descriptions.get(request.style, '默认风格')}

## 目标受众
{request.audience}

## 语气
{request.tone}

## 文章长度
{length_descriptions.get(request.length, '默认长度')}"""

        if request.keywords:
            prompt += f"\n\n## 必须包含的关键词\n{', '.join(request.keywords)}"

        if request.include_outline:
            prompt += "\n\n## 要求\n1. 先提供文章大纲\n2. 然后按大纲撰写完整文章"
        else:
            prompt += "\n\n## 要求\n直接撰写完整文章,结构清晰,段落分明"

        return prompt

    def write_article(self, request: WritingRequest) -> Dict:
        """
        撰写文章

        Args:
            request: 写作请求

        Returns:
            包含文章内容和元数据的字典
        """
        system_prompt = self.generate_system_prompt(request)

        user_prompt = f"请撰写一篇文章。主题:{request.topic}"

        response = self.client.chat.completions.create(
            model="gpt-3.5-turbo",
            messages=[
                {"role": "system", "content": system_prompt},
                {"role": "user", "content": user_prompt}
            ],
            max_tokens=2000,
            temperature=0.8
        )

        result = response.choices[0].message.content

        return {
            "article": result,
            "outline": self.extract_outline(result) if request.include_outline else None,
            "metadata": {
                "task": request.task,
                "topic": request.topic,
                "style": request.style.value,
                "length": request.length.value,
                "keywords": request.keywords
            }
        }

    def extract_outline(self, text: str) -> Optional[List[str]]:
        """从文章中提取大纲"""
        lines = text.split('\n')
        outline = []

        for line in lines:
            # 匹配大纲格式(一、二、三 或 1. 2. 3. 或 ## 标题)
            if re.match(r'^[一二三四五六七八九十]+[、..]', line.strip()):
                outline.append(line.strip())
            elif re.match(r'^##?\s+', line.strip()):
                outline.append(line.strip())

        return outline if outline else None

    def polish_text(
        self, 
        text: str, 
        style: WritingStyle,
        language: str = "zh"
    ) -> str:
        """
        润色文本

        Args:
            text: 待润色文本
            style: 目标风格
            language: 语言

        Returns:
            润色后的文本
        """
        style_prompts = {
            WritingStyle.FORMAL: "更加正式、严谨",
            WritingStyle.CASUAL: "更加轻松、亲切",
            WritingStyle.PROFESSIONAL: "更加专业、有深度",
            WritingStyle.CREATIVE: "更加生动、有创意"
        }

        system_prompt = f"""你是一位专业的内容编辑,擅长文本润色。
请将以下文本润色为{language}语言、{style_prompts.get(style, '更好')}的风格。

润色要求:
1. 保持原文的核心意思
2. 改善表达流畅度
3. 优化用词准确性
4. 调整句子结构使其更优美
5. 不要改变原文的基本立场和信息"""

        response = self.client.chat.completions.create(
            model="gpt-3.5-turbo",
            messages=[
                {"role": "system", "content": system_prompt},
                {"role": "user", "content": text}
            ],
            max_tokens=2000,
            temperature=0.7
        )

        return response.choices[0].message.content

    def expand_text(self, text: str, target_length: str = "medium") -> str:
        """
        扩展文本

        Args:
            text: 原文本
            target_length: 目标长度 (short/medium/long)

        Returns:
            扩展后的文本
        """
        length_descriptions = {
            "short": "扩展为200-300字",
            "medium": "扩展为500-800字",
            "long": "扩展为1500-2000字"
        }

        system_prompt = f"""你是一位专业的内容创作者。请将以下文本{length_descriptions.get(target_length, '扩展')}

扩展要求:
1. 保持原文的核心观点和风格
2. 添加更多细节、例子和论证
3. 丰富表达方式,但不啰嗦
4. 确保新内容与原文逻辑连贯"""

        response = self.client.chat.completions.create(
            model="gpt-3.5-turbo",
            messages=[
                {"role": "system", "content": system_prompt},
                {"role": "user", "content": text}
            ],
            max_tokens=3000,
            temperature=0.7
        )

        return response.choices[0].message.content

    def summarize_text(self, text: str, length: str = "medium") -> str:
        """
        摘要文本

        Args:
            text: 原文
            length: 摘要长度 (short/medium/long)

        Returns:
            摘要文本
        """
        length_descriptions = {
            "short": "简短的摘要(50-100字)",
            "medium": "中等长度的摘要(200-300字)",
            "long": "详细的摘要(500-800字)"
        }

        system_prompt = f"""请为以下文本生成{length_descriptions.get(length, '摘要')}

摘要要求:
1. 准确概括原文的核心观点
2. 保持原文的逻辑结构
3. 语言简洁明了
4. 突出重点信息"""

        response = self.client.chat.completions.create(
            model="gpt-3.5-turbo",
            messages=[
                {"role": "system", "content": system_prompt},
                {"role": "user", "content": text}
            ],
            max_tokens=1500,
            temperature=0.3
        )

        return response.choices[0].message.content

    def translate_text(
        self, 
        text: str, 
        target_language: str,
        preserve_format: bool = True
    ) -> str:
        """
        翻译文本

        Args:
            text: 原文
            target_language: 目标语言
            preserve_format: 是否保持格式

        Returns:
            翻译后的文本
        """
        format_instruction = "保持原有格式和段落结构" if preserve_format else ""

        system_prompt = f"""请将以下文本翻译成{target_language}

翻译要求:
1. 准确传达原文意思
2. 符合目标语言的表达习惯
3. {format_instruction}
4. 适当处理文化差异"""

        response = self.client.chat.completions.create(
            model="gpt-3.5-turbo",
            messages=[
                {"role": "system", "content": system_prompt},
                {"role": "user", "content": text}
            ],
            max_tokens=3000,
            temperature=0.3
        )

        return response.choices[0].message.content

    def generate_title(
        self, 
        content: str, 
        style: str = "吸引眼球",
        count: int = 5
    ) -> List[str]:
        """
        生成标题

        Args:
            content: 内容摘要
            style: 标题风格
            count: 生成数量

        Returns:
            标题列表
        """
        system_prompt = f"""请根据以下内容生成{count}{style}的标题。

标题要求:
1. 简洁有力,突出重点
2. 吸引读者注意力
3. 符合SEO优化要求
4. 每个标题不超过30个字

请按以下格式返回(每个标题一行):
1. 标题1
2. 标题2
..."""

        response = self.client.chat.completions.create(
            model="gpt-3.5-turbo",
            messages=[
                {"role": "system", "content": system_prompt},
                {"role": "user", "content": content}
            ],
            max_tokens=500,
            temperature=0.8
        )

        titles = []
        for line in response.choices[0].message.content.split('\n'):
            line = line.strip()
            if line and (line[0].isdigit() or line.startswith('-')):
                # 去掉序号
                title = re.sub(r'^[0-9]+[.、)]\s*', '', line)
                titles.append(title)

        return titles


def writing_assistant_demo():
    """写作助手演示"""
    from open_generative_ai import OpenAIClient

    client = OpenAIClient(api_base="http://localhost:8000")
    assistant = WritingAssistant(client)

    print("=" * 60)
    print("AI写作助手演示")
    print("=" * 60)

    # 示例1:撰写文章
    print("\n【示例1:撰写文章】\n")

    request = WritingRequest(
        task="撰写一篇博客文章",
        topic="人工智能对未来教育的影响",
        style=WritingStyle.PROFESSIONAL,
        length=WritingLength.MEDIUM,
        keywords=["人工智能", "教育", "未来"],
        audience="普通读者",
        tone="客观中立",
        include_outline=True,
        language="zh"
    )

    result = assistant.write_article(request)
    print("文章大纲:")
    if result["outline"]:
        for item in result["outline"]:
            print(f"  {item}")
    print("\n文章内容:")
    print(result["article"])

    # 示例2:润色文本
    print("\n" + "-" * 40)
    print("【示例2:润色文本】\n")

    original = "人工智能技术发展很快,已经影响了很多行业。我觉得未来会有更多的变化。"
    polished = assistant.polish_text(original, WritingStyle.PROFESSIONAL)
    print(f"原文:{original}")
    print(f"润色后:{polished}")

    # 示例3:生成标题
    print("\n" + "-" * 40)
    print("【示例3:生成标题】\n")

    content = "探讨人工智能如何改变传统教育模式,包括个性化学习、智能辅导等方面的发展趋势。"
    titles = assistant.generate_title(content, count=5)
    print("生成的文章标题:")
    for i, title in enumerate(titles, 1):
        print(f"  {i}. {title}")


if __name__ == "__main__":
    writing_assistant_demo()

第五部分:常见使用场景

5.1 内容创作场景

在内容创作领域,这个项目可以成为你的得力助手。无论是撰写营销文案、创作故事脚本、还是编写技术文档,它都能提供强大的支持。

营销文案生成:利用项目的文本生成能力,你可以快速生成各种营销文案。例如,为新产品撰写上市文案、为社交媒体生成推广内容、创作电子邮件营销模板等。通过调整参数,你可以控制文案的风格、长度和创意程度。

# 营销文案生成示例
def generate_marketing_copy(client, product_info: Dict, platform: str) -> str:
    """为不同平台生成营销文案"""

    prompts = {
        "weibo": """为以下产品生成一条微博风格的推广文案(不超过140字):
产品:{name}
特点:{features}
卖点:{selling_point}""",
        "xiaohongshu": """为以下产品生成小红书风格的种草文案:
产品:{name}
特点:{features}
卖点:{selling_point}

要求:轻松亲切的语气,适合小红书平台风格""",
        "email": """为以下产品生成邮件营销文案:
产品:{name}
特点:{features}
卖点:{selling_point}

要求:专业但有吸引力,包含明确的行动号召"""
    }

    prompt_template = prompts.get(platform, prompts["email"])
    prompt = prompt_template.format(**product_info)

    response = client.chat.completions.create(
        model="gpt-3.5-turbo",
        messages=[
            {"role": "system", "content": "你是一位经验丰富的营销文案专家。"},
            {"role": "user", "content": prompt}
        ],
        max_tokens=500,
        temperature=0.8
    )

    return response.choices[0].message.content

# 使用示例
product_info = {
    "name": "智能空气净化器 Pro",
    "features": "HEPA滤网、静音设计、智能感应",
    "selling_point": "守护家人呼吸健康"
}

weibo_copy = generate_marketing_copy(client, product_info, "weibo")
print(weibo_copy)

5.2 智能问答场景

智能问答系统是企业服务、教育培训、内容网站等领域的重要应用。通过这个项目,你可以快速搭建一个功能完备的问答系统。

# 智能问答系统示例
class SmartQASystem:
    """智能问答系统"""

    def __init__(self, client):
        self.client = client
        self.qa_pairs = []
        self.documents = []

    def add_qa_pairs(self, qa_pairs: List[Dict]):
        """添加问答对"""
        self.qa_pairs.extend(qa_pairs)

    def find_best_match(self, question: str) -> Optional[Dict]:
        """找到最佳匹配的问答对"""
        question_embedding = self.client.embeddings.create(
            input=question,
            model="text-embedding-ada-002"
        ).data[0].embedding

        best_match = None
        best_score = 0

        for qa in self.qa_pairs:
            q_embedding = self.client.embeddings.create(
                input=qa["question"],
                model="text-embedding-ada-002"
            ).data[0].embedding

            score = cosine_similarity(question_embedding, q_embedding)
            if score > best_score:
                best_score = score
                best_match = qa

        return best_match if best_score > 0.7 else None

    def answer(self, question: str) -> str:
        """回答问题"""
        # 首先尝试精确匹配
        match = self.find_best_match(question)

        if match:
            return match["answer"]

        # 如果没有匹配,使用生成式回答
        context = self._build_context()
        prompt = f"""基于以下信息回答用户的问题。如果现有信息无法回答,请说明。

{context}

用户问题:{question}

回答要求:简洁、准确、有帮助"""

        response = self.client.chat.completions.create(
            model="gpt-3.5-turbo",
            messages=[
                {"role": "system", "content": "你是一个乐于助人的问答助手。"},
                {"role": "user", "content": prompt}
            ],
            max_tokens=300
        )

        return response.choices[0].message.content

5.3 文本分析场景

文本分析是AI应用的基础功能之一。这个项目可以用于情感分析、文本分类、关键词提取等多种分析任务。

# 文本分析工具
class TextAnalyzer:
    """文本分析工具"""

    def __init__(self, client):
        self.client = client

    def analyze_sentiment(self, text: str) -> Dict:
        """情感分析"""
        prompt = f"""请分析以下文本的情感倾向,并给出评分。

文本:{text}

请按以下JSON格式返回结果(只返回JSON,不要其他内容):
{{
    "sentiment": "positive/negative/neutral",
    "score": -1到1之间的数值,
    "emotion": "主要情感类型",
    "confidence": 置信度0到1
}}"""

        response = self.client.chat.completions.create(
            model="gpt-3.5-turbo",
            messages=[
                {"role": "system", "content": "你是一个专业的情感分析专家。"},
                {"role": "user", "content": prompt}
            ],
            max_tokens=200,
            temperature=0.1
        )

        import json
        try:
            return json.loads(response.choices[0].message.content)
        except:
            return {"error": "解析失败"}

    def extract_keywords(self, text: str, top_n: int = 10) -> List[str]:
        """关键词提取"""
        prompt = f"""请从以下文本中提取{top_n}个最重要的关键词。

文本:{text}

请按重要性从高到低排列,以JSON数组格式返回:
["关键词1", "关键词2", ...]"""

        response = self.client.chat.completions.create(
            model="gpt-3.5-turbo",
            messages=[
                {"role": "system", "content": "你是一个专业的关键词提取专家。"},
                {"role": "user", "content": prompt}
            ],
            max_tokens=200,
            temperature=0.1
        )

        import json
        try:
            return json.loads(response.choices[0].message.content)
        except:
            return []

    def summarize(self, text: str, max_length: int = 200) -> str:
        """文本摘要"""
        prompt = f"""请为以下文本生成一个简洁的摘要,控制在{max_length}字以内。

文本:{text}

摘要要求:
1. 概括核心观点
2. 语言简洁
3. 保留关键信息"""

        response = self.client.chat.completions.create(
            model="gpt-3.5-turbo",
            messages=[
                {"role": "system", "content": "你是一个专业的文本摘要专家。"},
                {"role": "user", "content": prompt}
            ],
            max_tokens=500,
            temperature=0.3
        )

        return response.choices[0].message.content

    def classify_text(self, text: str, categories: List[str]) -> Dict:
        """文本分类"""
        categories_str = "、".join(categories)

        prompt = f"""请将以下文本分类到最合适的类别中。

文本:{text}

可选类别:{categories_str}

请按以下JSON格式返回:
{{
    "category": "分类结果",
    "confidence": 置信度0到1
}}"""

        response = self.client.chat.completions.create(
            model="gpt-3.5-turbo",
            messages=[
                {"role": "system", "content": "你是一个专业的文本分类专家。"},
                {"role": "user", "content": prompt}
            ],
            max_tokens=200,
            temperature=0.1
        )

        import json
        try:
            return json.loads(response.choices[0].message.content)
        except:
            return {"error": "分类失败"}

5.4 代码辅助场景

对于开发者来说,AI辅助编程是一个非常实用的功能。这个项目可以帮助你生成代码、调试错误、解释代码逻辑。

# 代码辅助工具
class CodeAssistant:
    """代码辅助工具"""

    def __init__(self, client):
        self.client = client

    def generate_code(
        self, 
        description: str, 
        language: str = "python",
        style: str = "clean"
    ) -> str:
        """生成代码"""
        prompt = f"""请用{language}语言实现以下功能。

功能描述:{description}

代码要求:
1. 代码风格:{style}
2. 添加必要的注释
3. 考虑错误处理
4. 遵循最佳实践"""

        response = self.client.chat.completions.create(
            model="gpt-3.5-turbo",
            messages=[
                {"role": "system", "content": "你是一个经验丰富的程序员。"},
                {"role": "user", "content": prompt}
            ],
            max_tokens=1500,
            temperature=0.3
        )

        return response.choices[0].message.content

    def explain_code(self, code: str) -> str:
        """解释代码"""
        prompt = f"""请解释以下代码的功能和工作原理。

代码:
```python
{code}

解释要求:
1. 说明代码的主要功能
2. 解释关键逻辑
3. 分析代码流程”””

    response = self.client.chat.completions.create(
        model="gpt-3.5-turbo",
        messages=[
            {"role": "system", "content": "你是一个耐心的编程导师。"},
            {"role": "user", "content": prompt}
        ],
        max_tokens=1000,
        temperature=0.3
    )

    return response.choices[0].message.content

def debug_code(self, code: str, error: str = None) -> str:
    """调试代码"""
    if error:
        prompt = f"""请帮助调试以下代码发现并修复其中的错误

代码:

{code}

错误信息:
{error}

请:
1. 分析错误原因
2. 提供修复后的代码
3. 解释修复方案”””
else:
prompt = f”””请审查以下代码,找出潜在的问题和改进建议。

代码:

{code}

请:
1. 找出代码中的问题
2. 提出改进建议
3. 提供优化后的代码”””

    response = self.client.chat.completions.create(
        model="gpt-3.5-turbo",
        messages=[
            {"role": "system", "content": "你是一个经验丰富的代码审查专家。"},
            {"role": "user", "content": prompt}
        ],
        max_tokens=1500,
        temperature=0.3
    )

    return response.choices[0].message.content

def review_code(self, code: str) -> str:
    """代码审查"""
    prompt = f"""请对以下代码进行全面的审查

代码:

{code}

审查维度:
1. 代码质量
2. 性能考虑
3. 安全问题
4. 可维护性
5. 最佳实践”””

    response = self.client.chat.completions.create(
        model="gpt-3.5-turbo",
        messages=[
            {"role": "system", "content": "你是一个资深的代码审查专家。"},
            {"role": "user", "content": prompt}
        ],
        max_tokens=1500,
        temperature=0.3
    )

    return response.choices[0].message.content
---

**第六部分最佳实践与技巧**

**6.1 提示词工程Prompt Engineering**

提示词工程是使用大语言模型的核心技能一个好的提示词可以显著提高输出质量而一个糟糕的提示词可能导致完全错误的输出

**结构化提示词模板**

```python
class PromptTemplate:
    """提示词模板类"""

    @staticmethod
    def get_system_prompt(task_type: str) -> str:
        """获取系统级提示词"""
        system_prompts = {
            "assistant": """你是一个专业、友好的AI助手。
你的目标是帮助用户解决问题,提供有用的信息和建议。
请用清晰、易懂的语言回答问题。
如果不确定某个问题的答案,请诚实说明。""",

            "expert": """你是一位在特定领域拥有丰富经验的专家。
请运用你的专业知识为用户提供准确、深入的解答。
在回答时,请提供具体的例子和细节来支持你的观点。
如果有多种观点,请客观呈现并解释各自的优劣。""",

            "teacher": """你是一位耐心的老师,擅长用简单易懂的方式解释复杂的概念。
请用由浅入深的方式讲解,确保学习者能够理解。
在适当的时候使用类比和例子。
鼓励学习者提问,但不要过度简化。""",

            "writer": """你是一位专业的内容创作者。
请创作高质量、有吸引力的内容。
注意文章的结构、逻辑和语言表达。
根据指定的风格和受众调整写作方式。"""
        }

        return system_prompts.get(task_type, system_prompts["assistant"])

    @staticmethod
    def format_few_shot_prompt(
        task: str,
        examples: List[Dict[str, str]],
        new_input: str
    ) -> str:
        """
        格式化Few-shot提示词

        Args:
            task: 任务描述
            examples: 示例列表,每项包含input和output
            new_input: 新的输入
        """
        prompt_parts = [f"任务:{task}\n"]

        for i, example in enumerate(examples, 1):
            prompt_parts.append(f"\n示例{i}:")
            prompt_parts.append(f"输入:{example['input']}")
            prompt_parts.append(f"输出:{example['output']}")

        prompt_parts.append(f"\n新输入:{new_input}")
        prompt_parts.append("\n输出:")

        return "\n".join(prompt_parts)

    @staticmethod
    def format_chain_of_thought_prompt(
        problem: str,
        steps: List[str] = None
    ) -> str:
        """
        格式化Chain-of-Thought提示词

        鼓励模型在回答时展示推理过程
        """
        if steps:
            # Few-shot CoT
            prompt = "请按以下步骤分析并解决问题:\n"
            for i, step in enumerate(steps, 1):
                prompt += f"{i}. {step}\n"
            prompt += f"\n问题:{problem}\n"
            prompt += "请逐步分析并给出答案。"
        else:
            # Zero-shot CoT
            prompt = f"""问题:{problem}

请逐步思考这个问题,展示你的推理过程,最后给出答案。

推理步骤:"""

        return prompt

# 使用示例
template = PromptTemplate()

# Few-shot示例
examples = [
    {
        "input": "今天天气真好!",
        "output": "正面情感"
    },
    {
        "input": "这个产品太让我失望了。",
        "output": "负面情感"
    }
]

few_shot_prompt = template.format_few_shot_prompt(
    task="判断文本的情感倾向",
    examples=examples,
    new_input="服务质量非常棒!"
)

# Chain-of-Thought示例
cot_prompt = template.format_chain_of_thought_prompt(
    problem="小明有10个苹果,送给小红3个,又买了5个,现在小明有多少个苹果?",
    steps=[
        "理解问题的初始条件",
        "识别第一个操作(送给他人)",
        "识别第二个操作(购买)",
        "计算最终结果"
    ]
)

6.2 参数调优指南

合理设置模型参数是获得理想输出的关键。让我详细解释每个参数的作用和推荐设置。

Temperature(温度):这个参数控制输出的随机性。较低的值(0-0.3)会产生更确定、可预测的输出,适合需要准确性的任务;中等的值(0.4-0.7)会在确定性和创造性之间取得平衡;较高的值(0.8-1.0)会产生更有创意但可能不太可靠的输出。

Top P(核采样):这个参数与temperature配合使用。它限制模型只从累积概率最高的token中进行采样。较低的值(如0.9)会让输出更集中于高概率词汇;较高的值(如1.0)允许更多样化的选择。

Max Tokens(最大token数):限制单次生成的最大token数量。根据任务需求设置合适的值,避免输出被截断或浪费资源。

Frequency Penalty(频率惩罚):防止模型重复使用相同的词汇或表达。适度的惩罚可以提高输出的多样性,但过高可能导致语句不自然。

Presence Penalty(存在惩罚):鼓励模型谈论新的话题,而不是重复之前的表达。

# 参数配置示例
class ModelConfig:
    """模型参数配置"""

    # 不同场景的推荐配置
    PRESETS = {
        "factual_qa": {
            "temperature": 0.1,
            "top_p": 0.95,
            "max_tokens": 500,
            "frequency_penalty": 0.0,
            "presence_penalty": 0.0,
            "description": "事实性问答,需要准确答案"
        },

        "creative_writing": {
            "temperature": 0.85,
            "top_p": 0.95,
            "max_tokens": 1500,
            "frequency_penalty": 0.5,
            "presence_penalty": 0.3,
            "description": "创意写作,需要丰富的想象力"
        },

        "code_generation": {
            "temperature": 0.2,
            "top_p": 0.95,
            "max_tokens": 1000,
            "frequency_penalty": 0.0,
            "presence_penalty": 0.0,
            "description": "代码生成,需要准确无误"
        },

        "summarization": {
            "temperature": 0.3,
            "top_p": 0.9,
            "max_tokens": 300,
            "frequency_penalty": 0.1,
            "presence_penalty": 0.1,
            "description": "文本摘要,保持原意但精简"
        },

        "translation": {
            "temperature": 0.2,
            "top_p": 0.95,
            "max_tokens": 2000,
            "frequency_penalty": 0.0,
            "presence_penalty": 0.0,
            "description": "翻译任务,需要准确流畅"
        },

        "conversation": {
            "temperature": 0.7,
            "top_p": 0.95,
            "max_tokens": 800,
            "frequency_penalty": 0.5,
            "presence_penalty": 0.3,
            "description": "日常对话,自然友好"
        }
    }

    @classmethod
    def get_config(cls, preset: str) -> Dict:
        """获取预设配置"""
        return cls.PRESETS.get(preset, cls.PRESETS["factual_qa"])

    @classmethod
    def merge_config(
        cls, 
        preset: str, 
        overrides: Dict = None
    ) -> Dict:
        """合并配置,支持覆盖预设值"""
        config = cls.get_config(preset).copy()
        if overrides:
            config.update(overrides)
        return config

# 使用示例
config = ModelConfig.merge_config(
    "creative_writing",
    overrides={"max_tokens": 2000}  # 增加最大长度
)

response = client.chat.completions.create(
    model="gpt-3.5-turbo",
    messages=[{"role": "user", "content": "写一首关于春天的诗"}],
    **config
)

6.3 错误处理与容错机制

在实际应用中,稳定的错误处理机制是保证服务可用性的关键。

# 错误处理与重试机制
import time
import logging
from functools import wraps
from typing import Callable, Any, Optional

class RetryStrategy:
    """重试策略"""

    def __init__(
        self,
        max_retries: int = 3,
        base_delay: float = 1.0,
        max_delay: float = 60.0,
        exponential_base: float = 2.0
    ):
        self.max_retries = max_retries
        self.base_delay = base_delay
        self.max_delay = max_delay
        self.exponential_base = exponential_base

    def get_delay(self, attempt: int) -> float:
        """计算延迟时间"""
        delay = min(
            self.base_delay * (self.exponential_base ** attempt),
            self.max_delay
        )
        # 添加随机抖动
        import random
        jitter = delay * 0.1 * random.random()
        return delay + jitter


class APIError(Exception):
    """API错误基类"""
    pass

class RateLimitError(APIError):
    """速率限制错误"""
    pass

class AuthenticationError(APIError):
    """认证错误"""
    pass

class ServerError(APIError):
    """服务器错误"""
    pass

def with_retry(
    strategy: RetryStrategy = None,
    on_retry: Callable[[Exception, int], None] = None
):
    """
    带重试的装饰器

    Args:
        strategy: 重试策略
        on_retry: 重试时的回调函数
    """
    if strategy is None:
        strategy = RetryStrategy()

    def decorator(func: Callable) -> Callable:
        @wraps(func)
        def wrapper(*args, **kwargs) -> Any:
            last_exception = None

            for attempt in range(strategy.max_retries + 1):
                try:
                    return func(*args, **kwargs)

                except RateLimitError as e:
                    last_exception = e
                    if attempt < strategy.max_retries:
                        delay = strategy.get_delay(attempt)
                        logging.warning(
                            f"Rate limit hit, retrying in {delay:.2f}s "
                            f"(attempt {attempt + 1}/{strategy.max_retries})"
                        )
                        if on_retry:
                            on_retry(e, attempt)
                        time.sleep(delay)
                    else:
                        raise

                except (AuthenticationError, ServerError) as e:
                    last_exception = e
                    if attempt < strategy.max_retries:
                        delay = strategy.get_delay(attempt)
                        logging.warning(
                            f"API error: {e}, retrying in {delay:.2f}s "
                            f"(attempt {attempt + 1}/{strategy.max_retries})"
                        )
                        if on_retry:
                            on_retry(e, attempt)
                        time.sleep(delay)
                    else:
                        raise

                except Exception as e:
                    # 其他错误不重试
                    raise

            if last_exception:
                raise last_exception

        return wrapper
    return decorator


class RobustClient:
    """带错误处理的健壮客户端"""

    def __init__(self, client):
        self.client = client
        self.retry_strategy = RetryStrategy(
            max_retries=3,
            base_delay=2.0
        )

    @with_retry(strategy=RetryStrategy())
    def chat(self, *args, **kwargs):
        """带重试的聊天接口"""
        try:
            return self.client.chat.completions.create(*args, **kwargs)
        except Exception as e:
            if "rate limit" in str(e).lower():
                raise RateLimitError(f"Rate limit exceeded: {e}")
            elif "authentication" in str(e).lower():
                raise AuthenticationError(f"Authentication failed: {e}")
            elif "server" in str(e).lower():
                raise ServerError(f"Server error: {e}")
            else:
                raise

    @with_retry(strategy=RetryStrategy())
    def embeddings(self, *args, **kwargs):
        """带重试的嵌入接口"""
        return self.client.embeddings.create(*args, **kwargs)


def graceful_degradation(
    primary_func: Callable,
    fallback_func: Callable = None,
    fallback_response: str = "服务暂时不可用,请稍后再试"
):
    """
    优雅降级装饰器

    当主要功能失败时,使用备用方案或返回友好提示
    """
    def decorator(func: Callable) -> Callable:
        @wraps(func)
        def wrapper(*args, **kwargs):
            try:
                return primary_func(*args, **kwargs)
            except Exception as e:
                logging.error(f"Primary function failed: {e}")

                if fallback_func:
                    try:
                        return fallback_func(*args, **kwargs)
                    except Exception as fallback_error:
                        logging.error(f"Fallback also failed: {fallback_error}")

                return fallback_response

        return wrapper
    return decorator

6.4 性能优化技巧

在实际生产环境中,性能优化是非常重要的。以下是一些实用的优化技巧:

批量处理:当需要处理多个请求时,尽量使用批量API而不是逐个调用。这可以显著减少网络开销和API调用次数。

# 批量处理示例
class BatchProcessor:
    """批量处理器"""

    def __init__(self, client, batch_size: int = 20):
        self.client = client
        self.batch_size = batch_size

    def batch_chat(
        self, 
        prompts: List[str],
        system_prompt: str = None,
        max_tokens: int = 500
    ) -> List[str]:
        """
        批量处理聊天请求

        注意:OpenAI的聊天API不支持真正的批量,
        这里使用自定义实现模拟批量处理的效果
        """
        results = []

        for i in range(0, len(prompts), self.batch_size):
            batch = prompts[i:i+self.batch_size]

            messages_batch = [
                [{"role": "user", "content": prompt}]
                for prompt in batch
            ]

            for messages in messages_batch:
                if system_prompt:
                    messages.insert(0, {"role": "system", "content": system_prompt})

                response = self.client.chat.completions.create(
                    model="gpt-3.5-turbo",
                    messages=messages,
                    max_tokens=max_tokens
                )
                results.append(response.choices[0].message.content)

        return results

    def batch_embeddings(self, texts: List[str]) -> List[List[float]]:
        """批量获取嵌入向量"""
        all_embeddings = []

        for i in range(0, len(texts), self.batch_size):
            batch = texts[i:i+self.batch_size]

            response = self.client.embeddings.create(
                input=batch,
                model="text-embedding-ada-002"
            )

            for data in response.data:
                all_embeddings.append(data.embedding)

        return all_embeddings

缓存策略:对于重复的请求,使用缓存可以显著提高响应速度。

# 缓存实现示例
from functools import lru_cache
import hashlib
import json

class SemanticCache:
    """语义缓存"""

    def __init__(self, client, similarity_threshold: float = 0.95):
        self.client = client
        self.similarity_threshold = similarity_threshold
        self.cache = {}  # {query_hash: (query, response, timestamp)}
        self.cache_hits = 0
        self.cache_misses = 0

    def _hash_query(self, query: str) -> str:
        """生成查询的哈希值"""
        return hashlib.md5(query.encode()).hexdigest()

    def _compute_similarity(self, query1: str, query2: str) -> float:
        """计算两个查询的语义相似度"""
        embeddings = self.client.embeddings.create(
            input=[query1, query2],
            model="text-embedding-ada-002"
        )

        vec1 = embeddings.data[0].embedding
        vec2 = embeddings.data[1].embedding

        # 余弦相似度
        dot = sum(a * b for a, b in zip(vec1, vec2))
        norm1 = sum(a * a for a in vec1) ** 0.5
        norm2 = sum(b * b for b in vec2) ** 0.5

        return dot / (norm1 * norm2 + 1e-10)

    def get_or_generate(
        self, 
        query: str, 
        generate_func: Callable
    ) -> str:
        """获取缓存或生成新响应"""
        query_hash = self._hash_query(query)

        # 精确匹配检查
        if query_hash in self.cache:
            cached_query, response, _ = self.cache[query_hash]
            if cached_query == query:
                self.cache_hits += 1
                return response

        # 语义相似度检查
        for cached_hash, (cached_query, response, _) in self.cache.items():
            similarity = self._compute_similarity(query, cached_query)
            if similarity >= self.similarity_threshold:
                self.cache_hits += 1
                return response

        # 生成新响应
        self.cache_misses += 1
        response = generate_func(query)

        # 更新缓存
        self.cache[query_hash] = (query, response, time.time())

        return response

    def get_stats(self) -> Dict:
        """获取缓存统计"""
        total = self.cache_hits + self.cache_misses
        hit_rate = self.cache_hits / total if total > 0 else 0

        return {
            "cache_size": len(self.cache),
            "cache_hits": self.cache_hits,
            "cache_misses": self.cache_misses,
            "hit_rate": hit_rate
        }

第七部分:总结与资源链接

7.1 项目核心价值回顾

通过本文的详细介绍,相信你已经对Open-Generative-AI项目有了全面的了解。让我总结一下这个项目的核心价值:

开源自由:作为一个完全开源的项目,它让每个人都能自由地使用、修改和分发代码,打破了商业AI模型的高门槛限制。

隐私保护:本地部署的能力确保了你的数据永远不会离开你的控制范围,这对于处理敏感信息的企业和个人来说至关重要。

成本效益:告别按token计费的模式,你可以无限次地使用开源模型,大大降低了AI应用的开发和运营成本。

学习价值:开源项目是学习的最佳资源,通过研究代码和文档,你可以深入理解AI技术的工作原理,提升自己的技术能力。

灵活性:模块化的设计和丰富的扩展能力让你可以根据自己的需求定制解决方案,而不是被限制在固定的框架内。

7.2 进阶学习路径

如果你想进一步提升自己在生成式AI领域的技能,以下是一些建议的学习路径:

基础阶段:深入学习Python编程、API设计基础、RESTful接口规范。这些是使用任何AI服务的必备技能。

进阶阶段:学习机器学习和深度学习的基础理论,了解Transformer架构的原理,阅读GPT系列论文的原始文献。

实践阶段:尝试构建自己的AI应用,参加开源项目贡献,参与AI竞赛和挑战赛。

专业阶段:深入研究某个垂直领域,如NLP、计算机视觉、语音识别等,成为该领域的专家。

7.3 相关资源推荐

官方资源

  • GitHub仓库:https://github.com/Anil-matcha/Open-Generative-AI
  • 官方文档:项目内的docs文件夹包含详细的使用文档
  • 示例代码:项目内的examples文件夹包含丰富的示例

学习资源

  • OpenAI官方API文档:学习API设计和最佳实践
  • Hugging Face Transformers:最流行的NLP模型库
  • LangChain:构建AI应用的开发框架
  • LangSmith:AI应用调试和优化工具

社区资源

  • GitHub Issues:获取帮助和报告问题
  • Discord服务器:与其他开发者交流
  • Reddit AI社区:了解最新动态和讨论

7.4 未来展望

生成式AI领域正在快速发展,新模型、新工具、新应用层出不穷。作为一个开源项目,Open-Generative-AI也在持续迭代和发展。我们可以期待:

更强大的模型支持:项目将持续集成最新的开源模型,提供更多选择。

更丰富的功能:计划中的功能包括多模态支持、Agent框架、更完善的工具系统等。

更好的性能:通过优化和硬件加速,推理速度将不断提升。

更活跃的社区:期待更多开发者参与贡献,共同推动项目发展。


结语

技术的力量在于分享和传承。希望通过这篇教程,能够帮助更多人了解和使用这个强大的开源项目,在AI的浪潮中找到属于自己的位置。无论你是刚刚入门的新手,还是经验丰富的老兵,这个项目都能为你提供有价值的工具和资源。

最后,如果你在使用过程中遇到任何问题,欢迎访问项目的GitHub页面提交Issue,或者在社区中寻求帮助。AI的未来属于每一个热爱技术、愿意探索的人。祝你在这个充满可能性的领域中收获满满!

祝学习愉快,创作顺利!


项目地址:https://github.com/Anil-matcha/Open-Generative-AI

Star关注:如果这个项目对你有帮助,请不要忘记在GitHub上给我们一个Star,你的支持是我们前进的动力!


本文档会持续更新,最新版本请参考项目仓库。如有任何问题或建议,欢迎提出Issue或Pull Request。

如果内容对您有帮助,欢迎打赏

您的支持是我继续创作的动力

前往打赏页面

评论区

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注