Agno实战自主式AI应用

在这篇教程中,我将展示如何在本地机器或专用云服务器上使用免费的LLM模型创建一个简单的聊天机器人。

我们将开发一个应用程序,回答关于《Gloomhaven》棋盘游戏规则的问题。这款游戏很有趣,但有时规则会让你头昏脑涨。

我们的智能助手将帮助我们解决游戏中的一些棘手情况,并提供相关规则书中的链接。

Gloomhaven 助手解释游戏规则并提供参考

完整的示例代码可以在这个仓库中找到。

1、工具概述

有许多更简单的方法可以通过无代码或低代码框架实现这一点,但我们将会深入探讨底层概念和框架,并使用最少的高级工具。

我们将使用Agno,这是一个易于启动的自主框架。它的优点之一是对各种向量数据库的广泛支持,例如pgVector、Pinecone 和 LanceDB。

我们将让演示在完全本地的LLM上运行。与本地LLM相比,OpenAI 更容易使用。然而,OpenAI 就像电子烟:看起来无害,但长期来看它会让人上瘾且昂贵,并且你可能并不需要它。此外,OpenAI 收集所有你的数据以创造强大的超级智能来奴役人类。

2、什么是RAG?

RAG通过从外部来源检索相关信息增强模型,通常是向量数据库。它处理各种格式的文档集合,将其拆分为块。然后,它使用专门的模型——嵌入器——为每个块创建向量嵌入,这些嵌入存储在向量数据库中。

嵌入器是一种函数(神经网络),它将文本块转换为更方便的表示形式。例如,“一杯牛奶”可以是一个数字向量,如[0.23, 1.58, ..., 8.45]。类似的短语将以相似的向量表示。然后,这些向量及其相应文本块的位置被存储在向量数据库中。

机器学习中的嵌入

当用户提出问题时,标准RAG为其创建一个嵌入,搜索数据库以查找几个最近的嵌入向量,并返回相应的文本块。例如,用户可以提供提示“喝”,RAG 将返回“一杯牛奶”和其他在我们的文档中引用的饮料。这是RAG管道中的“检索”部分。

之后,在将用户的原始查询传递给LLM之前,将其扩展以包括这些文本块作为附加信息,就像给LLM的一个提示,帮助其给出正确的答案而不会产生幻觉。这是RAG管道中的“增强”部分。

经典RAG管道

3、什么是自主式RAG?

另一方面,自主式RAG允许模型使用特殊工具以嵌入方式查询向量数据库。这样,模型可以决定是否需要访问相关信息以回答问题,使用哪些查询以及访问多少次。如果第一次查询不够充分,模型还可以查询更多额外的信息。

自主式RAG管道

自主式RAG系统功能更强大,但预测性较差,调试起来更复杂,设置起来更具挑战性。对于像我们这样的简单应用,经典RAG更受欢迎。

4、开发环境

我在一台配备4070Ti的PC上测试了这个教程。如果你的机器足够快,可以直接跳到下一节。否则,你可能想租一台GPU机器用于开发。要这样做,请查看如何在neuralrack.ai上租用GPU机器。我已经使用这个服务测试了本文中的代码。

5、依赖项

首先,如果你还没有在之前的步骤中创建Python虚拟环境,我们需要先创建一个。

python3 -m venv venv  
source venv/bin/activate

使用以下命令安装所需的依赖项。你也可以使用示例源代码中的requirements.txt文件。

pip install lancedb pylance tantivy agno ollama streamlit pypdf sqlalchemy

然后安装Ollama。Ollama 是一个易于使用的工具,用于在本地运行LLM模型。

curl -fsSL https://ollama.com/install.sh | sh

6、选择LLM

不同的模型适用于不同的应用。你可以在LLM排行榜网站ProLLM上找到比较结果。另一个重要的因素是模型的大小及其运行成本。

例如,如果你的计算资源有限,可以使用gemma3模型的1b或4b版本。对于RTX 4090(24GB内存),你可以使用27b版本。如果你有一台有两个或更多的RTX 4090机器,你可以运行llama3.3deepseek-r1:70b。要运行Llama4,你需要至少一个H100。

嵌入模型是一个单独的模型,仅用于创建嵌入向量。它们通常小得多,所以我们使用Ollama提供的顶级表现模型之一,即mxbai-embed-large

