大型语言模型(LLM)如ChatGPT、Gemini和Claude已成为企业的重要工具。每家公司都希望开发出适合自身特定需求或客户需求的定制化AI。在这次探索中,我们将专注于创建一个具备功能调用、将消息存储在数据库以支持多会话对话、并能执行网络搜索和总结结果的个性化助手。为了让其更加有组织并方便未来添加新功能,我们将使用Langchain、Langgraph和LangSmith,这些工具简化了流程并增强了功能。Langchain简化了流式传输和工具调用的过程,并支持你使用多个不同的LLM。Langgraph是一个决策工具,帮助决定使用哪种工具,并让代理自行选择路径。LangSmith是一个观察工具,让你从提问到获得答案的整个流程一览无余。
环境配置⭐️ 本指南中提到的完整源代码可在 GitHub (https://github.com/zpillsbury/ai-agent) 上找到
在 .env
文件中添加环境变量,你需要用到你的 openai_key
、tavily_key
和 mongo_uri
,并确保正确设置它们。
📝 笔记:.env 文件
OPENAPI_KEY=OPENAI_KEY=sk-proj-XXXXXX
TAVILY_API_KEY=tvly-XXXXXXXXXXXXXXXXXXXXXXXX
MONGO_URI=mongodb+srvXXXXXXXXXXXXXXXXXXXXXXXXXXX
LANGCHAIN_TRACING_V2=true
LANGCHAIN_ENDPOINT=https://api.smith.langchain.com
LANGCHAIN_API_KEY=lsv2_pt_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx_xxxxxxxxxx
LANGCHAIN_PROJECT=project-name
全屏 退出全屏
在设置中添加 langsmith、OpenAI key、Tavily key 和 Mongo URI。
📝 app/utilities/settings.py
from pydantic import SecretStr
from pydantic_settings import BaseSettings, SettingsConfigDict
class Settings(BaseSettings):
openai_key: SecretStr
tavily_api_key: str
mongo_uri: SecretStr
# LangSmith
langchain_tracing_v2: bool = True
langchain_endpoint: str = "https://api.smith.langchain.com"
langchain_project: str = "ai-agent"
langchain_api_key: str
model_config = SettingsConfigDict(env_file=".env", extra="ignore")
settings = Settings()
全屏模式 退出全屏
用在设置里找到的密钥来设置OpenAI客户端。
📝 编辑 app/应用主文件
或者更简洁地:编辑主文件
from langchain_openai import ChatOpenAI
from .utilities.settings import settings
# 初始化ChatOpenAI模型,设置API密钥和最大重试次数
llm = ChatOpenAI(
openai_api_key=settings.openai_key,
model_name="gpt-4o-mini",
max_retries=2,
)
点击全屏,点击退出.
Langgraph设置状态以便数据可以在节点间传递和使用。我们使用大模型为聊天机器人的消息记录添加消息。来自langgraph的add_messages
函数会将从节点返回的任何消息追加到现有消息记录中。
查看 app/main.py 这个文件
from typing import Annotated, TypedDict
from langchain_core.messages import BaseMessage
from langgraph.graph import END, START, StateGraph
from langgraph.graph.message import add_messages
from langgraph.graph.state import CompiledStateGraph
class State(TypedDict):
# 消息列表,由 add_messages 函数处理
messages: Annotated[list[BaseMessage], add_messages]
切换到全屏 退出全屏
节点是图中的点,在langgraph中节点用函数表示。创建一个新的名为 chatbot
的函数,该函数通过调用 llm.ainvoke
向OpenAI发送当前存储的消息。OpenAI将返回一个新的AI消息。然后返回包含AI消息的新状态更新。这将通过 add_messages
辅助函数添加到现有消息中。
在 langgraph 中,方法有两种版本:同步和异步。如果您需要使用异步版本,只需在方法名前加上一个字母 a
即可。在这种情况下,我们选择使用 ainvoke
这个异步方法而不是同步方法 invoke
。
📝 这是主应用程序文件
这里主要是...
(保持与源代码格式一致,此处为空行)
async def chatbot(state: State) -> State:
"""
聊天功能
"""
response_message = await llm.ainvoke(state["messages"])
return {"messages": [响应消息]}
全屏, 退出
使用 add_node
函数将功能添加到图中。你需要用边将节点连接起来,在查看图的图片时,这些边就是每个节点之间的线。第一条边总是从 START
开始。使用 add_edge
将 START
与聊天机器人节点连接起来。然后用 graph_builder.compile
编译图,编译完成后才能使用该图。
📝 app/main.py (这里查看主要文件)
async def get_graph() -> CompiledStateGraph:
"""
获取状态图
"""
graph_builder = StateGraph(State) # 状态图构建器
graph_builder.add_node("chatbot", chatbot) # 添加节点“聊天机器人”
graph_builder.add_edge(START, "chatbot") # 添加从开始到聊天机器人的边
graph_builder.add_edge("chatbot", END) # 添加从聊天机器人到结束的边
graph = graph_builder.compile() # 编译状态图
return graph
点击进入全屏 点击退出全屏
现在的图表看起来像这样:
创建一个新的异步函数 run_graph
,它使用 graph.astream
(如果是同步操作,则用 graph.stream
)。它将首先插入系统提示,然后插入用户的问题作为当前状态。将其发送到 openAI,后者将返回 AI 消息,你的函数会将其追加到状态中。在每次图流循环中,我们可以通过事件变量访问当前状态。从 value
中提取最后一条消息的内容并返回给用户。
给AI添加系统提示,就是给它提供信息。这样能让AI助手在查找信息时更准确。大模型只训练到某一个时间段,因此它更可能找到的是旧文章而不是新文章。
📝 查看主程序文件:
app/main.py
从 datetime 模块导入 datetime 和 timezone
从 langchain_core.messages 导入 BaseMessage, HumanMessage, SystemMessage
now = datetime.now(timezone.utc)
system_prompt = f"""
你是一个帮助用户的智能助手。
当前日期和时间: {now}
"""
async def run_graph(question: str) -> None:
"""
运行图表
"""
async for event in graph.astream(
{
"messages": [
SystemMessage(content=system_prompt),
HumanMessage(content=question),
]
}
):
for value in event.values():
print(value["messages"][-1].content)
# return None # 可以省略此行,因为在异步函数中返回 None 是常见的做法。
全屏 退出全屏
创建一个新的异步函数 main
,此函数将接收用户输入,并根据输入添加一个 while
循环,当用户输入 (quit, exit 或 q) 时停止聊天会话。该函数将使用 run_graph
函数处理用户输入,并按照之前所述的过程进行操作。
📝 修改app/main.py文件来编辑吧
或者让我们开始处理app/main.py这个文件
async def 主() -> None:
"""
AI 代理
"""
while True:
问题 = input("q: ")
if 问题.lower() in ["退出", "结束", "q"]:
print("再见!")
break
await 运行(问题)
# return None (removed as per expert suggestion)
if __name__ == "__main__":
anyio.run(主())
全屏模式 退出全屏
工具呼叫你将在 .env
和 .settings
文件中使用 tavily_api_key
。通过使用 TavilySearchResults
,你的 AI 助手可以搜索信息。我们将它们放入 tools
中,这样你可以方便地添加更多工具。然后设置 llm_with_tools = llm.bind_tools
,这将给你的 AI 助手提供工具列表。接下来,将所有曾使用 llm
的地方改为 llm_with_tools
。
📝 app/main.py # 主程序文件
从 langchain_community.tools.tavily_search 导入 TavilySearchResults 作为 TavilySearchResults
web_search = TavilySearchResults(max_results=2)
tools = [web_search]
llm = ChatOpenAI(
openai_api_key=settings.openai_key,
model_name="gpt-4o-mini",
max_retries=2,
)
llm_with_tools = llm.bind_tools(tools)
async def chatbot(state: State) -> State:
"""
处理聊天消息并返回回复
"""
response_message = await llm_with_tools.ainvoke(state["messages"])
return {"messages": [response_message]}
全屏模式 退出全屏
接下来添加一个 tool_node
,这个节点用于运行工具并发送AI消息。接下来添加 add_conditional_edge
,这将允许AI助手根据需要选择通往多个不同节点的边。它会先检查是否需要调用工具,如果不需调用工具,则会将其发送到 END
节点。
📝 app/main.py 文件 (主要的入口文件)
async def get_graph() -> CompiledStateGraph:
"""
获取图谱
"""
graph_builder = StateGraph(State) # 状态图(State)
graph_builder.add_node("chatbot", chatbot)
tool_node = ToolNode(tools=tools)
graph_builder.add_node("tools", tool_node) # 添加工具节点
graph_builder.add_edge(START, "chatbot")
graph_builder.add_conditional_edges("chatbot", tools_condition) # 添加条件边以处理工具条件
graph_builder.add_edge("tools", "chatbot")
graph = graph_builder.compile()
# 返回编译后的图谱
return graph
进入全屏 退出全屏
保存聊天记录你将使用从 .env
和 .settings
文件中获取的 mongo_uri
。然后在顶部添加你的 async_mongodb_client
。设置一个检查点,将内存数据保存到 MongoDB 中。在 get_graph
函数内部添加这些内容,因为这需要在一个异步函数中运行。
📝 app/main.py — 这是主程序文件,这里写着主要代码呢
from typing import Annotated, Any, TypedDict
from langchain_core.runnables import RunnableConfig
from langgraph.checkpoint.mongodb.aio import AsyncMongoDBSaver
from motor.motor_asyncio import AsyncIOMotorClient
async_mongodb_client: AsyncIOMotorClient[Any] = AsyncIOMotorClient(
settings.mongo_uri.get_secret_value()
)
async def get_graph() -> CompiledStateGraph:
"""
获取状态图
"""
checkpointer = AsyncMongoDBSaver(
client=async_mongodb_client,
db_name="ai",
checkpoint_collection_name="checkpoints",
writes_collection_name="checkpoint_writes",
)
graph_builder = StateGraph(State)
graph_builder.add_node("chatbot", chatbot)
tool_node = ToolNode(tools=tools)
graph_builder.add_node("tools", tool_node)
graph_builder.add_edge(START, "chatbot")
graph_builder.add_conditional_edges("chatbot", tools_condition)
graph_builder.add_edge("tools", "chatbot")
graph = graph_builder.compile(checkpointer=checkpointer)
return graph
进入全屏 退出全屏
现在使用 MongoDB 来配置你的 thread_id
,以便存储不同聊天历史中的消息。这样设置可以让助手记住多轮会话中的对话,并且允许你通过使用不同的 thread_id
来创建独立的聊天记录。
这是主程序文件:app/main.py。
从 langchain_core.runnables 导入 RunnableConfig
async def run_graph(config: RunnableConfig, question: str) -> None:
"""
运行图
"""
graph = await get_graph()
async for event in graph.astream(
{
"messages": [
SystemMessage(content=system_prompt),
HumanMessage(content=question),
]
},
config=config,
stream_mode="values",
):
event["messages"][-1].pretty_print()
return None
async def main() -> None:
"""
AI助手
"""
config = RunnableConfig(configurable={"thread_id": 1})
while True:
question = input("q: ")
if question.lower() in ["quit", "exit", "q"]:
print("拜拜了!")
break
await run_graph(config=config, question=question)
return None
点这里进入全屏,点这里退出全屏
你可以运行脚本并查看输出,因为我们让它用了当前日期,所以你可以看到它拿到了最新的团队信息。
$ python3 -m app.main
q: 卡罗莱纳黑豹队目前的战绩是什么?
================================ 人类消息 =================================
卡罗莱纳黑豹队目前的战绩是什么?
================================== AI 消息 ==================================
工具调用:
tavily_search_results_json (call_apvK6LYyrTMRunPcoO8enCqD)
调用ID:call_apvK6LYyrTMRunPcoO8enCqD
参数:
query: 卡罗莱纳黑豹队目前的战绩
================================= 工具消息 =================================
名称:tavily_search_results_json
[{"url": "https://www.footballdb.com/teams/nfl/carolina-panthers/results", "content": "查看2024年卡罗莱纳黑豹队的比赛日程、结果和分数,包括常规赛、季前赛和季后赛。... 2024年战绩:3胜11负。12月29日,2024年1:00 PM;卡罗莱纳(3-11)--坦帕湾(8-6)--最近一场比赛:TB 26 @ CAR 23(2024年12月1日)"}, {"url": "https://champsorchumps.us/team/nfl/carolina-panthers/2024", "content": "卡罗莱纳黑豹队目前战绩为3胜9负。2024年黑豹队主场战绩为2胜5负,客场战绩为1胜4负。2024年卡罗莱纳黑豹队所在的是哪个分区?2024年卡罗莱纳黑豹队在NFC南部分区比赛中。"}]
================================== AI 消息 ==================================
截至12月2024,卡罗莱纳黑豹队的战绩为**3胜11负**(3-11),目前排名第4。
全屏模式 退出全屏模式
你可以在langsmith项目中一步一步查看运行。
[图片]
这是获取一个能够自主决定是否需要工具调用的AI代理的基础知识,该代理可以自行决定是否在网络上查找信息或获取资料。此外,它还可以为每个对话存储信息,使你的助手能够记住之前的对话。由于我们使用的是LangChain,将来很容易添加其他功能,如流式处理、多模型支持和其他大型语言模型。
共同学习,写下你的评论
评论加载中...
作者其他优质文章