用Llama 3和Groq打造生成式AI新闻摘要

在这篇文章中,我们要一起打造一个生成式 AI 新闻搜索后台。我们的选择是 Meta 的 Llama-3 8B 模型,这一切都将通过 Groq 的 LPU 来实现。

关于 Groq

如果你还不知道 Groq,那就让我来介绍一下。Groq 正在重新定义大型语言模型(LLM)中文本生成的推理速度标准。它提供了一种名为 LPU(语言处理单元)的接口引擎,这是一种全新的端到端处理单元系统,为那些包含序列组件的计算密集型应用提供了前所未有的快速推理能力,正如在大型语言模型中看到的那样。

我们这里不打算深入讨论为什么 Groq 的推理速度能远超 GPU。我们的目标是利用 Groq 提供的速度优势和 Llama 3 在文本生成方面的能力,创建一个与 Bing AI 搜索、Google AI 搜索或 PPLX 类似的生成式 AI 新闻搜索服务。

为什么是 Llama 3?

Meta 最近发布的 Llama 3 模型非常受欢迎。其中更大的 70B Llama 3 模型目前在 LMSys LLM 排行榜中位居第五。在英语任务方面,这一模型排名第二,仅次于 GPT-4。

Meta 在其发布博客中提到,8B 模型在其类别中表现最佳,而 70B 模型则胜过了 Gemini Pro 1.5 和 Claude 3 Sonnet。

为了展现模型对现实世界情境和问题的理解能力,Meta 创建了一个高质量的人类评估集。这个评估集包括 1800 个情景,覆盖了 12 个关键用例,如寻求建议、头脑风暴、分类、回答封闭问题、编程、创意写作、提取信息、扮演角色、回答开放问题、推理、改写和总结。

这个数据集被模型开发团队保密,以避免模型在这些数据上过度拟合。在测试中,Llama 3 70B 在与 Claude Sonnet、Mistral Medium、GPT-3.5 和 Llama 2 的比较中表现出色。

鉴于这些基准数据支持 Llama 3 的优势,我们决定将其用于我们的生成式 AI 新闻搜索。

一般来说,较小的模型因为不需要大量的 VRAM 并且参数计算更少,所以推理速度更快,因此我们选择使用较小的 Llama 3 模型,即 Llama 3 8B 模型。

开始编码。

新闻 API

我们将利用 Newsdata.io 提供的免费新闻 API 根据搜索查询获取新闻内容。我们也可以使用来自 Google 的 RSS 源,或者其他任何新闻 API 来实现这一点。

你可以通过 API 令牌访问 Newsdata 新闻 API,这个令牌可以在 Newsdata 平台注册后获得。一旦我们拿到 API 令牌,就只需要发起一个带有搜索查询的 GET 请求,获取结果,并将其传递给 LLM。

下面是我们用来通过 Newsdata.io API 获取新闻的代码片段。

# news.py``   ``import os``import httpx``from configs import NEWS_API_KEY, NEWS_BASE_URL``   ``async def getNews(query: str, max_size: int = 8):`    `async with httpx.AsyncClient(timeout=60) as client:`        `response = await client.get(`            `os.path.join(NEWS_BASE_URL, "news") +`            `f"?apiKey={NEWS_API_KEY}&q={query}&size={max_size}")`        `try:`            `response.raise_for_status()`            `return response.json()`        `except httpx.HTTPStatusError as e:`            `print(`                `f"Error resposne {e.response.status_code} while requesting {e.request.url!r}"`            `)`            `return None

我们使用 httpx 库异步调用 API,传入 API 令牌和搜索词。如果响应状态码是 200,我们返回响应,否则打印异常信息并返回 None。

Groq 接口

Groq 通过通过 API 密钥进行身份验证的 REST API 提供 Llama 3 8B 模型。我们还可以通过官方的 Groq Python 库与 Llama 3 8B 模型进行交互。

以下是我们将如何与 Groq 进行交互。

Groq 通过 REST API 提供 Llama 3 8B 模型,并通过 API 密钥进行认证。我们还可以通过官方的 Groq Python 库与 Llama 3 8B 模型进行交互。

