杠精派
派聪明
0/512

热门评论

123. 2026年03月25日 19:38
引用原文:我们项目里的 PluginNode 也是类似的思路,但我们是自己解析大模型的输出来决定调用哪个工具,没有直接用 Spring AI 的 Function Calling。
@派聪明 具体是怎么解析的?
点赞
回复1 取消回复
派聪明 2026年03月25日 19:39
根据参考资料中提到的,你们项目里的 PluginNode 是自己解析大模型的输出来决定调用哪个工具,而不是直接使用 Spring AI 的 Function Calling。虽然没有详细的解析实现代码,但通常这类自定义工具调用解析的实现思路如下: ### 解析流程 1. **识别工具调用标记** - 检测大模型输出中是否包含特定的工具调用标记,如 JSON 结构、特殊标记或特定格式的文本 - 例如:`{"function": "getWeather", "parameters": {"city": "北京"}}` 2. **提取函数名和参数** - 使用正则表达式或 JSON 解析器从输出中提取函数名和参数 - 例如:从上述 JSON 中提取出函数名 "getWeather" 和参数 {"city": "北京"} 3. **匹配工具实现** - 根据函数名在预注册的工具列表中查找对应的实现 - 例如:找到之前注册的天气查询工具 4. **执行工具并返回结果** - 调用匹配到的工具,传入解析出的参数 - 将工具执行结果格式化后返回给大模型,让它生成最终回答 ### 可能的实现代码示例 ```java public class ToolCallParser { private Map<String, Function> toolRegistry = new HashMap<>(); // 注册工具 public void registerTool(String name, Function tool) { toolRegistry.put(name, tool); } // 解析并执行工具调用 public String parseAndExecute(String llmOutput) { // 1. 检测是否包含工具调用 if (!llmOutput.contains("function_call")) { return llmOutput; // 没有工具调用,直接返回 } // 2. 提取函数调用信息(简化示例) String functionName = extractFunctionName(llmOutput); Map<String, Object> params = extractParameters(llmOutput); // 3. 查找并执行工具 Function tool = toolRegistry.get(functionName); if (tool != null) { Object result = tool.apply(params); return "工具调用结果:" + result.toString(); } return "未找到工具: " + functionName; } // 其他解析方法... } ``` 这种自定义实现方式相比 Spring AI 的 Function Calling 更加灵活,可以根据项目特定需求定制解析逻辑,但也需要自己处理更多的细节,如错误处理、参数验证等。
点赞
回复 取消回复

4 条评论

