Repository navigation
Conversation
Filter both initial and cached tool lists using the current invocation context while retaining the full tool cache. Fixes trpc-group#352 RELEASE NOTES: SkillToolSet now honors configured tool filters when is_include_all_tools is false.
AI Code Review审查结论不通过 审查范围:base 02509b2..head e24e06c,共 2 个文件(+67/-4):trpc_agent_sdk/skills/_toolset.py 在 get_tools() 的首次构建路径与 _default_tools 缓存路径中均接入 _is_tool_selected 过滤;tests/skills/test_toolset.py 新增 63 行参数化测试覆盖 SkillToolSet 与 SkillToolSetWithDynamicTools。\n\n计划符合性:核心意图(在 SkillToolSet.get_tools 中应用 tool_filter)已实现,list/predicate 两种过滤形式、缓存路径过滤、is_include_all_tools 兼容语义均正确,新增测试覆盖首次/缓存调用、predicate 接收当前上下文、隐式上下文、过滤后行为保持等场景。\n\n主要风险:1) 缓存快照语义由 invocation_context 决定但该上下文未参与缓存键——首次调用发生在无显式上下文的位置(_agui_agent.py 的 get_tools(None))或与后续真实请求不同的上下文时,后续所有请求的工具集被首调快照固化,工具被错误隐藏或暴露(SEVERE);2) get_tools(None) 在无隐式上下文时依赖全局 ContextVar 残留值,且 SkillToolSetWithDynamicTools 首调过滤基于未完成扩展的 _function_tools(既有缺陷被过滤暴露,动态工具名过滤结果不稳定)(MODERATE)。\n\n测试充分性:新增测试对意图覆盖良好,但所有测试都显式传入同构 MagicMock 上下文或通过 set_invocation_ctx 设置同一上下文,未覆盖"首次调用无显式上下文/上下文不一致"场景,无法捕获缓存快照问题。\n\n门禁结论:FAILED——存在 1 个高置信 SEVERE(缓存快照固化过滤结果,与计划的上下文感知过滤意图冲突)和 1 个 MODERATE(隐式 ContextVar 回退与既有首调 _function_tools 延迟扩展交互)。 发现的问题严重
问题: 触发条件: 构造时配置了 实际影响: 后续所有真实请求的工具名集合与请求自身上下文无关:本应在的动词或工具(如 修正方向: 将按请求上下文过滤的结果与缓存分离——缓存仅保存构建好的全量工具列表( 中等
问题: 新增行 170 与 187 在 触发条件: ① 无隐式上下文路径( 实际影响: 工具集内容跨请求串扰(上下文 A 的过滤结果影响上下文 B 的请求);隐藏缺失的动态选择工具时,代理无法使用 修正方向: 在无显式上下文时不要回退到全局 |
| if self._default_tools: | ||
| return self._default_tools.copy() | ||
| return [tool for tool in self._default_tools if self._is_tool_selected(tool, invocation_context)] |
There was a problem hiding this comment.
问题: _default_tools 缓存路径(新增行 170)在缓存命中时按首个调用的 invocation_context 过滤后整体返回快照。_is_tool_selected 对 ToolPredicate 会调用 self._tool_filter(tool, invocation_context),因此过滤结果依赖调用时的上下文,而缓存列表本身不区分上下文——首次调用固化的过滤结果,后续请求无论传入什么上下文都读取同一份快照。
触发条件: 构造时配置了 tool_filter 为谓词(is_include_all_tools=False),且 get_tools() 首次调用发生在无显式上下文的位置(如 server/ag_ui/_core/_agui_agent.py:411 的 tool.get_tools(None)、_llm_agent.py 的工具预取),或首次调用与后续调用传入不同上下文。
实际影响: 后续所有真实请求的工具名集合与请求自身上下文无关:本应在的动词或工具(如 skill_run、workspace_exec)在 LLM 请求中缺失(convert_toolunion_to_tool_list->get_tools(context) 返回快照后,process_request 无法声明未包含的工具),LLM 无法调用;反之不应暴露的工具被固化暴露。缓存路径连 predicate 都不再被调用,违背计划"上下文感知过滤"意图。
修正方向: 将按请求上下文过滤的结果与缓存分离——缓存仅保存构建好的全量工具列表(_default_tools.copy() 原行为),每次调用都对该副本执行 _is_tool_selected;或确保首次调用带真实上下文,并为缓存结果记录生成时上下文、命中时重新过滤。
|
提交了相同的pr:https://github.com/trpc-group/trpc-agent-python/pull/357, 带有文档修改 |
问题与修复
Fixes #352
SkillToolSet.get_tools()在显式设置is_include_all_tools=False后,仍未应用tool_filter。例如,配置tool_filter=["skill_load"]时,首次调用和缓存调用都会返回全部工具。本次修复在两条返回路径中应用
_is_tool_selected(tool, invocation_context),并保留完整工具缓存,使谓词过滤器可以根据当前调用上下文重新选择工具。默认
is_include_all_tools=True、未配置过滤器及空列表过滤器的既有行为保持不变。测试
新增 14 个参数化回归用例,覆盖
SkillToolSet和SkillToolSetWithDynamicTools:原代码上新增用例为 6 failed, 8 passed;修复后全部通过。
本地验证:
pytest tests/skills tests/abc/test_toolset.py \ tests/tools/test_tool_adapter.py \ tests/agents/core/test_tools_processor.py # 720 passed, 1 warning yapf --diff trpc_agent_sdk/skills/_toolset.py flake8 trpc_agent_sdk/skills/_toolset.py tests/skills/test_toolset.py git diff --check其中 1 项 warning 来自已有流式并发测试
test_streaming_tool_runs_outside_parallel_batch:线程池退出等待约 300 秒后产生超时警告,测试最终通过。退出阻塞也在未修改的02509b2源码上单独复现;本 PR 未修改相关并发逻辑。Release notes
设置
is_include_all_tools=False时,SkillToolSet现在会正确应用工具名称或谓词过滤器。