LangGraph 深度学习教案
目录
- 引言
- LangChain 与 LangGraph 的关系
- 为什么选择 LangGraph
- LangGraph 基础概念
- 节点(Nodes)
- 边(Edges)
- 状态(State)
- 环境配置
- 安装必要的库
- 配置数据库和模型
- 构建单代理工作流程
- 定义 SQL 执行工具
- 定义代理状态
- 构建代理
- 可视化代理图
- 测试代理
- 持久化和流式处理
- 持久化状态
- 流式处理数据
- 多线程交互
- 构建多代理系统
- 定义多代理状态
- 构建路由器节点
- 构建专家节点
- 构建编辑器和人类反馈节点
- 测试多代理系统
- 总结
1. 引言
LangChain 与 LangGraph 的关系
LangChain 是一个用于构建由大型语言模型(LLM)驱动的应用程序的领先框架。它允许开发者使用 LangChain 表达语言(LCEL)来定义和执行操作序列,这些序列被称为链(Chains)。这些链可以视为有向无环图(DAG),用于线性执行任务。
然而,随着 LLM 应用程序的发展,特别是在构建代理(Agents)时,我们需要更复杂的交互,包括循环、条件逻辑和多步骤推理。这就引入了 LangGraph,它是 LangChain 的一个新模块,允许我们将交互建模为循环图,从而支持更复杂的工作流和代理行为。
为什么选择 LangGraph
LangGraph 提供了以下优势:
- 灵活性:支持循环和条件逻辑,能够构建复杂的对话和推理流程。
- 模块化设计:通过节点和边的组合,可以轻松地添加或修改代理的行为。
- 持久化和恢复:状态在每个步骤后自动保存,允许在任何时刻暂停和恢复执行,这对于需要人机交互的应用程序非常重要。
2. LangGraph 基础概念
在开始实际编码之前,我们需要理解 LangGraph 的三个核心概念:节点、边和状态。
节点(Nodes)
节点代表实际的操作,可以是以下之一:
- LLM 调用:调用大型语言模型进行推理或生成文本。
- 代理:可以是另一个嵌套的代理,负责特定任务。
- 函数或工具:执行特定的功能,如数据库查询、API 调用等。
边(Edges)
边连接节点,确定图的执行流程。边有两种类型:
- 基本边:简单地将一个节点连接到下一个节点,表示顺序执行。
- 条件边:包含条件逻辑,根据状态决定下一步执行哪个节点。
状态(State)
状态是图的快照,包含执行过程中所有需要共享或持久化的数据。状态在节点之间传递,并可以被节点读取或修改。状态的设计对于代理的正确执行至关重要,因为它允许节点之间共享信息,并支持复杂的交互。
3. 环境配置
在开始编写代码之前,我们需要设置开发环境,安装必要的库,并配置模型和数据库。
安装必要的库
确保您的计算机上安装了 Python 3.6 或更高版本。
# 安装 langchain_community
pip install langchain_community
# 更新安装 langgraph
pip install -U langgraph
# 安装 graphviz(用于绘制图形)
brew install graphviz # 如果您使用的是 macOS
# 安装 pygraphviz(用于在 Python 中使用 graphviz)
pip install pygraphviz
注意:在安装 pygraphviz
时,可能需要指定编译选项,以正确找到 graphviz
的头文件和库文件。如果遇到安装问题,请参考 pygraphviz 的安装指南。
配置数据库和模型
在本教案中,我们将使用 ClickHouse 数据库和 OpenAI 的 GPT-4 模型(或其替代模型)。
import os
import json
# 读取配置文件(假设您有一个包含 API 密钥的 config.json 文件)
with open('config.json') as f:
config = json.loads(f.read())
# 设置环境变量
os.environ["OPENAI_MODEL_NAME"] = 'gpt-4o-mini' # 或者您选择的模型
os.environ["OPENAI_API_KEY"] = config['OPENAI_API_KEY']
os.environ["TAVILY_API_KEY"] = config["TAVILY_API_KEY"]
4. 构建单代理工作流程
在这一部分中,我们将构建一个简单的代理,能够根据用户输入执行 SQL 查询,并返回结果。
4.1 定义 SQL 执行工具
首先,我们需要定义一个工具,用于执行 SQL 查询。
from langchain_core.tools import tool
from pydantic.v1 import BaseModel, Field
# 定义 SQL 查询的参数模型
class SQLQuery(BaseModel):
query: str = Field(description="要执行的 SQL 查询")
# 定义执行 SQL 的工具
@tool(args_schema=SQLQuery)
def execute_sql(query: str) -> str:
"""返回 SQL 查询执行的结果"""
return get_clickhouse_data(query)
我们还需要定义 get_clickhouse_data
函数,用于实际执行 SQL 查询。
CH_HOST = 'http://localhost:8123' # ClickHouse 默认地址
import requests
def get_clickhouse_data(query, host=CH_HOST, connection_timeout=1500):
r = requests.post(host, params={'query': query}, timeout=connection_timeout)
if r.status_code == 200:
return r.text
else:
return '数据库返回以下错误:\n' + r.text
说明:
- 我们使用
@tool
装饰器将execute_sql
函数注册为 LangChain 工具。 SQLQuery
是一个 Pydantic 模型,用于定义工具的参数和描述,帮助 LLM 正确地调用工具。execute_sql
函数调用了get_clickhouse_data
来执行实际的 SQL 查询。
4.2 定义代理状态
接下来,我们需要定义代理的状态,以便在节点之间共享信息。
from langgraph.graph import StateGraph, END
from typing import TypedDict, Annotated
import operator
from langchain_core.messages import AnyMessage, SystemMessage, HumanMessage, ToolMessage
# 定义代理状态
class AgentState(TypedDict):
messages: Annotated[list[AnyMessage], operator.add]
说明:
AgentState
是一个字典类型,包含一个messages
列表,用于存储对话历史。Annotated
和operator.add
用于指示在状态更新时,新的消息将添加到列表中,而不是替换。
4.3 构建代理
现在,我们开始构建代理,定义其节点和执行逻辑。
class SQLAgent:
def __init__(self, model, tools, system_prompt=""):
self.system_prompt = system_prompt
graph = StateGraph(AgentState)
# 添加节点
graph.add_node("llm", self.call_llm)
graph.add_node("function", self.execute_function)
# 添加条件边:如果存在函数调用,则执行函数节点,否则结束
graph.add_conditional_edges(
"llm",
self.exists_function_calling,
{True: "function", False: END}
)
# 添加边:从函数节点回到 llm 节点
graph.add_edge("function", "llm")
# 设置起点
graph.set_entry_point("llm")
# 编译图
self.graph = graph.compile()
self.tools = {t.name: t for t in tools}
self.model = model.bind_tools(tools)
# 检查是否存在函数调用
def exists_function_calling(self, state: AgentState):
result = state['messages'][-1]
return len(result.tool_calls) > 0
# 调用 LLM
def call_llm(self, state: AgentState):
messages = state['messages']
if self.system_prompt:
messages = [SystemMessage(content=self.system_prompt)] + messages
message = self.model.invoke(messages)
return {'messages': [message]}
# 执行函数调用
def execute_function(self, state: AgentState):
tool_calls = state['messages'][-1].tool_calls
results = []
for t in tool_calls:
if not t['name'] in self.tools:
result = "错误:没有这样的工具,请重试"
else:
result = self.tools[t['name']].invoke(t['args'])
results.append(ToolMessage(tool_call_id=t['id'], name=t['name'], content=str(result)))
return {'messages': results}
说明:
- 初始化:我们创建了一个
StateGraph
,添加了两个节点llm
和function
,以及条件边和普通边。 - 节点函数:
call_llm
:调用 LLM 模型,根据消息历史生成回复。execute_function
:执行 LLM 请求的函数调用(工具),并将结果返回给 LLM。
- 条件边函数:
exists_function_calling
:检查 LLM 的回复中是否包含函数调用,决定下一个节点。
4.4 可视化代理图
为了更好地理解代理的结构,我们可以可视化代理的图形。
from IPython.display import Image
# 实例化代理
prompt = '''您是 SQL 和数据分析方面的高级专家...
您的目标是为数据库中的表提供详细的文档,以帮助用户。'''
model = ChatOpenAI(model="gpt-4o-mini")
doc_agent = SQLAgent(model, [execute_sql], system_prompt=prompt)
# 可视化图形
Image(doc_agent.graph.get_graph().draw_png())
说明:
- 使用
pygraphviz
库来绘制图形。 - 图形显示了节点和边的连接关系,便于理解代理的执行流程。
4.5 测试代理
现在,我们可以测试代理,看看它如何响应用户的请求。
# 发送用户消息
messages = [HumanMessage(content="我们在 ecommerce_db.users 表中有什么信息?")]
result = doc_agent.graph.invoke({"messages": messages})
# 打印代理的回复
print(result['messages'][-1].content)
预期输出:
代理应该通过调用 execute_sql
工具,查询数据库表的结构,并返回表的列名和数据类型。
5. 持久化和流式处理
在实际应用中,代理需要能够处理长时间的对话,并在多个步骤之间保持状态。这就需要持久化和流式处理。
5.1 持久化状态
我们可以使用 SQLite 数据库来持久化代理的状态。
from langgraph.checkpoint.sqlite import SqliteSaver
# 使用内存中的 SQLite 数据库进行持久化
memory = SqliteSaver.from_conn_string(":memory:")
说明:
- 我们创建了一个内存中的 SQLite 数据库,可以替换为实际的文件路径来持久化状态。
5.2 流式处理数据
为了支持长对话和实时响应,我们可以使用流式处理。
# 使用预构建的 ReAct 代理
from langgraph.prebuilt import create_react_agent
prebuilt_doc_agent = create_react_agent(model, [execute_sql], checkpointer=memory)
# 定义线程 ID
thread = {"configurable": {"thread_id": "1"}}
messages = [HumanMessage(content="我们在 ecommerce_db.users 表中有什么信息?")]
# 流式处理
for event in prebuilt_doc_agent.stream({"messages": messages}, thread):
for v in event.values():
v['messages'][-1].pretty_print()
说明:
stream
方法允许我们逐步获取代理的响应,包括中间步骤,如工具调用。thread
参数用于标识对话线程,支持多线程交互。
5.3 多线程交互
我们可以在同一线程中发送后续消息,代理会保持对话上下文。
# 继续在同一线程中发送后续消息
followup_messages = [HumanMessage(content="我想知道列名和类型。也许你可以使用 DESCRIBE 在数据库中查看。")]
for event in prebuilt_doc_agent.stream({"messages": followup_messages}, thread):
for v in event.values():
v['messages'][-1].pretty_print()
说明:
- 代理会根据之前的对话历史,理解用户的意图,并做出适当的响应。
6. 构建多代理系统
在更复杂的应用场景中,我们可能需要多个代理协同工作,根据不同的用户请求,选择合适的代理来处理。这需要构建一个多代理系统。
6.1 定义多代理状态
首先,定义一个更复杂的状态,用于在多个代理之间传递信息。
class MultiAgentState(TypedDict):
question: str
question_type: str
answer: str
feedback: str
说明:
question
:用户的问题。question_type
:问题的类型,用于路由到不同的代理。answer
:代理的回答。feedback
:用户的反馈。
6.2 构建路由器节点
路由器节点的作用是根据用户的问题,确定应该由哪个代理来处理。
def router_node(state: MultiAgentState):
question_category_prompt = '''您是分析支持的高级专家。您的任务是对收到的问题进行分类。
根据您的回答,问题将被路由到正确的团队,所以您的任务对我们团队至关重要。
有 3 种可能的问题类型:
- DATABASE:与数据库(表或字段)相关的问题
- LANGCHAIN:与 LangGraph 或 LangChain 库相关的问题
- GENERAL:一般性问题
请仅返回一个单词(DATABASE、LANGCHAIN 或 GENERAL)。'''
messages = [
SystemMessage(content=question_category_prompt),
HumanMessage(content=state['question'])
]
model = ChatOpenAI(model="gpt-4o-mini")
response = model.invoke(messages)
return {"question_type": response.content.strip().upper()}
说明:
- 路由器使用 LLM 来分类问题类型。
- 返回的
question_type
将用于决定下一个执行的节点。
6.3 构建专家节点
根据不同的问题类型,我们需要构建不同的专家节点。
SQL 专家节点
def sql_expert_node(state: MultiAgentState):
sql_expert_system_prompt = '''
您是 SQL 方面的专家,可以帮助团队收集所需的数据以支持他们的决策。
您非常准确,并考虑到数据中的所有细微差别。
您使用 SQL 来获取数据,然后回答问题。
'''
model = ChatOpenAI(model="gpt-4o-mini")
sql_agent = create_react_agent(model, [execute_sql], state_modifier=sql_expert_system_prompt)
messages = [HumanMessage(content=state['question'])]
result = sql_agent.invoke({"messages": messages})
return {'answer': result['messages'][-1].content}
搜索专家节点
from langchain_community.tools.tavily_search import TavilySearchResults
tavily_tool = TavilySearchResults(max_results=5)
def search_expert_node(state: MultiAgentState):
search_expert_system_prompt = '''
您是 LangChain 和相关技术的专家。
您的目标是根据搜索提供的结果回答问题。
您不添加任何自己的信息,仅提供基于其他来源的信息。
'''
model = ChatOpenAI(model="gpt-4o-mini")
search_agent = create_react_agent(model, [tavily_tool], state_modifier=search_expert_system_prompt)
messages = [HumanMessage(content=state['question'])]
result = search_agent.invoke({"messages": messages})
return {'answer': result['messages'][-1].content}
通用助手节点
def general_assistant_node(state: MultiAgentState):
general_prompt = '''您是一个友好的助手,目标是回答一般性问题。
请不要提供任何未经验证的信息,如果您没有足够的信息,请直接说您不知道。
'''
messages = [
SystemMessage(content=general_prompt),
HumanMessage(content=state['question'])
]
model = ChatOpenAI(model="gpt-4o-mini")
response = model.invoke(messages)
return {"answer": response.content}
6.4 构建编辑器和人类反馈节点
我们还可以添加一个编辑器节点,用于根据用户的反馈修改答案。
def human_feedback_node(state: MultiAgentState):
pass # 该节点用于等待用户反馈
def editor_node(state: MultiAgentState):
editor_prompt = '''您是一个编辑,您的目标是根据反馈为客户提供最终答案。
您不添加任何自己的信息。您使用友好和专业的语气。
在输出中,请提供给客户的最终答案,不要添加额外的评论。
以下是您需要的所有信息:
客户的问题:
----
{question}
----
初步答案:
----
{answer}
----
反馈:
----
{feedback}
----
'''
messages = [
SystemMessage(content=editor_prompt.format(
question=state['question'],
answer=state['answer'],
feedback=state['feedback']
))
]
model = ChatOpenAI(model="gpt-4o-mini")
response = model.invoke(messages)
return {"answer": response.content}
说明:
human_feedback_node
:用于等待用户的反馈,可以在此处暂停执行。editor_node
:根据用户的反馈,修改答案并生成最终回复。
6.5 测试多代理系统
构建图形
builder = StateGraph(MultiAgentState)
# 添加节点
builder.add_node("router", router_node)
builder.add_node('database_expert', sql_expert_node)
builder.add_node('langchain_expert', search_expert_node)
builder.add_node('general_assistant', general_assistant_node)
builder.add_node('human', human_feedback_node)
builder.add_node('editor', editor_node)
# 添加条件边
builder.add_conditional_edges(
"router",
lambda state: state['question_type'],
{'DATABASE': 'database_expert', 'LANGCHAIN': 'langchain_expert', 'GENERAL': 'general_assistant'}
)
# 设置起点
builder.set_entry_point("router")
# 添加边
builder.add_edge('database_expert', 'human')
builder.add_edge('langchain_expert', 'human')
builder.add_edge('general_assistant', 'human')
builder.add_edge('human', 'editor')
builder.add_edge('editor', END)
# 编译图形,设置在 human 节点前中断
graph = builder.compile(checkpointer=memory, interrupt_before=['human'])
测试代理
thread = {"configurable": {"thread_id": "2"}}
# 发送初始问题
for event in graph.stream({'question': "ecommerce_db.users 表中的字段类型是什么?"}, thread):
print(event)
# 获取用户反馈
user_input = input("是否需要修改答案?")
graph.update_state(thread, {"feedback": user_input}, as_node="human")
# 继续执行
for event in graph.stream(None, thread, stream_mode="values"):
print(event['answer'])
说明:
- 执行流程在
human
节点前暂停,等待用户的反馈。 - 用户提供反馈后,代理继续执行,
editor
节点生成最终的答案。
7. 总结
在本教案中,我们深入学习了 LangGraph 的使用方法,包括:
- 构建单代理工作流程:创建一个能够执行 SQL 查询的代理,理解节点、边和状态的基本概念。
- 持久化和流式处理:实现代理状态的持久化,支持长对话和多线程交互。
- 构建多代理系统:创建一个包含路由器、专家和编辑器的复杂系统,能够根据问题类型自动选择合适的代理进行回答,并引入人机交互以提高答案质量。
关键要点:
- LangGraph 提供了强大的工具来构建复杂的代理系统,支持循环、条件逻辑和多步骤推理。
- 状态管理对于代理的执行至关重要,正确地设计和维护状态,可以实现丰富的交互和持久化。
- 人机交互能够提高系统的可靠性和用户满意度,在关键步骤引入用户反馈,确保最终的答案符合用户期望。
通过本次学习,您应该能够:
- 理解 LangGraph 的核心概念和优势。
- 使用 LangGraph 构建复杂的对话代理系统。
- 在实际项目中应用 LangGraph,提升 LLM 应用程序的灵活性和可扩展性。
希望本教案对您的学习有所帮助!如有任何疑问,建议您查阅 LangGraph 的官方文档,或尝试在实践中应用这些概念,以加深理解。
Swarm 框架入门教案
目录
- 引言
- 什么是 Swarm?
- 为什么选择 Swarm?
- 安装与环境配置
- 系统要求
- 安装 Swarm
- Swarm 的基本概念
- Swarm 客户端
- Agent(代理)
- 交接(Handoffs)
- Swarm 的基本使用方法
- 创建 Swarm 客户端
- 定义 Agent
- 运行 Swarm
- Agent 的深入理解
- Agent 的属性和字段
- 指令(Instructions)
- 功能(Functions)
- 交接与上下文变量更新
- 运行 Swarm 的参数和响应
client.run()
的参数详解- Response 对象的结构
- 高级主题
- 函数模式与类型提示
- 上下文变量的使用
- 流式传输(Streaming)
- Swarm 的优势与应用场景
- 轻量级和可扩展性
- 高度可定制的设计模式
- 适用场景
- 总结
1. 引言
什么是 Swarm?
Swarm 是 OpenAI 于 2024 年 10 月 12 日开源的一个实验性质的多智能体编排框架。它的核心目标是让智能体(Agents)之间的协调和执行变得更加轻量级、易于控制和测试。Swarm 提供了一种简化的方式来创建和管理多个 AI 代理,允许它们之间进行高效的通信和任务协作。
为什么选择 Swarm?
- 轻量级:Swarm 几乎完全在客户端运行,不需要复杂的服务器设置。
- 可扩展性:能够处理大量独立的功能和指令,适用于构建复杂的多代理系统。
- 高可控性:提供了对代理和函数执行的精细控制,方便测试和调试。
- 易于使用:提供了简洁的 API,使开发者可以快速上手。
2. 安装与环境配置
系统要求
- Python 版本:需要 Python 3.10 或更高版本。
安装 Swarm
在命令行中执行以下命令安装 Swarm:
pip install git+https://github.com/openai/swarm.git
3. Swarm 的基本概念
Swarm 客户端
Swarm 客户端是与 Swarm 框架交互的主要接口。它类似于 OpenAI 的 ChatCompletion
API,可以接受消息并返回响应。
Agent(代理)
Agent 是 Swarm 的核心抽象,代表了具有特定指令和功能的独立实体。每个 Agent 包含:
- Instructions(指令):定义 Agent 的行为方式。
- Functions(功能):Agent 可以调用的 Python 函数,用于执行特定任务。
交接(Handoffs)
Agent 可以在对话过程中将执行权交接给另一个 Agent。这允许在多个 Agent 之间进行任务协作,实现复杂的工作流程。
4. Swarm 的基本使用方法
创建 Swarm 客户端
首先,导入 Swarm 并创建一个客户端实例:
from swarm import Swarm
client = Swarm()
定义 Agent
创建两个 Agent,分别具有不同的指令和功能:
from swarm import Agent
def transfer_to_agent_b():
return agent_b # 将执行权交接给 Agent B
agent_a = Agent(
name="Agent A",
instructions="You are a helpful agent.",
functions=[transfer_to_agent_b],
)
agent_b = Agent(
name="Agent B",
instructions="Only speak in Haikus.",
)
运行 Swarm
使用 client.run()
方法来运行 Agent,并传入初始消息:
response = client.run(
agent=agent_a,
messages=[{"role": "user", "content": "I want to talk to agent B."}],
)
print(response.messages[-1]["content"])
预期输出:
An example haiku
From Agent B to you now
Hope you enjoy it
5. Agent 的深入理解
Agent 的属性和字段
- name:Agent 的名称。
- instructions:Agent 的指令,定义其行为。
- functions:Agent 可以调用的函数列表。
- model:Agent 使用的模型(默认为 “gpt-4o”)。
指令(Instructions)
Agent 的指令可以是字符串,也可以是返回字符串的函数。这些指令会作为系统提示,指导 Agent 的行为。
示例:
agent = Agent(
instructions="You are a helpful assistant."
)
或者使用函数动态生成指令:
def dynamic_instructions(context_variables):
user_name = context_variables.get("user_name", "User")
return f"Help {user_name} with their requests."
agent = Agent(
instructions=dynamic_instructions
)
功能(Functions)
Agent 可以调用 Python 函数来执行特定任务。这些函数可以访问上下文变量,并返回值或交接给另一个 Agent。
示例:
def greet(context_variables, language):
user_name = context_variables.get("user_name", "User")
greeting = "Hola" if language.lower() == "spanish" else "Hello"
print(f"{greeting}, {user_name}!")
return "Done"
agent = Agent(
functions=[greet]
)
交接与上下文变量更新
Agent 可以通过函数返回另一个 Agent 来实现交接,还可以更新上下文变量。
示例:
from swarm import Result
sales_agent = Agent(name="Sales Agent")
def transfer_to_sales():
return Result(
agent=sales_agent,
context_variables={"department": "sales"}
)
agent = Agent(
functions=[transfer_to_sales]
)
6. 运行 Swarm 的参数和响应
client.run()
的参数详解
- agent(必需):初始运行的 Agent。
- messages(必需):消息列表,与 OpenAI 的 Chat Completion API 格式相同。
- context_variables:可选的上下文变量字典,供函数和 Agent 指令使用。
- max_turns:允许的最大对话轮数。
- model_override:覆盖 Agent 使用的模型。
- execute_tools:是否执行工具(函数),默认为 True。
- stream:是否启用流式响应。
- debug:是否启用调试日志。
Response 对象的结构
- messages:对话过程中生成的消息列表。
- agent:处理最后一条消息的 Agent。
- context_variables:最新的上下文变量。
示例:
response = client.run(
agent=agent_a,
messages=[{"role": "user", "content": "Hello!"}],
context_variables={"user_name": "Alice"}
)
print(response.messages)
print(response.agent.name)
print(response.context_variables)
7. 高级主题
函数模式与类型提示
Swarm 可以自动将函数转换为 JSON 模式,用于函数调用。支持类型提示和文档字符串。
示例:
def greet(name: str, age: int, location: str = "New York"):
"""Greets the user.
Args:
name: Name of the user.
age: Age of the user.
location: Location of the user.
"""
return f"Hello {name}, age {age}, from {location}!"
上下文变量的使用
上下文变量可以在 client.run()
时传入,供 Agent 的指令和函数使用。
示例:
response = client.run(
agent=agent,
messages=[{"role": "user", "content": "Hi!"}],
context_variables={"user_name": "Bob"}
)
流式传输(Streaming)
Swarm 支持流式响应,类似于 OpenAI 的 Chat Completion 流式 API。
使用方法:
stream = client.run(agent, messages, stream=True)
for chunk in stream:
print(chunk)
8. Swarm 的优势与应用场景
轻量级和可扩展性
Swarm 几乎完全在客户端运行,不需要复杂的服务器设置,非常适合快速开发和测试。
高度可定制的设计模式
通过简单的 Agent 和函数组合,可以构建复杂的多代理系统,满足各种特定需求。
适用场景
- 多角色对话系统:如客服、销售等不同部门的交互。
- 任务编排与工作流程管理:定义复杂的任务流,并在不同的 Agent 之间切换。
- 教育与教学:模拟不同的教学助手,提供多样化的教学支持。
9. 总结
Swarm 框架为多智能体系统的开发提供了一个轻量级、高效且易于使用的解决方案。通过深入理解 Agent、函数和交接等核心概念,开发者可以快速构建复杂的多代理应用。
学习要点:
- 理解 Swarm 的基本架构和运行机制。
- 学会定义 Agent 及其指令和功能。
- 掌握上下文变量和交接的使用方法。
- 了解 Swarm 的高级特性,如函数模式和流式传输。
下一步:
- 尝试扩展示例代码,创建更多自定义的 Agent 和函数。
- 探索 Swarm 在您特定领域的应用,如数据处理、自动化任务等。
- 关注 Swarm 的更新和社区,获取更多资源和支持。
附录:Swarm 官方文档和资源
- GitHub 仓库:https://github.com/openai/swarm
- OpenAI 官方博客:介绍 Swarm 的设计理念和应用场景
- 示例代码和教程:探索更多 Swarm 的实际应用案例
基于本地 AI 的新闻聚合器构建教案
目录
- 引言
- 项目背景与目标
- 技术栈简介
- 环境设置
- 安装必要的软件和库
- 配置环境变量
- 核心组件解析
- Ollama 与 Llama 3.2 模型
- Swarm 代理编排框架
- DuckDuckGo 搜索
- 项目实现步骤
- 步骤一:设置环境
- 步骤二:创建新闻搜索功能
- 步骤三:定义 AI 代理
- 步骤四:协调工作流程
- 步骤五:运行系统
- 代码详解
- 完整代码展示
- 关键代码解析
- 项目运行与测试
- 运行示例
- 预期输出
- 扩展与优化
- 个性化定制
- 安全与隐私考虑
- 可能的改进方向
- 总结
1. 引言
项目背景与目标
在信息爆炸的时代,及时获取感兴趣领域的最新新闻变得越来越重要。然而,面对大量的信息源,手动筛选和跟踪特定主题的新闻可能既耗时又困难。本教案的目标是引导您构建一个本地运行的个性化新闻聚合器,利用生成式 AI 和代理技术,实现自动化的新闻收集、整理和展示。
技术栈简介
为了实现上述目标,我们将使用以下技术:
- Ollama 与 Llama 3.2 模型:Ollama 提供了在本地运行大型语言模型的能力,Llama 3.2 是一个强大的语言模型,用于自然语言处理任务。
- Swarm 代理编排框架:Swarm 允许我们创建和管理多个 AI 代理,实现复杂的任务编排。
- DuckDuckGo 搜索:作为一个注重隐私的搜索引擎,DuckDuckGo 提供了可靠的搜索结果,而不会跟踪用户数据。
2. 环境设置
安装必要的软件和库
首先,确保您的计算机满足以下要求:
- 操作系统:Windows、macOS 或 Linux
- Python 版本:3.7 或更高
安装 Ollama 并拉取 Llama 3.2 模型:
ollama pull llama3.2
安装 Python 库:
pip install git+https://github.com/openai/swarm.git duckduckgo-search
配置环境变量
设置必要的环境变量,以便 Ollama 和 Swarm 正确运行:
export OPENAI_MODEL_NAME=llama3.2
export OPENAI_BASE_URL=http://localhost:11434/v1
export OPENAI_API_KEY=any
注意:根据您的操作系统,设置环境变量的方式可能有所不同。上述命令适用于 UNIX 系统;在 Windows 上,您可以使用 set
命令。
3. 核心组件解析
Ollama 与 Llama 3.2 模型
- Ollama:一个用于在本地运行大型语言模型的工具,支持多种模型的管理和部署。
- Llama 3.2 模型:由 Meta AI 开发的先进语言模型,具备强大的自然语言理解和生成能力。
Swarm 代理编排框架
- Swarm:一个用于创建和管理 AI 代理的框架,支持代理之间的通信和任务协调。
- 代理(Agent):在 Swarm 中,代理是具有特定职责的独立实体,能够处理输入并生成输出。
DuckDuckGo 搜索
- DuckDuckGo:一个强调用户隐私的搜索引擎,不会跟踪用户的搜索行为。
- DuckDuckGo Search API:允许开发者通过编程方式访问搜索结果,用于集成到自定义应用中。
4. 项目实现步骤
步骤一:设置环境
-
导入必要的库:
from duckduckgo_search import DDGS from swarm import Swarm, Agent from datetime import datetime
-
初始化 Swarm 客户端和获取当前日期:
current_date = datetime.now().strftime("%Y-%m") client = Swarm()
步骤二:创建新闻搜索功能
-
定义搜索函数:
def get_news_articles(topic): ddg_api = DDGS() results = ddg_api.text(f"{topic} {current_date}", max_results=5) if results: news_results = "\n\n".join([ f"标题: {result['title']}\n网址: {result['href']}\n描述: {result['body']}" for result in results ]) return news_results else: return f"未能找到关于 {topic} 的新闻结果。"
-
功能说明:
- 使用
DuckDuckGo
API 搜索指定主题的新闻。 - 格式化搜索结果,提取标题、网址和描述。
- 使用
步骤三:定义 AI 代理
-
创建新闻助手代理:
news_agent = Agent( model="llama3.2", name="新闻助手", instructions="您提供有关给定主题的最新新闻文章,使用 DuckDuckGo 搜索。", functions=[get_news_articles], )
-
创建编辑助手代理:
editor_agent = Agent( model="llama3.2", name="编辑助手", instructions="您审阅并最终确定新闻文章以供发布。", )
-
代理职责:
- 新闻助手:负责获取新闻数据。
- 编辑助手:负责审阅和精炼新闻内容。
步骤四:协调工作流程
-
定义工作流程函数:
def run_news_workflow(topic): # 获取新闻 news_response = client.run( agent=news_agent, messages=[{"role": "user", "content": f"获取关于 {topic} 在 {current_date} 的新闻"}], ) raw_news = news_response.messages[-1]["content"] # 将新闻传递给编辑助手 edited_news_response = client.run( agent=editor_agent, messages=[{"role": "system", "content": raw_news}], ) print(f"{edited_news_response.messages[-1]['content']}")
-
流程说明:
- 获取新闻:新闻助手代理接收主题,使用搜索功能获取新闻。
- 编辑新闻:将获取的新闻内容传递给编辑助手代理,进行审阅和精炼。
- 输出结果:打印最终的新闻内容。
步骤五:运行系统
-
运行示例:
run_news_workflow("药物发现中的 AI")
-
说明:调用
run_news_workflow
函数,指定感兴趣的主题,即可运行完整的新闻聚合流程。
5. 代码详解
完整代码展示
from duckduckgo_search import DDGS
from swarm import Swarm, Agent
from datetime import datetime
current_date = datetime.now().strftime("%Y-%m")
# 初始化 Swarm 客户端
client = Swarm()
# 1. 创建互联网搜索工具
def get_news_articles(topic):
print(f"正在为 {topic} 进行 DuckDuckGo 新闻搜索...")
# DuckDuckGo 搜索
ddg_api = DDGS()
results = ddg_api.text(f"{topic} {current_date}", max_results=5)
if results:
news_results = "\n\n".join([
f"标题: {result['title']}\n网址: {result['href']}\n描述: {result['body']}"
for result in results
])
return news_results
else:
return f"未能找到关于 {topic} 的新闻结果。"
# 2. 创建 AI 代理
# 新闻助手代理
news_agent = Agent(
model="llama3.2",
name="新闻助手",
instructions="您提供有关给定主题的最新新闻文章,使用 DuckDuckGo 搜索。",
functions=[get_news_articles],
)
# 编辑助手代理
editor_agent = Agent(
model="llama3.2",
name="编辑助手",
instructions="您审阅并最终确定新闻文章以供发布。",
)
# 3. 创建工作流程
def run_news_workflow(topic):
print("运行新闻代理工作流程...")
# 第一步: 获取新闻
news_response = client.run(
agent=news_agent,
messages=[{"role": "user", "content": f"获取关于 {topic} 在 {current_date} 的新闻"}],
)
raw_news = news_response.messages[-1]["content"]
print(f"获取的新闻: {raw_news}")
# 第二步: 将新闻传递给编辑助手
edited_news_response = client.run(
agent=editor_agent,
messages=[{"role": "system", "content": raw_news}],
)
print(f"最终新闻内容:\n{edited_news_response.messages[-1]['content']}")
# 运行示例
run_news_workflow("药物发现中的 AI")
关键代码解析
-
get_news_articles
函数:核心的新闻搜索功能,利用 DuckDuckGo API,返回格式化的新闻结果。 -
代理的创建:
news_agent
包含get_news_articles
函数,能够主动获取新闻。editor_agent
不包含额外函数,主要处理传入的文本,进行编辑。
-
工作流程的运行:
- 使用
client.run
方法,分别运行两个代理。 - 代理之间通过消息传递,实现数据的流动和任务的衔接。
- 使用
6. 项目运行与测试
运行示例
在终端或命令提示符中运行脚本:
python app.py
预期输出
运行新闻代理工作流程...
正在为 药物发现中的 AI 进行 DuckDuckGo 新闻搜索...
获取的新闻: 标题: AI在药物发现中的作用
网址: https://example.com/article1
描述: 这是一篇关于AI在药物发现中应用的文章。
标题: 人工智能如何改变制药业
网址: https://example.com/article2
描述: 探讨了AI技术在制药行业的影响。
...
最终新闻内容:
[编辑后的新闻内容]
注意:由于网络搜索的结果是实时的,实际输出可能会有所不同。
7. 扩展与优化
个性化定制
- 增加更多的代理:可以添加更多的代理,例如主题分析助手、摘要生成助手等。
- 自定义代理指令:根据需求修改代理的
instructions
,以改变其行为。
安全与隐私考虑
- 数据隐私:所有处理都在本地完成,确保用户数据的安全性。
- 搜索引擎选择:可以替换为其他搜索引擎,或者使用本地数据源。
可能的改进方向
- 增加错误处理:例如,当搜索结果为空时,提供友好的提示或采取替代措施。
- 改进编辑助手:引入更复杂的自然语言处理技术,提升编辑质量。
- 用户交互界面:开发图形用户界面(GUI)或命令行界面,提升用户体验。
8. 总结
本教案详细介绍了如何构建一个基于本地 AI 的新闻聚合器,利用 Ollama 的 Llama 3.2 模型、Swarm 代理编排框架和 DuckDuckGo 搜索,实现了一个功能完整、可扩展的系统。
主要收获:
- 理解了本地 AI 技术的应用:在保护隐私的同时,实现强大的数据处理能力。
- 掌握了 Swarm 框架的基本使用:能够创建、管理和协调多个 AI 代理。
- 学会了整合网络搜索功能:利用公开的 API,为系统提供实时的数据支持。
未来展望:
随着人工智能技术的不断发展,基于本地 AI 的应用将越来越普及。通过深入理解和实践这些技术,我们可以开发出更多创新、实用的工具,满足个性化的需求。