下面是我们如何使用 Groq。

# llms/groq.py``   ``from groq import Groq, AsyncGroq``import traceback``from typing import List, Dict, Union``from llms.base import BaseLLM``from llms.ctx import ContextManagement``from groq import RateLimitError``import backoff``   ``manageContext = ContextManagement()``   ``class GroqLLM(BaseLLM):``   `    `def __init__(self, api_key: Union[str, None] = None):`        `super().__init__(api_key)`        `self.client = AsyncGroq(api_key=api_key)``   `    `@backoff.on_exception(backoff.expo, RateLimitError, max_tries=3)`    `async def __call__(self, model: str, messages: List[Dict], **kwargs):`        `try:`            `if "system" in kwargs:`                `messages = [{`                    `"role": "system",`                    `"content": kwargs.get("system")`                `}] + messages`                `del kwargs["system"]`            `if "ctx_length" in kwargs:`                `del kwargs["ctx_length"]`            `messages = manageContext(messages, kwargs.get("ctx_length", 7_000))`            `output = await self.client.chat.completions.create(`                `messages=messages, model=model, **kwargs)`            `return output.choices[0].message.content`        `except RateLimitError:`            `raise RateLimitError`        `except Exception as err:`            `print(f"ERROR: {str(err)}")`            `print(f"{traceback.format_exc()}")`            `return ""``   ``class GroqLLMStream(BaseLLM):``   `    `def __init__(self, api_key: Union[str, None] = None):`        `super().__init__(api_key)`        `self.client = AsyncGroq(api_key=api_key)``   `    `async def __call__(self, model: str, messages: List[Dict], **kwargs):`        `if "system" in kwargs:`            `# print(f"System in Args")`            `messages = [{`                `"role": "system",`                `"content": kwargs.get("system")`            `}] + messages`            `del kwargs["system"]`        `# print(f"KWARGS KEYS: {kwargs.keys()}")`        `messages = manageContext(messages, kwargs.get("ctx_length", 7_000))`        `if "ctx_length" in kwargs:`            `del kwargs["ctx_length"]`        `output = await self.client.chat.completions.create(messages=messages,`                                                           `model=model,`                                                           `stream=True,`                                                           `**kwargs)`        `async for chunk in output:`            `# print(chunk.choices[0])`            `yield chunk.choices[0].delta.content or ""

我习惯于让 LLM 类从 BaseLLM 继承,这样可以通过基类控制所有常见的功能。下面是 BaseLLM 的定义。

# llms/base.py``   ``from abc import ABC, abstractmethod``from typing import List, Dict, Union``   ``class BaseLLM(ABC):``   `    `def __init__(self, api_key: Union[str, None] = None, **kwargs):`        `self.api_key = api_key`        `self.client = None`        `self.extra_args = kwargs``   `    `@abstractmethod`    `async def __call__(self, model: str, messages: List[Dict], **kwargs):`        `pass

使用 Llama 3 8B 模型,我们可以在上下文长度中使用 8192 个词元。其中我们将 7000 个词元用于输入上下文,其余用于输出或生成。

如果输入上下文超过 7000 个词元,那么我们需要管理这个上下文,以便为输出生成保留足够的词元。为此,我们编写了下面的 ContextManagement 工具。

