Nexent SDK 工具开发指南:从零打造生产级 AI Agent 工具

  • AI Agent
  • AI 应用
  • 后端
  • 前端
  • 大模型
  • RAG

【免费下载链接】nexent

Nexent is a zero-code platform for auto-generating production-grade AI agents using Harness Engineering principles — unified tools, skills, memory, and orchestration with built-in constraints, feedback loops, and control planes.

项目地址: https://gitcode.com/gh_mirrors/ne/nexent
点击查看 免费下载

导读

Nexent 是一个基于 Harness Engineering 原则、用于自动生成生产级 AI Agent 的零代码平台。本文档聚焦其 Python SDK(sdk/nexent)中工具(Tool)开发的全套规范与最佳实践:包括内置工具的全景分类、工具类的共性架构与核心属性、基于 MessageObserver 的消息流式处理机制、命名与 tool_sign 标识符约定、可复用的代码结构模板,以及开发流程、安全与性能最佳实践。读完本文,你将掌握在 Nexent SDK 中从零编写一个与内置工具保持一致规范、支持中英双语、具备流式输出能力并可通过 core_agent.py 桥接集成到 Agent 运行时的完整工具开发方法论。

本文以 doc/docs/en/sdk/core/tools.md 为骨架,结合 sdk/nexent/core/tools/ 目录下的真实实现、core_agent.py 的桥接逻辑以及 test/sdk/core/tools/ 下的单元测试进行纵深印证,保证每个结论都有源码级依据。

一、工具全景:Nexent SDK 内置工具分类

Nexent SDK 的内置工具按功能划分为九大类。除少数系统内部管理的工具外,大部分工具统一在 sdk/nexent/core/tools/init.py 中导出,供 Agent 运行时装配。以下是原文档与源码双重印证下的完整分类:

搜索工具(Search Tools)

面向公网与私域数据的检索类工具,统一使用 SearchResultTextMessage 结构化输出,并携带 tool_sign 以便前端引用标签(如 [b0]、[a1])区分检索来源:

  • ExaSearchTool:基于 EXA API 的 Web 搜索工具,实现见 exa_search_tool.py
  • TavilySearchTool:基于 Tavily API 的 Web 搜索工具,实现见 tavily_search_tool.py
  • LinkupSearchTool:基于 Linkup API 的搜索工具
  • KnowledgeBaseSearchTool:本地知识库(向量库)检索工具,实现见 knowledge_base_search_tool.py
  • RAGFlowSearchTool:RAGFlow 知识检索
  • HaotianSearchTool / IndependentAidpSearchTool / AidpSearchTool / DifySearchTool / DataMateSearchTool / IdataSearchTool:企业级检索源接入,分别对接浩天、独立 AIDP、AIDP、Dify、DataMate、iData 等平台

其中 AidpSearchTool 位于 sdk/nexent/core/ext_components/aidp/aidp_search_tool.py,与其余搜索工具解耦存放。

文件管理工具(File Management Tools)

围绕工作空间文件系统的全套操作,统一以 tool_sign = ToolSign.FILE_OPERATION.value 标记:

  • CreateFileTool:创建带内容的文件
  • ReadFileTool:从文件系统读取文件内容
  • DeleteFileTool:删除文件
  • MoveItemTool:移动或重命名文件/目录
  • CreateDirectoryTool:创建目录
  • DeleteDirectoryTool:删除目录及其内容
  • ListDirectoryTool:列出目录内容及详细信息

系统工具(System Tools)

  • TerminalTool:通过 SSH 执行 shell 命令并管理系统操作,支持会话管理以跨命令保持 shell 状态(见 terminal_tool.py)

通信工具(Communication Tools)

  • GetEmailTool:基于 IMAP 的邮件获取
  • SendEmailTool:基于 SMTP 的邮件发送

多模态工具(Multimodal Tools)

  • AnalyzeTextFileTool:基于数据处理与大语言模型的文档问答工具
  • AnalyzeImageTool:基于视觉语言模型(VLM)的图片问答工具
  • AnalyzeAudioTool:基于语音模型的音频理解工具
  • AnalyzeVideoTool:基于视觉语言模型的视频理解工具

