Function Calling 框架对比:LangChain、Semantic Kernel 和自研方案

发布时间:2026/7/30 1:16:05
Function Calling 框架对比:LangChain、Semantic Kernel 和自研方案 Function Calling 框架对比LangChain、Semantic Kernel 和自研方案一、LangChain生态丰富但复杂度高LangChain 是当前最流行的 LLM 应用开发框架之一。自 2022 年推出以来LangChain 迅速成为 AI 应用开发的首选工具GitHub Star 数超过 80k。它提供了丰富的组件和工具支持快速构建 Chatbot、RAG 系统、Agent 等应用。核心优势生态系统完善LangChain 拥有庞大的生态系统包括 LangChain核心库、LangChain-Community社区集成、LangServe部署工具、LangSmith监控调试等。几乎涵盖了 LLM 应用开发的全部环节。组件丰富提供了 LLM、Chat Model、Prompt Template、Memory、Chain、Agent、Tool、Retriever 等完整组件开发者可以像搭积木一样组合出复杂的应用。集成广泛支持几乎所有主流 LLMOpenAI、Anthropic、Hugging Face、本地模型、向量数据库Chroma、Pinecone、Weaviate、Qdrant、Embedding 模型、文档加载器等。社区活跃拥有庞大的开发者社区遇到问题容易找到解决方案。大量教程、博客、视频可供学习。快速原型通过声明式配置如使用LLMChain、ConversationChain可以在几十行代码内实现复杂功能非常适合快速验证想法。主要问题抽象层级过高LangChain 为了通用性引入了大量抽象Chain、Agent、Memory 等。初学者往往会用但不懂遇到问题时难以调试。随着版本迭代API 变化频繁导致代码脆弱。性能开销LangChain 的抽象层引入了额外的性能开销。在高频调用场景下如实时客服响应延迟可能成为瓶颈。过度封装某些功能的实现过于复杂。例如简单的 Function Calling 功能使用 LangChain 可能需要理解 Agent、Tool、Toolkit 等多个概念。文档质量参差不齐核心功能文档完善但部分集成组件的文档简陋甚至缺失。某些示例代码已经过时无法运行。生产 readinessLangChain 适合快速原型但在生产环境中可能需要大量定制和优化。其默认的错误处理、日志记录、监控告警能力有限。# LangChain 示例构建一个简单的 RAG 系统 from langchain.document_loaders import TextLoader from langchain.text_splitter import CharacterTextSplitter from langchain.embeddings import OpenAIEmbeddings from langchain.vectorstores import Chroma from langchain.chains import RetrievalQA from langchain.llms import OpenAI # 1. 加载文档 loader TextLoader(data/company_handbook.txt) documents loader.load() # 2. 文档分块 text_splitter CharacterTextSplitter(chunk_size1000, chunk_overlap200) texts text_splitter.split_documents(documents) # 3. 创建向量库 embeddings OpenAIEmbeddings() vectorstore Chroma.from_documents(texts, embeddings) # 4. 创建 RetrievalQA 链 qa_chain RetrievalQA.from_chain_type( llmOpenAI(), chain_typestuff, retrievervectorstore.as_retriever() ) # 5. 使用 query 公司的年假政策是什么 result qa_chain.run(query) print(result) # 看似简单但隐藏了大量细节 # - Prompt 的具体格式是什么 # - Retrieval 返回的文档如何组合到 Prompt # - 错误如何处理 # - Token 消耗多少 # 这些在生产环境中都很重要但 LangChain 封装后难以干预。# LangChain 的过度封装问题示例自定义 Tool 的复杂度 from langchain.tools import BaseTool from typing import Optional, Type from pydantic import BaseModel, Field # 定义一个简单的计算器 Tool class CalculatorInput(BaseModel): 计算器输入 a: float Field(description第一个数字) b: float Field(description第二个数字) operation: str Field(description操作add, subtract, multiply, divide) class CalculatorTool(BaseTool): name calculator description 执行基本算术运算 args_schema: Type[BaseModel] CalculatorInput def _run(self, a: float, b: float, operation: str) - str: 执行计算 if operation add: return str(a b) elif operation subtract: return str(a - b) elif operation multiply: return str(a * b) elif operation divide: if b 0: return 错误除数不能为 0 return str(a / b) else: return f错误不支持的操作 {operation} async def _arun(self, a: float, b: float, operation: str) - str: 异步执行可选 return self._run(a, b, operation) # 为了实现一个简单的计算器需要写这么多代码 # 而实际上核心逻辑只有 10 行左右。尽管有问题LangChain 仍然是快速原型和学习 LLM 应用开发的好选择。对于生产环境建议深入理解原理不要仅仅调用 API要理解底层的 Prompt、Retrieval、Agent 逻辑。定制和优化基于 LangChain 的开发往往需要大量定制。提前规划好定制点。考虑替代方案对于性能敏感的场景可以考虑使用原生 API 或其他更轻量的框架。二、Semantic Kernel微软的优雅方案Semantic KernelSK是微软推出的 LLM 应用开发框架支持 C#、Python 和 Java。与 LangChain 的全家桶思路不同SK 更加轻量、模块化强调与现有代码的集成。核心优势轻量级设计SK 的核心库非常轻量没有过多的依赖。开发者可以逐步引入所需功能而非一次性引入整个框架。模块化与可扩展SK 的核心概念是 Kernel内核所有的功能插件、内存、规划器都以模块形式注册到 Kernel。这种设计使得功能解耦易于测试和替换。多语言支持原生支持 C#、Python、Java对于.NET 技术栈的团队尤其友好。与微软生态集成SK 与 Azure OpenAI、Microsoft 365、Power Platform 等微软产品深度集成适合已经在用微软技术栈的企业。规划器PlannerSK 的规划器可以自动将复杂任务分解为多个步骤并调度执行。这是 SK 的亮点功能。主要问题生态系统不如 LangChainSK 的社区和第三方集成数量远少于 LangChain。某些功能如特定向量数据库的支持可能需要自行实现。学习曲线虽然 SK 设计优雅但其概念Kernel、Plugin、Function、Planner需要时间理解。特别是 Planner 的工作原理文档说明不够详细。Python 版本成熟度SK 最初是 C# 实现Python 版本相对较新某些功能可能不如 C# 版本完善。调试工具相比 LangSmithLangChain 的调试工具SK 的调试和监控工具不够成熟。# Semantic Kernel 示例使用 Plugin 实现 Function Calling import semantic_kernel as sk from semantic_kernel.connectors.ai.open_ai import OpenAIChatCompletion from semantic_kernel.skill_definition import sk_function, sk_function_context_parameter from semantic_kernel.planning import SequentialPlanner # 1. 创建 Kernel kernel sk.Kernel() # 2. 配置 AI 服务 kernel.add_chat_service( chat_completion, OpenAIChatCompletion(gpt-3.5-turbo, api_keyyour-api-key) ) # 3. 定义 Plugin类似 LangChain 的 Tool class MathPlugin: 数学计算 Plugin sk_function( description计算两个数的和 ) def add( self, a: str, b: str ) - str: 加法 return str(float(a) float(b)) sk_function( description计算两个数的差 ) def subtract( self, a: str, b: str ) - str: 减法 return str(float(a) - float(b)) # 4. 注册 Plugin kernel.import_skill(MathPlugin(), skill_nameMath) # 5. 使用 Planner 自动规划 planner SequentialPlanner(kernel) # 用户请求计算 (123 456) * 2 prompt 计算 (123 456) * 2先算加法再算乘法 plan planner.create_plan(prompt) # 执行计划 result await plan.invoke_async() print(result) # Semantic Kernel 的设计更加模块化但配置相对复杂# Semantic Kernel 的 Kernel 设计示例 from semantic_kernel import Kernel from semantic_kernel.connectors.ai.open_ai import OpenAIChatCompletion from semantic_kernel.memory import VolatileMemoryStore from semantic_kernel.core_skills import TextSkill # Kernel 是 SK 的核心所有功能都注册到 Kernel kernel Kernel() # 注册 AI 服务 kernel.add_chat_service(chat, OpenAIChatCompletion(gpt-4, api_keyyour-key)) # 注册内存存储 kernel.register_memory_store(VolatileMemoryStore()) # 注册技能Skill kernel.import_skill(TextSkill(), text) # 注册自定义 Plugin kernel.import_skill(MathPlugin(), math) # 使用 Kernel 执行功能 # 这种设计的优点是解耦和可测试性高LangChain vs Semantic Kernel维度LangChainSemantic Kernel生态非常丰富中等易用性快速上手需要理解概念性能中等抽象开销较高轻量级模块化低紧耦合高解耦设计多语言Python、JavaScriptC#、Python、Java企业支持创业公司微软适合场景快速原型、学习生产环境、.NET 技术栈选择建议如果你是使用 Python 的创业公司需要快速验证想法选择 LangChain。如果你是使用 .NET 的企业已经深度绑定微软生态选择 Semantic Kernel。如果你关注长期维护和生产稳定性Semantic Kernel 的企业支持更有保障。如果你需要特定的集成如某个小众向量数据库LangChain 的社区集成更多。三、自研方案完全掌控的代价除了使用现有框架许多团队选择自研 Function Calling 和 Agent 开发方案。这种方式可以完全掌控实现细节但也需要投入大量 engineering 资源。自研方案的优势完全掌控自研方案可以根据业务需求精确实现功能无需受限于框架的设计。性能优化、错误处理、日志记录等都可以深度定制。轻量级自研方案通常只包含必需的功能没有框架的额外开销。在高频调用场景下性能优势明显。可维护性自研方案的代码库通常更小、更易理解。团队成员可以快速熟悉代码降低人员流动风险。无依赖风险使用第三方框架存在依赖风险如框架停止维护、许可证变更、安全漏洞。自研方案避免了这些风险。自研方案的挑战开发成本高从零开始实现 Function Calling、RAG、Agent 等功能需要大量的开发时间。而且这些功能并非核心业务投入产出比可能不高。功能不完整自研方案往往只实现了当前需要的功能缺乏框架的完整性。随着业务扩展可能需要不断补丁导致技术债务累积。缺乏最佳实践框架如 LangChain凝聚了社区的智慧和最佳实践。自研方案可能重复造轮子甚至引入框架已经解决的坑。人才要求高自研需要团队对 LLM、Prompt Engineering、Agent 架构有深入理解。如果团队经验不足可能设计出有缺陷的架构。# 自研 Function Calling 方案示例极简实现 import json import openai from typing import Callable, Dict, List, Any class SimpleFunctionCaller: 极简的 Function Calling 实现 def __init__(self, model: str gpt-3.5-turbo): self.model model self.functions: Dict[str, Callable] {} self.function_schemas: List[Dict] [] def register_function(self, func: Callable, description: str): 注册函数 schema self._generate_schema(func, description) self.functions[func.__name__] func self.function_schemas.append(schema) def _generate_schema(self, func: Callable, description: str) - Dict: 根据函数签名生成 JSON Schema import inspect sig inspect.signature(func) parameters {} for name, param in sig.parameters.items(): param_type param.annotation # 简化示例实际应处理更复杂的类型 if param_type int: json_type integer elif param_type float: json_type number elif param_type str: json_type string elif param_type bool: json_type boolean else: json_type string parameters[name] { type: json_type, description: # 实际应从 docstring 提取 } return { name: func.__name__, description: description, parameters: { type: object, properties: parameters, required: list(parameters.keys()) # 简化假设所有参数都必需 } } def call(self, user_message: str) - str: 处理用户请求 # 1. 调用 LLM传递可用函数 response openai.ChatCompletion.create( modelself.model, messages[ {role: user, content: user_message} ], functionsself.function_schemas, function_callauto ) message response[choices][0][message] # 2. 检查是否需要调用函数 if message.get(function_call): function_name message[function_call][name] function_args json.loads(message[function_call][arguments]) # 3. 执行函数 func self.functions[function_name] result func(**function_args) # 4. 将函数执行结果返回给 LLM second_response openai.ChatCompletion.create( modelself.model, messages[ {role: user, content: user_message}, message, {role: function, name: function_name, content: str(result)} ] ) return second_response[choices][0][message][content] else: # 无需调用函数直接返回响应 return message[content] # 使用示例 caller SimpleFunctionCaller() # 注册函数 def get_weather(city: str) - str: 获取指定城市的天气 # 简化示例 return f{city} 的天气晴25°C caller.register_function(get_weather, description获取指定城市的天气) # 使用 result caller.call(北京今天天气怎么样) print(result) # 这个自研方案只有 100 行代码但实现了基本的 Function Calling 功能。 # 优点轻量、可控。 # 缺点缺乏错误处理、不支持流式调用、不支持并发、缺乏记忆...自研 vs 框架何时选择自研以下情况适合自研性能要求极高框架的抽象开销不可接受需要极致优化。业务场景特殊现有框架无法很好地支持如特定的安全要求、特定的集成需求。团队能力强团队对 LLM 应用有深入理解能够快速迭代。长期维护计划长期维护该系统不希望依赖第三方框架。以下情况不适合自研快速原型需要快速验证想法自研会拖慢速度。团队经验不足团队对 LLM 应用开发不熟悉自研容易踩坑。功能需求通用现有框架已经能够满足需求无需重复造轮子。混合方案基于框架定制实际的做法是基于框架定制使用 LangChain 或 Semantic Kernel 作为基础但仅使用其核心组件并在必要时自行实现特定功能。这种方式兼顾了开发效率和灵活性。# 混合方案示例使用 LangChain 的 LLM但自研 Agent 逻辑 from langchain.llms import OpenAI from langchain.chat_models import ChatOpenAI from langchain.schema import HumanMessage, SystemMessage class CustomAgent: 自定义 Agent仅使用 LangChain 的 LLM 接口 def __init__(self, model_name: str gpt-3.5-turbo): # 使用 LangChain 的 Chat Model仅此而已 self.llm ChatOpenAI(model_namemodel_name) # 自研的 Tool 注册表 self.tools {} # 自研的 Memory self.memory [] def register_tool(self, name: str, func: Callable, description: str): 注册工具 self.tools[name] { function: func, description: description } def run(self, user_input: str) - str: 执行 Agent # 1. 构建 Prompt自研 messages self._build_prompt(user_input) # 2. 调用 LLM使用 LangChain response self.llm(messages) # 3. 解析响应判断是否调用工具自研 if self._needs_tool_call(response): tool_name, tool_input self._parse_tool_call(response) # 执行工具 tool_result self.tools[tool_name][function](**tool_input) # 将工具结果返回给 LLM final_response self._continue_with_tool_result(tool_result) return final_response else: return response def _build_prompt(self, user_input: str) - List: 构建 Prompt自研完全可控 messages [] # System Message system_msg 你是一个有帮助的助手。可用工具\n for name, tool in self.tools.items(): system_msg f- {name}: {tool[description]}\n messages.append(SystemMessage(contentsystem_msg)) # Memory messages.extend(self.memory) # 用户输入 messages.append(HumanMessage(contentuser_input)) return messages def _needs_tool_call(self, response: str) - bool: 判断是否需要调用工具自研逻辑 # 简化实际应更智能地判断 return 需要调用工具 in response def _parse_tool_call(self, response: str) - tuple: 解析工具调用请求自研逻辑 # 简化实际应使用更可靠的解析方法 return get_weather, {city: 北京} def _continue_with_tool_result(self, tool_result: str) - str: 将工具结果返回给 LLM messages self.memory [HumanMessage(contentf工具执行结果{tool_result})] return self.llm(messages) # 这种混合方案既利用了 LangChain 的 LLM 接口避免重复实现 # 又保持了 Agent 逻辑的完全掌控。四、选型建议与最佳实践基于以上对比给出 Function Calling 框架的选型建议。选型决策树你的技术栈是什么PythonLangChain 或自研.NETSemantic KernelJavaSemantic Kernel 或自研你的主要目标是什么快速验证想法LangChain生产环境长期维护Semantic Kernel 或混合方案极致性能自研或混合方案你的团队经验如何经验不足LangChain生态和教程多经验丰富混合方案或自研你的业务场景特殊吗通用场景LangChain 或 Semantic Kernel特殊场景自研或混合方案最佳实践从小做起不要一开始就引入完整的框架。先使用原生 API 实现核心功能遇到痛点后再引入框架。理解原理无论使用哪个框架都要理解 Function Calling 的底层原理Prompt 设计、工具调用协议、错误处理。这样才能在框架不满足需求时自行扩展。关注性能在生产环境中Function Calling 的性能直接影响用户体验。关注 Token 消耗、响应延迟、并发能力等指标。建立评估体系Function Calling 的效果工具选择准确率、参数提取准确率需要量化评估。建立评估数据集和指标指导优化。安全第一Function Calling 可能存在安全风险如 Prompt 注入、恶意工具调用。在生产环境中必须实施严格的安全管控。# Function Calling 评估框架示例 from typing import List, Dict import json class FunctionCallingEvaluator: Function Calling 效果评估 def __init__(self): self.test_cases [] def add_test_case(self, user_input: str, expected_function: str, expected_args: Dict): 添加测试用例 self.test_cases.append({ user_input: user_input, expected_function: expected_function, expected_args: expected_args }) def evaluate(self, function_caller) - Dict: 评估 Function Calling 效果 Args: function_caller: 待评估的 Function Calling 实现 Returns: 评估结果 results [] for test_case in self.test_cases: user_input test_case[user_input] expected_function test_case[expected_function] expected_args test_case[expected_args] # 调用待评估系统 try: response function_caller.call(user_input) # 解析实际调用简化假设 response 包含工具调用信息 actual_function, actual_args self._parse_response(response) # 判断正确性 function_correct actual_function expected_function args_correct self._compare_args(actual_args, expected_args) results.append({ user_input: user_input, expected_function: expected_function, actual_function: actual_function, function_correct: function_correct, expected_args: expected_args, actual_args: actual_args, args_correct: args_correct, overall_correct: function_correct and args_correct }) except Exception as e: results.append({ user_input: user_input, error: str(e), overall_correct: False }) # 统计指标 total len(results) function_accuracy sum(1 for r in results if r.get(function_correct, False)) / total args_accuracy sum(1 for r in results if r.get(args_correct, False)) / total overall_accuracy sum(1 for r in results if r.get(overall_correct, False)) / total return { total_cases: total, function_accuracy: function_accuracy, args_accuracy: args_accuracy, overall_accuracy: overall_accuracy, details: results } def _parse_response(self, response: str) - tuple: 解析响应提取工具调用信息简化示例 # 实际实现应解析 LLM 返回的 function_call # 这里假设 response 包含 JSON 格式的工具调用信息 try: data json.loads(response) return data[function], data[args] except: return None, None def _compare_args(self, actual: Dict, expected: Dict) - bool: 比较参数是否一致 # 简化实际应考虑容错如参数顺序、类型转换 return actual expected # 使用示例 evaluator FunctionCallingEvaluator() # 添加测试用例 evaluator.add_test_case( user_input北京今天天气怎么样, expected_functionget_weather, expected_args{city: 北京} ) evaluator.add_test_case( user_input帮我算一下 123 加 456, expected_functionadd, expected_args{a: 123, b: 456} ) # 评估自研的 SimpleFunctionCaller caller SimpleFunctionCaller() caller.register_function(get_weather, description获取天气) # ... 注册其他函数 result evaluator.evaluate(caller) print(f整体准确率: {result[overall_accuracy]:.2%}) print(f函数选择准确率: {result[function_accuracy]:.2%}) print(f参数提取准确率: {result[args_accuracy]:.2%})五、总结Function Calling 是 LLM 应用开发的核心能力。LangChain、Semantic Kernel 和自研方案各有优劣需要根据具体场景选择。关键要点LangChain 适合快速原型和学习但需要注意其抽象带来的复杂度和性能开销。在生产环境中可能需要大量定制。Semantic Kernel 更加轻量、模块化适合生产环境和 .NET 技术栈。但生态系统不如 LangChain 丰富。自研方案完全可控但开发成本高。适合性能要求极高或业务场景特殊的团队。混合方案基于框架定制是推荐选择利用框架的成熟组件同时保持核心逻辑的掌控。建立评估体系Function Calling 的效果需要量化评估。使用测试集持续评估和优化。没有最好的框架只有最适合的选择。建议从小规模试点开始积累经验后再扩大到全团队。参考资料LangChain 官方文档https://python.langchain.com/docs/Semantic Kernel 官方文档https://learn.microsoft.com/semantic-kernel/OpenAI Function Calling Guidehttps://platform.openai.com/docs/guides/function-callingBuilding LLM Apps: Frameworks Compared (Sequence, 2024)《LangChain 实战手册》电子书本文基于作者的实践经验和框架文档。具体选型请结合团队情况和技术栈决定。