TaskHandler 类型设计;typing 模块详解;

TaskHandler 类型设计

问题起因

新增任务 interrupt 支持后,TaskHandler 签名从 1 个参数变成 3 个,导致不需要 interrupt 的 run_pdf_structured_task 也必须接收多余参数。

三种解决方案

方案一:统一签名(最简单,现在用的)

TaskHandler = Callable[[dict, TaskRecord, TaskDispatcherService], Awaitable[dict]]

所有 handler 都必须声明三个参数,不用就忽略。
缺点:不需要 interrupt 的 handler 被迫接收无意义参数。

方案二:try/except 判断签名(hack,不推荐)

try:
    return await handler(payload, task_record=record, dispatcher=self)
except TypeError:
    return await handler(payload)

用异常来探测函数签名,属于 hack 写法——
hack 写法指绕过正常设计、靠副作用或错误来实现功能,可以跑但不可靠、难维护。

方案三:注册时标记(最终采用)

SimpleTaskHandler = Callable[[dict], Awaitable[dict]]
InterruptTaskHandler = Callable[[dict, TaskRecord, TaskDispatcherService], Awaitable[dict]]
TaskHandler = SimpleTaskHandler | InterruptTaskHandler
# handler注册处
dispatcher.register_handler(TaskType.RAG_CHAT, run_rag_chat_task, supports_interrupt=True)
dispatcher.register_handler(TaskType.PDF_STRUCTURED, run_pdf_structured_task)  # 默认 False

_dispatch 根据 supports_interrupt 决定传几个参数,意图最清晰。


typing 模块

Python 是动态类型语言,运行时不强制检查类型。
typing 提供的工具是给类型检查器(Pyright、mypy)和开发者看的,运行时没有实际约束。

容器类型

list[str]           # 字符串列表
dict[str, Any]      # 键为 str 的字典
tuple[int, str]     # 固定结构元组

函数类型

Callable[[int, str], bool]  # 接收 int/str,返回 bool 的函数
Awaitable[dict]             # async 函数的返回值

特殊标记

Any                    # 任意类型,跳过检查
Literal["a", "b"]      # 只能是这几个值
Optional[str]          # str 或 None,等价于 str | None
NotRequired[str]       # TypedDict 里的可选字段

结构描述

TypedDict   # 描述 dict 的字段结构,项目中 AdaptiveRagState 用的就是这个
Protocol    # 描述任意对象必须实现的接口

注:SimpleTaskHandler = Callable[[dict[str, Any]], Awaitable[dict[str, Any]]]这个“=”号是定义类型别名本身

posted @ 2026-06-29 17:06  asphyxiasea  阅读(13)  评论(0)    收藏  举报