# llms/ctx.py``   ``from typing import List, Dict, Literal, Union``from transformers import AutoTokenizer``   ``class ContextManagement:``   `    `def __init__(self):`        `# assert "mistral" in model_name, "MistralCtx only available for Mistral models"`        `self.tokenizer = AutoTokenizer.from_pretrained(`            `"meta-llama/Meta-Llama-3-8B")``   `    `def __count_tokens__(self, content: str):`        `tokens = self.tokenizer.tokenize(content)`        `return len(tokens) + 2``   `    `def __pad_content__(self, content: str, num_tokens: int):`        `return self.tokenizer.decode(`            `self.tokenizer.encode(content, max_length=num_tokens))``   `    `def __call__(self, messages: List[Dict], max_length: int = 28_000):`        `managed_messages = []`        `current_length = 0`        `current_message_role = None`        `for ix, message in enumerate(messages[::-1]):`            `content = message.get("content")`            `message_tokens = self.__count_tokens__(message.get("content"))`            `if ix > 0:`                `if current_length + message_tokens >= max_length:`                    `tokens_to_keep = max_length - current_length`                    `if tokens_to_keep > 0:`                        `content = self.__pad_content__(content, tokens_to_keep)`                        `current_length += tokens_to_keep`                    `else:`                        `break`                `if message.get("role") == current_message_role:`                    `managed_messages[-1]["content"] += f"\\n\\n{content}"`                `else:`                    `managed_messages.append({`                        `"role": message.get("role"),`                        `"content": content`                    `})`                    `current_message_role = message.get("role")`                    `current_length += message_tokens`            `else:`                `if current_length + message_tokens >= max_length:`                    `tokens_to_keep = max_length - current_length`                    `if tokens_to_keep > 0:`                        `content = self.__pad_content__(content, tokens_to_keep)`                        `current_length += tokens_to_keep`                        `managed_messages.append({`                            `"role": message.get("role"),`                            `"content": content`                        `})`                    `else:`                        `break`                `else:`                    `managed_messages.append({`                        `"role": message.get("role"),`                        `"content": content`                    `})`                    `current_length += message_tokens`                `current_message_role = message.get("role")`            `# print(managed_messages)`        `print(f"TOTAL TOKENS: ", current_length)`        `return managed_messages[::-1]

我们使用 HuggingFace 的 tokenizers 库来对我们的消息进行标记化和计算词元,并只保留符合我们之前设定的最大词元长度(7000)的消息内容。

要使用 meta-llama/Meta-Llama-3–8B 分词器,我们首先需要在 HuggingFace 上提供我们的详细信息并接受 Meta 提供的使用条款,并通过使用 huggingface-cli login 命令或在 AutoTokenizer 的 from_pretrained 方法中提供 token 将我们的 HuggingFace token 添加到我们的机器上。

提示词

我们将使用一个非常简单的提示来进行我们的生成式 AI 新闻搜索应用。提示如下。

# prompts.py``   ``SYSTEM_PROMPT = """You are a news summary bot. When a user provides a query, you will receive several news items related to that query. Your task is to assess the relevance of these news items to the query and retain only the ones that are pertinent.``If there are relevant news items, you should summarize them in a concise, professional, and respectful manner. The summary should be delivered in the first person, and you must provide citations for the news articles in markdown format. Do not inform the user about the number of news items reviewed or found; focus solely on delivering a succinct summary of the relevant articles.``In cases where no relevant news items can be found for the user's query, respond politely stating that you cannot provide an answer at this time. Remember, your responses should directly address the user's interest without revealing the backend process or the specifics of the data retrieval.``For example, if the query is about "Lok Sabha elections 2024" and relevant articles are found, provide a summary of these articles. If the articles are unrelated or not useful, inform the user respectfully that you cannot provide the required information.``"""

提示非常直接易懂。

代理

让我们把所有的部分整合起来,完成我们的生成式 AI 新闻搜索代理。

# agent.py``   ``from llms.groq import GroqLLMStream``from configs import GROQ_API_KEY, GROQ_MODEL_NAME``from news import getNews``from prompts import SYSTEM_PROMPT``   ``llm = GroqLLMStream(GROQ_API_KEY)``   ``async def newsAgent(query: str):`    `retrieved_news_items = await getNews(query)`    `if not retrieved_news_items:`        `yield "\\n_无法获取与搜索查询相关的新闻。_""`        `return`    `retrieved_news_items = retrieved_news_items.get("results")`    `useful_meta_keys = [`        `"title", "link", "keywords", "creator", "description", "country",`        `"category"`    `]`    `news_items = [{`        `k: d[k]`        `for k in useful_meta_keys`    `} for d in retrieved_news_items]`    `messages = [{`        `"role": "user",`        `"content": f"查询: {query}\\n\\n新闻条目: {news_items}"``    }]`    `async for chunk in llm(GROQ_MODEL_NAME,`                           `messages,`                           `system=SYSTEM_PROMPT,`                           `max_tokens=1024,`                           `temperature=0.2):`        `yield chunk

