Files
Bubbles/function_call_next_steps.md
zihanjian 33731cb83b refactor
2025-09-24 20:01:22 +08:00

6.1 KiB
Raw Blame History

Function Call 架构改进指南

1. 架构一致性如何提升?

  • 现状诊断
    • function_calls/handlers.py:147 等 handler 仍依赖 commands/handlers.py 中的正则/自然语言逻辑,导致新旧两套体系并存,增大耦合与维护成本。
    • function_calls/router.py:41 的直接匹配逻辑与 LLM 选择逻辑混在一起,职责边界不清晰;而参数校验仅在 LLM 分支执行(function_calls/router.py:150)。
    • 业务逻辑散落:例如新闻查询同时存在 _get_news_info 与命令 handler 版本,缺少统一 service 层。
  • 建议的架构骨架
    1. 分层组织代码
      • function_calls/spec.py:仅保留数据结构。
      • function_calls/registry.py:集中注册所有函数。
      • function_calls/router.py:只负责入口路由、模型互操作和参数校验。
      • function_calls/services/(新增目录):存放与业务相关的纯函数(例如天气、提醒、骂人等),对外只接受结构化参数。
      • function_calls/handlers/(可拆分模块):每个 handler 只做 (ctx, args) → 调 service → 组装 FunctionResult。
    2. 统一入口robot.py 只初始化 FunctionCallRouter,其余旧路由移除,避免双写状态。
    3. 约束约定:所有 handler 必须声明 args 的 Pydantic 模型;禁止 handler 内再次解析自然语言或修改 ctx.msg.content
    4. 配置与日志:为 FunctionCallRouter 添加统一的日志上下文(如 request_id方便追踪函数调用链路。

2. 如何让 function 直接填参数、避免重复 LLM 解析?

  • 目标路由阶段完成所有参数解析与校验handler 全部消费结构化 args,不再依赖二次自然语言处理。
  • 改造步骤
    1. 强制类型转换:在 _create_args_instance 后无论 direct/LLM 均执行 args_type.model_validate,并捕获校验错误,向用户返回提示。
    2. 拆分提醒业务逻辑
      • 编写 function_calls/services/reminder.py,内含 create_reminder(ctx, ReminderArgs) 等函数,直接调用 ctx.robot.reminder_manager
      • 调整 ReminderArgs 为真正的结构字段(例如 schedule: ScheduleArgs),由 FunctionCallRouter/LLM 负责生成 JSON。
      • 对 direct 命令的需求,若要保留,可做一个轻量的自然语言 → ReminderArgs 的解析器,独立成 util避免回写 ctx.msg.content
    3. 其他 handler 同理
      • insult:直接调用封装好的 generate_random_insult(target_user),不要构造 fake matchfunction_calls/handlers.py:216)。
      • perplexity_search:把 query 直接传给 serviceservice 负责与 ctx.robot.perplexity 交互。
    4. 落地校验:在 function_calls/llm.py:123 的决策结果里,若 schema 校验不通过,构建友好错误提示并返回 FunctionResult
    5. 测试:为每个 handler 编写参数驱动的单测,例如 test_reminder_set_structured_args → 传 ReminderArgs(time_spec="2024-05-01 15:00", content="开会"),验证生成的提醒记录。

3. 目前改造是否达标?还需修什么?

  • 仍存在的问题
    • Handler 依赖旧命令逻辑(function_calls/handlers.py:147, :189, :216说明“function 直接消费参数”的目标尚未实现。
    • 直接命令分支跳过 validate_arguments,导致 ReminderArgs 这类模型的必填字段不会被校验(function_calls/router.py:118)。
    • FunctionResult.at_list 虽已在 _execute_function 中 join但数据类仍声明为 list[str]。如果后续有人直接调用 ctx.send_text(message, result.at_list) 将再次踩坑。建议统一改成 str 或封装发送逻辑。
    • 仍缺少针对新路由的自动化测试,仅有打印式脚本(test_function_calls.py)。建议补充 pytest 单测或集成测试。
  • 建议修复顺序
    1. 清理 handler 对旧命令的依赖,迁移业务逻辑到 service 层。
    2. 在 router 中统一调用 validate_arguments_create_args_instance → handler。
    3. 更新 FunctionResult 类型定义,提供 helper 方法如 result.send_via(ctx) 集中处理消息发送。
    4. 编写覆盖天气/新闻/提醒/骂人等核心流程的单测,确保 Function Call 路径稳定。

4. 只保留 Function Call旧路由是否移除到位

  • 现状robot.py:172-272 仍初始化并调用 CommandRouterai_router,函数回退逻辑依旧存在。
  • 移除建议
    1. 删除 self.command_router = CommandRouter(...) 及相关 import同时移除 CommandRouter.dispatch 调用与辅助日志。
    2. 移除 ai_router 回退逻辑和配置项 FUNCTION_CALL_ROUTER.fallback_to_legacy。确保配置文件同步更新(config.yaml.template:151)。
    3. 将闲聊 fallback 改为:当 FunctionCallRouter 返回 False 时直接走 handle_chitchat,并记录原因日志。
    4. 清理不再使用的命令注册表与正则代码(commands/registry.pycommands/router.py 等),确认没有别的模块引用后可删。
    5. 回归测试:运行原有功能用例,确保删除旧路由不会影响提醒、天气等功能;同时观察日志,确认不再出现“命令路由器”相关输出。

5. 推荐行动清单(按优先级)

  1. 剥离 handler 对旧命令体系的依赖:完成 service 层拆分,更新所有 handler 为结构化实现。
  2. 统一参数校验与错误返回:调整 router 逻辑,新增校验失败提示,并完善 FunctionResult 类型。
  3. 移除旧路由与配置:清理 robot.py 中的命令/AI 路由初始化与 fallback更新配置模板。
  4. 补全测试:为 Function Call 核心流程编写 pytest 单元与集成测试,覆盖 direct/LLM 两条路径。
  5. 整理文档:更新开发文档,说明如何新增 function、如何编写参数模型与 service确保团队成员按统一规范扩展功能。

执行完以上步骤后,你将拥有一套纯 Function Call、结构化且易维护的机器人指令体系满足题述的四个目标。