Skip to content

Feature: LlmAgent支持配置最大轮数/LLM次数/工具调用次数 - #286

Open
weimch wants to merge 1 commit into
mainfrom
feature/agentloop_can_exit
Open

Feature: LlmAgent支持配置最大轮数/LLM次数/工具调用次数#286
weimch wants to merge 1 commit into
mainfrom
feature/agentloop_can_exit

Conversation

@weimch

@weimch weimch commented Aug 5, 2026

Copy link
Copy Markdown
Contributor

--story=136739020 LlmAgent支持配置最大轮数/LLM次数/工具调用次数

--story=136739020 LlmAgent支持配置最大轮数/LLM次数/工具调用次数
@helloopenworld

Copy link
Copy Markdown
Contributor

AI Code Review

目前没有任何针对 max_turnsmax_tool_callsagent_limitsRunLimitException 的测试。现在我来撰写审查结论。

发现的问题

⚠️ Warning

  • trpc_agent_sdk/agents/core/_tools_processor.py:222-232:并行工具批量触发 RunLimitException 后,仅 cancel 未完成任务,但 function_response_events 可能已被部分任务写入 None/错误事件,且后续 if function_response_events: 合并逻辑在 raise 之前不会执行(raise 在 try 内),行为正确;但 cancel 后的 gather(..., return_exceptions=True) 会把 CancelledError 作为异常吞掉,不影响结果。真正风险在于:__invoke_tools 在工具内部抛 RunLimitException 时会被 line 152 的 except RunLimitException: raise 正确透传,但同一批中其他已完成任务已 append 结果事件到共享列表——由于 raise 后直接退出,这些事件被丢弃,符合"整批不执行"语义。建议补一条并行批量超限的测试以锁定该语义。

    • 实际更需关注的是:MAX_TOOL_CALLS 计数在 _llm_agent.py:566increment=len(collected_tool_calls) 一次性累加整批并 raise,但并行执行时若任务内部再触发其他 limit(如子 agent 的 max_llm_calls),多个 RunLimitException 会通过 gather 同时抛出,except RunLimitException 只捕获第一个,其余作为 CancelledError 被吞。建议确认这是预期,并补充并发超限场景测试。
  • tests/configs/test_run_config.py 及全仓测试目录:新增的 max_turnsmax_tool_callsagent_limitsAgentRunLimitsRunLimitExceptionraise_if_limit 等核心逻辑没有任何单元测试覆盖。raise_if_limit 的边界(configured_value<=0 跳过、observed>configured 触发、increment<0ValueError)、_get_run_limit 的 per-agent 继承与 0 显式禁用语义、以及 _reset_run_limit_observed 的隔离性,均属高风险且无回归保护。建议至少补 InvocationContext.raise_if_limit / _get_run_limit 的纯逻辑测试(不依赖 LLM),不依赖外部模型的 limit 触发集成测试。

    • 仓库内已有的 examples/llmagent_with_limit/run_agent.py 是需真实 LLM key 的示例,不计入测试覆盖。
  • trpc_agent_sdk/server/a2a/executor/_a2a_agent_executor.py:271-284:当 run_config_factory/run_config 配置了 server-owned RunConfig 时,用 model_copy(update={"agent_run_config": {...}}) 合并,但合并后丢失了 request 自身的顶层 limit 字段(如请求 RunConfig 若带 max_turns 会被整体替换为 configured_run_config 的值)。当前 convert_a2a_request_to_run_args 仅构造 agent_run_config、不设 limit,所以现状无 bug;但该合并是 shallow 替换整个 RunConfig,未来若请求侧也带 limit 会静默丢失。建议显式合并 limit 字段或在注释中明确"server-owned 覆盖请求 limit"的契约。

  • trpc_agent_sdk/configs/_agent_run_limits.py:29AgentRunLimits.max_llm_callsField(..., ge=0, lt=sys.maxsize),而 RunConfig.max_llm_callsfield_validator==sys.maxsize 时抛错、<=0 时打 warning(不抛错)。两者对边界值(如负数、sys.maxsize)的处理不一致:AgentRunLimits 会直接 422 校验失败,RunConfig 则宽容。建议统一两处的校验语义,避免 per-agent override 与 top-level 行为不一致引发困惑。

💡 Suggestion

  • trpc_agent_sdk/agents/_llm_agent.py:474:503raise_if_limit(MAX_TURNS) / raise_if_limit(MAX_LLM_CALLS) 计数器递增与实际"执行"之间存在窗口——计数在调用前预扣,若后续 build_request 返回 error_event 直接 return,该 turn/llm call 实际未发生但仍被计数。对低配额场景会略微提前触顶。可考虑在确认实际发起后再递增,或在文档注明"预扣"语义。

总结

整体为新增 run-limit 能力,框架各层 except RunLimitException: raise 的透传链路完整,Runner/AG-UI/A2A 三条出口的清理与事件下发处理合理,未发现阻塞级缺陷。主要风险集中在缺少对新 limit 逻辑的单元测试以及若干边界/合并语义不一致,建议合并前补齐 raise_if_limit/_get_run_limit 的纯逻辑测试。

测试建议

  • 补充 InvocationContext.raise_if_limit_get_run_limit 的纯逻辑单测:覆盖 configured<=0 跳过、observed>configured 抛错且 observed_value/configured_value 正确、agent_limits 继承与 0 显式禁用、increment<0ValueError_reset_run_limit_observed 在子 agent 调用间计数隔离。
  • 补充并行工具批量超 max_tool_calls 时"整批不执行"的测试,以及子 agent(AgentTool/run_subagent_streaming)独立计数不串扰父 agent 的测试。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants