近年来,大型语言模型(LLM)席卷了人工智能领域。它们能撰写文章、回答问题、总结文档,甚至可以辅助编程。而现在,新一轮的 AI 创新浪潮正在兴起—— AI Agent。与一次只能回复一个问题的简单聊天机器人不同,AI Agent 能够思考问题、采取行动、使用工具并完成复杂的任务,而且通常无需太多人工干预。它们更像是数字助理,能够计划、推理,甚至与其他 Agent 协作来完成工作。本文将带你入门 Llama Stack,一步步构建你的第一个 AI Agent。

什么是 AI Agent?

可以将 AI Agent 视为一个超级聪明的实习生,而且你无需多次培训它。你不是与它聊天,而是给它一个目标,它会自行找出完成目标的方法。例如,假设你想要一份关于网站流量趋势的报告。一个 AI Agent 可以提取数据,分析数据,编写摘要,甚至将摘要通过电子邮件发送给你的团队——所有这些都无需你亲自动手。

AI Agent 的核心是由模块化部分组成,每个部分都有特定的作用,这使它们能够自主运行。典型的 AI Agent 架构包含以下几个关键组件:

  • 语言模型 (LLM):Agent 的大脑。通常是像 GPT、Mistral 或 LLaMA 这样强大的模型,能够理解并生成类似人类的文本。
  • 记忆 (Memory):允许 Agent 记住过去的交互或事实,形成长期记忆或短期记忆,以便更好地理解上下文。
  • 规划与推理引擎 (Planning and Reasoning Engine):帮助 Agent 将任务分解为更小的步骤,做出决策,并选择下一步要采取的最佳行动。 例如,给定一个 “预订下周二北京到上海的机票” 的任务,规划引擎会将其分解为“查询机票”、“选择航班”、“填写乘客信息”、“支付” 等步骤。
  • 工具使用 (Tool Use/Tool Calling):Agent 可以使用外部工具——如搜索引擎 API、计算器、文件读取器或数据库——来完成任务。 这是使它们具有实际操作能力的关键。例如,Agent可以使用搜索引擎API来查询天气预报,或者使用数据库工具来检索客户信息。
  • 环境或接口 (Environment or Interface):Agent 与之交互的世界——它可以是 Web 应用程序、命令行,甚至是现实世界(用于机器人)。
  • 控制器或 Agent 框架 (Controller or Agent Framework):充当管理者——它决定如何将所有内容组合在一起,协调各个组件的工作。

顶级的 AI Agent 框架

目前涌现出许多开源 Agent 框架,使开发人员能够更轻松地构建、部署和管理 AI Agent,而无需重新发明轮子。以下是其中一些最受欢迎的框架:

  • AutoGen (Microsoft):一个强大的多 Agent 框架,使 AI Agent 能够有效地沟通、协作和使用工具。 它灵活且高度可定制,使其成为构建企业级 AI 系统的首选。AutoGen 的一个实际应用场景是:构建一个由 “产品经理” 和 “工程师” 组成的 Agent 团队, “产品经理” 负责提出产品需求, “工程师” 负责编写代码实现需求,并通过不断沟通迭代最终完成项目。
  • LangGraph:构建于 LangChain 之上,LangGraph 引入了基于图的工作流程,可以更轻松地管理多步骤 Agent 逻辑。 它非常适合需要 Agent 遵循结构化计划或决策路径的应用程序。例如,在金融风控场景中,LangGraph 可以构建一个包含多个节点的风控流程图,每个节点代表一个风控规则,Agent根据用户的行为路径在图上进行推理,最终判断是否存在欺诈风险。
  • CrewAI:围绕为不同的 Agent 分配角色(如“研究员”或“作家”)的想法而设计,CrewAI 使 Agent 团队能够协同处理单个任务。 它简单、直观,非常适合协作场景。例如,一个CrewAI Agent团队可以共同完成一篇新闻报道的撰写, “研究员” 负责收集资料, “作家” 负责撰写文章, “编辑” 负责校对和润色。
  • LlamaIndex:虽然本身不是一个完整的 Agent 框架,但 LlamaIndex 是 Agent 生态系统中的一个关键工具。 它帮助 Agent 连接到你的数据——从文档到数据库——确保它们可以在正确的时间检索到正确的信息。 LlamaIndex 可以将各种格式的数据(如PDF、Word文档、网页等)转换为向量,并存储到向量数据库中,Agent 可以通过查询向量数据库来检索相关信息,从而更好地完成任务。
  • Llama Stack (Meta):由 Meta 开发,Llama Stack 是一个综合框架,提供了一套统一的工具,用于构建、扩展和部署生成式 AI 应用程序和 Agent。Llama Stack 的目标是简化 AI Agent 的开发流程,提供从数据处理、模型训练、到部署的一站式解决方案。