fang jing wei 2026年03月30日 19:06
引用原文:业务层完全感知不到底层是哪家,换模型只需要改 provider 参数,业务逻辑一行不用动。
@派聪明 将这三部总结一下,面试如何把这个讲清楚
点赞
回复1 取消回复
派聪明 2026年03月30日 19:08
以下是对Spring AI统一抽象模型切换三步法的面试总结,清晰呈现核心逻辑: --- ### **三步实现模型统一切换** #### **1. 定义统一接口,屏蔽底层差异** ```java public interface LLMClient { LLMResponse chat(LLMRequest request); // 统一请求/响应格式 } ``` - **目的**:业务层只依赖接口,不关心具体厂商(OpenAI/DeepSeek/智谱等) - **关键**:统一`LLMRequest`/`LLMResponse`结构,隐藏各厂商API格式差异(如认证方式、请求字段) #### **2. 实现各厂商适配器** ```java @Component public class DeepSeekAdapter implements LLMClient { @Override public LLMResponse chat(LLMRequest request) { // ① 转换请求格式(适配DeepSeek协议) // ② 调用DeepSeek API // ③ 转换响应格式 } } ``` - **核心**:每个厂商独立实现适配器,处理协议转换(如DeepSeek兼容OpenAI格式,智谱需JWT签名) - **扩展性**:新增模型只需实现新适配器,无需修改业务代码 #### **3. 工厂动态选择适配器** ```java @Component public class LLMClientFactory { private final Map<String, LLMClient> clients; public LLMClient getClient(String provider) { return clients.get(provider.toLowerCase()); // 如"deepseek"/"zhipu" } } ``` - **运行时切换**:业务层通过`provider`参数动态选择模型 - **配置驱动**:模型配置(API密钥、BaseURL等)可从数据库/配置中心加载 --- ### **面试表达技巧** #### **1. 用比喻降低理解门槛** > “我们做了一个‘翻译官’层:业务层说中文,适配器翻译成各厂商的‘方言’(API协议)。换模型就像换翻译官,业务方完全不用学新语言。” #### **2. 强调业务价值** - **快速迭代**:新增模型只需2小时(写适配器+配置),无需重构业务代码 - **降本增效**:可低成本测试不同模型效果,优化成本 - **风险隔离**:某厂商故障时,切换provider参数即可切换备用模型 #### **3. 对比传统方案** | 传统方式 | 统一抽象方案 | |----------|--------------| | 每个模型独立SDK | 单一`LLMClient`接口 | | 换模型需改业务代码 | 仅改`provider`参数 | | 代码与厂商强耦合 | 业务层完全解耦 | #### **4. 补充技术亮点** - **注解驱动**:通过`@Description`让LLM理解函数用途(Function Calling场景) - **响应式流式**:用`Flux<ChatResponse>`实现打字机效果,提升用户体验 - **动态配置**:支持运行时切换模型参数(如温度、Token上限) --- ### **总结话术** > “我们通过**接口统一、适配器转换、工厂调度**三步,实现了模型的无感切换。业务层只需关注`provider`参数,底层无论是OpenAI、DeepSeek还是智谱,代码逻辑完全不变。这套设计让模型选型像‘插拔式组件’,支持快速试错和成本优化。”
点赞
回复 取消回复
123. 2026年03月25日 19:38
引用原文:我们项目里的 PluginNode 也是类似的思路,但我们是自己解析大模型的输出来决定调用哪个工具,没有直接用 Spring AI 的 Function Calling。
@派聪明 具体是怎么解析的?
点赞
回复1 取消回复
派聪明 2026年03月25日 19:39
根据参考资料中提到的,你们项目里的 PluginNode 是自己解析大模型的输出来决定调用哪个工具,而不是直接使用 Spring AI 的 Function Calling。虽然没有详细的解析实现代码,但通常这类自定义工具调用解析的实现思路如下: ### 解析流程 1. **识别工具调用标记** - 检测大模型输出中是否包含特定的工具调用标记,如 JSON 结构、特殊标记或特定格式的文本 - 例如:`{"function": "getWeather", "parameters": {"city": "北京"}}` 2. **提取函数名和参数** - 使用正则表达式或 JSON 解析器从输出中提取函数名和参数 - 例如:从上述 JSON 中提取出函数名 "getWeather" 和参数 {"city": "北京"} 3. **匹配工具实现** - 根据函数名在预注册的工具列表中查找对应的实现 - 例如:找到之前注册的天气查询工具 4. **执行工具并返回结果** - 调用匹配到的工具,传入解析出的参数 - 将工具执行结果格式化后返回给大模型,让它生成最终回答 ### 可能的实现代码示例 ```java public class ToolCallParser { private Map<String, Function> toolRegistry = new HashMap<>(); // 注册工具 public void registerTool(String name, Function tool) { toolRegistry.put(name, tool); } // 解析并执行工具调用 public String parseAndExecute(String llmOutput) { // 1. 检测是否包含工具调用 if (!llmOutput.contains("function_call")) { return llmOutput; // 没有工具调用,直接返回 } // 2. 提取函数调用信息(简化示例) String functionName = extractFunctionName(llmOutput); Map<String, Object> params = extractParameters(llmOutput); // 3. 查找并执行工具 Function tool = toolRegistry.get(functionName); if (tool != null) { Object result = tool.apply(params); return "工具调用结果:" + result.toString(); } return "未找到工具: " + functionName; } // 其他解析方法... } ``` 这种自定义实现方式相比 Spring AI 的 Function Calling 更加灵活,可以根据项目特定需求定制解析逻辑,但也需要自己处理更多的细节,如错误处理、参数验证等。
点赞
回复 取消回复

目录