以编程方式使用文档

本指南介绍了将深度智能体从本地原型部署到生产环境时需要考虑的事项。涵盖记忆范围配置、执行环境配置、添加防护栏以及连接前端。

概述

智能体利用记忆及其执行环境中的信息来完成任务。 在生产环境中,有几个基本要素决定了信息的共享和访问方式:

  • 线程:单个对话。消息历史和临时文件默认限定在线程范围内,不会跨会话保留。
  • 用户:与您的智能体交互的人。记忆和文件可以私有给某个用户,也可以在用户之间共享。身份验证和授权来自您的 认证层.
  • 助手:已配置的智能体实例。记忆和文件可以绑定到单个助手,也可以在所有助手之间共享。

本页面涵盖: - **LangSmith 部署**:带有认证、 webhook 和定时任务的可管理基础设施 - **生产环境注意事项**:调用、多租户、认证、凭证、异步和持久性 - **记忆**:跨对话持久化信息 - **执行环境**:文件存储和代码执行 - **防护栏**:速率限制、错误处理和数据隐私 - **前端**:将您的 UI 连接到已部署的智能体

LangSmith 部署

!托管式深度智能体将您的智能体配置、工具和运行时设置打包到 LangSmith

将深度智能体投入生产的推荐路径是 托管式深度智能体,这是 LangSmith 中用于创建、运行和管理深度智能体的 API 优先托管运行时。托管式深度智能体目前处于私人预览阶段(加入等待列表)。对于需要自定义应用代码、自定义路由、高级认证或完整智能体服务器 API 的团队,您可以直接配置 LangSmith 部署 。任一路径都会为您配置智能体需要的基础设施: 线程, 运行、存储和检查点器,因此您无需自行设置这些组件。传统 LangSmith 部署还为您提供开箱即用的 认证, webhook, 定时任务可观测性 ,并可以通过以下方式公开您的智能体 MCP or A2A.

本页中的所有代码片段均使用以下 langgraph.json 除非另有说明:

{
  "dependencies": ["."],
  "graphs": {
    "agent": "./agent.py:agent"
  },
  "env": ".env"
}

langgraph.json 是一个配置文件,用于告诉 LangGraph 平台如何构建和运行您的应用程序。它位于项目根目录,对于本地开发(使用 langgraph dev)和生产部署都是必需的。关键字段如下:

字段描述
dependencies要安装的包。 ["."] 将当前目录安装为一个包(从 requirements.txt, pyproject.toml, or package.json).
graphs将图 ID 映射到其代码位置。每个条目为 "<id>": "./<file>:<variable>",其中 <id> 是您通过 API 调用图时使用的名称,而 <variable> 是从导出的已编译图或构造函数 <file>.
env指向包含环境变量(API 密钥、密钥)的 .env 文件的路径。这些变量在构建时设置,在运行时可用。

有关完整的配置选项(自定义 Docker 步骤、存储索引、身份验证处理程序等),请参阅 应用结构.

生产注意事项

调用代理

在生产环境中,每次调用都应携带两个运行级参数:

  • - **thread_id** (通过 config={"configurable": {"thread_id": ...}}传递):对话的稳定标识符。 检查点 使用它来持久化和恢复消息历史,因此后续交互会继续同一对话。生成新的 thread_id 以开始新的对话。
  • - **context**:您的工具和中间件在调用时读取的每次运行数据,例如 user_id、API 密钥、功能标志或会话元数据。使用 context_schema 定义其形状,并通过 runtime.context访问。请参阅 运行时上下文.

两者相互独立,几乎总是同时传递:

使用 LangGraph SDK 部署时,SDK 会为您管理线程,您只需将返回的 thread_id 传递给每次运行:

from langgraph_sdk import get_client

client = get_client(url="", api_key="")

thread = await client.threads.create()
async for chunk in client.runs.stream(
    thread["thread_id"],  # [!code highlight]
    "agent",
    input={"messages": [{"role": "user", "content": "Plan a 3-day trip to Tokyo"}]},
    context={"user_id": "user-123"},  # [!code highlight]
    stream_mode="updates",
):
    print(chunk.data)

