PraisonAI Agents Tools 开发指南:从函数工具到 pip 插件包的完整实践
2026/9/16 21:49:06 网站建设 项目流程

PraisonAI Agents Tools 开发指南:从函数工具到 pip 插件包的完整实践

【免费下载链接】PraisonAIPraisonAI 🦞 — Hire a 24/7 AI Workforce. Stop writing boilerplate and start shipping autonomous self-improving agents that research, plan, code, and execute tasks. Deployed in 5 lines of code with built-in memory, RAG, and support for 100+ LLMs.项目地址: https://gitcode.com/GitHub_Trending/pr/PraisonAI

导读:本文以 PraisonAI Agents 的 Tools 官方指南 为核心骨架,系统讲解 PraisonAI 中"工具(Tool)"的核心概念、函数式与类式两种创建范式、基于 entry_points 的插件分发机制,并结合praisonaiagents/tools目录下的真实源码(BaseTool、@tool 装饰器、ToolRegistry)深入剖析工具注册、Schema 自动生成与自动发现的底层原理。读完本文,你将能够独立为 Agent 编写、测试并打包分发自己的工具,让 Agent 获得搜索、抓取、行情查询等任意"特殊能力"。

什么是 Tool:Agent 的"特殊能力"

在 PraisonAI 中,一个Tool(工具)就是一段赋予 AI Agent 特定能力的代码。可以把工具想象成我们给 Agent 装备的"特殊能力":

  • 互联网搜索工具:让 Agent 具备联网检索网页的能力;
  • 股票行情工具:让 Agent 能查询实时股价与公司信息;
  • 天气工具:让 Agent 能获取指定地点的天气状况。

从源码实现看,工具的本质是"可以被 LLM 调用并返回可序列化结果的函数或对象"。PraisonAI 为工具建立了一套完整的抽象体系,核心定义位于 tools/base.py:BaseTool是全部工具的抽象基类,它强制要求子类实现run()方法,并通过get_schema()输出 OpenAI 兼容的 function calling 结构({"type": "function", "function": {...}}),这样无论是 OpenAI、Gemini 还是其他 100+ 兼容 LLM,都能理解并调用你的工具。

插件系统:把工具打包成 pip 安装包

PraisonAI 现在支持完整的插件系统(Plugin System),外部开发者可以创建可通过pip install安装的工具包,安装后工具会被 PraisonAI 自动发现。这是将自定义工具分发给社区或其他团队的标准方式。

快速开始:两种在代码中定义工具的方式

from praisonaiagents import BaseTool, tool, Agent # 方法一:基于类(Class-based) class WeatherTool(BaseTool): name = "get_weather" description = "Get weather for a location" def run(self, location: str) -> dict: return {"temp": 72, "condition": "sunny"} # 方法二:基于装饰器(Decorator-based) @tool def search(query: str) -> list: """Search the web.""" return [{"title": "Result", "url": "https://..."}] # 两种方式都可以直接挂载到 Agent 上 agent = Agent( name="Assistant", tools=[WeatherTool(), search] )

从源码看,BaseTool(定义于 tools/base.py)是一个抽象基类,子类必须覆盖两个类属性name(工具的唯一标识)和description(供 LLM 阅读的人性化描述,直接影响模型何时选择调用该工具),并实现抽象方法run()@tool装饰器(定义于 tools/decorator.py)则把普通函数包装成FunctionTool实例——它是BaseTool的子类,因此两种方式产出的对象在 Agent 眼中完全等价,可以混用。

创建插件包(Plugin Package)的完整流程

1. 创建工具包目录结构:

praisonai-weather/ ├── pyproject.toml ├── src/ │ └── praisonai_weather/ │ ├── __init__.py │ └── tools.py

2. 在tools.py中定义工具:

from praisonaiagents import BaseTool class WeatherTool(BaseTool): name = "weather" description = "Get current weather" def run(self, location: str) -> dict: # Your implementation return {"temp": 72}

3. 在pyproject.toml中通过 entry_points 注册:

[project] name = "praisonai-weather" version = "1.0.0" [project.entry-points."praisonaiagents.tools"] weather = "praisonai_weather.tools:WeatherTool"

注意(源码实证):README 中使用的入口组名praisonaiagents.tools是历史组名。查看 tools/registry.py 可以发现,当前官方规范入口组(canonical group)是praisonai.tools,而praisonaiagents.toolspraisonai.tool_sources已降级为向后兼容的别名——别名组首次被发现时会发出DeprecationWarning,且名称冲突时 canonical 组优先。因此新插件建议直接使用[project.entry-points."praisonai.tools"],两种写法当前都能被识别。

4. 用户安装并直接使用:

pip install praisonai-weather
from praisonaiagents import Agent # Tool is auto-discovered! agent = Agent(tools=["weather"])

这里的"自动发现"机制实现在 tools/registry.py 的ToolRegistry.discover_plugins()中:注册表通过importlib.metadata.entry_points扫描安装包中声明为工具入口点的类(或可调用对象),类会被自动实例化并注册到全局注册表;该扫描只执行一次(_discovered标志),且整个过程由threading.RLock保护,天然适配多 Agent 并发场景。

