news 2026/10/14 2:26:03

FIT 框架 FEL 工具调用机制实战:从 Pattern 委托到插件化工具编排

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
FIT 框架 FEL 工具调用机制实战:从 Pattern 委托到插件化工具编排
  • 人工智能
  • 大模型
  • AI 应用
  • 后端
  • AI Agent
  • RAG
  • 流程编排
  • 微服务

【免费下载链接】fit-framework

FIT: 企业级AI开发框架,提供多语言函数引擎(FIT)、流式编排引擎(WaterFlow)及Java生态的LangChain替代方案(FEL)。原生/Spring双模运行,支持插件热插拔与智能聚散部署,无缝统一大模型与业务系统。

项目地址:https://gitcode.com/ModelEngine/fit-framework
点击查看免费下载

导读

本文聚焦 FIT 框架中 FEL(Framework for Engineering LLM)的**工具调用(Tool Calling)**能力。大模型受限于训练知识截止时间,无法获取实时数据、执行精确计算或访问外部系统,而 FEL 通过两套互补机制解决这一短板:一是基于Pattern委托单元的代理模式,让开发者以最小代码把任意业务逻辑(如天气查询、计算、数据库访问)接入 AI 流程;二是基于 FIT 插件体系的工具插件化方案,通过@ToolMethod注解、编译期tools.json清单生成和运行期插件热插拔,实现工具的自动发现、大模型自主选择与统一执行。读完本文,你将掌握 FEL 中两种工具接入方式的工作原理、核心源码结构以及可运行的完整示例。

为什么大模型需要工具调用

大模型在语言生成与理解上能力极强,但在以下场景中必须借助外部工具才能给出可靠答案:

  1. 获取最新信息:模型训练数据存在知识截止时间,无法提供实时数据;通过调用浏览器或 API,可查询最新事件与动态数据。
  2. 精确计算:模型虽可做简单数学推理,却不擅长精确或复杂的数值运算,调用计算工具更可靠。
  3. 数据库/知识库查询:通过工具连接外部数据库、知识库或搜索引擎,查询结构化数据或更准确的答案。
  4. 多步逻辑推理:部分任务涉及多步骤推理、算法应用或代码执行,可调用专门程序完成。

FEL-Flow 提供两种接入方式(见 fel-flow 模块 README 中的核心特点说明):

  • 委托机制Pattern:在 AI 流程中插入一个委托节点,把输入数据交给外部函数处理后回流到流程中;
  • 预定义工具调用的流程编排:将工具封装为 FIT 插件,由大模型在运行时自主选择工具,通过流程编排轻松调用多个工具完成复杂任务(如多智能体互通)。

委托机制:用 Pattern 把任意逻辑接入 AI 流程

委托机制本质上是一种代理模式:大模型(或流程本身)根据任务内容与输入信息,自动识别需要调用的工具并将任务分配出去。其工作流程分三步:

  1. 输入解析和识别任务:模型分析用户输入上下文,判断是否需要外部工具协助(如检测到时间敏感信息、复杂计算等)。
  2. 工具选择和调用:模型通过预定义策略或规则选择合适的工具。常见工具包括 API 工具(浏览器、数据库查询接口、天气预报 API)、计算工具(计算器或数据处理工具)以及嵌入模型(文本检索或搜索工具)。
  3. 执行任务和结果返回:工具完成任务并返回结果,模型将结果整合进原始任务并反馈给用户。

Pattern 与 SimplePattern:委托单元的源码剖析

Pattern是 FEL 定义的委托单元接口,<I>表示输入数据类型,<O>表示输出数据类型。其定义位于 Pattern.java:

public interface Pattern<I, O> { O invoke(I input); }

SimplePattern是该接口的简单实现,位于 SimplePattern.java。它通过运行时传入的Function<I, O>(即文档中的func)实现动态行为委托——不直接定义具体逻辑,而是接受外部传入的函数逻辑,因此非常灵活:

public class SimplePattern<I, O> implements Pattern<I, O> { private final Function<I, O> func; public SimplePattern(Function<I, O> func) { this.func = Validation.notNull(func, "The action function cannot be null."); } @Override public O invoke(I input) { Validation.notNull(input, "The input data cannot be null."); return this.func.apply(input); } }

从源码可见两个关键约束:构造函数与invoke方法均通过Validation.notNull做了空值校验,分别保证委托函数和输入数据不为空。这是 FEL 对Pattern输入输出契约的强制要求。

delegate 操作:把 Pattern 编排进 AI 流程

SimplePattern要真正参与 AI 应用,需要通过 FEL-Flow 的delegate操作挂载到流程上。AiStart.java 中的实现说明了委托节点的语义:

/** * 将数据委托给 {@link Pattern}{@code <}{@link O}{@code , }{@link R}{@code >} * 处理,然后自身放弃处理数据。处理后的数据会发送回该节点,作为该节点的处理结果。 */ public <R> AiState<R, D, O, RF, F> delegate(Pattern<O, R> pattern) { Validation.notNull(pattern, "Pattern operator cannot be null."); return this.delegate(new SimpleFlowPattern<>(pattern)); }

即delegate节点接收上游数据,交给Pattern处理后把结果发送回流程继续流转。除了接收Pattern,delegate还有多个重载:委托给Operators.ProcessMap(在独立线程池执行,适合 IO 密集型任务)、委托给子流程AiProcessFlow,甚至可以从子流程的指定节点开始处理(delegate(AiProcessFlow, nodeId))。这为"预定义工具调用流程"提供了基础。

对应的单元测试见 PatternTest.java,其中shouldOkWhenDelegateSimplePattern验证了"prompt → delegate(pattern) → close → converse → offer"的完整链路:

SimplePattern<Prompt, String> pattern = new SimplePattern<>(prompt -> { String inputContextValue = AiFlowSession.get() .map(target -> ObjectUtils.<String>cast(target.getState(key))) .orElse(StringUtils.EMPTY); return prompt.text() + inputContextValue; }); ConverseLatch<String> offer = AiFlows.<Tip>create() .prompt(Prompts.human("{{0}}")) .delegate(pattern) .close() .converse(session) .offer(Tip.fromArray("human msg.")); String result = offer.await(); assertThat(result).isEqualTo("human msg." + value);

测试还展示了Pattern可以通过AiFlowSession访问流程会话上下文(session.getState(key)),说明委托单元并非孤立的黑盒,而是可以与Conversation绑定数据交互。

委托示例:天气查询

以下代码创建一个简单的委托Pattern:用户输入位置信息,将调用委托给WeatherTool获取天气,输出该位置的天气信息:

WeatherTool weatherTool = new WeatherTool(); SimplePattern<Prompt, String> pattern = new SimplePattern<>(prompt -> { String userInput = prompt.text(); String location = getLocation(userInput); if (location != null && !location.isEmpty()) { return weatherTool.getWeather(location); } else { return "Sorry, I couldn't identify the location."; } }); // 模型会话流程定义 AiFlows.<Tip>create() .prompt(Prompts.human("{{0}}")) // 以用户输入作为prompt .delegate(pattern) // 使用定义好的pattern进行委托调用 .close() .converse(session) // 开始对话 .offer(Tip.fromArray("Can you tell me the weather in Paris?")) // 模拟输入 .await(); // 等待结果输出

流程节点依次为:prompt(将用户输入包装为提示词)→delegate(pattern)(调用天气工具)→close(终止)→converse(建立会话)→offer(注入输入)→await(阻塞等待结果)。

工具插件:基于 FIT 插件化的工具发现与执行

当工具数量增多、需要被大模型自主调度时,委托机制就显得不够体系化。FEL-Flow 通过FIT 插件将工具封装为插件,利用 FIT 插件化的优势支持工具的热插拔,并监听所有插件的加载和卸载。整个链路分为"插件扫描"与"插件选择和执行"两个阶段。