Multi-tenancy

当您的代理为多个用户提供服务时,您需要处理三个问题:验证每个用户的身份、控制他们可以访问的内容,以及管理代理代表他们操作的凭据。

!三个认证层级组成:最终用户认证、代理代表用户认证和团队 RBAC

用户身份与访问控制

LangSmith 部署 支持 自定义认证 用于建立用户身份和 授权处理程序 用于控制对线程、助手和存储命名空间等资源的访问。授权处理程序在认证成功后运行,可以:

  • - 使用所有权元数据标记资源(例如, owner: user_id)
  • - 返回过滤器以使用户只能看到自己的资源
  • - 对未授权操作返回 HTTP 403 拒绝访问

有关分步教程,请参阅 使对话私有化。有关演示,请观看 自定义认证视频.

您如何 设置内存范围执行环境范围 决定了哪些数据在用户之间共享。请参阅下文了解详情。

团队访问控制(RBAC)

LangSmith 的 基于角色的访问控制 管理着您的团队中谁可以部署、配置和监控代理。这与上述最终用户授权是分开的。

角色访问权限
工作区管理员完整权限,包括设置和成员管理
工作区编辑者创建和修改资源,但无法删除运行记录或管理成员
工作区查看者只读访问权限

具有细粒度权限的自定义角色在企业计划中可用。请参阅 RBAC 参考文档 了解完整的权限模型。

最终用户凭证

当您的代理需要代表用户调用外部 API(例如读取他们的 GitHub 仓库、发送 Slack 消息、查询他们的数据仓库)时,您需要一种方式将用户凭证传递给代理,而不是硬编码它们。

通过 Agent Auth 的 OAuth。 Agent Auth 提供托管的 OAuth 2.0 流程。配置 OAuth 提供商后,代理可以请求针对每个用户范围的令牌。首次使用时,代理会 中断 执行并显示 OAuth 同意 URL。用户认证后,代理将使用有效令牌恢复执行。令牌会自动存储和刷新。

from langchain_auth import Client
from langchain.tools import tool, ToolRuntime

auth_client = Client()

# Inside your agent's tool:
@tool
async def github_action(runtime: ToolRuntime):
    """Perform an action on behalf of the user via GitHub."""
    auth_result = await auth_client.authenticate(
        provider="github",
        scopes=["repo", "read:org"],
        user_id=runtime.server_info.user.identity,  # [!code highlight]
    )
    # Use auth_result.token for GitHub API calls on the user's behalf

沙箱凭证注入。 如果您的代理在 沙箱 中运行代码并调用外部 API, 沙箱认证代理 可以自动将凭证注入到出站请求中,因此沙箱代码永远不会收到原始 API 密钥。请参阅 管理密钥 了解设置详情。

工作区密钥。 对于所有用户共享的 API 密钥(例如您组织的 LLM 提供商密钥、搜索 API 密钥),请将它们存储为 工作区密钥 在 LangSmith 中。请参阅 管理密钥 了解更多详情。

异步

LLM-based applications are heavily I/O-bound: calling language models, databases, and external services. Async programming lets these operations run concurrently instead of blocking, improving throughput and responsiveness.

构建生产环境时:

  • 创建异步工具。 LangChain 在单独线程中运行同步工具以避免阻塞,但原生异步可以完全避免线程开销。
  • 使用异步中间件方法。 自定义 中间件 应实现异步钩子(例如, abefore_agent 而不是 before_agent).
  • 使用异步进行外部资源生命周期管理。 创建 沙箱 或连接到 MCP 服务器 涉及网络调用,应使用 await。这就是为什么 图工厂 (用于配置这些资源)是异步的。

持久性

Deep Agents 运行在 LangGraph 上,LangGraph 原生提供持久执行。 持久化 层在每个步骤检查点保存状态,因此运行中断(由故障、超时或 human-in-the-loop 暂停引起)会从上次记录的状态恢复,无需重新处理之前的步骤。对于生成许多子代理的长时间运行的 deep agents,这意味着中途故障不会丢失已完成的工作。

