关于 add-context-gateway
指导将 Agent 的 MCP 连接转由 Redis Context Gateway 路由,并配置上游服务和统一端点。自托管部署还可按需启用工具搜索、缓存及大型结果句柄。
主要功能
- 01盘点 MCP 服务及凭据
- 02配置 HTTP 上游服务
- 03完整暴露工具或通过搜索调用
- 04为只读工具设置缓存策略
- 05将大型结果作为句柄返回
- 06创建并检查 Gateway
适用场景
- 01用一个端点替代多个 Agent MCP 连接
- 02减少 Agent 可见的工具模式数量
- 03缓存可重复的只读查询
- 04处理大型导出、列表或日志
MCP 相关
该技能将 Gateway 配置为上游 HTTP MCP 服务的统一 MCP 端点。框架客户端可连接其 URL 并使用密钥;没有 MCP 客户端的 Agent 可通过 SDK 的模型工具或 hooks 接入。
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ redis/ agent-skills --skill add-context-gateway安装后在 Claude Code 中输入/add-context-gateway确认已加载。
详细介绍
添加 Context Gateway
使用一个 MCP 端点和一个 Agent 密钥,替代 Agent 当前配置的所有 MCP 服务。Gateway 会保存每个上游的密钥,为工具名称添加命名空间以避免冲突;可以将大型目录以 search_tools 和 run_tool 的形式公开,而不是提供每个工具的架构;可以缓存你选择启用缓存的只读工具;还能将大型结果作为句柄返回。Agent 保留原有工具;改变的只有工具的访问入口。先询问,再配置,最后更换指向。
1. 调查
阅读项目:
- 找出 Agent 配置的所有 MCP 服务:
.mcp.json、.cursor/mcp.json、McpToolset、MCPServerStreamableHttp、MultiServerMCPClient、stdio_client,或手写的 MCP 客户端。记录每个端点及其密钥的来源。 - 找出工具交给模型的位置,以及运行每轮对话的位置。
- 根据导入内容识别框架,并确认它是否有自己的 MCP 客户端。
- 记录仅支持 stdio 的服务:上游是一个 HTTP MCP 端点(
streamable-http)。stdio 服务必须先通过 HTTP 提供服务,否则就留在 Gateway 之外。
首先询问 Gateway 的运行位置:
- Redis Cloud(控制台)。 开发者在控制台中创建 Gateway 和上游,CLI 只与 Gateway 的 MCP 端点通信(第 3 步“在 Redis Cloud 中”)。Cloud 会关闭 Gateway 的缓存和压缩,因此跳过问题 3 和 4。
- 自行管理(本地部署,或本地 Compose 堆栈)。CLI 配置所有内容(第 3 步)。
然后只问开发者以下五个问题,不要多问。对方若不确定,则采用默认值。
| 询问 | 如果答案是 | 配置 |
|---|---|---|
| Agent 使用哪些 MCP 服务,它们的密钥存放在哪里? | 一组 HTTP 端点 | 每个端点添加一个上游:upstream add --name NAME --endpoint URL,并使用 --bearer-secret env:VAR 或 --header NAME --header-secret env:VAR |
| Agent 要查询的 Redis 数据库 | Context Surface 上游:--kind context-surface --surface-database-id ID --data-model FILE(自行管理时,可以省略 ID,默认使用部署配置中的 ID。在 Redis Cloud 中,控制台的 Create Context Surface 会询问数据库)。先编写数据模型:参见“编写数据模型” | |
| Agent 总共会看到多少个工具? | 几十个(默认) | --tool-exposure-mode full:提供所有工具,并为名称添加命名空间 |
| 数百个,或工具架构让提示词过于拥挤 | --tool-exposure-mode search:模型会看到 search_tools 和 run_tool | |
| 哪些只读工具在参数相同时会返回相同结果? | 查询、搜索、参考数据 | 使用启用 cache 的数据库创建 Gateway(参见“Gateway 开关和数据库”),然后针对每个工具设置 policy set UPSTREAM TOOL --cache-ttl DURATION |
| 没有,或不确定 | 不设置缓存策略 | |
| 哪些工具返回的结果太大,无法一次性完整读取? | 导出、列表端点、日志 | 使用 noeviction 数据库并启用 compression 创建 Gateway(参见“Gateway 开关和数据库”)。然后使用部署的句柄默认设置,或针对每个工具设置 --compression-ttl DURATION;对于必须始终返回完整结果的工具,使用 --compression-capture never |
| 框架会自行连接 MCP 服务吗? | 会:Claude Code、Cursor、ADK、OpenAI Agents SDK、LangChain MCP adapters | 将其 MCP 客户端指向 Gateway URL 和密钥 |
| 不会,或 Agent 需要普通函数工具 | 使用 SDK:gateway.model_tools() 或 gateway.hooks() |
2. 从 MCP 获取当前信息
编写代码前先执行此操作。切勿凭记忆猜测框架 API。
- 框架文档:查询可用的文档 MCP(Context7,或框架自带的文档 MCP),了解已安装版本的 MCP 客户端如何接收 streamable HTTP URL 和
Authorization请求头。 - Redis 文档:如果已连接 Redis 文档 MCP,请使用它了解 Context Gateway 概念(上游、暴露模式、缓存、句柄)。
- 没有可用的 MCP:阅读虚拟环境中已安装的软件包源码,并在报告中说明。
3. 配置
安装 CLI
pip install redis-iris
需要 Python 3.11 或更高版本。在 LangGraph 上,请安装 redis-iris[langgraph]。如果在搜索模式的 Gateway 上设置了 Gateway ID(--gateway-id 或 IRIS_CONTEXT_GATEWAY_ID),但运行 tools call crm__lookup_customer 时因 tool_not_found 失败,这是因为已安装的版本会在第一个 . 处分割工具名称:请升级 redis-iris,或在设置 IRIS_CONTEXT_GATEWAY_URL 且不设置 Gateway ID 的情况下运行 tools call,这样 CLI 就会通过 search_tools 解析名称。
在 Redis Cloud 中
Redis Cloud 目前还没有用于设置 Gateway 的 API。控制平面只接受控制台会话,因此 cloud 配置文件会对 service、upstream 和 policy 命令返回 cloud_unsupported,Agent 也无法进行配置。开发者需在控制台中操作:
- Iris → Context Gateway:创建 Gateway,或打开现有 Gateway。
- 在 Gateway 中,进入 Upstreams:为问题 1 中的每个 HTTP 服务选择 Add MCP server,或为 Redis 数据库选择 Create Context Surface(先编写数据模型:参见“编写数据模型”)。
- 在连接步骤中,复制 MCP 端点并创建 Agent 密钥。
- 将它们设置为 Agent 环境或其
.env中的IRIS_CONTEXT_GATEWAY_URL和IRIS_CONTEXT_GATEWAY_API_KEY。这些值由开发者设置,绝不能由 Agent 设置:不要在聊天中索要密钥,也绝不要回显、运行cat或grep查看环境文件。
在 .env.example 中添加这两个名称,并将值留空;绝不要提交 .env。然后跳过本步骤的其余内容,转到步骤 4。Cloud 会关闭缓存和压缩,因此无需设置策略或句柄。
自行管理
请让用户导出 IRIS_CONTEXT_GATEWAY_SERVICE_URL、IRIS_CONTEXT_GATEWAY_SERVICE_TOKEN、IRIS_IDENTITY_URL 和 IRIS_IDENTITY_TOKEN。对于本地 Compose 堆栈,在命令后添加 --local(service list --local)会提供服务 URL 和令牌,但不会提供 Identity URL,因此 create 仍需要 IRIS_IDENTITY_URL。
Identity 令牌。 每个产品的 chart 都可以运行自己的 Identity Service。此时请设置该产品自己的 IRIS_CONTEXT_GATEWAY_IDENTITY_TOKEN(以及 IRIS_CONTEXT_GATEWAY_IDENTITY_URL,或配置文件中的 identity_url),并取消设置 IRIS_IDENTITY_URL:它会覆盖配置文件中每个产品的 identity_url。在共享一个 Identity Service 的套件中,IRIS_IDENTITY_TOKEN 和 IRIS_IDENTITY_URL 适用于所有产品。CLI 按以下顺序获取令牌:--identity-token、IRIS_CONTEXT_GATEWAY_IDENTITY_TOKEN、IRIS_IDENTITY_TOKEN,最后是该产品的服务令牌;只有两个令牌是同一个密钥时,最后一种方式才有效。
iris --json --no-input context-gateway service list
iris --json --no-input context-gateway service create --name support --tool-exposure-mode full --write-env .env
set -a; . ./.env; set +a; iris --json --no-input context-gateway service check <gatewayId from the result>
Gateway CLI 只会从环境变量中读取 IRIS_CONTEXT_GATEWAY_API_KEY,绝不会从 .env 中读取,因此在密钥位于命令的环境中之前,service check、tools 和 handle 都会因 configuration_error 失败。请像上面那样在同一条 Shell 命令中加载该文件(或使用 uv run --env-file .env iris ...),这样密钥就不会出现在输出中。
Gateway 开关和数据库
每个 Gateway 都有两个开关:cache 和 compression,它们的状态分别为 ENABLED 或 DISABLED。service show gw_0123456789abcdef0123456789abcdef 会显示这两个开关。若 Gateway 的 cache 为 DISABLED,则 --cache-ttl 策略会被拒绝并返回 400,因此请先启用 cache。当 compression 关闭时,压缩策略虽会保存,但不会生效。这两项功能还需要由运维人员启用部署开关(数据平面配置中的 cache.enabled 和 compression.enabled,默认关闭)。
| 创建方式 | cache 和 compression |
|---|---|
使用数据库:--database-id ID,或使用本地部署的默认值 defaultDatabases.gatewayDb | 两者均为 ENABLED |
| 不使用数据库 | 两者均为 DISABLED。不指定数据库却发送 ENABLED,该字段会返回 400 |
使用无法进行压缩的数据库(见下文,或数据库不可访问),且省略 compression | cache 为 ENABLED,compression 保存为 DISABLED |
| 功能 | 生效条件 |
| --- | --- |
| 缓存 | Gateway 的 cache 为 ENABLED,工具可缓存(未标记 readOnlyHint: false 或 destructiveHint: true;未提供提示的工具也视为可缓存,因此只为确定为只读的工具启用),且设置了 --cache-ttl 策略 |
| 压缩 | Gateway 的 compression 为 ENABLED,且工具的策略不是 --compression-capture never |
service create 和 service update 均接受 --cache enabled|disabled 和 --compression enabled|disabled,并会发送大写 API 值。省略标志会保留服务端默认值或现有值。之后添加数据库不会启用任何一项功能,因此请显式启用:
iris --json --no-input context-gateway service update gw_0123456789abcdef0123456789abcdef --database-id gateway-db --cache enabled --compression enabled
要分离数据库,请在一次更新中传入 --clear-database --cache disabled --compression disabled。过期的 --expected-revision 会返回 412 revision_conflict。请先重新读取资源,再决定是否重试。
数据库要求:
- 压缩需要一个
maxmemory-policy noeviction且已加载 JSON 模块的 Gateway 数据库。在其他策略下启用压缩(创建、更新,或压缩保持启用时更改databaseId)会返回 400,且errors[]中会有一项指向/compression,原因类似database lru-db uses allkeys-lru, compression needs noeviction。发送compression enabled时,如果数据库无法访问,会返回 503:请重试。在不适用或无法访问的数据库上创建服务时,若省略compression,请求不会被拒绝:系统会将compression设为DISABLED,请使用service show读取确认。 - 仅缓存适用于任何 Gateway 数据库。句柄和缓存条目共用该数据库,因此请为其预留足够的
maxmemory。对于采用驱逐策略的仅缓存数据库,Redis 会驱逐条目,且下方的共享内存限制不适用。 - 句柄和缓存各自拥有独立的
maxmemory份额。 句柄使用量上限为compression.max_memory_share(默认值为 0.5),缓存使用量上限为cache.max_memory_share(默认值为 0.4),两者合计最多为 0.95,因此不会占用对方的空间。两者还会在使用量超过maxmemory的 90% 时停止增长,但这只是对份额限制未能覆盖情况的兜底。 - 句柄份额已满时,自动捕获会完整返回结果,而显式调用
run_tool_as_handle会返回工具错误:handle storage is full, release handles or narrow the query。缓存份额已满时,只会跳过写入并返回结果。释放句柄会立即释放其份额,过期句柄则会在约 10 秒内释放份额。 - 请根据 TTL 为 Gateway 数据库配置容量。 句柄和缓存条目会一直保留到 TTL 到期(句柄默认保留 15 分钟),因此每个份额都需要足够的空间来容纳
每秒创建数 x TTL x 存储大小。不要根据结果大小估算存储大小。请实际测量:service diagnose --metrics-url会显示缓存和压缩计数器;skipped_low_memory或out_of_memory结果不断增加,意味着对应份额已满。如果空间不足,请降低--compression-ttl或--cache-ttl,或者提高maxmemory或运维人员设置的份额。 - 本地部署时,数据库来自部署配置,绝不会来自 CLI:
shared.config.databases注册各个 ID,databaseConnections提供 URL,defaultDatabases.gatewayDb和defaultDatabases.surfaceDb指定默认值。若找不到某个 ID,请联系运维人员。启用压缩时,Gateway 数据库和 Surface 数据库应使用不同的 Redis 实例:否则noeviction也会应用于客户数据。
service diagnose gw_0123456789abcdef0123456789abcdef 会报告 Gateway 的数据库(no Gateway database 表示每次调用都会绕过缓存)、每个 Upstream 的目录以及缓存策略。添加 --metrics-url 可查看缓存和压缩计数器;eviction_policy、skipped_low_memory 或 out_of_memory 结果不断增加,意味着句柄无法被保留。
将 CLI 用作 Agent
- 始终将
--json --no-input放在产品名称之前。标准输出会返回一个 JSON 值,标准错误会返回一个 JSON 值作为错误,并且不会显示提示。 - 先读取,再写入。
service create没有--dry-run,因此先运行service list:它能验证服务 URL 和令牌;如果那里出现configuration_error、unauthenticated或forbidden,则在创建任何内容之前交由他人处理(步骤 4)。 - 始终使用
--write-env PATH(或在service key中使用--write PATH)交付密钥。绝不要在没有文件的情况下使用--json运行create或key:这会将密钥打印到对话记录中。 - 遇到
configuration_error、unauthenticated或forbidden时,停止操作。告知对方需要设置哪个变量(见错误消息或details.env),并在存在details.obtain时附上链接。绝不要在聊天中索要机密、在命令行中传递机密,也不要回显、使用cat或grep查看环境变量文件。 - 上游机密只能通过引用传入:
env:NAME、file:PATH或-。请对方导出变量;绝不要自行写入机密。 - 遇到
resource_exists时,询问对方是使用--reuse复用details.gatewayId,还是选择其他名称。绝不要为了重试而删除资源。如果create失败且details.created: true,则使用--reuse --write-env重新运行。
每个错误都会以一个 JSON 值的形式输出到标准错误,并包含 error.code;凭据错误还会包含 details.env 和 details.obtain,但绝不会包含凭据值。出现第一个故障时立即停止并转达:
error.code | 由谁处理 | 操作 |
|---|---|---|
credential_required | 对方 | 在 Agent 的 shell 中设置 details.env 指定的变量。请参阅上文“身份令牌”。 |
unauthenticated | 对方 | details.source 中的令牌被拒绝:令牌已过期或属于其他部署。请签发新令牌。 |
forbidden | 对方 | 令牌有效,但缺少所需角色或租户。请为该产品使用具有正确角色的令牌。 |
configuration_error | 对方或 Agent | 缺少 URL,例如 url。请将其添加到配置文件。 |
invalid_request | Agent | HTTP 400。请修正错误消息中指出的请求。 |
resource_exists | 对方 | 决定是使用 --reuse 重新运行以接管 details.gatewayId,还是选择其他名称。 |
unavailable | 对方 | 无法访问该跳点。请检查 URL、入口和服务的 Pod。 |
check_failed | 对方 | details.hop 和 details.cause 会指出故障跳点。请修复并重新运行检查。 |
cloud_unsupported | 对方 | 配置文件的 kind = "cloud"。请按照控制台中的 details.steps 操作。 |
input_error, usage_error | Agent | 修正命令。在 --no-input 下执行破坏性命令,需要对方提供 --yes。 |
--write-env .env 会写入 IRIS_CONTEXT_GATEWAY_URL(Gateway 的 MCP 端点)、IRIS_CONTEXT_GATEWAY_ID 和 IRIS_CONTEXT_GATEWAY_API_KEY。请将同样的三个名称以空值添加到 .env.example。绝不要提交 .env。
添加上游(问题 1)。IRIS_CONTEXT_GATEWAY_ID 不是机密;请使用 --gateway-id 传入 create 输出的 gatewayId(gw_ 加 32 个十六进制字符):
iris --json --no-input context-gateway --gateway-id gw_0123456789abcdef0123456789abcdef upstream add --name CRM --endpoint https://crm.example.com/mcp --bearer-secret env:CRM_TOKEN
iris --json --no-input context-gateway --gateway-id gw_0123456789abcdef0123456789abcdef upstream add --name Tickets --endpoint https://tickets.example.com/mcp --header X-Api-Key --header-secret env:TICKETS_KEY
iris --json --no-input context-gateway --gateway-id gw_0123456789abcdef0123456789abcdef upstream tools crm
upstream add 即使输出 initialCatalogFailure,也仍然创建了上游:422 表示上游拒绝了凭据(使用 upstream update 修复,然后运行 upstream refresh);424 表示发现失败(请检查控制平面是否能够访问端点);408 表示超时。对于 --kind context-surface 上游,422 表示 Surface 数据库拒绝了控制平面的登录,424 表示工具生成失败(例如 Redis 返回 NOPERM):这两种情况都需要在部署配置中修复,然后运行 upstream refresh。
编写数据模型
Context Surface 上游需要一个数据模型:用于说明 Agent 可以读取哪些记录以及如何建立索引的 JSON。Gateway 会根据它生成工具,因此请在执行 upstream add --kind context-surface 之前编写好。
| 级别 | 成员 |
|---|---|
| 模型 | title、description、entities[] |
| 实体 | name、description、redis_key_template(例如 order:{id},默认值为 <Name>:{id})、relationships[]、fields[]、可选的 document_type |
| 字段 | name、type、description、is_key_component、redis_indices[];标签可选 allowed_values |
| 关系 | name、target(一个实体)、description、source_field(此实体的一个字段) |
规则:
- 键模板中的每个
{placeholder}都必须是is_key_component: true的字段。键字段不建立索引。第一个占位符之前的文本(order:)必须以:、_、-、/或.结尾:这是索引前缀。 - 字段
type可以是str、int、float、bool、list[str]、list[float]、geo、timestamp或object。object不能建立索引。 - 默认情况下,记录以 RedisJSON 格式存储。
"document_type": "hash"会将实体存储为 Hash:不能包含object字段,list[float]仅可与向量索引搭配使用,键字段必须是标量。 - Gateway 遇到
acl_field_mappings会返回 400,因此请将其省略:每个有权访问 Gateway 的 Agent 密钥都能读取 Surface 的所有记录。iris 仓库中的示例文件包含此字段,请勿复制该文件。
根据 Agent 的查询方式选择索引:
| 索引 | 字段类型 | 用途 | 生成的工具 |
|---|---|---|---|
tag | str、bool、list[str] | 精确筛选:状态、ID、类别。allowed_values 列出合法值 | filter_<entity> |
text | str | 对名称、描述、备注进行全文检索。weight 用于字段排序,no_stem 用于关闭词干提取 | search_<entity>_by_text |
numeric | int、float、timestamp | 范围查询和排序。除非设置 sortable: false,否则字段可排序;list_ 需要可排序字段,且 timestamp 不能设置为 sortable: false | filter_<entity>、list_<entity>、summarize_<entity> |
vector | list[float] | 基于语义的搜索。需要 vector_dim 和 distance_metric(cosine、euclidean、dot_product),并且数据平面上需有嵌入服务。Redis Cloud 目前无法嵌入查询,因此这些工具目前在该平台上会失败 | 当 source_field 指定要嵌入的文本字段时,生成 search_<entity>_by_<field>_semantic;否则生成 _similarity。如果该文本字段有 text 索引,且 Surface Redis 支持通过 RESP3 进行原生混合搜索,也会生成 search_<entity>_by_<field>_hybrid(同时对文本和向量进行排序) |
geo | geo | 查找指定半径内的记录 | find_<entity>_near_<field> |
键模板只有一个占位符的实体还会生成 get_<entity>_by_id;count_<entity> 用于统计记录数。跨实体的集合工具 intersect_results、union_results、except_results 和 expand_results 可组合筛选结果并沿关系展开。每个工具均为只读,并以 <namespace>__<tool> 的形式显示,例如 orders__search_order_by_text。只有模型包含工具所需字段时,该工具才会生成:没有 text 索引,就不会有文本搜索工具。
最简订单模型:
{
"title": "Orders",
"description": "Customer orders",
"entities": [
{
"name": "Order",
"description": "A customer order",
"redis_key_template": "order:{id}",
"relationships": [],
"fields": [
{"name": "id", "type": "str", "description": "Order ID", "is_key_component": true, "redis_indices": []},
{"name": "status", "type": "str", "description": "open, shipped or cancelled", "redis_indices": [{"type": "tag"}]},
{"name": "notes", "type": "str", "description": "Free-text order notes", "redis_indices": [{"type": "text", "weight": 1.0}]},
{"name": "total", "type": "float", "description": "Order total in dollars", "redis_indices": [{"type": "numeric", "sortable": true}]}
]
}
]
}
将其保存为 orders.json,并使用 --surface-database-id ID --data-model orders.json 添加。记录以 JSON 文档形式存储在 order:<id>,字段名称与模型中的名称相同。执行 upstream add 后,运行 upstream tools orders 查看生成的工具。在 Redis 为现有键完成索引之前,搜索结果可能不完整(FT.INFO <index> 中的 percent_indexed 达到 1 即表示完成)。更改数据模型(upstream update)会重新建立索引,因此请在数据库有足够空间时操作。
设置策略(问题 3 和 4)。upstream tools 会指出哪些工具可以缓存;只有这些工具支持 --cache-ttl:
iris --json --no-input context-gateway --gateway-id gw_0123456789abcdef0123456789abcdef policy set crm search_customers --cache-ttl 5m
iris --json --no-input context-gateway --gateway-id gw_0123456789abcdef0123456789abcdef policy set crm export_orders --compression-ttl 1h
轮换密钥和机密
- 新建 Agent 密钥:运行
service key gw_0123456789abcdef0123456789abcdef --write .env,即可生成密钥并将其写入文件。重启 Agent,使其读取新值。 - 同一 Gateway 上的另一位开发者:运行
service env gw_0123456789abcdef0123456789abcdef --write .env,即可写入 URL 和 ID,而不会生成密钥;然后运行service key为其生成专属密钥。 - 新建 Upstream 机密:让对方导出新值,然后运行
upstream update crm --bearer-secret env:CRM_TOKEN(或--header-secret),再运行upstream refresh crm。
完整参考:iris context-gateway <command> --help(例如 iris context-gateway upstream add --help)。
4. 重新配置 Agent
MCP 原生框架(问题 5,回答是)。将每个服务端条目替换为一个 Gateway 条目。connect 会写入从变量中读取的密钥,且不会打印密钥。在 Redis Cloud 中,使用 cloud 配置运行 connect,并且不指定 --gateway-id:它会从 IRIS_CONTEXT_GATEWAY_URL 获取端点。
iris context-gateway --gateway-id gw_0123456789abcdef0123456789abcdef connect --client claude-code --write .mcp.json
iris context-gateway --gateway-id gw_0123456789abcdef0123456789abcdef connect --client cursor --write .cursor/mcp.json
iris context-gateway --gateway-id gw_0123456789abcdef0123456789abcdef connect --client adk > gateway_tools.py
iris context-gateway --gateway-id gw_0123456789abcdef0123456789abcdef connect --client json
对于其他 MCP 客户端(OpenAI Agents SDK、LangChain MCP 适配器),使用 json 输出:其中包含 URL、streamable-http,以及值为 IRIS_CONTEXT_GATEWAY_API_KEY 的 Authorization: Bearer 标头。请在步骤 2 中确认客户端的参数名称。.env 文件不会传递给正在运行的客户端:该变量必须存在于启动客户端时使用的环境中。
SDK 工具(问题 5,回答否):
from redis_iris import ContextGateway
gateway = ContextGateway.from_env()
tools = gateway.model_tools() # framework-free Tool objects, one per Gateway tool
TypeScript Agent:请参阅 @redis-iris/context-gateway API。
在 LangGraph 中,redis_iris.integrations.langgraph 提供的 langchain_tools(gateway.hooks()) 可为 ToolNode 创建 LangChain 工具。如果还接入了 Agent Memory 或 Agent Playbooks,可将它们叠加起来,让模型从一个位置获取每个产品的所有工具:
from redis_iris.hooks import stack
from redis_iris.integrations.langgraph import attach, langchain_tools
hooks = stack(memory.hooks(), playbook.disclosure(), gateway.hooks())
graph.add_node("tools", ToolNode(langchain_tools(hooks)))
app = attach(hooks, graph).compile()
gateway.call("crm__lookup_customer", id="cust-1042") 可直接调用工具(result.data、result.is_error);gateway.call_as_handle(...) 则会将大型结果作为 Handle 保存在 Gateway 上。读取操作由 Gateway 处理:gateway.page(handle, limit=5)、gateway.query(handle, ...)、count、aggregate、describe 和 gateway.release(handle)。异步版本包括 atools、acall、apage 等。
然后,移除由 Gateway 替代的内容:每个服务端对应的 MCP 条目、每个服务端对应的机密(现在由 Gateway 保存),以及任何手写的命名空间或工具筛选逻辑。
工具名称会改为 namespace__tool,例如 crm__lookup_customer。请更新任何提及工具名称的提示词文本或代码。
在搜索模式下,模型不会在 tools/list 中看到这些名称。它会使用 query(以及可选的 limit,默认值为 5)调用 search_tools,获取完整的 MCP 工具定义,然后通过 run_tool 运行其中一个工具:tool 包含匹配项中的 upstreamId 和 originalName,toolArgs 则包含参数。提示词文本应描述工具执行的任务,而不是写出工具名称。通过 SDK 和 CLI 按名称调用工具的代码仍可正常工作,因为它们会为你解析 namespace__tool。
Agent 端的句柄
启用 Gateway compression 后,两种暴露模式下的 tools/list 都会新增七个工具:run_tool_as_handle、describe_result、count_results、page_results、query_results、aggregate_results 和 release_results。如果工具结果超过 32 KiB,返回的将是一个小型存根,其中包含一个句柄(h_ 加 32 个十六进制数字)、预览内容和后续步骤,而非完整载荷。在完整模式下,声明了 outputSchema 的工具会返回完整结果。使用 --compression-capture never 的工具会返回完整结果,对它调用 run_tool_as_handle 则会产生工具错误,提示 Agent 直接调用该工具。请在提示词中告知 Agent 使用下方工具读取句柄,且不要再次请求完整载荷。
| Agent 想要 | 调用 |
|---|---|
| 无论大小,保留较大结果以供后续多次调用 | run_tool_as_handle(完整模式使用 name 和 toolArgs;搜索模式使用 tool、upstreamId、originalName 和 toolArgs) |
| 了解句柄的形状、大小、字段和过期时间 | describe_result |
| 统计项目总数,或按某个字段的值分组统计 | 使用 jsonpath 或 groupBy 调用 count_results |
| 计算数字的总和、最小值、最大值或平均值 | 使用 jsonpath 调用 aggregate_results |
| 只读取符合条件的项目 | 使用 JSONPath(如 $[[email protected]=="open"])调用 query_results,并分页读取 |
| 按顺序读取项目,或按字节读取文本结果 | 使用 offset 和 limit 调用 page_results |
| 提前释放内存 | release_results |
当 run_tool_as_handle 返回 handle storage is full, release handles or narrow the query 时,Agent 应对不再需要的句柄调用 release_results,然后使用范围更窄的查询重试,或直接调用该工具。
句柄会在部署的 TTL(默认 15 分钟)或工具的 --compression-ttl 之后过期,读取不会延长其有效期。已过期、已释放或属于其他键的句柄会被 Gateway 拒绝,拒绝原因是 unknown_handle;CLI 的 handle 命令会将其报告为 handle_not_found(退出码 1):请重新调用该工具获取新句柄。不完整句柄(较长结果中的一页)会在其 completeness 和 warning 中说明这一点。要读取下一页,请再次调用 run_tool_as_handle 并提供分页参数。Context Surface 捕获会自行读取所有页面,最多达到部署限制(10,000 行),因此单个大型 Surface 查询可能占满句柄存储(已知问题 MOD-20735)。禁用 compression(DISABLED)后,tools/list 中将不再包含这七个工具。使用 SDK 时,gateway.call_as_handle(...) 会返回一个 Handle,而 redis_context_gateway.mcp.HANDLE_TOOLS 会列出这七个名称。
5. 验证
检查 1、3、4、6 和 7 需要在命令的环境中提供 Agent 密钥:在同一个 shell 命令中运行 set -a; . ./.env; set +a; iris ...,切勿打印该文件。
在 Redis Cloud 中,不带 --gateway-id 运行 3、4、8 和 9:tools 命令使用 IRIS_CONTEXT_GATEWAY_URL 和 Agent 密钥。其他检查会调用控制平面或需要缓存和句柄,而云端不提供这些功能。
iris context-gateway service check gw_0123456789abcdef0123456789abcdef通过所有步骤:令牌、Gateway、Identity Service、Agent 密钥,以及使用 Agent 密钥执行一次tools/list。iris --json context-gateway service show gw_0123456789abcdef0123456789abcdef显示cache和compression符合问题要求:每项正在使用的功能都显示为ENABLED,并且存在databaseBinding。如果某项功能显示为DISABLED,而 Agent 并未选择禁用它,则说明数据库缺失或拒绝压缩(第 3 步“Gateway 开关和数据库”)。iris context-gateway --gateway-id gw_0123456789abcdef0123456789abcdef tools list会显示所有 Upstream 的工具都带有命名空间(完整模式),或者显示search_tools和run_tool(搜索模式)。启用压缩后,还会列出七个句柄工具。iris context-gateway --gateway-id gw_0123456789abcdef0123456789abcdef tools call crm__lookup_customer --arg id=42会直接返回服务端返回的内容。iris context-gateway --gateway-id gw_0123456789abcdef0123456789abcdef policy list crm会显示问题 3 和 4 中的缓存和压缩策略。- 缓存命中:使用具有缓存策略的工具,将同一命令
iris --json context-gateway --gateway-id gw_0123456789abcdef0123456789abcdef tools call crm__search_customers --arg query=acme连续运行两次。第二次结果的_meta["com.redis.context-gateway/invocation"]包含"cache": {"status": "hit", ...},而第一次结果中没有cache条目。 - 句柄往返:
tools call crm__export_orders --as-handle会打印一个包含h_...的存根,随后handle describe h_...、handle page h_... --limit 5和handle release h_...都会返回结果。对已释放的句柄再次运行handle describe会以handle_not_found退出,退出码为 1。 - 让 Agent 执行一次会使用 Gateway 工具的任务,并展示调用经过了 Gateway(跟踪记录或日志中出现带命名空间的名称)。
- 取消设置
IRIS_CONTEXT_GATEWAY_API_KEY,并确认 SDK 会抛出指出该变量名的ConfigurationError,或者 MCP 客户端会报告身份验证失败。
iris context-gateway service diagnose gw_0123456789abcdef0123456789abcdef 会说明导致失败的 Upstream、缓存或句柄设置问题,以及 Gateway 数据库缺失的问题。
6. 报告
列出 Gateway 的运行位置(Redis Cloud 或自托管)、五个问题的答案、添加的每个 Upstream(名称、命名空间、端点、密钥变量名,绝不包含密钥值)、暴露模式、设置的每项策略、Gateway 的 cache 和 compression 值及其所用的数据库、写入的数据模型、修改的文件、写入的客户端配置、添加和移除的环境变量、验证输出,以及任何无法通过 MCP 确认的事项。