创建新工具:两种范式

1. 函数式(Function-Based):适合简单工具

函数式最适合"只做一件具体事情"的简单工具,就像只做加法的计算器。

适用场景:

  • 工具只完成一个简单任务;
  • 不需要在多次调用之间记忆状态;
  • 不需要与其他工具共享信息;
  • 是一次性的快速操作。

示例:

def internet_search(query: str): # Search the internet and return results return search_results

使用方式:

from praisonaiagents.tools import internet_search results = internet_search("AI news")

源码层面,internet_search是 tools/tools.py 中懒加载的 DuckDuckGo 搜索函数,同时在 tools/init.py 的TOOL_MAPPINGS注册表中映射到duckduckgo_tools模块。你完全可以照葫芦画瓢,把自己写的纯函数直接作为工具使用——PraisonAI 的解析器resolve_tool_name(见 tools/resolver.py)会依次尝试"注册表 → 内置 TOOL_MAPPINGS → 可选外部包"三级解析,普通函数只要能被找到就能被 Agent 调用。

2. 类式(Class-Based):适合复杂工具

类式适合"包含多个相关功能、或需要记忆信息"的复杂工具,就像一台能记住历史运算、支持多种数学操作的智能计算器。

适用场景:

  • 工具包含多个相互关联的功能;
  • 需要记忆或共享信息;
  • 需要高效管理资源(如连接池);
  • 有复杂的初始化配置需求。

示例:

class StockTools: def get_stock_price(self, symbol): # Get current stock price return price def get_stock_info(self, symbol): # Get detailed stock information return info

使用方式:

from praisonaiagents.tools import get_stock_price, get_stock_info price = get_stock_price("AAPL") info = get_stock_info("AAPL")

类式的底层优势在于可以复用BaseTool的完整能力矩阵。从 tools/base.py 可以梳理出子类可用的关键资产:

成员作用
name/description必填类属性,工具的标识与 LLM 可读描述
version工具版本号,默认"1.0.0"
parameters参数 JSON Schema,不提供时会根据run()签名自动生成
restart_safe声明工具的"重启安全"契约:True表示只读/幂等、崩溃后可安全重跑;False表示有副作用、恢复时绝不静默重放;None(默认)表示未声明
input_guardrails/output_guardrails仅作用于该工具的输入/输出护栏(与Agent(guardrails=...)的全局护栏不同)
run(**kwargs)抽象方法,必须实现,返回任意类型(会字符串化后交给 LLM)
safe_run(**kwargs)带异常捕获的执行入口,统一返回ToolResult(含success/error/metadata字段)
get_schema()输出 OpenAI 兼容的 function schema,支持动态覆写
validate()/validate_schema_roundtrip()定义期校验:检查 name/description/run 是否齐全、Schema 能否通过 JSON 序列化往返

此外,ToolResult还支持多模态内容通道:工具可以通过multimodal_content()text_part()image_part()file_part()(见 tools/base.py)返回结构化文本/图片/文件片段,使截图工具、图表渲染器等产出能直接成为下一轮对话中模型可见的消息部件。

@tool装饰器的进阶参数

@tool装饰器(tools/decorator.py)远不止包装函数那么简单,它还暴露了与 Agent 对齐的完整配置面:

@tool(name="web_search", description="Search the internet") def search(query: str, max_results: int = 5) -> list: return [...]
  • availability:传入() -> (is_available, reason)回调,运行时检查工具是否可用(例如 API Key 缺失时自动对模型隐藏该工具),结果会被注册表以 30 秒 TTL 缓存;
  • retry_policy:为工具执行配置指数退避重试策略;
  • approval:标记该工具需要人工审批,True使用默认"high"风险等级,字符串可显式指定"critical"/"high"/"medium"/"low",定义时即注册到全局 ApprovalRegistry,本地、网关与服务化运行都会强制执行;
  • to_model_output:提供result -> compact_view回调,给 LLM 喂精简摘要以节省上下文 token,完整结果仍保留给展示、钩子与追踪;
  • restart_safe:与BaseTool相同的重启安全声明;
  • input_guardrails/output_guardrails:本工具专属的参数/结果护栏,例如拦截发往外部域名的邮件、脱敏结果中的密钥;
  • Injected[T]参数:将参数声明为Injected[dict]类型即可在调用时由框架自动注入会话状态(如session_id),此类参数会被自动排除出对外暴露的 Schema(见 tools/decorator.py)。

如何选择你的实现方式

动手前先问自己四个问题:

  1. 你的工具只做一件简单的事吗?
    • 是 → 用函数式;否 → 考虑类式
  2. 你的工具需要记忆信息吗?
    • 是 → 用类式;否 → 用函数式
  3. 工具的多个操作之间相互关联吗?
    • 是 → 用类式;否 → 用函数式
  4. 你的工具需要高效管理资源吗?
    • 是 → 用类式;否 → 用函数式