下载你想要使用的Ollama模型。一个是用于聊天客户端,另一个是用于嵌入。

ollama pull gemma3:27b  
ollama pull mxbai-embed-large

7、简单的RAG代理

要使用Agno框架与RAG一起工作,我们必须首先创建一个包含所有文档的知识库。知识库包含我们将引用的Gloomhaven规则。创建知识库意味着将其转换为嵌入模型的向量表示,如前面几节所述。我们使用LanceDB因为它是一个简单的向量数据库,可以在本地使用。

from agno.embedder.ollama import OllamaEmbedder  
from agno.models.ollama import Ollama  
from agno.knowledge.pdf_url import PDFUrlKnowledgeBase  
from agno.vectordb.lancedb import LanceDb, SearchType  

embedder = OllamaEmbedder(id="mxbai-embed-large", dimensions=1024)  
vector_db = LanceDb(  
    table_name="gloomhaven",  
    uri="/tmp/lancedb",  
    search_type=SearchType.hybrid,  
    embedder=embedder  
)  
knowledge_base = PDFUrlKnowledgeBase(  
    urls=["https://cdn.1j1ju.com/medias/8d/c5/21-gloomhaven-rulebook.pdf"],  
    vector_db=vector_db  
)

加载知识库。你只需要做一次。脚本将在你的文件系统中创建一个本地数据库,因此你不需要每次运行时都执行以下操作:

knowledge_base.load(upsert=True)

让我们先使用传统的RAG。在创建Agno代理时,必须提供知识库并设置标志 add_context=True 来启用RAG。标志 add_history_to_messages=Truenum_history_responses=10 允许该代理在同一会话中使用简单的、固定长度的内置聊天历史记录。

from agno.agent import Agent

agent = Agent(
    model=Ollama(id="gemma3:27b", options={"num_ctx": 16192}),
    # Enable RAG
    knowledge=knowledge_base,
    add_context=True,
    # Add references to the original documents
    add_references=True,
    description="You are an expert in the rules of the board game gloomhaven.",
    instructions=[
        "Use additional data provided for the corresponding rules.",
        "Cite the rules book with the corresponding information at the end of the answer to a question"
    ],
    search_knowledge=False,
    add_history_to_messages=True,
    num_history_responses=10,
    markdown=True,
    # debug_mode=True,
)

使用 RAG 运行 ollama 模型时,必须指定上下文大小,我们通过向模型添加 options={“num_ctx”: 16192} 来实现。更大的上下文需要更多的 GPU 内存,因此请根据可用硬件调整上下文大小。

默认大小 2048 通常不足以满足 RAG 应用程序的需求。在将模型从 OpenAI 更改为本地 LLM 后,我在调试应用程序时花了不少时间才弄清楚这一点。

我们可以像这样测试代理。

prompt = "Summarize game rules in three sentences"
response = agent.run(prompt)
print(response.content)

运行此代码后我们将得到类似的结果:

如果我们想将其更改为 Agentic RAG,只需对代理进行一些小的更改。请记住,Agentic RAG 功能更强大,它使 LLM 能够灵活地多次查询数据库。然而,这也会使应用程序的可预测性降低。

from agno.agent import Agent

agent = Agent(
    model=Ollama(id="gemma3:27b", options={"num_ctx": 16192}),
    # Enable RAG
    knowledge=get_knowledge_base(),
    # Add references to the original documents
    add_references=True,
    description="You are an expert in the rules of the board game gloomhaven.",
    instructions=[
        "Use additional data provided for the corresponding rules.",
        "Cite the rules book with the corresponding information at the end of the answer to a question"
    ],
    # Add a tool to search the knowledge base which enables agentic RAG.
    search_knowledge=True,
    add_history_to_messages=True,
    num_history_responses=10,
    show_tool_calls=True,
    markdown=True,
    # debug_mode=True,
)

8、聊天机器人 UI

让我们创建一个简单的 Web 界面,让聊天机器人运行并回答我们的问题。

我们将使用 Streamlit(一个开源 Python 框架)来创建一个交互式 Web 应用。Gradio 是一个不错的选择。利用 Gradio 和 HuggingFace Spaces 是与好友分享应用的好方法。

Streamlit 框架的工作原理是每次我们与网页交互时都会重新运行脚本。这意味着保存不同运行之间可用的数据至关重要。

此脚本应与我们的模型 Python 文件放在一个单独的文件中;我们将其命名为 app.py。

