DEBUG.WIKI
ZgoCloud:多地区部署,按需选节点;日本、美国、香港、德国
雨云;给项目一台云服务器
RackNerd;$21.99/年 · 1GB KVM

function_tool 报上下文参数不在首位,RunContextWrapper 的签名怎样写

function_tool 用首个参数的位置和类型识别注入上下文。将 RunContextWrapper 或 ToolContext 移到首位,保留业务参数与授权检查,再核对工具 schema 和本地调用。

function_tool 报上下文参数不在首位,RunContextWrapper 的签名怎样写

刚给函数加上 function_tool,还没有调用模型,注册阶段就出现:

RunContextWrapper/ToolContext param found at non-first position in function

这条错误指向函数签名。Agents SDK 用首个参数的位置与类型注解识别注入上下文;如果它出现在普通业务参数后面,就会拒绝构建工具。

把上下文移到首位

例如,工具只允许读取一小组公开记录,同时由模型提供 record_key。上下文应使用专门的 public_records 映射,不要把 API key、个人信息或其他内部配置混入其中:

from dataclasses import dataclass
from typing import Mapping
from agents import RunContextWrapper, function_tool

ALLOWED_RECORD_KEYS = frozenset({"welcome", "hours"})

@dataclass(frozen=True)
class PublicRecordContext:
    public_records: Mapping[str, str]

def lookup_public_record(context: PublicRecordContext, key: str) -> str:
    if key not in ALLOWED_RECORD_KEYS:
        raise ValueError("该记录不允许通过工具读取")
    return context.public_records.get(key, "暂无公开记录")

@function_tool
def read_record(
    ctx: RunContextWrapper[PublicRecordContext],
    record_key: str,
) -> str:
    """读取允许公开的 welcome 或 hours 记录。"""
    return lookup_public_record(ctx.context, record_key)

# 仅使用可公开的测试数据作为本例运行上下文。
example_context = PublicRecordContext(
    public_records={"welcome": "欢迎使用示例", "hours": "工作日 09:00–17:00"}
)

这里的 ctx 由应用运行上下文提供,模型只负责填写 record_key。允许读取哪些键由应用白名单决定,不能由模型修改;上下文注入本身也不构成读取授权。如果原来把 record_key 写在前面,应调整顺序,同时修改应用中直接调用原函数的代码与测试。

保留类型注解同样重要。为了躲过报错而删掉 RunContextWrapper 注解,会破坏上下文识别;把 context 改成模型需要生成的普通字段,也改变了原本的数据来源。

不调用模型也能检查修复

工具注册和 schema 构建发生在本地。重新加载工具模块后,先确认不再抛出该错误,再查看工具的输入 schema:

  • 业务参数 record_key 应出现
  • 注入的 ctx 不应要求模型填写
  • 必填字段应与业务函数的参数设计一致

接着用受控的本地工具调用测试,确认函数取得的是运行时提供的上下文对象。业务读取逻辑还可以单独做不联网测试:

assert lookup_public_record(example_context, "welcome") == "欢迎使用示例"

for denied_key in ("api_key", "__dict__", "not_allowed"):
    try:
        lookup_public_record(example_context, denied_key)
    except ValueError:
        pass
    else:
        raise AssertionError("未授权键必须被拒绝")

不要只检查“schema 能生成”。还应确认任意未授权键都会在读取前被拒绝;正式应用需要用户或租户隔离时,应另外实现对应授权检查。

版本与适用边界

这个判断可在 Agents SDK 固定源码快照 中直接核对:扫描首个参数之后的参数时,发现 RunContextWrapper 或 ToolContext 就抛出 UserError。该快照体现的是 SDK 上下文注入规则,不能据此推定最早引入该限制的发行版本。

如果 context 本来就是模型应填写的业务字段,应给它真实的业务类型,而不是注入上下文类型。参数名字相同不代表用途相同,位置约定针对的是 SDK 上下文注入。