这些框架各有优势。 无论你是在寻找工具编排、结构化任务规划还是数据增强的智能,都可能有一个框架适合你的需求。

Llama Stack 概述:构建 AI Agent 的工作流

Llama Stack 如何让 AI Agent 工作?简单来说,它定义了一套标准化的流程和工具,使得 Agent 能够接收用户指令,利用 LLM 进行推理,调用外部工具,最终给出结构化的响应。下图说明了使用 Llama Stack 构建的 LLM 驱动的 Agent 的高级架构:

  1. 用户查询 (User Query):用户向 Agent 发出指令,例如 “总结这篇新闻报道”。
  2. LLM 推理 (LLM Reasoning): Agent 使用 LLM (如 Llama 3) 理解用户意图,并规划完成任务所需的步骤。
  3. 工具交互 (Tool Interaction): Agent 根据规划结果,调用相应的工具来执行任务。 这可能涉及到调用 MCP 服务器 (例如 Google Drive MCP) 来访问外部数据,或者调用自定义函数来执行特定操作。
  4. 结构化响应 (Structured Response): Agent 将工具执行的结果整合,生成结构化的响应返回给用户。例如,如果用户要求总结新闻报道,Agent 可能会返回一个包含文章标题、摘要和关键词的 JSON 对象。

这个工作流的核心在于工具的定义和使用。 AI Agent 的能力很大程度上取决于它可以访问的工具。 这些工具使 Agent 能够执行操作、检索数据以及与外部系统交互。Llama Stack 提供了两种主要的工具定义方式:简单函数 (Simple Functions) 和模型上下文协议 (Model Context Protocol, MCP)。

工具定义:简单函数与模型上下文协议 (MCP)

1. 简单函数 (Simple Functions)

对于特定的、面向项目的任务,可以定义简单的函数。 这些是根据特定需求量身定制的自定义函数,允许直接集成,而无需复杂的协议开销。 为了确保模型正确使用该工具,必须清楚地记录该工具及其参数——这包括为每个函数提供一个写得很好的文档字符串 (docstring)。例如,可以定义一个名为 calculate_interest 的函数来计算利息,该函数接受本金、利率和期限作为参数,并返回计算出的利息金额。这个函数需要包含清晰的 docstring,说明它的作用、参数和返回值。

2. 模型上下文协议 (Model Context Protocol, MCP)

对于更具可扩展性和标准化集成,模型上下文协议 (MCP) 提供了一个强大的解决方案。 MCP 是一种开放标准,可促进 AI 模型与外部工具或数据源之间的无缝通信。 可以将其视为 AI 应用程序的 “USB-C”,为连接各种组件提供通用接口。

MCP 的优势在于其标准化和可扩展性。 不同的 MCP 服务器可以提供各种功能,例如访问数据库、调用 API、执行计算等。 Agent 可以通过 MCP 协议与这些服务器进行通信,从而扩展其能力。

根据你的用例,有多个 MCP 服务器可供选择。 但是,你也可以构建自己的自定义 MCP 服务器来满足特定需求——我们将在本文后面介绍如何做到这一点。 有关 MCP 标准的更多详细信息,你可以查看官方文档。

本文项目中的核心工具包括:

  • summarize_context(text: str) -> str:提示 Agent 根据输入文本生成摘要,并按照所需的模板进行格式化。
  • create_google_doc(title: str, content, folder_id: str) -> dict:使用给定的标题在指定的文件夹中创建一个 Google 文档,并用提供的内容填充它。
  • share_google_doc(file_id: str, email_id: str, role: str) -> str:与指定的电子邮件地址共享一个 Google 文档,授予所需的访问级别(例如,查看者、评论者、编辑者)。
  • read_google_doc(file_url: str) -> str:从提供的 URL 读取并返回 Google 文档的内容。

Llama Stack 的实现步骤

1. 安装和设置

首先,按照 Ollama 网站上的说明安装 Ollama,然后下载 Llama 3.2 3B 模型(或你选择的任何其他模型),然后启动 Ollama 服务。

ollama pull llama3.2:3b
ollama run llama3.2:3b --keepalive 60m

创建一个虚拟环境并使用以下命令安装 uv 或此处描述的任何替代方法。

python3 -m venv agent_venv
pip3 install uv

2. 运行 Llama Stack

你可以使用 Python 构建和运行 Llama Stack 服务器以进行测试和开发。 可以使用虚拟环境 venv(如下所示)、conda 或容器(如此处所示)进行设置。 该设置基于 Ollama 模板,并利用 llama3.2:3b 作为推理模型。

INFERENCE_MODEL=llama3.2:3b uv run --with llama-stack llama stack build --template ollama --image-type venv --run

3. 定义工具