阶段一:插件扫描(编译期生成 tools.json)

FEL-Flow 提供一个 Maven 插件(tool-maven-plugin,源码位于 tool-maven-plugin 模块),在编译期间扫描所有 Tool class 文件。其工作方式为:

  1. 开发者在工具方法上使用注解@ToolMethod描述工具,包括命名空间、工具名称、描述、方法参数等信息(注解定义见 ToolMethod.java)。
  2. 编译期由GroupPluginCompiler(见 GroupPluginCompiler.java)驱动ByteBuddyGroupParser解析 class 文件中@ToolMethod注解,生成ToolEntity列表,最终输出工具清单文件tools.json(默认文件名常量见 ToolSchema.java 中的TOOL_MANIFEST = "tools.json")。

@ToolMethod注解的核心属性如下:

属性类型默认值说明
namespaceString"Common"工具的命名空间,工具名在命名空间内需唯一
nameString无(必填)工具方法名
descriptionString空字符串工具方法描述,供大模型理解工具用途
extraParamsString[]{}工具的额外参数名
returnConverterString空字符串输出转换器工具方法
extensionsAttribute[]{}工具方法的扩展属性(键值对)

其中Attribute注解(见 Attribute.java)由key()和value()组成。而方法参数的语义描述(参数名、描述、是否必填、默认值、样例值)由 FIT 框架的@Property注解提供(见 Property.java)。

tools.json的反序列化结构由 ToolJsonEntity.java 定义:包含version、definitionGroups(定义组)和toolGroups(工具组);每个工具由 ToolEntity.java 表示,携带namespace、schema(含名称、描述、参数、顺序、返回值、参数扩展等)、runnables、extensions和tags。

阶段二:插件选择和执行(运行期)

应用启动后:

  1. 解析清单入仓库:DefaultToolDiscoverer(见 DefaultToolDiscoverer.java)实现了 FIT 的PluginStartedObserver与PluginStoppingObserver,在插件加载/卸载时扫描插件资源中的tools.json,将ToolEntity转成ToolInfoEntity注册进ToolRepository(加载时调用addTool,卸载时调用deleteTool)。它同时受tool.max-num配置约束,限制单插件可注册的工具数量。
  2. 工具仓库:默认实现SimpleToolRepository(见 SimpleToolRepository.java)以ConcurrentHashMap缓存工具,用ToolInfo.identify(namespace, name)生成的namespace:name唯一标识(见 ToolInfo.java),并在工具增删时通知ToolChangedObserver观察者。
  3. 模型选择工具:应用把用户请求和可用工具列表(toolRepository.listTool(namespace))通过ChatOption.tools(...)传给大模型(tools字段定义见 ChatOption.java),模型返回要调用的工具。
  4. 执行工具:DefaultToolExecutor(见 DefaultToolExecutor.java)根据返回的namespace:name从仓库取出工具,通过ToolFactoryRepository匹配runnables类型对应的工厂创建Tool实例,再调用executeWithJson/executeWithJsonObject执行并返回结果。工具工厂按类型注册(DefaultToolFactoryRepository见 DefaultToolFactoryRepository.java),例如FitToolFactory负责把@Genericable定义的 FIT 函数封装为工具(见 FitToolFactory.java)。

完整可运行示例:天气助手 Agent

仓库中的 06-agent 示例 完整演示了"插件化工具 + Agent 自主调度"的用法。示例定义一个天气助手,将两个 FIT 函数get_current_temperature和get_rain_probability作为助手可调用的工具。

步骤 1:引入依赖。除fit-starter、fel-core、fel-flow、fel-model-openai-plugin外,还需引入工具相关的插件与服务依赖:

<!-- 工具自动发现服务 --> <dependency> <groupId>org.fitframework</groupId> <artifactId>fel-tool-discoverer</artifactId> <version>${fel.version}</version> </dependency> <!-- 工具执行服务 --> <dependency> <groupId>org.fitframework</groupId> <artifactId>fel-tool-executor</artifactId> <version>${fel.version}</version> </dependency> <!-- Fit 工具工厂 --> <dependency> <groupId>org.fitframework</groupId> <artifactId>fel-tool-factory-fit</artifactId> <version>${fel.version}</version> </dependency> <!-- 工具工厂存储 --> <dependency> <groupId>org.fitframework</groupId> <artifactId>fel-tool-factory-repository</artifactId> <version>${fel.version}</version> </dependency> <!-- 工具存储 --> <dependency> <groupId>org.fitframework</groupId> <artifactId>fel-tool-repository-simple</artifactId> <version>${fel.version}</version> </dependency>

同时在<plugins>中加入工具编译插件tool-maven-plugin,绑定build-toolgoal 于 compile 阶段(对应 BuildGroupPluginMojo.java 中的@Mojo(name = "build-tool", defaultPhase = LifecyclePhase.COMPILE))。

步骤 2:配置模型参数(application.yml):

fel: openai: api-base: '${api-base}' api-key: '${your-api-key}' example: model: '${model-name}'

步骤 3:定义工具。接口使用@Genericable声明可服务化的方法:

public interface WeatherService { @Genericable("modelengine.example.weather.temperature") String getCurrentTemperature(String location, String unit); @Genericable("modelengine.example.weather.rain") String getRainProbability(String location); }

实现类通过@ToolMethod提供工具元数据,通过@Property描述参数:

@Component public class WeatherServiceImpl implements WeatherService { @Override @Fitable("default") @ToolMethod(namespace = "example", name = "get_current_temperature", description = "获取指定城市的当前温度") public String getCurrentTemperature(@Property(description = "城市名称", required = true) String location, @Property(description = "使用的温度单位,可选:Celsius,Fahrenheit", defaultValue = "Celsius") String unit) { return "26"; } @Override @Fitable("default") @ToolMethod(namespace = "example", name = "get_rain_probability", description = "获取指定城市下雨的概率") public String getRainProbability(@Property(description = "城市名称", required = true) String location) { return "0.06"; } }

步骤 4:使用默认 Agent 调度。AgentExampleController.java 构建了DefaultAgent并把它作为Pattern通过delegate挂进 AI 流程:

DefaultAgent agent = new DefaultAgent(new ChatFlowModel(chatModel, this.chatOption), "example", toolExecuteService); this.agentFlow = AiFlows.<String>create() .map(query -> Tip.fromArray(query)) .prompt(Prompts.human("{{0}}")) .delegate(agent) .close();

请求处理时,把toolRepository.listTool("example")得到的工具列表绑定进会话,模型即可在对话中自主选择工具:

@GetMapping("/chat") public ChatMessage chat(@RequestParam("query") String query) { List<ToolInfo> toolInfos = asParent(toolRepository.listTool("example")); return this.agentFlow.converse() .bind(ChatOption.custom(this.chatOption).tools(toolInfos).build()) .offer(query) .await(); }

DefaultAgent的内部实现(见 DefaultAgent.java)与基类 AbstractAgent.java 揭示了 Agent 的循环调度逻辑:模型输出若包含工具调用(ChatMessage::isToolCall),则把toolCalls交给doToolCall执行(DefaultAgent通过ToolExecuteService按命名空间执行工具并封装为ToolMessage),再把工具结果合并进记忆后跳回检查点CHECK_POINT重新调用模型,直到模型输出不含工具调用为止。这正是"大模型选择工具 → 应用执行工具 → 结果回填 → 再次调用模型"闭环的源码级体现。

验证:启动应用后访问http://localhost:8080/ai/example/chat?query=北京下雨的概率是多少,得到:

{ "content": "北京下雨的概率是6%。", "toolCalls": [] }

可以看到大模型根据工具返回的原始概率数据("0.06")进行了自然语言回答。

总结