这些工具的提示词模板位于 sdk/nexent/core/prompts/(如 analyze_image_zh.yaml、analyze_video_en.yaml 等,均提供中英双语版本)。

记忆工具(Memory Tools)

  • StoreMemoryTool:将重要信息写入当前 Agent 的短期记忆(MemoryLayer.AGENT + MemoryType.SHORT_TERM),单次运行最多写入 3 条。源码中通过 self.max_stores_per_run = 3 强制限制(见 store_memory_tool.py)
  • SearchMemoryTool:以自然语言查询检索当前 Agent 的记忆,top_k 默认为 5(见 search_memory_tool.py)

值得关注的是,search_memory_tool.py 在运行时优先通过 MemoryContextService.build_context 走 Phase 4 检索流水线(分数融合、时间衰减、MMR 去重、token 预算选择),未配置时降级为 SDK 直连 MemoryService 模式——这是"优雅降级"原则的典型实现。

编排工具(Orchestration Tools)

  • ParallelExecutorTool:并发执行多个子 Agent 或工具调用,实现见 parallel_executor.py。它要求任务以二元组 (tool_or_agent, kwargs_dict) 或三元组 (tool_or_agent, kwargs_dict, result_key) 传入,且同一次调用不能混用两种格式;timeout 默认 120 秒、max_workers 默认 4
  • CreatePlanTool / UpdatePlanStepTool:计划待办事项(plan todo)的创建与更新,实现见 plan_tools.py

数据工具(Data Tools)

技能与任务工具(系统内部管理,Skill and Task Tools)

  • ReadSkillConfigTool / ReadSkillMdTool:读取技能目录下的 config.yaml 与 SKILL.md
  • RunSkillScriptTool:执行技能脚本
  • WriteSkillFileTool:写入租户隔离的技能目录文件
  • CreateScheduledTaskProposalTool:创建待用户确认的定时任务提案(仅保存提案,不执行业务任务)

注意:上述系统内部工具不在 sdk/nexent/core/tools/init.py 中统一导出,由系统在运行时按需装配。

二、工具共性特征:四层基础架构

无论哪种工具,Nexent SDK 都遵循同一套基础架构约定:

1. 基类继承

所有工具必须继承 smolagents.tools.Tool。例如 exa_search_tool.py 第 18 行 class ExaSearchTool(Tool)。这使工具天然兼容 smolagents 的 CodeAgent 工具注册表,可被直接注入 Agent 运行环境。

2. 参数管理

使用 pydantic.Field 定义构造参数并进行验证。例如 ExaSearchTool 的 max_results 声明了 ge=1, le=100 的范围约束,pydantic_utils.py 中的 unwrap_field_info 负责把 smolagents 传入的 FieldInfo 解包为声明默认值。工具的真实参数如 exa_api_key、tavily_api_key、ssh_host、password 等都通过构造器注入——SDK 层不直接读取环境变量,环境变量由服务层读取后再传入(原文档"注意事项"第 4 条对此有明确规定)。

3. 流式输出

