ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

插件化Agent框架实战:用DeepSeek构建可扩展的Python智能体

插件化Agent框架实战:用DeepSeek构建可扩展的Python智能体 在 DeepSeek 官方开源 Agent 框架公布之后“一切皆插件”成了 Agent 开发社区里讨论度最高的一个词。它想解决的是很多团队构建智能体时都会遇到的同一个问题模型调用、工具执行、记忆读写、安全限制、用户会话这些能力如果全部写进同一个项目项目很快就会变成无法维护的“巨无霸”。插件化的核心不是把代码拆成多个文件而是把行为边界拆成可插入、可替换、可独立验证的单元。这篇文章会先解释插件化 Agent 的设计逻辑然后给出一个可运行的 Python 最小框架用 DeepSeek API 接入一个能调用工具的 Agent最后补充生产环境需要的安全、版本和可观测性设计。1. 先理解 Agent 框架为什么要走“一切皆插件”路线在写代码之前需要先想清楚一个问题Agent 框架为什么值得插件化而不是像传统 Web 项目那样按 Controller、Service、DAO 分层就够了。1.1 从单体 Agent 到插件化 Agent 的演进早期做 LLM 应用最常见的形态是把一轮对话写成一个大函数拿到用户输入拼 Prompt调用模型解析输出再拼一段代码去调搜索或计算器。功能少的时候这种方式确实直接。但一旦模型、工具、记忆和策略都要参与单独的函数很快会变成“面条代码”因为每个模块之间互相都知道对方的实现细节。插件化 Agent 的核心变化是把“能力单元”作为一等公民。一个能力单元可以是工具比如计算器、搜索引擎、数据库查询器也可以是策略比如是否允许模型访问某个高危接口还可以是记忆组件比如把关键信息写入向量库。每个单元都实现同一个接口由宿主程序统一加载和调度。这个演进过程和浏览器插件、IDE 插件很像核心宿主保持稳定能力通过插件扩展。用户不需要改写核心代码只需要把需要的插件放进指定目录宿主在启动时扫描目录并注册即可。单体 Agent 和插件化 Agent 的差异可以整理成下表对比维度单体 Agent插件化 Agent代码组织按流程写在一个模块中按能力边界拆成插件新增工具修改主流程代码新增一个插件文件行为替换改函数内部实现替换同接口插件测试范围容易影响主流程每个插件可独立测试安全边界工具权限和主流程混在一起插件可设置独立权限部署升级整体发布按插件单独更新1.2 “一切皆插件”到底指什么只看“插件”两个字很多人会误以为它只是普通的设计模式中的策略模式或者只是把工具函数注册到列表里。“一切皆插件”强调的是更彻底的边界拆分。在这个框架里不只是 Python 工具函数可以做成插件以下几类能力通常也会被插件化模型插件把 DeepSeek 或其他模型封装成统一的模型插件Agent 核心不关心底层 API 是 OpenAI 兼容格式还是私有 SDK。工具插件计算、搜索、数据库读写、HTTP 请求都作为工具由 Agent 调度。记忆插件短期会话记忆、长期向量记忆、用户画像记忆分开实现按场景选择。策略插件是否允许某个工具执行、遇到错误时是重试还是终止、多步任务如何拆解这些都可以做成策略插件。观测插件日志、指标上报、链路追踪作为插件挂到 Agent 生命周期上不影响核心逻辑。这样设计的直接收益是“替换成本低”。比如从 DeepSeek 切换到其他兼容模型时只需要替换模型插件不需要修改 Agent 循环如果希望计算器插件执行前先做参数校验只需要在策略插件里增强校验逻辑。1.3 Harness 与宿主环境的关系在 DeepSeek 相关的 Agent 社区讨论中Harness 是一个经常出现的词。Harness 可以理解成“宿主执行器”它负责把模型、工具、记忆和策略装配起来并驱动 Agent 循环。官方框架强调插件化之后Harness 就不再是一个写死的执行器而是一个可装配的容器。这篇文章中的最小实现会参考这个思路宿主只负责插件扫描、注册和循环调度模型能力、工具能力通过插件接口接入。这样即使你还没有拿到完整的官方框架源码也可以先按同样思路搭出一个可运行的原型。2. 环境准备用最小项目跑通插件化 Agent下面开始落地。先准备一套可以直接运行的 Python 工程结构再逐步填充插件内核和示例插件。2.1 Python 环境和依赖建议使用 Python 3.10 或更高版本。代码会用到importlib.util、pathlib、dataclasses这些都是标准库。调用 DeepSeek API 时需要 HTTP 客户端示例使用requests。创建虚拟环境并安装依赖mkdir deepseek-plugin-agent cd deepseek-plugin-agent python -m venv venv source venv/bin/activate pip install requests python-dotenv pyyaml如果网络环境允许也可以把依赖写入requirements.txtrequests2.31.0 python-dotenv1.0.0 PyYAML6.0这里需要注意实际项目落地前先确认你使用的 DeepSeek API 版本和 Python 客户端要求。本文只使用requests调 HTTP 接口不依赖其他 SDK这样对版本变化的容忍度更高。2.2 项目目录结构推荐按下面的目录组织项目插件统一放在plugins目录中deepseek-plugin-agent/ ├── agent/ │ ├── __init__.py │ ├── plugin_base.py │ ├── plugin_loader.py │ ├── registry.py │ └── agent.py ├── plugins/ │ ├── deepseek_llm.py │ ├── calculator.py │ └── current_time.py ├── config.yaml ├── .env ├── main.py └── requirements.txtagent目录存放宿主框架代码plugins目录存放具体插件。这样划分的另一个好处是框架代码和插件代码分成两个可测试边界插件的单元测试不需要拉起完整 Agent。2.3 配置文件和 API Key项目根目录创建.env文件用于保存密钥和可变配置DEEPSEEK_API_KEYsk-你的密钥 DEEPSEEK_API_URLhttps://api.deepseek.com/chat/completions AGENT_MODELdeepseek-chat MAX_STEPS5 PLUGIN_DIRplugins再创建config.yaml把 Agent 级别的参数和插件目录配置统一放进去agent: max_steps: 5 model: deepseek-chat plugin_dir: plugins allow_remote_tools: false logging: level: INFO需要说明的是.env中的DEEPSEEK_API_KEY不要提交到 Git 仓库。建议在.gitignore中忽略.env只保留.env.example作为模板。生产环境可以通过密钥管理服务注入环境变量而不是把密钥写入配置文件。3. 手写插件内核接口、加载器与 Agent 循环这一节是实现的核心部分。我们会定义一个统一的插件接口再实现目录扫描加载器最后写一个简单的 Agent 循环。3.1 插件接口如何定义插件接口的职责是让宿主不关心插件内部逻辑。宿主只需要知道插件有名称、描述、元信息和执行方法。创建agent/plugin_base.pyfrom abc import ABC, abstractmethod from typing import Any, Dict class Plugin(ABC): name: str base_plugin description: str version: str 0.1.0 abstractmethod def execute(self, context: Dict[str, Any], **kwargs) - Dict[str, Any]: raise NotImplementedError这个接口有几个关键设计name是插件的唯一标识Agent 调度工具时通过名称定位。description会被写入系统 Prompt帮助模型理解什么时候调用这个插件。execute统一返回字典避免不同插件返回类型不一致。context用于传递会话 ID、用户 ID、预算限制等宿主上下文信息。可能有人会问为什么不用**kwargs直接传参而是统一返回字典因为 Agent 的多步循环中模型输出可能是字符串、数字、JSON插件统一返回字典后宿主的下一轮 Prompt 可以把结果序列化成统一结构减少解析异常。3.2 插件加载器怎么动态扫描目录插件加载器要完成三件事扫描目录、动态导入 Python 文件、找出Plugin子类并实例化。创建agent/plugin_loader.pyimport importlib.util import inspect import sys from pathlib import Path from typing import List, Type from agent.plugin_base import Plugin def load_plugin_classes(file_path: Path) - List[Type[Plugin]]: module_name fplugin_{file_path.stem} spec importlib.util.spec_from_file_location(module_name, file_path) if spec is None or spec.loader is None: return [] module importlib.util.module_from_spec(spec) sys.modules[module_name] module spec.loader.exec_module(module) plugin_classes [] for _, obj in inspect.getmembers(module, inspect.isclass): if ( issubclass(obj, Plugin) and obj is not Plugin and obj.__module__ module.__name__ ): plugin_classes.append(obj) return plugin_classes def load_plugins_from_dir(plugin_dir: str) - List[Plugin]: path Path(plugin_dir) if not path.exists(): return [] plugins [] for file_path in path.glob(*.py): if file_path.name.startswith(__): continue classes load_plugin_classes(file_path) for cls in classes: try: plugins.append(cls()) except Exception as exc: print(f[loader] failed to init {cls.__name__}: {exc}) return plugins这里要特别注意obj.__module__ module.__name__的判断。不做这个判断时导入模块里的基类和被依赖的第三方类会被误判成当前目录的插件。加上这个条件后只有定义在这个 Python 文件中的插件子类才会被加载。插件注册表可以做成一个简单容器from typing import Dict, List from agent.plugin_base import Plugin class PluginRegistry: def __init__(self) - None: self._plugins: Dict[str, Plugin] {} def register(self, plugin: Plugin) - None: if plugin.name in self._plugins: raise ValueError(fplugin {plugin.name} already exists) self._plugins[plugin.name] plugin def get(self, name: str) - Plugin: if name not in self._plugins: raise KeyError(fplugin {name} not found) return self._plugins[name] def all(self) - List[Plugin]: return list(self._plugins.values())3.3 Agent 核心循环如何调度插件Agent 核心循环采用经典的“观察-思考-行动-观察”模型。宿主把系统 Prompt、用户消息和历史消息发给模型模型决定是直接回答还是调用某个插件。如果调用插件宿主把结果追加到消息列表再进入下一轮。创建agent/agent.pyimport json from typing import Any, Dict, List from agent.plugin_base import Plugin from agent.registry import PluginRegistry class Agent: def __init__( self, registry: PluginRegistry, llm_plugin: Plugin, max_steps: int 5, ) - None: self.registry registry self.llm llm_plugin self.max_steps max_steps def _build_system_prompt(self) - str: tool_lines [] for plugin in self.registry.all(): if plugin.name deepseek_llm: continue tool_lines.append(f- {plugin.name}: {plugin.description}) tool_text \n.join(tool_lines) return f你是一个运行在插件化框架中的 Agent。 当需要调用工具完成用户请求时必须输出如下 JSON不要输出其他内容 {{tool_name: 工具名, args: {{参数: 值}}}} 当已经拿到工具结果并可以回答用户时输出如下 JSON {{finish: true, content: 回答内容}} 不需要调用工具时直接输出 {{finish: true, content: 你的回答}} 可用工具 {tool_text} def run(self, user_message: str) - Dict[str, Any]: messages [{role: user, content: user_message}] system_prompt self._build_system_prompt() for step in range(1, self.max_steps 1): response self.llm.execute( context{}, messagesmessages, system_promptsystem_prompt, ) if response.get(finish): return { answer: response.get(content, ), steps: step, } tool_name response.get(tool_name) args response.get(args, {}) if not tool_name: return {answer: 模型没有给出有效工具调用, steps: step} tool self.registry.get(tool_name) tool_result tool.execute(context{}, **args) messages.append( { role: tool, content: json.dumps(tool_result, ensure_asciiFalse), } ) raise RuntimeError(agent reached max steps)这里刻意简化了模型输出解析没有直接接厂商的 function calling 能力。这样做的原因是先让人人都能跑通循环再切换成更严格的工具调用协议。3.4 编写两个简单工具插件先写一个计算器插件plugins/calculator.pyfrom agent.plugin_base import Plugin class CalculatorPlugin(Plugin): name calculator description 适合做四则运算输入示例expression1 2 * 3 version 0.1.0 def execute(self, context, expression: str ): try: # 仅用于演示不要在生产环境直接使用 eval result eval(expression, {__builtins__: {}}, {}) return {status: ok, expression: expression, result: result} except Exception as exc: return {status: error, error: str(exc)}再写一个获取当前时间的插件plugins/current_time.pyfrom datetime import datetime from agent.plugin_base import Plugin class CurrentTimePlugin(Plugin): name current_time description 获取当前系统时间不需要额外参数 version 0.1.0 def execute(self, context): return { status: ok, now: datetime.now().isoformat(), }这两个插件虽然简单但已经能验证插件加载、注册、调度、结果回传这些核心链路。4. 编写模型插件把 DeepSeek API 接入 Agent工具插件解决了“能做什么”模型插件解决“怎么决策”。在插件化架构里DeepSeek 也是其中一个插件。4.1 使用 OpenAI 兼容接口封装 LLM 插件DeepSeek API 支持 OpenAI 兼容的接口格式。为降低 SDK 依赖下面直接用requests封装。创建plugins/deepseek_llm.pyimport json import os import requests from agent.plugin_base import Plugin DEFAULT_API_URL https://api.deepseek.com/chat/completions DEFAULT_MODEL deepseek-chat class DeepSeekLLMPlugin(Plugin): name deepseek_llm description DeepSeek 大模型插件用于对话和决策 version 0.1.0 def __init__(self, api_key: str None, model: str DEFAULT_MODEL): self.api_key api_key or os.getenv(DEEPSEEK_API_KEY) if not self.api_key: raise RuntimeError(DEEPSEEK_API_KEY not found) self.model model self.api_url os.getenv(DEEPSEEK_API_URL, DEFAULT_API_URL) def execute(self, context, messages, system_prompt: str ): payload { model: self.model, messages: [ {role: system, content: system_prompt}, *messages, ], temperature: 0.2, max_tokens: 1024, } headers { Authorization: fBearer {self.api_key}, Content-Type: application/json, } response requests.post( self.api_url, jsonpayload, headersheaders, timeout30, ) response.raise_for_status() data response.json() content data[choices][0][message][content] return self._parse_content(content) def _parse_content(self, content: str): try: return json.loads(content) except json.JSONDecodeError: return { finish: True, content: content, }这个封装有几个需要解释的点temperature设置为 0.2是为了让模型在“输出 JSON 指令”这种场景下更稳定。如果做创意写作可以把温度调高。_parse_content优先把模型输出解析为 JSON。如果模型没有按约定输出 JSON就把它当成普通回答。把 API Key 放在请求头中而不是拼进 URL避免日志里泄露密钥。4.2 关键参数和语义接入大模型插件时以下参数需要真正理解而不是简单抄配置。参数含义常见值调大的影响调小的表现temperature采样随机性0.2 到 0.8回答更多样但不稳定更确定适合工具调用max_tokens单次输出最大 token 数512 到 2048能输出更长内容增加成本输出可能被截断top_p核采样保留概率0.7 到 1.0增大候选范围输出更集中timeoutHTTP 请求超时时间10 到 60 秒减少误报超时但用户等待时间长快速失败但容易误判对于 Agent 场景通常建议temperature控制在 0.2 以下max_tokens根据工具参数复杂度设置。如果max_tokens太小模型可能在输出 JSON 指令时被截断Agent 会误以为没有工具调用。4.3 工具调用结果为什么统一返回 JSON工具插件的execute方法返回字典最终转成 JSON 字符串追加到消息列表里。这样做的原因是模型对结构化文本的理解更稳定。如果在插件里返回普通字符串比如计算结果: 7模型可能不理解这是成功还是失败。如果统一返回{status: ok, result: 7}模型就能根据status判断是否继续下一次工具调用。这个约定看起来简单但它决定了 Agent 多轮调度的稳定性。插件作者应该把“结果状态”和“具体数据”分开让模型和宿主都能快速判断下一步动作。5. 运行验证观察插件加载和调度过程完成了框架、工具插件和模型插件后现在启动一个最小入口验证整个链路。5.1 启动 Agent 并输出回答创建main.pyimport os from agent.agent import Agent from agent.plugin_loader import load_plugins_from_dir from agent.registry import PluginRegistry def main(): plugin_dir os.getenv(PLUGIN_DIR, plugins) plugins load_plugins_from_dir(plugin_dir) registry PluginRegistry() llm_plugin None for plugin in plugins: registry.register(plugin) if plugin.name deepseek_llm: llm_plugin plugin if llm_plugin is None: raise RuntimeError(deepseek_llm plugin not found) agent Agent( registryregistry, llm_pluginllm_plugin, max_stepsint(os.getenv(MAX_STEPS, 5)), ) result agent.run(请帮我计算 (2 3) * 4 等于多少并告诉我当前时间。) print(answer:, result[answer]) print(steps:, result[steps]) if __name__ __main__: main()启动命令source venv/bin/activate python main.py正常情况下程序会输出类似下面的结果answer: (2 3) * 4 20。当前时间是 2025-01-01T10:00:00。 steps: 3steps为 3说明模型先决定调用计算器再决定调用时间插件最后回答用户。当然具体轮数会随模型输出变化但只要不是直接回答就说明调度链路已生效。5.2 观察注册表和调度日志如果启动时没有输出任何插件加载信息可以先在main.py里临时打印注册表for name in registry.all(): print(f[registry] plugin {name.name} loaded)也可以给插件加载器加一行调试日志print(f[loader] found {len(classes)} plugin class(es) in {file_path.name})这样能确认插件扫描是否正常。常见的失败原因是plugins目录路径不对或者插件类重名导致注册失败。5.3 验证异常分支工具调用并不总是成功。以计算器插件为例如果用户让 Agent 计算1/0插件会返回status: errorAgent 会把错误结果回传给模型模型应当根据错误信息给出说明而不是直接崩溃。可以在main.py中用下面的输入验证result agent.run(请计算 1/0如果失败请告诉我计算错误的原因。)如果 Agent 的设计合理最终回答应该类似计算失败因为除数不能为 0。这一步验证的是错误信息能不能在“模型-宿主-工具”三个角色之间正确传递而不仅仅是代码不抛异常。6. 从 Demo 到生产插件隔离、版本与可观测性演示项目的设计目标是打通链路。生产环境如果把插件目录扫描、eval计算、无约束 HTTP 请求直接搬上去会带来一系列稳定性问题。6.1 隔离和安全边界插件代码本质上是可执行代码。插件可以读取文件、发送请求、访问数据库如果插件来源不可信Agent 的权限边界就形同虚设。生产环境中建议做以下几层隔离插件来源只加载经过审查的插件目录不允许普通用户上传 Python 文件。进程隔离把高危插件放到独立进程或子进程中执行崩溃后不影响 Agent 主进程。权限控制为插件设置运行身份、网络白名单、文件系统白名单。工具参数校验计算器示例中的eval只能用于演示生产环境应使用安全解析器例如ast结合白名单函数。需要特别注意不要因为配置了allow_remote_tools: false就以为所有插件都安全。插件可以自行发 HTTP 请求配置项只能约束宿主默认行为完整的权限控制必须在插件执行前接管。6.2 插件版本与热更新插件越来越多后版本管理会成为新的问题。插件 A 的更新可能影响 Agent 对插件 B 的调用顺序。生产环境建议给注册表加入版本信息{ name: calculator, version: 1.2.0, dependencies: [], entrypoints: [CalculatorPlugin] }如果需要热更新流程不能简单粗暴地替换文件。推荐先加载到临时目录校验插件版本和依赖后再更新注册表更新失败时自动回滚到上一版本。没有热更新需求时插件随 Agent 进程一起发版更稳妥。6.3 可观测性与评估Agent 是典型的异步编排系统一次用户请求会产生多条模型调用、多个工具调用。生产环境至少需要记录每一轮 Prompt 的 input 和 output。模型选择了哪个工具传入了什么参数。工具返回的状态和耗时。异常发生时错误堆栈和当前消息上下文。有了这些痕迹才能回答“为什么 Agent 这次回答错了”。同时要建立评估集比如 100 条标准问题每次插件版本更新后跑一遍回归比较回答质量和步骤数是否退化。下面的表格可以帮助对比学习环境和生产环境的差异能力项学习 Demo生产 Agent配置环境变量配置中心 密钥管理插件来源本地目录私有制品仓库 签名权限控制无网络/文件/进程白名单日志print结构化日志 链路追踪模型调用固定参数按场景动态调整异常处理抛异常重试、回退、告警工具执行同进程可独立进程隔离7. 常见问题排查安装、加载和调用失败插件化 Agent 的报错往往不是集中在某个文件里而是分散在“加载、注册、调用、模型解析”这四个环节。建议按链路倒查。7.1 插件目录扫不到插件现象启动时注册表为空模型直接回答“我无法使用工具”。可能原因PLUGIN_DIR路径配置错误。插件文件中不是Plugin子类。子类没有继承相同模块下的基类导致__module__判断失败。插件初始化抛异常被加载器吞掉。检查方式python -c from agent.plugin_loader import load_plugins_from_dir; print(load_plugins_from_dir(plugins))如果返回空列表先检查文件后缀是不是.py再检查类是否真的有name和execute方法。可以把加载器里的except改为完整堆栈打印避免异常被静默吞掉。7.2 DeepSeek API 鉴权失败或超时现象调用deepseek_llm时抛出HTTPError或 Agent 一直卡在等待模型返回。常见原因环境变量未加载api_key为None。.env文件没有使用dotenv加载。请求timeout太短模型生成长回答时超时。API URL 配置错误。检查顺序确认.env里DEEPSEEK_API_KEY有值。在main.py最前面添加from dotenv import load_dotenv; load_dotenv()。打印请求 payload 的model和messages确认没有把密钥误发到日志。手工用curl或 Python 脚本发一次请求确认网络可达。生产环境建议把timeout拆成连接超时和读取超时例如requests.post(..., timeout(5, 60))避免网络抖动时直接拖死 Agent。7.3 插件执行异常导致 Agent 卡死现象模型已经决定调用某个工具但工具内部报错后 Agent 没有继续回答反而在下一轮反复调用同一个工具。原因插件没有捕获异常execute直接抛错。Agent 循环没有捕获插件异常导致整个请求中断。工具返回的错误信息太模糊模型无法判断应该放弃。解决方案插件内部捕获所有异常并返回{status: error, ...}。Agent 循环对registry.get(tool_name)和tool.execute加异常捕获。工具描述里写清楚输入限制例如“当表达式非法时返回 status error”。在 Agent 循环中记录“同一工具连续 N 次失败”的计数器超过阈值后直接终止多步调用。问题现象可能原因检查方式处理建议插件列表为空路径错误或类不是 Plugin 子类打印加载器返回值修正插件目录和类定义API 鉴权失败API Key 未加载或过期检查环境变量和请求头使用密钥管理服务注入模型不调用工具系统 Prompt 中工具描述不清晰打印完整 Prompt补充工具使用示例工具反复调用失败异常被吞或模型无法从错误恢复查看工具错误返回值插件返回结构化错误并增加连续失败上限插件重名导致注册失败不同文件出现相同 name查看注册异常日志建立插件命名规范8. 最佳实践如何把插件化 Agent 做成可维护工程最后落回工程实践。插件化 Agent 的优势不是“目录好看”而是“可以增量演化和分工协作”。要发挥这个优势需要把规范立起来。8.1 插件命名、元信息和接口版本插件命名建议使用小写字母加下划线例如calculator、http_get、memory_redis。每个插件应当声明唯一名称。语义化版本号。用途描述。依赖的外部资源。需要的最小权限。接口版本是经常被忽略的一项。当Plugin.execute的参数从(**kwargs)变化时旧插件会静默出错。建议在注册表里记录接口版本号并在加载时做兼容性检查。PLUGIN_INTERFACE_VERSION 1.0 class Plugin(ABC): interface_version: str PLUGIN_INTERFACE_VERSION如果插件声明的interface_version与宿主不一致直接拒绝加载。这个检查能在插件数量很多时避免“上线后才发现某个插件不兼容”的尴尬。8.2 错误处理、重试和回退Agent 的错误处理不能只看单个插件是否成功还要考虑整条任务链。推荐按以下优先级设计插件层内部捕获异常返回结构化错误。Agent 层捕获插件调度异常把错误追加到消息列表让模型根据错误信息调整计划。应用层对模型 API 调用做重试重试间隔使用指数退避。用户层达到最大步数或连续失败次数后明确返回“任务未完成”不要硬生成答案。回退策略也很重要。如果deepseek-chat不可用可以回退到兼容模型如果高级工具不可用可以降级到基础工具。但回退逻辑也必须作为插件配置的一部分记录下来方便审计。8.3 复用检查清单在把插件化 Agent 发布到测试或生产环境前建议核对下面的清单插件目录是否只包含经过审查的插件没有临时文件或调试文件。是否已检查插件重名、接口版本不匹配等问题。是否配置了插件运行权限白名单包括文件、网络、进程。模型插件是否支持超时、重试和错误回传。工具插件是否统一返回结构化结果并标记status。Agent 是否设置了最大步数和连续失败上限。是否记录模型请求、工具调用、错误堆栈的完整日志。是否准备好回归评估集插件更新后可以自动执行。是否保留上一版本插件目录支持一键回滚。是否确认.env和密钥不会进入 Git 仓库。插件化 Agent 的真正价值在于模型会更新工具会变化业务需求会调整但宿主框架可以保持稳定。DeepSeek 官方开源框架把“一切皆插件”作为设计范式也是在提醒开发者用组合思维构建智能体而不是把每个能力都写成主流程里的一个分支。下一步可以继续做的事情包括把插件加载器改成支持 ZIP 插件包和签名校验把工具调度从 JSON 指令切换成厂商原生 function calling再为插件执行加入链路追踪和评估看板。先把最小闭环跑通再按照生产环境清单逐步加固这种推进方式对 Agent 项目同样适用。
返回列表