!持久执行:当工作线程在运行中途崩溃时,另一个工作线程从最新的检查点继续执行

检查点还支持:

  • - **无限期 中断.** 人机交互工作流可以暂停数分钟或数天,然后从中断处精确恢复。
  • - **时间旅行.** 每个检查点步骤都是一个快照,您可以回滚到该快照,在出现问题时从早期状态重放。
  • 安全处理敏感操作。 对于涉及支付或其他不可逆操作的工作流,检查点提供了审计追踪和恢复点,可以检查导致操作的精确状态。

内存

没有内存,每次对话都从零开始。内存让您的代理保留跨对话的信息(用户偏好、已学到的指令、过去的经验),以便随着时间推移个性化其行为。要了解内存类型的概述,请参阅 内存概念指南.

!短期记忆通过检查点限定在单个线程内;长期记忆通过存储跨线程持久化

作用域

记忆在对话之间始终是持久化的。主要问题是如何在用户和助手边界之间进行作用域划分。正确的作用域取决于谁应该查看和修改数据:

作用域命名空间使用场景示例
**用户** (推荐默认值)(user_id)按用户偏好和上下文"我偏好简洁的回复"
**助手**(assistant_id)单个助手的共享指令"推文最多280个字符"
**全局**(org_id)所有用户和助手的只读策略"永不透露内部定价"

配置

在深度代理中,记忆以文件形式存储在虚拟文件系统中。默认情况下,文件限定在单个线程(对话)内,不在线程之间共享。 否则,要在线程之间共享记忆,请将路径路由到 /memories/ 到写入 LangGraph 的 StoreBackend 存储。使用 CompositeBackend 为代理提供线程范围的临时空间和跨线程 长期记忆.

User (recommended)

user_id命名空间。每个用户获得自己的私有记忆。这是推荐的默认值,因为大多数应用程序部署单个助手。

from deepagents import create_deep_agent
from deepagents.backends import CompositeBackend, StateBackend, StoreBackend

agent = create_deep_agent(
    model="google_genai:gemini-3.5-flash",
    backend=CompositeBackend(
        default=StateBackend(),
        routes={
            "/memories/": StoreBackend(
                namespace=lambda rt: (
                    rt.server_info.assistant_id,  # [!code highlight]
                    rt.server_info.user.identity,  # [!code highlight]
                ),
            ),
        },
    ),
    system_prompt="""You have persistent memory at /memories/.

    Read /memories/instructions.txt at the start of each conversation for
    accumulated knowledge and preferences. When you learn something that
    should persist, update that file.""",
)

Assistant

assistant_id命名空间。记忆在同一助手的所有用户之间共享,因此任何用户都可以读取或更新它。将其用于适用于使用给定助手的所有人的共享指令或知识(例如,"始终以正式语气回复")。

from deepagents import create_deep_agent
from deepagents.backends import CompositeBackend, StateBackend, StoreBackend

agent = create_deep_agent(
    model="google_genai:gemini-3.5-flash",
    backend=CompositeBackend(
        default=StateBackend(),
        routes={
            "/memories/": StoreBackend(
                namespace=lambda rt: (
                    rt.server_info.assistant_id,  # [!code highlight]
                ),
            ),
        },
    ),
)

User

user_id 单独命名空间。记忆跟随用户跨所有助手。将其用于全局用户配置文件(姓名、时区、沟通偏好),无论用户与哪个助手交谈都应适用。

from deepagents import create_deep_agent
from deepagents.backends import CompositeBackend, StateBackend, StoreBackend

agent = create_deep_agent(
    model="google_genai:gemini-3.5-flash",
    backend=CompositeBackend(
        default=StateBackend(),
        routes={
            "/memories/": StoreBackend(
                namespace=lambda rt: (rt.server_info.user.identity,),  # [!code highlight]
            ),
        },
    ),
)

Organization