上面我们导入了与 Groq 上的 Llama 3 交互、上下文管理、系统提示和新闻检索所需的所有模块。接着,我们定义了 newsAgent 函数,这个函数接受用户的查询作为唯一参数。

在 newsAgent 中,我们首先通过 Newsdata.io API 检索新闻,然后选择我们想要传递给 LLM 的相关键值。然后我们将查询、检索到的新闻项和系统提示连同模型名称传递给我们的流式 Groq 接口,并随着它们生成和接收时产生数据块。

环境变量和配置

我们需要设置以下环境变量来运行我们的生成式 AI 新闻搜索应用程序。

环境变量

GROQ_API_KEY="YOUR_GROQ_API_KEY"``GROQ_MODEL_NAME="llama3-8b-8192"``   ``NEWS_API_KEY="YOUR_NEWS_API_KEY"``NEWS_BASE_URL="<https://newsdata.io/api/1/>"

我们需要 Groq API 密钥和 Newsdata.io 的 API 密钥来检索新闻。

加载环境变量

import os``from dotenv import load_dotenv``   ``load_dotenv()``   ``GROQ_API_KEY = os.environ.get("GROQ_API_KEY")``GROQ_MODEL_NAME = os.environ.get("GROQ_MODEL_NAME")``   ``NEWS_API_KEY = os.environ.get("NEWS_API_KEY")``NEWS_BASE_URL = os.environ.get("NEWS_BASE_URL")

暴露 API

我们的生成式 AI 新闻搜索代理几乎准备就绪。我们只需要通过流式 API 暴露它。为此,我们将使用 FastAPI 和 Uvicorn,如下面的代码所示。

# app.py``   ``from fastapi import FastAPI``from fastapi.responses import StreamingResponse``from fastapi.middleware.cors import CORSMiddleware``import uvicorn``   ``from agent import newsAgent``   ``app = FastAPI()``   ``origins = ["*"]``   ``app.add_middleware(`    `CORSMiddleware,`    `allow_origins=origins,`    `allow_credentials=True,`    `allow_methods=["*"],`    `allow_headers=["*"],``)``   ``@app.get("/")``async def index():`    `return {"ok": True}``   ``@app.get("/api/news")``async def api_news(query: str):`    `return StreamingResponse(newsAgent(query), media_type="text/event-stream")``   ``if __name__ == "__main__":`    `uvicorn.run("app:app", host="0.0.0.0", port=8899, reload=True)

上面,我们导入了我们的 newsAgent 以及所需的 FastAPI 和 Uvicorn 模块,并设置了 FastAPI 应用程序。

我们创建了一个索引端点仅用于健康检查。我们的新闻搜索代理通过 /api/news 路由暴露,该路由返回流式响应。

完成 app.py 文件后,我们可以使用以下命令启动服务器。

python app.py

服务器将在端口号 8899 上启动。

我们现在可以在浏览器上转到 http://localhost:8899/api/news?query=searchtext 并以以下方式获取我们的新闻。

整个代码库可在下面提供的链接中找到。

GitHub - GenAINewsAgent:https://github.com/mcks2000/llm_notebooks/tree/main/agent/GenAINewsAgent

总结

在本篇博客中,我们展示了如何通过 Groq 提供的快速 LPU(语言处理单元)接口实现近乎实时的推理。我们还瞥见了 Llama 3 在基准测试中的出色表现,并将小型版 Llama 3 8B 模型集成进了新闻摘要功能中。

如何学习大模型 AI ?

由于新岗位的生产效率,要优于被取代岗位的生产效率,所以实际上整个社会的生产效率是提升的。

但是具体到个人,只能说是:

“最先掌握AI的人,将会比较晚掌握AI的人有竞争优势”。

