mirror of
https://github.com/zhenxun-org/zhenxun_bot.git
synced 2026-10-13 16:10:05 +08:00
* ♻️ refactor(ai): 重构 AI 服务模块并完善文档注释 - 【重构】统一清理并优化所有 AI 服务模块文件的导入语句,将其移至文件顶部 - 【重构】重构 `hooks.py` 中的 `Hooks` 派发逻辑,使用通用管道函数消除重复代码,并引入 `HookPoint` 描述符 - 【重构】重构工具装饰器实现,新增 `toolkit` 类装饰器,优化 `BaseToolkit` 配置合并与前缀处理 - 【功能】Docker 沙箱容器创建时支持自动注入系统代理环境变量并配置 `ExtraHosts` - 【功能】Jupyter 服务启动前自动清理旧进程并初始化临时目录权限 - 【修复】优化 Pydantic 结构化输出校验失败时的错误信息提取,提供更详细的字段级错误反馈 - 【修复】在 `api.py` 中避免将 `ModelRetry` 和 `ControlFlowExit` 异常错误地包装为 `LLMException` - 【文档】为 AI 服务、沙箱、工具链、工作流等核心模块补充完整的 Docstring 和类型注释 * 📝 docs(ai): 补全核心模块文档注释并清理冗余代码 - 补全 `run/context`、`run/hooks` 和 `tools/engine/registry` 中类与方法的中文文档注释 - 清理 `tools/providers/builtin/sandbox` 中未使用的 `PythonPluginProtocol` 协议及相关导入 - 规范化部分代码的格式与尾随逗号 * ♻️ refactor!(flow): 重构 Task 为 AgentTask 并优化工作流元数据定义 - 【Breaking Change】将 `Task` 重命名为 `AgentTask` 以避免命名冲突 - 更新 Agent、Team、Workflow 等模块中的类型声明与相关逻辑 - 引入 `AutoNodeMeta` 强类型元数据,替换工作流装饰器中的裸字典定义 - 将 `StepMeta`、`ConditionMeta` 和 `RouterMeta` 统一移动至 `types.py` - 优化 `RunnableNode` 对上游 `AgentTask` 的处理与拼接逻辑 - 调整团队协作策略中 `FinishAction` 的返回值为完整结果对象 * ♻️ refactor(workflow): 移除人工确认机制并重构错误策略 - 移除工作流节点的人工确认(HITL)与挂起继续机制 - 删除 `auto` 自动化工作流及相关装饰器文件 - 将错误处理策略类从 `types.py` 拆分并移动到新文件 `policies.py` - 优化节点执行失败时的异常信息格式化输出 - 移除 `WorkflowRunResult` 和 `StepOutput` 中与挂起相关的状态字段 * 🚨 auto fix by pre-commit hooks --------- Co-authored-by: webjoin111 <455457521@qq.com> Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
108 lines
4.0 KiB
Python
108 lines
4.0 KiB
Python
from typing import Any
|
||
|
||
from pydantic import BaseModel, Field, create_model
|
||
|
||
from zhenxun.services.ai.run.context import RunContext
|
||
from zhenxun.services.ai.tools.core.tool import BaseTool
|
||
from zhenxun.services.ai.tools.models import HandoffResult, ToolResult
|
||
|
||
|
||
class HandoffTool(BaseTool):
|
||
"""
|
||
触发控制权移交 (Handoff) 信号的底层工具。
|
||
当大模型调用此工具时,当前 Agent 执行流将被立即熔断并向外抛出 ToolHandoff 信号。
|
||
"""
|
||
|
||
def __init__(
|
||
self,
|
||
target_name: str,
|
||
target_description: str,
|
||
input_schema: type[BaseModel] | Any | None = None,
|
||
):
|
||
"""
|
||
初始化移交工具,为模型赋予转移对话控制权到指定实体的能力。
|
||
|
||
参数:
|
||
target_name: 被转移的目标接收者(Agent 或负责人)的唯一标识名称。
|
||
target_description: 目标接收者的职责或专长说明,供模型决策是否移交。
|
||
input_schema: 自定义移交数据结构,指定转移时所需携带的结构化参数。
|
||
"""
|
||
super().__init__(
|
||
name=f"transfer_to_{target_name}",
|
||
description=(
|
||
f"将对话控制权移交给 {target_name}。专长/职责:{target_description}"
|
||
),
|
||
)
|
||
self.target_name = target_name
|
||
|
||
actual_schema = None
|
||
if input_schema:
|
||
from zhenxun.services.ai.core.options import BaseOutputDefinition
|
||
|
||
if isinstance(input_schema, BaseOutputDefinition):
|
||
actual_schema = input_schema.type_
|
||
else:
|
||
actual_schema = input_schema
|
||
|
||
if actual_schema:
|
||
fields: dict[str, Any] = {
|
||
"reason": (str, Field(..., description="移交的原因或简要状态说明")),
|
||
}
|
||
schema_fields = getattr(
|
||
actual_schema, "model_fields", getattr(actual_schema, "__fields__", {})
|
||
)
|
||
for k, v in schema_fields.items():
|
||
fields[k] = (v.annotation, v)
|
||
self.args_schema = create_model(
|
||
f"DynamicHandoffArgs_{target_name}", **fields
|
||
)
|
||
else:
|
||
|
||
class DefaultHandoffArgs(BaseModel):
|
||
reason: str = Field(..., description="移交的原因或简要状态说明")
|
||
context_data: Any = Field(
|
||
default="",
|
||
description="你需要传递给下一个负责人的所有核心数据",
|
||
)
|
||
|
||
self.args_schema = DefaultHandoffArgs
|
||
|
||
async def execute(
|
||
self, context: RunContext | None = None, **kwargs: Any
|
||
) -> ToolResult:
|
||
reason = kwargs.pop("reason", "")
|
||
|
||
if "context_data" in kwargs and len(kwargs) == 1:
|
||
context_data = kwargs["context_data"]
|
||
else:
|
||
context_data = kwargs
|
||
|
||
if context:
|
||
counts = context.session.shared_state.setdefault("__handoff_counts__", {})
|
||
counts[self.target_name] = counts.get(self.target_name, 0) + 1
|
||
if counts[self.target_name] > 3:
|
||
return ToolResult(
|
||
output=(
|
||
f"❌ 系统拦截:检测到严重的踢皮球现象!\n"
|
||
f"你所在的团队已经连续 {counts[self.target_name]} 次将任务"
|
||
f"移交给 {self.target_name},\n"
|
||
"但问题仍未解决。请立刻改变策略,"
|
||
"由你亲自处理或得出最终结论,严禁再次移交!"
|
||
)
|
||
).as_error()
|
||
|
||
from zhenxun.services.ai.core.messages import HandoffEvent
|
||
|
||
if context:
|
||
context.run.add_event(
|
||
HandoffEvent(
|
||
target=self.target_name,
|
||
reason=reason,
|
||
context_data=context_data,
|
||
)
|
||
)
|
||
|
||
return HandoffResult(
|
||
target=self.target_name, reason=reason, context_data=context_data
|
||
)
|