对于 AI 代理:可在 https://www.mongodb.com/zh-cn/docs/llms.txt 获取文档索引—通过在任何 URL 路径后添加 .md 可获取所有页面的 Markdown 版本。
Docs 菜单

MongoDB 与 OpenAI 代理 SDK 集成

您可以将 MongoDB 用作使用 OpenAI Agents SDK 构建的代理的后端数据库。Agents SDK 是一个 Python 框架,用于通过一小组原语构建代理应用程序:

  • 代理,它们是配置了指令和工具的大型语言模型 (LLMs)。

  • 交接,允许一个代理将任务委托给另一个代理。

  • 安全护栏,用于验证代理的输入和输出。

  • 会话,用于存储跨代理运行的对话历史。

SDK 遵循两个设计原则。它包含足够的功能来构建真实的应用程序,但原始元素很少,可以在短时间内学习。它的默认设置也会产生良好的结果,并且您可以自定义代理运行的每个步骤。

代理 SDK 提供 MongoDBSession,这是一个可在 MongoDB 中持久保存会话历史的会话实现。在 MongoDB 中存储该历史记录,可为您的代理提供以下优势:

  • 水平可扩展的多进程会话存储。会话状态存储在您的集群中,而不是存储在单个进程的内存中。因此,任何连接到同一集群的工作进程、容器或无服务器函数都可以继续会话。每条消息都带有一个单调递增的 seq 计数器,可以保持在并发写入器之间的消息顺序。

  • 会话和应用程序数据的单一数据库。如果您的应用程序已经使用 MongoDB,您的代理会通过相同的连接和相同的驱动程序读取运行数据,并写入会话历史,无需部署和保护单独的内存服务。

  • 用于代理状态的灵活文档。document model 会随着对话轮次、工具调用和结构化输出的演变而将它们一起存储。因此,您可以扩展您记录的内容,而无需进行模式迁移。

  • 可查询的代理历史记录。会话历史存储在普通集合中,因此,您可以对其进行查询、聚合和索引,以 Atlas 审核代理行为或构建分析。

  • A path to retrieval. Because your agents already connect to MongoDB, you can add MongoDB Vector Search to the same cluster to give them semantic retrieval over your data. To learn more, see Agentic RAG.

在本教程中,您将构建一个多代理旅行助手。分诊代理通过调用两个专业代理作为工具来回答问题,这两个专业代理都从存储对话会话的同一个集群中读取参考数据。

如要完成本教程,您必须具备以下条件:

  • Python 3.10 或更高版本。

  • 以下MongoDB 集群类型之一:

    • 运行 MongoDB 6.0.11 版本的 Atlas 集群,7.0.2或以上版本。确保您的 IP 地址 包含在 Atlas 项目的 访问列表 中。

    • 使用 Python 和 Docker 创建的本地 Atlas 部署。安装 atlas-local-lib-py (pip install atlas-local-lib-py),以编程方式创建和管理本地部署。要了解更多信息,请参阅 atlas-local-lib-py 存储库。

    • A MongoDB Community cluster with Search and Vector Search installed.

  • OpenAI API密钥。您必须拥有一个具有可用于API请求的积分的 OpenAI 帐户。要学习;了解有关注册 OpenAI 帐户的更多信息,请参阅 OpenAI API网站。

1

本教程使用 uv 来托管环境:

uv venv
source .venv/bin/activate
2

安装带有 mongodb 额外的代理 SDK。引用包名,以便 shell 不会解释括号:

uv pip install "openai-agents[mongodb]"

额外的安装包安装 pymongo 版本 4.14 或更高版本,其中提供 session 工具和代理工具均使用的 AsyncMongoClient 类。

3

应用程序从 ATLAS_URI 读取您的 Atlas 连接字符串,并且代理 SDK 从 OPENAI_API_KEY 读取您的密钥:

export ATLAS_URI="<connection-string>"
export OPENAI_API_KEY="<api-key>"

将 <connection-string> 占位符值替换为集群的 SRV连接字符串。

连接字符串应使用以下格式:

mongodb+srv://<db_username>:<db_password>@<clusterName>.<hostname>.mongodb.net
1

创建一个名为 multi_agent_app.py 的文件并将以下代码粘贴到该文件中。内联注释解释了应用程序的每个部分如何使用 MongoDB。