核心原则:简单工具用函数,复杂、有状态、需要资源管理的工具用类

真实世界示例:两种范式的典型代表

PraisonAI 内置工具本身就是两种范式的最佳范本,全部可以通过from praisonaiagents.tools import ...导入:

互联网搜索工具(函数式)

  • 只做一件事:搜索互联网;
  • 无需记忆历史搜索;
  • 每次搜索相互独立;
  • 输入输出简单直接。

SearxNG 搜索工具(函数式)

  • 基于本地 SearxNG 实例的隐私优先网页搜索;
  • 支持可定制参数(max_results结果数量上限、searxng_url实例地址);
  • 每次搜索独立且安全;
  • 是传统搜索引擎的隐私替代方案。

其实现在 tools/searxng_tools.py,默认连接http://localhost:32768/search,聚合 google/bing/duckduckgo 多个引擎,结果统一标准化为{"title", "url", "snippet"}格式,并对连接失败、超时、解析错误均返回带error键的字典而不是抛异常——这正是"错误处理优雅"的代码示范。

Spider 工具(函数式)

  • 通用网页抓取与爬取;
  • 支持 CSS 选择器进行精确内容提取;
  • 可抓取多页面并抽取链接/图片;
  • 灵活应对各类爬取需求。

Newspaper 工具(函数式)

  • 专注新闻文章抽取;
  • 提取文章标题、正文、作者与发布日期;
  • 内置 NLP 处理生成关键词与摘要;
  • 按主题对新闻来源分类。

股票行情工具(类式)

  • 做多件事:查价格、查公司信息、查历史数据;
  • 记忆股票信息以避免重复下载;
  • 各操作相互关联(都围绕股票);
  • 高效管理连接资源。

类式工具的典型调用链可以对照 tools/init.py:注册表对类式工具采用"缓存类、每次新建实例"的工厂策略(_create_tool_instance),确保并发 Agent 之间不会共享可变状态、避免状态泄漏。

上手步骤:从零开始写一个工具

  1. 选择范式:依据上面的决策清单确定函数式还是类式;
  2. 创建工具文件:起一个描述性的文件名(如weather_tools.py),放在praisonaiagents/tools目录下(或你自己的包目录中);
  3. 编写工具:添加清晰的文档字符串,包含类型注解(type hints)以便于 Schema 自动生成,优雅处理错误;
  4. 测试工具:验证功能符合预期,覆盖错误分支,检查性能。

关于 Schema 自动生成,可以补充一个有趣的源码细节:tools/schema.py 的annotation_to_json_schema会把 Python 类型注解翻译成 JSON Schema——Optional[int]变成{"anyOf": [{"type": "integer"}, {"type": "null"}]}Literal["fast", "deep"]变成带枚举的字符串,List[T]Dict[K, V]、Enum 子类也各有对应。这意味着写好类型注解,就等于给 LLM 写好了调用参数约束,所以编写工具时务必为参数和返回值标注完整类型。

最佳实践

  1. 文档(Documentation)

    • 说明工具做什么、给什么输入、返回什么;
    • 提供使用示例;
    • 列出依赖与前置条件(如 API Key、本地服务)。
  2. 错误处理(Error Handling)

    • 始终处理可能的异常;
    • 返回有帮助的错误信息(参考 searxng_tools 返回{"error": ...}字典的做法);
    • 绝不让工具崩溃中断整个 Agent 运行——safe_run()会在底层兜住异常并封装为ToolResult(success=False, error=...)
  3. 性能(Performance)

    • 保持高效,不浪费资源;
    • 适合时使用缓存(股票工具记忆行情避免重复下载就是典型);
    • 善用availability回调 + TTL 缓存避免频繁探测不可用工具。
  4. 用户友好(User-Friendly)

    • 让工具易于使用;
    • 使用清晰的函数/方法命名(name 会直接暴露给 LLM 作为调用标识);
    • 保持简单,不过度设计。

需要帮助?

  • 查看 tools 目录 下 60+ 个内置工具模块作为范例;
  • 参考 examples/tools/example_tools_discover.py 了解如何枚举内置工具与外部工具包;
  • 阅读 examples/tools/example_tools_resolve.py 与 examples/tools/example_tools_sources.py 学习工具名称解析与来源排查;
  • 查阅 examples/tools/example_tools_discover.py 之外的工具示例文件,理解常见用法;
  • 查阅项目文档,或查看官方 CLI 命令praisonai tools list的解析提示(见 tools/resolver.py 中的_format_unknown)。

记住:目标是做出易于使用、易于维护的工具。选择最适合你具体工具需求的方式,让 Agent 的能力边界由你亲手定义。

【免费下载链接】PraisonAIPraisonAI 🦞 — Hire a 24/7 AI Workforce. Stop writing boilerplate and start shipping autonomous self-improving agents that research, plan, code, and execute tasks. Deployed in 5 lines of code with built-in memory, RAG, and support for 100+ LLMs.项目地址: https://gitcode.com/GitHub_Trending/pr/PraisonAI

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询