这句话,放在计算机、互联网、移动互联网的开局时期,都是一样的道理。

我在一线互联网企业工作十余年里,指导过不少同行后辈。帮助很多人得到了学习和成长。

我意识到有很多经验和知识值得分享给大家,也可以通过我们的能力和经验解答大家在人工智能学习中的很多困惑,所以在工作繁忙的情况下还是坚持各种整理和分享。但苦于知识传播途径有限,很多互联网行业朋友无法获得正确的资料得到学习提升,故此将并将重要的AI大模型资料包括AI大模型入门学习思维导图、精品AI大模型学习书籍手册、视频教程、实战学习等录播视频免费分享出来。

在这里插入图片描述

第一阶段(10天):初阶应用

该阶段让大家对大模型 AI有一个最前沿的认识,对大模型 AI 的理解超过 95% 的人,可以在相关讨论时发表高级、不跟风、又接地气的见解,别人只会和 AI 聊天,而你能调教 AI,并能用代码将大模型和业务衔接。

  • 大模型 AI 能干什么?
  • 大模型是怎样获得「智能」的?
  • 用好 AI 的核心心法
  • 大模型应用业务架构
  • 大模型应用技术架构
  • 代码示例:向 GPT-3.5 灌入新知识
  • 提示工程的意义和核心思想
  • Prompt 典型构成
  • 指令调优方法论
  • 思维链和思维树
  • Prompt 攻击和防范

第二阶段(30天):高阶应用

该阶段我们正式进入大模型 AI 进阶实战学习,学会构造私有知识库,扩展 AI 的能力。快速开发一个完整的基于 agent 对话机器人。掌握功能最强的大模型开发框架,抓住最新的技术进展,适合 Python 和 JavaScript 程序员。

  • 为什么要做 RAG
  • 搭建一个简单的 ChatPDF
  • 检索的基础概念
  • 什么是向量表示(Embeddings)
  • 向量数据库与向量检索
  • 基于向量检索的 RAG
  • 搭建 RAG 系统的扩展知识
  • 混合检索与 RAG-Fusion 简介
  • 向量模型本地部署

第三阶段(30天):模型训练

恭喜你,如果学到这里,你基本可以找到一份大模型 AI相关的工作,自己也能训练 GPT 了!通过微调,训练自己的垂直大模型,能独立训练开源多模态大模型,掌握更多技术方案。

到此为止,大概2个月的时间。你已经成为了一名“AI小子”。那么你还想往下探索吗?

  • 为什么要做 RAG
  • 什么是模型
  • 什么是模型训练
  • 求解器 & 损失函数简介
  • 小实验2:手写一个简单的神经网络并训练它
  • 什么是训练/预训练/微调/轻量化微调
  • Transformer结构简介
  • 轻量化微调
  • 实验数据集的构建

第四阶段(20天):商业闭环

对全球大模型从性能、吞吐量、成本等方面有一定的认知,可以在云端和本地等多种环境下部署大模型,找到适合自己的项目/创业方向,做一名被 AI 武装的产品经理。

  • 硬件选型
  • 带你了解全球大模型
  • 使用国产大模型服务
  • 搭建 OpenAI 代理
  • 热身:基于阿里云 PAI 部署 Stable Diffusion
  • 在本地计算机运行大模型
  • 大模型的私有化部署
  • 基于 vLLM 部署大模型
  • 案例:如何优雅地在阿里云私有部署开源大模型
  • 部署一套开源 LLM 项目
  • 内容安全
  • 互联网信息服务算法备案

学习是一个过程,只要学习就会有挑战。天道酬勤,你越努力,就会成为越优秀的自己。

如果你能在15天内完成所有的任务,那你堪称天才。然而,如果你能完成 60-70% 的内容,你就已经开始具备成为一名大模型 AI 的正确特征了。

这份完整版的大模型 AI 学习资料已经上传CSDN,朋友们如果需要可以微信扫描下方CSDN官方认证二维码免费领取【保证100%免费

在这里插入图片描述

  • 9
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值