multi_agent_app.py
"""Multi-agent travel assistant backed by MongoDB Atlas.
A triage agent answers travel questions by calling two specialist
agents as tools. Both specialists read reference data from the same
Atlas cluster that stores the conversation session, so every agent in
the application shares one database.
"""
import asyncio
import os
from agents import Agent, Runner, function_tool
from agents.extensions.memory import MongoDBSession
from pymongo import AsyncMongoClient
# The script reads your credentials from the environment so that you
# don't commit them to source control.
REQUIRED_ENV_VARS = ("ATLAS_URI", "OPENAI_API_KEY")
DATABASE_NAME = "travel_assistant"
# One client serves both the agent tools and the session store. Because
# you create the client yourself, your application owns its lifecycle.
# main() assigns both of these after it validates the environment.
client: AsyncMongoClient | None = None
database = None
@function_tool
async def lookup_destination(city: str) -> str:
"""Look up travel guidance for a destination city."""
# Sub-agent tools query the shared database directly, so the agents
# answer from your data instead of from model training data.
document = await database.destinations.find_one({"city": city})
if document is None:
return f"No destination guide found for {city}."
return (
f"{document['city']}: best months are {document['best_months']}. "
f"{document['summary']}"
)
@function_tool
async def lookup_policy(topic: str) -> str:
"""Look up the company travel policy for a topic."""
document = await database.policies.find_one({"topic": topic})
if document is None:
return f"No policy found for {topic}."
return f"{document['topic']}: {document['rule']}"
# Each specialist is a full agent with its own instructions and tools.
destination_agent = Agent(
name="Destination expert",
instructions=(
"You advise travelers on destinations. Always call "
"lookup_destination and answer only from what it returns."
),
tools=[lookup_destination],
)
policy_agent = Agent(
name="Policy expert",
instructions=(
"You answer questions about the company travel policy. Always "
"call lookup_policy and answer only from what it returns."
),
tools=[lookup_policy],
)
# The as_tool() pattern turns each specialist into a tool that the
# triage agent can call. Unlike a handoff, control returns to the
# triage agent after each call, so it can combine both answers in one
# reply.
triage_agent = Agent(
name="Travel assistant",
instructions=(
"You are a travel assistant. Use the destination and policy "
"tools to gather facts before you answer, and call both when "
"the question needs both. Remember details the traveler shared "
"earlier in the conversation."
),
tools=[
destination_agent.as_tool(
tool_name="ask_destination_expert",
tool_description="Get travel guidance about a city.",
),
policy_agent.as_tool(
tool_name="ask_policy_expert",
tool_description="Get the company travel policy for a topic.",
),
],
)
async def seed_reference_data() -> None:
"""Load the sample data that the specialist agents read."""
await database.destinations.delete_many({})
await database.policies.delete_many({})
await database.destinations.insert_many(
[
{
"city": "Lisbon",
"best_months": "March through May",
"summary": "Mild spring weather and low hotel rates.",
},
{
"city": "Reykjavik",
"best_months": "June through August",
"summary": "Long daylight hours and open highland roads.",
},
]
)
await database.policies.insert_many(
[
{"topic": "flights", "rule": "Book economy for flights under six hours."},
{"topic": "hotels", "rule": "Nightly rates must stay under 250 USD."},
]
)
async def main() -> None:
global client, database
# Fail fast with a clear message instead of surfacing a connection
# error or an authentication error later in the run.
missing = [name for name in REQUIRED_ENV_VARS if not os.environ.get(name)]
if missing:
raise SystemExit(
"Set these environment variables before you run this script: "
+ ", ".join(missing)
)
client = AsyncMongoClient(os.environ["ATLAS_URI"])
database = client[DATABASE_NAME]
await seed_reference_data()
# The session stores conversation history in Atlas. Pass the
# existing client so the session and the agent tools share one
# connection pool.
session = MongoDBSession(
session_id="traveler-123",
client=client,
database=DATABASE_NAME,
)
# Confirm connectivity before the first run.
await session.ping()
# The Runner loads prior turns from the session and writes the new
# turn back, so the second question resolves "there" without you
# passing the history yourself.
first = await Runner.run(
triage_agent,
"I'm planning a trip to Lisbon. When should I go?",
session=session,
)
print(first.final_output)
second = await Runner.run(
triage_agent,
"What's our hotel budget for that trip?",
session=session,
)
print(second.final_output)
# session.close() is a no-op when you supply the client, so close
# the client yourself.
await client.close()
if __name__ == "__main__":
asyncio.run(main())
2
python multi_agent_app.py

代理回答来自 destinations 集合的第一个问题和来自 policies 集合的第二个问题。因为会话在 MongoDB 中存储第一轮对话,助手可以在第二个问题中解析“该旅行”,无需您自己传递对话历史。

应用程序创建一个 AsyncMongoClient,并在代理和会话之间共享它:

  • 专业代理会从其工具函数中查询 destinations 和 policies 集合,因此,他们会从您的数据中回答。

  • MongoDBSession 将每个对话回合写入同一数据库中的 agent_sessions 和 agent_messages 集合。两个集合名称都可以配置,并且会话会在首次使用时创建所需的索引。

由于应用程序自行构建客户端,因此客户端生命周期属于应用程序,并且 session.close() 不执行任何操作。为了反而让会话拥有客户端,请使用 MongoDBSession.from_uri() 创建它。

要了解有关使用代理 SDK 协调多个代理的更多信息,请参阅 OpenAI 文档中的以下页面:

  • 编排多个代理,了解通过代码编排与通过 LLM 编排之间的权衡。

  • Handoffs 用于将对话委托给另一个代理,而不是将其作为工具调用。

  • Guardrails 用于验证代理输入和输出。

  • 会话 以获取完整的 MongoDBSession 参考。