集成 MessageObserver 实现实时消息传递。MessageObserver 的实现见 sdk/nexent/core/utils/observer.py:它维护一个线程安全的 message_query 队列,工具通过 observer.add_message(...) 将各类消息推入队列,由 Agent 运行时流式桥接层消费并推送给前端。MessageObserver 还内置了 ANSI 转义序列清洗(_ANSI_ESCAPE_PATTERN),避免终端 traceback 的 [31m 等控制字符污染 JSON/SSE 协议输出。

4. 多语言支持

内置中英文双语提示:类属性 description(英文)与 description_zh(中文)、init_param_descriptions 中每个构造参数的 description / description_zh,以及 observer.lang 驱动的运行时提示语选择。

三、核心属性清单

每个工具类必须声明以下类属性(原文档完整示例):

class ToolExample(Tool):
    name = "tool_name"                     # Tool unique identifier
    description = "Tool function description"  # Detailed feature description (English)
    description_zh = "工具功能描述"        # Detailed feature description (Chinese)
    inputs = {                             # Input parameter definition
        "param": {
            "type": "string",
            "description": "Parameter description",
            "description_zh": "参数描述"
        }
    }
    init_param_descriptions = {            # Constructor parameter descriptions (corresponding to __init__ parameters)
        "config_param": {"description": "Config parameter description", "description_zh": "配置参数说明"}
    }
    output_type = "string"                 # Output type
    category = "search"                    # Tool category (ToolCategory enum value)
    tool_sign = "b"                        # Tool identifier (ToolSign enum value)

各字段职责:

  • name:工具在 Agent 环境中的唯一调用标识(如 exa_search、terminal),模型据此发起调用;
  • inputs:声明 forward 的输入参数结构(type/description/description_zh/default/nullable),会注入系统提示词供 LLM 理解参数语义;
  • output_type:forward 的返回类型,搜索类工具统一返回 JSON 字符串;
  • category:取自 ToolCategory 枚举(见下文);
  • tool_sign:取自 ToolSign 枚举,用于前端引用标签区分检索来源。

ToolCategory 与 ToolSign 两个枚举统一定义在 sdk/nexent/core/utils/tools_common_message.py:

class ToolCategory(Enum):
    SEARCH = "search"
    FILE = "file"
    EMAIL = "email"
    TERMINAL = "terminal"
    MULTIMODAL = "multimodal"
    DATABASE = "database"
    MEMORY = "memory"
    SKILL = "skill"
    PLANNING = "planning"

四、消息处理机制:Observer 模式与 TOOL 桥接

ProcessType 枚举

消息类型由 ProcessType 枚举统一管理,除文档列出的 TOOL、CARD、SEARCH_CONTENT、PICTURE_WEB 外,observer.py 中还包含 FINAL_ANSWER、EXECUTION_LOGS、SUBAGENT_START/END、PLAN、PLAN_STEP_UPDATE、AUTOMATION_PROPOSAL、MEMORY_SEARCH、VERIFICATION 等 30 余种类型,覆盖模型流式输出、子 Agent 边界、计划状态、定时任务提案等全部运行时事件。每种类型在 MessageObserver._init_message_transformers() 中映射一个消息转换器(如 StepCountTransformer、ExecutionLogsTransformer),转换后再以统一 JSON 格式推入队列,Message 类负责将类型、内容、工具元数据(tool_name、tool_arguments、tool_call_id)、子 Agent 归属(agent_id、agent_name、depth、invocation_id)序列化为 JSON。

TOOL 消息的统一发送:core_agent 桥接

这是新版 SDK 最重要的架构约定:工具自身不再发送 ProcessType.TOOL 运行状态消息,而是由 core_agent.py 中的 _wrap_tool_for_observer 桥接(第 477-509 行)在每次工具被调用时统一发送,并附带 tool_call_id 用于上下文关联:

def _wrap_tool_for_observer(tool, observer, agent_name) -> None:
    ...
    def observed_forward(*args, **kwargs):
        tool_call_id = str(uuid.uuid4())
        observer.add_message(
            agent_name or "",
            ProcessType.TOOL,
            "",
            tool_name=tool_name,
            tool_arguments=_observer_call_arguments(tool, args, kwargs),
            tool_call_id=tool_call_id,
        )
        with observer.tool_call_context(tool_call_id):
            return original_forward(*args, **kwargs)
    tool.forward = observed_forward

桥接在 _wrap_visible_tool_events()(第 662-673 行)中对所有可见工具逐一打包装饰,MessageObserver.tool_call_context 通过 ContextVar 把 tool_call_id 与当前工具调用关联,工具内部通过 observer.add_message 发出的补充消息(CARD、SEARCH_CONTENT、PICTURE_WEB 等)也会自动带上该调用上下文,从而保证前端对工具调用的全过程追踪一致。

遗留约定:部分早期工具(如 SQL 工具基类 sql_database_base_tool.py)仍保留 running_prompt_zh/en 属性并在工具内部发送 TOOL 消息;新开发的工具不应再使用该模式,仅发送补充消息即可。

消息格式

所有消息内容使用 JSON 格式。搜索工具通过 SearchResultTextMessage(定义于 tools_common_message.py)统一封装搜索结果,其 to_dict() 保存全量数据(供前端渲染),to_model_dict() 生成喂给大模型摘要的紧凑格式——其中 index = f"{self.tool_sign}{self.cite_index}",即前端引用标签 [b0]、[a1] 的生成源头,reference_mark 为 [[b0]] 形式的引用标记。

五、命名规范

文件命名

  • 格式:{功能名}_tool.py
  • 风格:小写字母、下划线连接
  • 示例:exa_search_tool.py、knowledge_base_search_tool.py

类命名

  • 格式:{功能名}Tool
  • 风格:PascalCase(大驼峰)
  • 示例:ExaSearchTool、KnowledgeBaseSearchTool

属性和方法命名

  • 格式:小写字母、下划线连接
  • 私有方法:以单下划线开头(如 _filter_images、_decode_subject、_format_result)
  • 示例:max_results、description_zh、record_ops

tool_sign 标识符约定

tool_sign 是单字母标识符,用于在总结与前端引用标签中区分工具来源。取值必须来自 tools_common_message.py 的 ToolSign 枚举,完整分配规则(以源码第 7-26 行为准):

字母枚举成员用途
aKNOWLEDGE_BASE知识库搜索(KnowledgeBaseSearchTool)
bEXA_SEARCHEXA 搜索(ExaSearchTool)
cLINKUP_SEARCHLinkup 搜索(LinkupSearchTool)
dTAVILY_SEARCHTavily 搜索(TavilySearchTool)
eDATAMATE_SEARCHDataMate 搜索
fFILE_OPERATION文件操作
gDIFY_SEARCHDify 搜索
hIDATA_SEARCHiData 搜索
iHAOTIAN_SEARCHHaotian 搜索
jAIDP_SEARCHAIDP 搜索
kRAGFLOW_SEARCHRAGFlow 搜索
lINDEPENDENT_AIDP_SEARCH独立 AIDP 搜索
mMULTIMODAL_OPERATION多模态操作
nMEMORY_OPERATION记忆操作
pPLAN_OPERATION计划/步骤状态工具
sSKILL_OPERATION技能脚本/文件工具
tTERMINAL_OPERATION终端操作
zDATABASE_OPERATION数据库操作

源码同时维护了 TOOL_SIGN_MAPPING(工具名→字母)与 REVERSE_TOOL_SIGN_MAPPING(字母→工具名)用于向后兼容与反向查询。

六、代码结构模板

基础工具模板

以下模板完整继承自原文档,并结合源码补充了 category/tool_sign 赋值与注释说明,可直接复制落地:

import json
import logging
from typing import Optional
from smolagents.tools import Tool
from pydantic import Field

from ..utils.observer import MessageObserver, ProcessType
from ..utils.tools_common_message import ToolCategory, ToolSign

logger = logging.getLogger("your_tool_name")

class YourTool(Tool):
    name = "your_tool"
    description = "Detailed description of the tool function, including applicable scenarios and usage"
    description_zh = "工具功能的中文描述,说明适用场景和使用方法"
    inputs = {
        "param1": {
            "type": "string",
            "description": "Detailed description of parameter 1",
            "description_zh": "参数1的中文描述"
        },
        "param2": {
            "type": "integer",
            "description": "Detailed description of parameter 2",
            "description_zh": "参数2的中文描述",
            "default": 10,
            "nullable": True
        }
    }
    init_param_descriptions = {          # Constructor parameter descriptions (corresponding to __init__ parameters)
        "config_param": {"description": "Config parameter description", "description_zh": "配置参数说明"},
        "optional_param": {"description": "Optional parameter description", "description_zh": "可选参数说明"}
    }
    output_type = "string"
    category = ToolCategory.FILE.value  # Choose the ToolCategory enum member by tool type
    tool_sign = ToolSign.FILE_OPERATION.value  # Choose the ToolSign enum member by tool type

    def __init__(
        self,
        config_param: str = Field(description="Config parameter"),
        observer: MessageObserver = Field(description="Message observer", default=None, exclude=True),
        optional_param: int = Field(description="Optional parameter", default=5)
    ):
        super().__init__()
        self.config_param = config_param
        self.observer = observer
        self.optional_param = optional_param

        # Record operation sequence (if needed)
        self.record_ops = 0

    def forward(self, param1: str, param2: int = 10) -> str:
        """Main execution method of the tool

        Args:
            param1: Parameter 1 description
            param2: Parameter 2 description

        Returns:
            JSON format string result

        Raises:
            Exception: Detailed error information
        """
        try:
            # Send card information (optional)
            if self.observer:
                card_content = [{"icon": "your_icon", "text": param1}]
                self.observer.add_message("", ProcessType.CARD,
                                        json.dumps(card_content, ensure_ascii=False))

            # Main business logic
            result = self._execute_main_logic(param1, param2)

            # Process result and return
            return self._format_result(result)

        except Exception as e:
            logger.error(f"Error in {self.name}: {str(e)}")
            raise Exception(f"Error executing {self.name}: {str(e)}")

    def _execute_main_logic(self, param1: str, param2: int):
        """Private method for executing main business logic"""
        # Implement specific business logic
        pass

    def _format_result(self, result) -> str:
        """Format return result"""
        formatted_result = {
            "status": "success",
            "data": result,
            "tool": self.name
        }
        return json.dumps(formatted_result, ensure_ascii=False)

模板要点(与真实实现的对照):

  • observer 参数必须声明 exclude=True,确保它不作为工具参数暴露给 LLM(所有内置工具如 exa_search_tool.py、terminal_tool.py 均如此);
  • record_ops 用于记录操作序号,在搜索类工具中作为引用序号(cite_index)的累加起点;
  • 异常统一抛 Exception 并记录日志,错误信息包含 {self.name} 便于定位。

搜索工具模板

搜索类工具在基础模板之上叠加 SearchResultTextMessage 统一结果封装与 SEARCH_CONTENT 消息推送:

import json
import logging
from typing import List
from smolagents.tools import Tool
from pydantic import Field

from ..utils.observer import MessageObserver, ProcessType
from ..utils.tools_common_message import SearchResultTextMessage, ToolCategory, ToolSign

logger = logging.getLogger("search_tool_name")

class SearchTool(Tool):
    name = "search_tool"
    description = "Detailed description of the search tool, including search scope and applicable scenarios"
    description_zh = "搜索工具的中文描述,包括搜索范围和适用场景"
    inputs = {
        "query": {"type": "string", "description": "The search query to perform", "description_zh": "搜索查询词"},
        "max_results": {"type": "integer", "description": "Maximum number of results", "description_zh": "最大结果数", "default": 5, "nullable": True}
    }
    init_param_descriptions = {          # Constructor parameter descriptions (corresponding to __init__ parameters)
        "api_key": {"description": "API key", "description_zh": "API密钥"}
    }
    output_type = "string"
    category = ToolCategory.SEARCH.value
    tool_sign = ToolSign.EXA_SEARCH.value  # Choose the ToolSign enum member by actual search source

    def __init__(
        self,
        api_key: str = Field(description="API key"),
        observer: MessageObserver = Field(description="Message observer", default=None, exclude=True),
        max_results: int = Field(description="Maximum number of search results", default=5)
    ):
        super().__init__()
        self.api_key = api_key
        self.observer = observer
        self.max_results = max_results
        # Citation index starts from 1 (used by SearchResultTextMessage's cite_index)
        self.record_ops = 1

    def forward(self, query: str, max_results: int = None) -> str:
        if max_results is None:
            max_results = self.max_results

        # Send card information (optional; TOOL running status messages are sent uniformly by the core_agent bridge)
        if self.observer:
            card_content = [{"icon": "search", "text": query}]
            self.observer.add_message("", ProcessType.CARD,
                                    json.dumps(card_content, ensure_ascii=False))

        try:
            # Execute search
            search_results = self._perform_search(query, max_results)

            if not search_results:
                raise Exception("No search results found! Please try shorter or broader queries.")

            # Format search results
            formatted_results = self._format_search_results(search_results)

            # Record search content
            if self.observer:
                search_results_data = json.dumps(formatted_results["json"], ensure_ascii=False)
                self.observer.add_message("", ProcessType.SEARCH_CONTENT, search_results_data)

            return json.dumps(formatted_results["return"], ensure_ascii=False)

        except Exception as e:
            logger.error(f"Search error: {str(e)}")
            raise Exception(f"Search failed: {str(e)}")

    def _perform_search(self, query: str, max_results: int):
        """Execute actual search operation"""
        # Implement specific search logic
        pass

    def _format_search_results(self, results):
        """Format search results into unified format"""
        search_results_json = []
        search_results_return = []

        for index, result in enumerate(results):
            search_result_message = SearchResultTextMessage(
                title=result.get("title", ""),
                url=result.get("url", ""),
                text=result.get("content", ""),
                published_date=result.get("date", ""),
                source_type="url",
                filename="",
                score=result.get("score", ""),
                score_details=result.get("score_details", {}),
                cite_index=self.record_ops + index,
                search_type=self.name,
                tool_sign=self.tool_sign
            )
            search_results_json.append(search_result_message.to_dict())
            search_results_return.append(search_result_message.to_model_dict())

        self.record_ops += len(search_results_return)

        return {
            "json": search_results_json,
            "return": search_results_return
        }

以真实的 exa_search_tool.py 为参照,其 forward 的具体实现展示了搜索模板的完整落地形态:调用 Exa.search_and_contents 后,逐条构造 SearchResultTextMessage,同时把 PICTURE_WEB 图片列表通过 _filter_images 交给数据处理服务(/tasks/filter_important_image)过滤(负向提示词为 "logo or banner or background or advertisement or icon or avatar"),过滤失败时优雅降级为直接发送未过滤的图片 URL 列表。单元测试见 test/sdk/core/tools/test_exa_search_tool.py,通过模块级 mock(patch.dict('sys.modules', ...))隔离 exa_py 与 aiohttp 依赖,验证了工具在无真实网络环境下的行为。

七、开发流程规范

1. 开发前准备

  • 确定工具功能与适用场景;
  • 选择合适的工具分类(ToolCategory)与标识符(ToolSign);
  • 检查是否与现有工具功能重复(对照 tools/init.py 的既有导出清单)。

2. 实现步骤

  1. 创建工具文件:按命名规范创建 {name}_tool.py;
  2. 定义类结构:继承 Tool 基类,定义必要类属性(name、description、inputs、output_type、category、tool_sign 等);
  3. 实现构造函数:用 pydantic.Field 定义参数,observer 参数 exclude=True;
  4. 实现 forward 方法:核心功能逻辑,返回 JSON 字符串;
  5. 添加私有方法:将复杂逻辑拆分为 _ 开头的私有方法(如 _perform_search、_format_result);
  6. 集成 MessageObserver:按需发送 CARD、SEARCH_CONTENT、PICTURE_WEB 等补充消息,支持流式输出与多语言;
  7. 异常处理:完善错误处理与日志记录(logger = logging.getLogger("your_tool_name"))。

3. 测试与集成

  1. 单元测试:测试各种输入场景与边界条件。仓库内每个工具都有对应测试,如 test_terminal_tool.py、test_store_memory_tool.py、test_knowledge_base_search_tool.py、SQL 工具测试位于 test/sdk/core/tools/sql_tools/;
  2. 集成测试:与 CoreAgent(core_agent.py)集成,验证 TOOL 桥接与流式消息链路;
  3. 更新导出:在 tools/init.py 的导入与 __all__ 中登记新工具(系统内部管理的技能/任务类工具除外);
  4. 文档更新:更新相关文档与示例(如 tools/README.md 及其英文版 README_EN.md)。

八、最佳实践

1. 性能优化

  • 异步处理:耗时操作使用异步。如 exa_search_tool.py 的 _filter_images 用 asyncio.gather 并发处理图片;记忆工具通过 _run_coroutine 将协程调度到受管线程管理器(get_current_thread_manager)执行;
  • 连接池:复用网络连接。Exa/Tavily 工具复用 aiohttp.TCPConnector(limit=0),SQL 工具复用数据库连接;
  • 缓存机制:适当使用缓存提升响应速度;
  • 并发控制:用 Semaphore 控制并发请求数(图片过滤设置 asyncio.Semaphore(10),ParallelExecutorTool 通过 max_workers 控制线程数)。

2. 安全性

  • 输入验证:严格验证输入参数。SQL 工具在 sql_database_base_tool.py 中内置 HIGH_RISK_SQL_PATTERNS 黑名单(DROP DATABASE、GRANT、REVOKE、CREATE USER、INTO OUTFILE、LOAD DATA INFILE、EXEC xp_ 等),并强制 UPDATE/DELETE 语句必须包含 WHERE 子句(否则抛出 MISSING_WHERE 安全拦截异常);
  • 敏感信息:API 密钥等敏感信息不得出现在日志中——注意 exa_search_tool.py 与 terminal_tool.py 的日志只记录事件类型与状态,不打印密钥;store_memory 日志记录的是 content_length 而非内容本身;
  • 错误信息:避免在错误消息中泄露敏感信息;
  • 超时控制:设置合理超时。SQL 查询默认 timeout=10 秒、max_rows=100;TerminalTool 命令默认超时 30 秒;SSH 连接超时 10 秒。

3. 可维护性

  • 模块化设计:复杂功能拆分为多个方法;
  • 清晰注释:为复杂逻辑添加详细注释(真实实现中注释密度很高);
  • 类型注解:使用完整类型注解(如 Optional[List[Any]]、Dict[str, Any]);
  • 文档字符串:为所有公共方法添加 docstring(含 Args/Returns/Raises)。

4. 用户体验

  • 多语言支持:中英文双语提示(description_zh、init_param_descriptions 双语描述、双语 prompts 位于 sdk/nexent/core/prompts/);
  • 进度反馈:通过 MessageObserver 提供实时反馈(卡片消息、搜索内容流、图片流);
  • 错误提示:提供清晰错误信息与解决建议(如 "No results found! Try a less restrictive/shorter query."、知识库搜索的 "NOTICE" 提示,见 knowledge_base_search_tool.py 中 build_knowledge_search_response 对权限过滤/范围回退的模型侧说明);
  • 参数验证:执行前验证参数有效性(ge/le 范围约束、unwrap_field_info 解包默认值)。

九、重要注意事项

  1. 版本兼容:确保工具兼容不同版本的依赖库(如 smolagents、pydantic、aiohttp);
  2. 资源清理:及时释放网络连接、文件句柄等资源。TerminalTool._cleanup_session 负责关闭 SSH channel 与 client,并实现了会话保活检测(_is_session_alive),发现连接失效自动重建;
  3. 日志级别:合理设置日志级别,避免过多调试信息(如 _filter_images 中对图片过滤异常使用 logger.info 而非 logger.error 以避免噪音);
  4. 配置管理:所有配置通过构造参数传入,SDK 不直接读环境变量(DATA_PROCESS_SERVICE 等环境变量由服务层读取后传入);
  5. 错误恢复:尽可能提供错误恢复机制。记忆工具在存储超限时返回 "Information will be saved automatically at the end." 的降级提示;图片过滤失败时回退为发送未过滤图片列表;SearchMemoryTool 在流水线异常时返回 "Continuing without memory results." 而非中断 Agent。

遵循以上规范,新工具将与现有工具保持高度一致,具备良好的可维护性与可扩展性,并能无缝接入 Nexent Agent 运行时的消息流、引用标注与前端渲染链路。

关键源码索引

  • AI Agent
  • AI 应用
  • 后端
  • 前端
  • 大模型
  • RAG

【免费下载链接】nexent

Nexent is a zero-code platform for auto-generating production-grade AI agents using Harness Engineering principles — unified tools, skills, memory, and orchestration with built-in constraints, feedback loops, and control planes.

项目地址: https://gitcode.com/gh_mirrors/ne/nexent
点击查看 免费下载

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

实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值