首先,我们将知识库创建过程封装在一个函数中,并使用 @st.cache_resource 装饰器。这将确保该函数仅在脚本启动时运行一次,并且其结果将被缓存,并在同一会话的不同运行中甚至在其他会话(每个会话对应一个打开的 Web 应用选项卡)中重复使用。

import streamlit as st
from agno.agent import Agent
from agno.embedder.ollama import OllamaEmbedder
from agno.models.ollama import Ollama
from agno.knowledge.pdf_url import PDFUrlKnowledgeBase
from agno.vectordb.lancedb import LanceDb, SearchType

@st.cache_resource
def get_knowledge_base():
    embedder = OllamaEmbedder(id="mxbai-embed-large", dimensions=1024)
    vector_db = LanceDb(
        table_name="gloomhaven",
        uri="/tmp/lancedb",
        search_type=SearchType.keyword,
        embedder=embedder
    )
    knowledge_base = PDFUrlKnowledgeBase(
        urls=["https://cdn.1j1ju.com/medias/8d/c5/21-gloomhaven-rulebook.pdf"],
        vector_db=vector_db
    )
    # Load the knowledge base on the first run
    knowledge_base.load(upsert=True)
    return knowledge_base

现在,让我们创建一个生成器函数,每次返回一个文本标记。我们将用它来模拟聊天机器人响应中的打字机效果。

def stream_response(agent, prompt):
    response = agent.run(prompt, stream=True)
    for chunk in response:
        yield chunk.content

Streamlit 有一个 st.session_state 字段,可用于存储整个会话的数据。让我们用消息历史记录和当前会话中要使用的代理来初始化它。

if 'messages' not in st.session_state:
    st.session_state.messages = []

if 'agent' not in st.session_state:
    st.session_state.agent = Agent(
        model=Ollama(id="gemma3:27b", options={"num_ctx": 16192}),
        knowledge=get_knowledge_base(),
        add_context=True,
        add_references=True,
        description="You are an expert in the rules of the board game gloomhaven.",
        instructions=[
            "Use additional data provided for the corresponding rules.",
            "Cite the rules book with the corresponding information at the end of the answer to a question"
        ],
        search_knowledge=False,
        add_history_to_messages=True,
        num_history_responses=10,
        show_tool_calls=True,
        markdown=True,
        debug_mode=True,
    )

agent = st.session_state.agent

接下来,让我们为一个简单的聊天机器人创建 Web 界面。这里的主要组件是 st.chat_input(用户将使用它来输入问题)和 st.chat_message(用于显示上一个问题的答案以及机器人之前的聊天记录)。

st.title("Chat with the Gloomhaven expert")
prompt = st.chat_input("Your question")
if prompt:
    st.session_state.messages.append({'role': 'user', 'text': prompt})
    for message in st.session_state.messages:
        with st.chat_message(message['role']):
            st.write(message['text'])
    with st.chat_message('assistant'):
        response = st.write_stream(stream_response(agent, prompt))
        st.session_state.messages.append({'role': 'assistant', 'text': response})

使用以下命令运行脚本:

streamlit run app.py

然后,转到链接查看聊天机器人界面:http://localhost:8501 — 如果在本地运行,http://:8501 — 如果在远程服务器上运行。

我们的 AI 代理正在回答有关 Gloomhaven 的问题

你可以在代理中使用 debug_mode=True 标志来启用调试模式。在这种情况下,您可以查看日志或正在运行的启用 RAG 的代理,查看从数据库中提取了哪些文本块,并检查它们与所提问题的对应程度。

代理在调试模式下运行时,其控制台输出显示了从规则手册中提取的用于回答提示的参考资料

9、结束语

本教程教我们如何使用 RAG 实现一个基本的 AI 代理,该代理可以使用本地 LLM 查询知识库。使用本地 LLM 比依赖现成的 OpenAI 端点更复杂,但它提供了更大的灵活性,可以节省计算成本,并允许您开发具有严格安全要求的应用程序。

我使用了 Agno 代理框架、mxbai-embed-large 嵌入、LanceDB 矢量数据库、Ollama LLM 运行器、Streamlit UI 框架和 NeuralRack GPU 租赁服务。

示例代码可在此处获取。


原文链接:How to Develop your First (Agentic) RAG Application?

汇智网翻译整理,转载请标明出处