FEL 的工具调用能力覆盖了两类典型诉求:

  • 轻量、确定性的工具接入:使用SimplePattern把任意Function封装为委托单元,通过delegate操作嵌入 AI 流程,适合逻辑固定、无需模型决策的调用场景;
  • 动态、模型驱动的工具编排:通过@ToolMethod注解 +tool-maven-plugin编译期扫描生成tools.json,运行期由DefaultToolDiscoverer随插件热插拔注册/注销工具,ToolRepository统一管理,DefaultAgent与ToolExecuteService完成"模型选工具—执行—回填"的循环调度,适合需要大模型自主决策、多工具协作乃至多智能体互通的复杂场景。

两种机制共享同一套Pattern抽象与 FEL-Flow 流程编排底座,开发者可根据业务对"确定性"与"智能性"的需求灵活选用。

  • 人工智能
  • 大模型
  • AI 应用
  • 后端
  • AI Agent
  • RAG
  • 流程编排
  • 微服务

【免费下载链接】fit-framework

FIT: 企业级AI开发框架,提供多语言函数引擎(FIT)、流式编排引擎(WaterFlow)及Java生态的LangChain替代方案(FEL)。原生/Spring双模运行,支持插件热插拔与智能聚散部署,无缝统一大模型与业务系统。

项目地址:https://gitcode.com/ModelEngine/fit-framework
点击查看免费下载

相关推荐

上一篇:5大亮点揭秘:这款开源社交平台为何值得关注?
下一篇:Umi-OCR:免费离线OCR软件的完整解决方案

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

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/14 2:26:00

SageMaker上KV Cache复用实战:缓存命中与性能调优

KV Cache复用这个概念&#xff0c;我最早看到时觉得没什么技术含量&#xff1a;既然计算过的键值对可以缓存&#xff0c;那就放起来给下次用&#xff0c;省一遍前向计算而已。真到Amazon SageMaker上做LLM推理优化&#xff0c;才发现这里面的“复用”二字藏着很多前置条件&…

作者头像 李华
网站建设 2026/10/14 2:25:58

联邦学习遇上区块链:破解跨机构数据协作的信任与激励难题

最近跟一位做跨机构数据协作的朋友聊到深夜&#xff0c;他反复念叨一件事&#xff1a;手里攒了一批高价值标注数据&#xff0c;想和另一家机构联合训练行业模型&#xff0c;双方都认可模型的价值&#xff0c;却在信任环节彻底卡死——怕上传的梯度被服务器留存&#xff0c;怕对…

作者头像 李华
网站建设 2026/10/14 2:25:52

【单片机课设毕设项目】基于51单片机的智能洗衣机预约与多模式控制系统设计 基于单片机的洗衣机多模式洗衣流程自动控制装置设计(032801)

博主介绍&#xff1a;✌️码农一枚 &#xff0c;专注于大学生项目实战开发、讲解和毕业&#x1f6a2;文撰写修改等。全栈领域优质创作者&#xff0c;博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于嵌入式单片机&#xff0c;Java、小程序技术领域和毕业项目实战 ✌️…

作者头像 李华
网站建设 2026/10/14 2:25:06

Cisco交换机路由器命令行实战:从Packet Tracer入门到排错命令详解

学网络的朋友&#xff0c;十个有九个是用Cisco Packet Tracer入的门。这工具看起来简单&#xff0c;真想把指令玩明白&#xff0c;却得靠长期积累。我最早啃CCNA的时候&#xff0c;就在Packet Tracer里敲了不知多少遍命令&#xff0c;后来干脆把常用指令整理成笔记&#xff0c;…

作者头像 李华
网站建设 2026/10/14 2:24:39

Agent 查数据库:自然语言问句怎么变成 SQL

说明&#xff1a;本文讨论的是把自然语言问句接进业务数据库、由模型生成可执行 SQL 的工程约束&#xff0c;属于 Agent 工程落地话题&#xff0c;不涉及具体模型版本与价格。AI 领域版本迭代极快&#xff0c;凡涉及版本号、价格、可用性&#xff0c;请以你阅读时的官方页面为准…

作者头像 李华