org_id命名空间。记忆在所有用户和所有助手之间共享。通常用于组织范围的策略(合规规则、品牌指南),代理应只读访问。写访问权限应限制在应用程序代码中,以防止提示注入。

from deepagents import create_deep_agent
from deepagents.backends import CompositeBackend, StateBackend, StoreBackend

agent = create_deep_agent(
    model="google_genai:gemini-3.5-flash",
    backend=CompositeBackend(
        default=StateBackend(),
        routes={
            "/memories/": StoreBackend(
                namespace=lambda rt: (rt.context.org_id,),
            ),
        },
    ),
)

您还可以使用以下方式从应用程序代码中读取和写入存储 存储 API。请参阅 高级用法 获取示例。

完整的命名空间工厂 API,请参阅 命名空间工厂。对于自我改进指令和知识库等记忆模式,请参阅 长期记忆.

执行环境

在本地,代理可以直接读取和写入磁盘上的文件并运行 shell 命令。在生产环境中,您需要考虑隔离和持久化。正确的设置取决于您的代理是否需要执行代码:

  • 文件系统后端 如果您的代理仅读取和写入文件,这些后端就足够了。选择符合您持久化需求的后端:线程作用域的临时空间、跨线程存储,或两者的混合。
  • 沙箱 添加一个带 execute tool for running shell commands. Use a sandbox if your agent needs to run code, install packages, or do anything beyond file I/O.

文件系统

根据需要持久化的内容选择后端:

  • - StateBackend(默认):线程作用域的临时空间。文件通过检查点程序在同一个线程内的多轮对话中持久化,但不会在线程间共享。每个步骤都会进行检查点保存,因此应避免写入大文件。
  • - StoreBackend:跨线程存储,可在对话间保留。使用 命名空间工厂.
  • - CompositeBackend:混合两者。默认使用线程作用域的临时空间,为特定路径设置跨线程路由,例如 /memories/.
  • - ContextHubBackend:LangSmith Hub 仓库中的持久文件(owner/name or name)。当您需要 LangSmith 原生持久化而无需配置单独的 LangGraph 存储时使用此选项。

有关后端的完整列表以及如何构建自定义后端,请参阅 后端.

沙箱

如果您的代理需要运行代码(而不仅仅是读取和写入文件),请使用 沙箱。沙箱提供文件系统以及 execute 工具用于运行 shell 命令,所有操作都在隔离的容器内进行。这种隔离也保护您的主机:如果代理的代码耗尽内存或崩溃,只会影响到沙箱。您的服务器会继续运行。

生命周期

关键决策是沙箱的存活时长。是每个对话获得一个新的沙箱,还是多个对话共享一个持久化环境?

作用域沙箱 ID 存储位置生命周期示例用例
**Thread-scoped**线程 元数据每个对话全新,TTL 后清理数据分析机器人,每个对话都从干净状态开始
**Assistant-scoped**助手 配置所有对话共享跨对话维护克隆仓库的编码助手

Thread-scoped (most common)

每个对话获得自己的沙箱。该 图工厂 读取 thread_id 从运行配置中读取,所以每个 线程 自动获得自己独立的环境。命名沙箱查找处理跨运行的去重。在沙箱时进行清理 TTL expires.

Assistant-scoped

所有会话共享一个沙箱。 图工厂助手 ID 从 config["configurable"],因此同一助手上的每个线程返回到相同的环境。文件、安装的包和克隆的仓库在会话之间保持存在。

因为 agent 变量是一个异步函数(不是编译图),服务器将其视为 图工厂 并在每次运行时调用它,注入配置。工厂按名称查找或创建沙箱,并返回连接到该沙箱的新代理图。

一旦使用 langgraph deploy部署后,使用 SDK 从应用程序代码调用代理。客户端代码在不同范围内保持一致。范围管理完全由上述代理工厂处理,但行为存在差异:

Thread-scoped

每个线程获得自己的沙箱。同线程内的后续消息复用同一沙箱,但新线程始终全新启动,不保留之前会话的文件或已安装的包。

from langgraph_sdk import get_client

client = get_client(url="", api_key="")

# Conversation 1: install pandas and analyze data
thread_1 = await client.threads.create()
async for chunk in client.runs.stream(
    thread_1["thread_id"],
    "agent",
    input={"messages": [{"role": "human", "content": "Install pandas and analyze sales_data.csv"}]},
    stream_mode="updates",
):
    print(chunk.data)

# Follow-up in the same conversation — pandas is still installed
async for chunk in client.runs.stream(
    thread_1["thread_id"],
    "agent",
    input={"messages": [{"role": "human", "content": "Now plot the results"}]},
    stream_mode="updates",
):
    print(chunk.data)

# Conversation 2: fresh sandbox — pandas is NOT installed, no files from conversation 1
thread_2 = await client.threads.create()
async for chunk in client.runs.stream(
    thread_2["thread_id"],
    "agent",
    input={"messages": [{"role": "human", "content": "What packages are installed?"}]},
    stream_mode="updates",
):
    print(chunk.data)

Assistant-scoped

所有线程共享一个沙箱。当沙箱状态重建成本高昂时很有价值,例如克隆仓库、安装的依赖或构建产物。同一助手上的任何会话都能从上次中断处继续,无需重复设置。

from langgraph_sdk import get_client

client = get_client(url="", api_key="")

# Conversation 1: clone and set up the project
thread_1 = await client.threads.create()
async for chunk in client.runs.stream(
    thread_1["thread_id"],
    "agent",
    input={"messages": [{"role": "human", "content": "Clone https://github.com/org/repo and install dependencies"}]},
    stream_mode="updates",
):
    print(chunk.data)

# Conversation 2: repo and dependencies are still there
thread_2 = await client.threads.create()
async for chunk in client.runs.stream(
    thread_2["thread_id"],
    "agent",
    input={"messages": [{"role": "human", "content": "Run the test suite and fix any failures"}]},
    stream_mode="updates",
):
    print(chunk.data)

文件传输

沙箱是隔离的容器,因此应用程序代码无法直接访问其中的文件。使用 upload_files()download_files() 来跨沙箱边界移动数据:

  • 在代理运行前向沙箱注入种子数据:上传用户文件, 技能 脚本、配置或 持久化记忆 ,让代理从一开始就有所需内容
  • 在代理完成后获取结果:下载生成的产物(报告、图表、导出文件)并将更新的记忆同步回来以供未来会话使用

有关特定提供商的文件传输示例,请参阅 处理文件。有关提供商设置、安全性和生命周期模式,请参阅完整的 沙箱指南.

Example: syncing skills and memories with custom middleware

技能 代理需要执行的脚本必须在代理运行前上传到沙箱中。您可能还需要同步 记忆 ,以便代理可以在容器内读取和更新它们。使用 自定义中间件before_agent 钩子跨沙箱边界移动文件: after_agent

from deepagents import create_deep_agent
from deepagents.backends import CompositeBackend, StoreBackend
from deepagents.backends.langsmith import LangSmithSandbox
from langchain.agents.middleware import AgentMiddleware, AgentState
from langgraph.runtime import Runtime
from langsmith.sandbox import SandboxClient


def _safe_filename(key: str) -> str:
    """Reject keys that contain path traversal or glob characters."""
    name = key.split("/")[-1]
    if ".." in name or any(c in name for c in ("*", "?")):
        raise ValueError(f"Invalid key: {key}")
    return name


class SandboxSyncMiddleware(AgentMiddleware):
    """Sync skills and memories between the store and the sandbox."""

    def __init__(self, backend: CompositeBackend):
        super().__init__()
        self.backend = backend

    async def abefore_agent(self, state: AgentState, runtime: Runtime) -> None:
        """Upload skill scripts and memories into the sandbox."""
        user_id = runtime.server_info.user.identity  # [!code highlight]
        store = runtime.store
        files = []
        for item in await store.asearch(("skills", user_id)):
            name = _safe_filename(item.key)
            files.append((f"/skills/{name}", item.value["content"].encode()))
        for item in await store.asearch(("memories", user_id)):
            name = _safe_filename(item.key)
            files.append((f"/memories/{name}", item.value["content"].encode()))
        if files:
            await self.backend.upload_files(files)

    async def aafter_agent(self, state: AgentState, runtime: Runtime) -> None:
        """Sync updated memories back to the store."""
        user_id = runtime.server_info.user.identity  # [!code highlight]
        store = runtime.store
        items = await store.asearch(("memories", user_id))
        results = await self.backend.download_files(
            [f"/memories/{item.key}" for item in items]
        )
        for result in results:
            if result.content is not None:
                await store.aput(
                    ("memories", user_id),
                    result.path.split("/")[-1],
                    {"content": result.content.decode()},
                )


client = SandboxClient()
ls_sandbox = client.create_sandbox()


backend = CompositeBackend(
    default=LangSmithSandbox(sandbox=ls_sandbox),
    routes={
        "/skills/": StoreBackend(
            rt,
            namespace=lambda rt: ("skills", rt.server_info.user.identity),  # [!code highlight]
        ),
        "/memories/": StoreBackend(
            rt,
            namespace=lambda rt: ("memories", rt.server_info.user.identity),  # [!code highlight]
        ),
    },
)

agent = create_deep_agent(
    model="google_genai:gemini-3.5-flash",
    backend=backend,
    middleware=[SandboxSyncMiddleware(backend)],
)

管理密钥

沙箱是隔离的容器,因此主机上的环境变量在沙箱内不可用。有两种方式可以向沙箱代码提供 API 密钥和其他密钥:

认证代理(推荐)沙箱认证代理 拦截来自沙箱的出站请求并自动注入认证头。沙箱代码正常调用外部 API,代理根据目标主机添加正确的凭据。这意味着 API 密钥永远不会出现在沙箱代码、环境变量或日志中。

!沙箱认证代理将凭据注入出站请求,因此密钥永远不会进入沙箱

{
  "proxy_config": {
    "rules": [
      {
        "name": "openai-api",
        "match_hosts": ["api.openai.com"],
        "inject_headers": {
          "Authorization": "Bearer ${OPENAI_API_KEY}"
        }
      },
      {
        "name": "anthropic-api",
        "match_hosts": ["api.anthropic.com"],
        "inject_headers": {
          "x-api-key": "${ANTHROPIC_API_KEY}"
        }
      }
    ]
  }
}

这些 ${SECRET_KEY} 引用会根据存储在 LangSmith 中的密钥进行解析 工作区设置。在创建引用它们的模板之前,请在该处配置密钥。

工作区密钥 对于不需要代理注入的 API 密钥(例如,代理服务器本身使用的密钥,而非沙箱代码使用的密钥),请将它们存储为 工作区密钥 在 LangSmith 中。这些在运行时可作为环境变量供工作区中的所有代理使用。

防护措施

生产环境中的代理自主运行,这意味着它们可能会无限循环、达到速率限制或处理包含敏感信息的用户数据。Deep Agents 提供两层保护:

  • - **权限**: declarative allow/deny rules that control which files and directories the agent can read or write. Use permissions to isolate the agent to a working directory, protect sensitive files, or enforce read-only memory.
  • - **中间件**:包装模型和工具调用的钩子,用于速率限制、错误处理和数据隐私。

!中间件钩子——在_模型、封装_模型_调用、封装_工具_调用之后_模型——封装代理循环,以便策略在每个相关步骤周围确定性运行

速率限制

此处的速率限制是指限制代理在一次运行中的 LLM 和工具使用量,而非 API 网关对传入请求的速率限制。

没有限制的情况下,混乱的代理可能会在几分钟内因重复调用同一工具或进行数百次模型调用而耗尽您的 LLM API 预算。请为每次运行设置模型调用和工具执行的上限:

from deepagents import create_deep_agent
from langchain.agents.middleware import ModelCallLimitMiddleware, ToolCallLimitMiddleware

