feat(agent_wrapper): add answer_reach_limit to base reply signature#359
feat(agent_wrapper): add answer_reach_limit to base reply signature#359xyf2020 wants to merge 2 commits into
Conversation
xyf2020
commented
Jul 15, 2026
- Add answer_reach_limit parameter to BaseAgentWrapper.reply() abstract method
- Add pylint disable comments for protected-access in as_agent_wrapper
- Add 24 unit tests for answer_reach_limit in tests/unit/test_answer_reach_limit.py
- Add answer_reach_limit parameter to BaseAgentWrapper.reply() abstract method - Add pylint disable comments for protected-access in as_agent_wrapper - Add 24 unit tests for answer_reach_limit in tests/unit/test_answer_reach_limit.py
The uncommented as_embedding component was eagerly instantiated at startup and failed without embedding credentials (windows smoke test). It was orphaned anyway since file_store.embedding_store is empty, so revert to commented state to restore local-first startup.
总体结论这个功能目标是合理的:默认情况下完全保持现有行为;只有显式开启参数,并且 agent 确实因为达到最大迭代/最大 turn 数而退出时,才追加一条 hint message,禁止继续调用工具,并额外调用一次 LLM,让它基于已有上下文生成最终回答。 不过当前实现还没有完全满足这个契约,尤其是“默认行为不变”、配置参数生效范围、异常处理边界以及流式路径。建议修改后再合并。 一、参数命名
建议改为: generate_final_answer_on_limit: bool = False这个名字能比较准确地表达实际行为:
如果希望名字更短,也可以考虑: finalize_on_limit: bool = False但 如果未来可能增加多种超限策略,则可以进一步设计为: limit_reached_behavior: Literal["return", "generate_final_answer"] = "return"但当前只有开/关两种行为,使用 二、期望的行为契约建议明确以下行为: 默认关闭generate_final_answer_on_limit=False必须完整保留原有逻辑,包括:
显式开启只有同时满足以下条件时,才执行额外调用:
额外调用应该:
推荐的整体流程是: 三、AgentScope 后端:默认逻辑已经发生变化原实现是: await agent.reply()
await self._dump_state(agent.state)
last_msg = agent.state.context[-1]PR 改成了使用: final_msg = await agent.reply()
result_text = final_msg.get_text_content()这两个值在正常完成时可能相同,但达到 而原实现从 建议保留原有返回值构造方式,只在参数开启且确认达到上限后,用额外生成的回答覆盖 测试中的 A3 当前断言默认关闭时返回超限占位消息,这实际上固定了新的行为,无法验证向后兼容。建议增加回归测试,明确断言参数关闭时的返回结构与修改前一致。 四、参数放在组件配置中可能不会生效当前签名类似: async def reply(
self,
inputs: Any,
answer_reach_limit: bool = False,
**kwargs,
) -> dict:随后虽然调用了: kwargs = self._merged_kwargs(kwargs)但合并后的配置不会赋值回局部变量 agent_wrapper:
default:
generate_final_answer_on_limit: true这个值会进入 await wrapper.reply(
prompt,
generate_final_answer_on_limit=True,
)需要明确这个参数究竟只支持 call-time,还是同时支持组件配置。如果两种方式都支持,建议统一解析优先级: 为了区分“本次调用没有指定”和“本次调用显式传入 False”,可以将公开参数定义为 五、Claude Code 后端:异常吞掉范围过大当前代码在 query iterator 抛出异常时使用了类似条件: if not (answer_reach_limit and last_msg is not None):
raise这意味着只要参数开启且已经收到过任意一个 建议至少限制为: if not (
generate_final_answer_on_limit
and last_msg is not None
and self._is_max_turns_result(last_msg)
):
raise如果 SDK 提供了可识别的尾随 测试 C8 当前把“成功 ResultMessage 后发生任意异常也应吞掉”作为预期,这会掩盖上述问题。建议改成:
六、Claude Code 后端:第二次调用应该保留完整结果语义
建议 另外,第二次调用本身也可能再次返回 七、流式路径尚未支持当前改动只实现了
需要明确此功能是否要求支持 streaming:
八、AgentScope 的额外模型调用与流式响应处理当前实现通过 AgentScope 的 protected methods: agent._prepare_model_input()
agent._call_model(...)功能上可以复用 model retry 和 middleware,但这会直接依赖 AgentScope 的内部 API,升级依赖时容易失效。建议优先确认是否有公开接口能够表达“基于现有上下文、禁用工具、只生成一次最终回答”。如果确实只能使用内部接口,应把这部分封装成一个很窄的 helper,并增加与固定 AgentScope 版本对应的测试。 此外,流式 九、测试建议目前测试数量很多,但主要基于高度简化的 mock,部分测试还把需要修复的行为写成了预期。建议重点补充以下契约测试:
十、无关改动
建议的最小修改方向
在这些问题修复后,这个功能的边界会更清晰,也能真正保证不开启参数时完全向后兼容。 |