我们将在本博客中使用两种工具——简单函数和 MCP 服务器。 虽然有很多现成的 MCP 服务器,但我们将逐步构建我们自己的服务器。

Google Drive MCP

在此用例中,我们需要创建和读取 Google 文档,以及与用户共享它们。 虽然现有的 Google Drive 服务器支持列出、读取和搜索文件,但它目前不允许创建新文档。 因此,我们将构建我们自己的解决方案。

首先,你需要设置一个 OAuth 客户端 ID。 你可以按照此处的 “入门” 和 “身份验证” 部分中概述的步骤进行操作。 完成后,我们就可以开始编写代码了。

def get_drive_service(client_secret_path):
    """
    初始化 Google Drive 客户端
    Args:
        client_secret_path: client_secret.json 的路径
    Returns:
        Google Drive 服务客户端
    """
    SCOPES = ["https://www.googleapis.com/auth/drive"]
    creds = None
    if os.path.exists("token.json"):
        creds = Credentials.from_authorized_user_file("token.json", SCOPES)
    if not creds or not creds.valid:
        if creds and creds.expired and creds.refresh_token:
            creds.refresh(Request())
        else:
            flow = InstalledAppFlow.from_client_secrets_file(client_secret_path, SCOPES)
            creds = flow.run_local_server(port=0)
        with open("token.json", "w") as token:
            token.write(creds.to_json())
    return build("drive", "v3", credentials=creds)

gdrive_service = get_drive_service(client_secret_path)

使用 FastMCP 类创建 MCP 服务器的一个实例。 @mcp.tool() 是一个装饰器,用于将下面的函数注册为 MCP 工具。 虽然此示例涵盖了读取文档,但也可以为创建和共享 Google 文档定义类似的工具。 完整的实现可在链接的 GitHub 存储库中找到。

from fastmcp import FastMCP
mcp = FastMCP("gdrive")

@mcp.tool()
def read_google_doc(file_url: str) -> str:
    """
    从 Google Drive 读取 Google 文档或纯文本文件的内容。
    Args:
        file_url (str): Google Drive 文件的 URL。
    Returns:
        str: 文件内容,以 UTF-8 解码的字符串。
    Raises:
        ValueError: 如果文件的 MIME 类型不受支持。
        HttpError: 如果在 API 请求期间发生错误。
    """
    file_id = get_file_id_from_url(file_url)
    try:
        # 检索文件的 MIME 类型
        file_metadata = (
            gdrive_service.files().get(fileId=file_id, fields="mimeType").execute()
        )
        mime_type = file_metadata.get("mimeType")

        # 根据 MIME 类型确定适当的请求
        if mime_type == "application/vnd.google-apps.document":
            request = gdrive_service.files().export(
                fileId=file_id, mimeType="text/plain"
            )
        elif mime_type == "text/plain":
            request = gdrive_service.files().get_media(fileId=file_id)
        else:
            raise ValueError(f"Unsupported MIME type: {mime_type}")

        # 下载文件内容
        fh = io.BytesIO()
        downloader = MediaIoBaseDownload(fh, request)
        done = False
        while not done:
            status, done = downloader.next_chunk()
        fh.seek(0)
        content_bytes = fh.read()
        return content_bytes.decode("utf-8") if content_bytes else None

    except HttpError as error:
        print(f"An error occurred: {error}")
        return None

@mcp.tool()
def create_google_doc(title: str, content, folder_id: str = None) -> dict:
    pass

@mcp.tool()
def share_google_doc(file_id: str, email: str, role: str = "writer") -> None:
    pass

# 使用 SSE 协议启动 MCP 服务器。
if __name__ == "__main__":
    print("Starting MCP server on default port...")
    mcp.run("sse", port=3002)

该服务器可以集成到各种项目中,从而实现一致的功能,而无需重建。

2. 会议摘要自定义函数工具

此函数是一个基本示例,它提供提示或说明,供 Agent 以特定格式生成会议摘要。 为了演示目的,它保持简单,但可以轻松扩展以包括预处理、后处理,甚至处理完全不同的任务等步骤。

注意:请确保为所使用的特定模型使用适当的提示模板。 此外,自定义函数中的文档字符串至关重要——Agent 依赖它来选择正确的工具并正确传递参数。 你可能需要尝试不同的文档字符串才能获得所需的行为。

def summarize_context(text: str) -> str:
    """
    生成会议记录的结构化摘要。
    当用户请求任何会议记录的摘要时,应调用此函数。
    它处理输入文本,以便语言模型生成一致的输出。
    此函数是会议记录任务的默认入口点。
    :param text: 要汇总的记录的原始文本。
    :return: 要传递给模型以生成摘要的格式化提示字符串。
    """
    return f"""<|begin_of_text|><|start_header_id|>system<|end_header_id|>
    You are provided with a meeting transcript.
    Your task is to generate minutes of meeting with all the crucial information.
    Do not assume that the reader is aware of the details. Add any minute detail you think will be beneficial.
    Do not alter any information or names.

    Organize the MoM in the following format -
    Attendees: Participants involved
    Agenda: Include the motive/agenda of the scheduled meeting
    Points discussed: Include all essential points that were discussed along with the person name. Make sure to add all important terms.
    Blocker: Include this field only if a blocker exists
    Next steps: Follow up tasks

    Make sure to follow this template exactly.
    <|eot_id|><|start_header_id|>user<|end_header_id|>
    Meeting Transcript: {text}<|eot_id|><|start_header_id|>assistant<|end_header_id|>"""

4. MCP 服务器注册

要使用 MCP 服务器,你首先需要将它们注册为工具组。 这允许 Agent 发现和使用通过模型上下文协议公开的工具。

以下是如何注册 MCP 工具组(例如,我们之前创建的 Google Drive MCP 服务器)的示例:

from llama_stack_client import LlamaStackClient
from llama_stack_client.types.tool_group import McpEndpoint

client = LlamaStackClient(base_url="http://localhost:8321")

# 注册 Google Drive mcp 服务器
client.toolgroups.register(
    toolgroup_id="mcp::gdrive",
    provider_id="model-context-protocol",
    mcp_endpoint=McpEndpoint(uri="http://0.0.0.0:3001/sse"),
)

5. Agent 配置

使用 AgentConfig 类设置 Agent,该类定义以下组件:

  • 模型 (Model):驱动 Agent 的推理和响应的 LLM。
  • 说明 (Instructions):指导 Agent 的行为和语气的系统提示。
  • 工具 (Tools):Agent 可以利用的函数或外部集成。
  • 安全防护 (Safety Shields):强制执行安全和负责任的 AI 使用的机制。
from llama_stack_client import Agent
from api.summariser_custom_tool import generate_summary

# 创建 Agent
agent = Agent(
    client,
    model="llama3.2:3b",  # 与运行 llamastack 时使用的 LLM 相同
    instructions="""You are a helpful assistant that can use tools to answer questions.""",
    tools=[
        "mcp::gdrive",
        generate_summary,
    ],  # 在此处添加工具 - mcp 服务器或函数
)

6. 创建会话和轮次

Agent 通过会话维护状态,会话表示一个对话线程。

# 创建会话
session_id = agent.create_session(session_name="demo session")

与 Agent 的每次交互都称为 “轮次”,它由以下部分组成:

  • 输入消息 (Input Messages):发送到 Agent 的用户的查询或提示。
  • 步骤 (Steps):Agent 遵循的内部工作流程,包括推理、工具使用和中间操作。
  • 输出消息 (Output Message):Agent 生成的最终响应。

我们使用相同的 session_id 发送多个轮次,以帮助 Agent 维护上下文并遵循对话线程。

user_prompts = [
    "Read the contents of <your_file_url>",
    "Generate a summary for this."
]

for prompt in user_prompts:
    response = agent.create_turn(
        messages=[
            {
                "role": "user",
                "content": prompt,
            }
        ],
        session_id=session_id,
    )
    for log in EventLogger().log(response):
        log.print()

7. UI 创建

通过 Streamlit 应用程序(在 streamlit_app.py 中定义)提供了一个用户友好的界面来与 Agent 交互。 以下是该应用程序的演示。

完整的代码可以在这里找到。

结论:AI Agent 的未来与 Llama Stack 的潜力

在本文中,我们探讨了 Llama Stack 的基础知识,并演示了如何构建你的第一个 AI Agent。 虽然提供的示例很简单,但 Llama Stack 旨在进行扩展,从而可以根据你的需求创建更复杂、多步骤甚至多 Agent 的工作流程。 重要的是要注意,虽然 Llama 3.2 3B 是轻量级且高效的,但它可能难以处理高级任务,例如在单个提示中处理多个工具调用。 用户报告说,较大的模型在这些场景中提供了更好的性能。

AI Agent 功能强大,但并非总是必需的。 对于重复性的、基于规则的任务(如数据输入或简单通知),传统的自动化工具通常更高效且更易于管理。 但是,如果你的任务需要决策、适应性或处理非结构化数据,AI Agent 可以提供显着的优势。

总而言之,虽然 AI Agent 越来越受欢迎,但在采用它们之前评估你的具体需求和资源至关重要。 从简单的开始,评估收益,并根据需要进行扩展。Llama Stack 提供了一个强大的平台,帮助开发者快速构建和部署 AI Agent,并在各个领域发挥其潜力。随着技术的不断发展,我们可以期待看到 AI Agent 在更多领域发挥重要作用,改变我们的工作和生活方式。

发表回复

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