agent = create_deep_agent(
    model="google_genai:gemini-3.5-flash",
    middleware=[
        ModelCallLimitMiddleware(run_limit=50),
        ToolCallLimitMiddleware(run_limit=200),
    ],
)

使用 run_limit 来限制单次调用中的调用次数(每次轮次重置)。使用 thread_limit 来限制整个对话中的调用次数(需要检查点)。请参阅 ModelCallLimitMiddlewareToolCallLimitMiddleware 获取完整配置。

错误处理

并非所有错误都应采用相同方式处理。暂时性故障(网络超时、速率限制)应自动重试。LLM 可以恢复的错误(工具输出不良、解析失败)应反馈给模型。需要人工输入的错误应暂停代理。包含代码示例的完整分类,请参阅 正确处理错误.

中间件处理暂时性故障。模型调用和工具调用各有自己的重试中间件,采用指数退避策略。如果您的主要模型提供商完全宕机,回退中间件会切换到备选方案:

from deepagents import create_deep_agent
from langchain.agents.middleware import (
    ModelFallbackMiddleware,
    ModelRetryMiddleware,
    ToolRetryMiddleware,
)

agent = create_deep_agent(
    model="google_genai:gemini-3.5-flash",
    middleware=[
        # Retry model calls on rate limits, timeouts, and 5xx errors
        ModelRetryMiddleware(max_retries=3, backoff_factor=2.0, initial_delay=1.0),
        # If the primary model is fully down, fall back to an alternative
        ModelFallbackMiddleware("gpt-5.5"),
        # Retry specific tools that hit external APIs (not all tools)
        ToolRetryMiddleware(
            max_retries=2,
            tools=["search", "fetch_url"],
            retry_on=(TimeoutError, ConnectionError),
        ),
    ],
)

ToolRetryMiddleware 作用域限定为特定工具,而不是重试所有内容。文件系统 read_file 失败的文件系统不会从重试中受益,但超时的网络搜索可能会。参见 ModelRetryMiddlewareModelFallbackMiddleware 获取完整配置。

数据隐私

如果您的智能体处理的用户输入可能包含电子邮件、信用卡号码或其他 PII,您可以在其到达模型或存储到日志之前进行检测和处理:

from deepagents import create_deep_agent
from langchain.agents.middleware import PIIMiddleware

agent = create_deep_agent(
    model="google_genai:gemini-3.5-flash",
    middleware=[
        PIIMiddleware("email", strategy="redact", apply_to_input=True),
        PIIMiddleware("credit_card", strategy="mask", apply_to_input=True),
    ],
)

策略包括 redact (替换为 [REDACTED_EMAIL]), mask (部分掩码,如 ****-****-****-1234), hash (确定性哈希),以及 block (抛出错误)。您也可以为特定领域的模式编写自定义检测器。 参见 PIIMiddleware 获取完整配置。

关于默认的 Deep Agents 中间件堆栈,请参见 自定义。有关其他 LangChain 预构建中间件(重试、回退、PII 检测等),请参见 预构建中间件.

前端

Deep Agents 使用 useStream 将您的 UI 连接到智能体后端。useStream 是一个前端钩子(适用于 React、Vue、Svelte 和 Angular),可实时从您的智能体流式传输消息、子智能体进度和自定义状态。

在本地环境中, useStream 指向 http://localhost:2024。在生产环境中,请将其指向您的 LangSmith 部署 并配置重连机制,以便用户在连接中断时不会丢失进度。

function App() {
  const stream = useStream<typeof agent>({
    apiUrl: "https://your-deployment.langsmith.dev",
    assistantId: "agent",
  });
}

对于生成许多子智能体的深度智能体工作流,在提交时应设置较长的 recursionLimit 以避免截断长时间运行的执行:

stream.submit(
  { messages: [{ type: "human", content: text }] },
  {
    streamSubgraphs: true,
    config: { recursionLimit: 10000 },
  },
);

有关深度智能体特有的 UI 模式(如子智能体卡片、待办事项列表和自定义状态渲染),请参见 前端指南.