尧图建网站 尧图建网站 YAOTU WEB BUILD 免费咨询
ARTICLE DETAIL

资讯详情

深耕网站建设与建站编程的一线实战洞察。

从零手写Tool Calling:深入理解LLM函数调用与ReAct框架实现

从零手写Tool Calling:深入理解LLM函数调用与ReAct框架实现 1. 项目概述为什么我们需要“手写”Tool Calling如果你最近在折腾大语言模型应用尤其是想构建一个能自主调用外部工具、完成复杂任务的智能体那么“Tool Calling”这个概念你一定不陌生。简单说它就是让LLM大语言模型长出“手脚”的能力——模型不仅能和你聊天还能根据你的指令去执行一个具体的操作比如查天气、发邮件、操作数据库甚至是控制智能家居。市面上成熟的框架比如LangChain、Dify已经把这套能力封装得相当完善你只需要几行配置代码就能用上。那为什么我们还要“从零手写”呢这就像学开车自动挡固然方便但如果你真正理解了手动挡的离合器、变速箱是如何协同工作的你不仅能开得更好在车子出问题时也能自己排查。直接使用框架你得到的是一个黑盒你只知道输入和输出但中间LLM是如何思考、如何决定调用哪个工具、参数如何解析的你一无所知。当你的需求变得独特或者框架的默认行为不符合你的预期时你就会感到束手无策。更现实的是很多生产环境中的需求是高度定制化的框架的抽象层有时反而会成为瓶颈和额外的复杂度来源。因此这个实战指南的目的不是教你如何使用某个框架而是带你亲手拆解并重建“Tool Calling”这个核心机制。我们将从最原始的、直接与LLM API对话开始一步步构建起一个灵活、可控的Tool Calling系统并最终将其抽象成一个小而美的框架。这个过程会让你彻底掌握LLM与工具交互的底层逻辑、数据流转的每一个环节以及如何设计一个健壮的Agent工作流。无论你是想深入理解AI Agent的原理还是计划打造属于自己的专属Agent框架这都是一次不可多得的深度实践。2. 核心概念拆解Tool Calling、ReAct与JSON Schema在动手之前我们必须厘清几个核心概念它们是构建我们系统的基石。2.1 Tool CallingLLM的“函数调用”能力Tool Calling本质上是一种标准化的通信协议。它规定了LLM在需要执行外部操作时应该如何向系统“表达”这个意图。目前主流的方式是让LLM以结构化的格式通常是JSON输出一个“工具调用请求”。这个请求通常包含tool_name: 要调用哪个工具。arguments: 调用这个工具所需的参数也是一个JSON对象。例如当用户说“查询北京明天的天气”我们希望LLM能输出类似{tool_name: get_weather, arguments: {city: 北京, date: tomorrow}}的内容。后端系统接收到这个结构化的请求后就能找到对应的get_weather函数传入参数并执行最后将结果返回给LLM由LLM组织成自然语言回复给用户。2.2 ReAct推理与行动的循环框架ReActReasoning Acting是推动Tool Calling的核心思维框架。它不是一个具体的API而是一种设计模式。其核心思想是让LLM进行“思考-行动-观察”的循环推理LLM分析当前的用户目标、已有的上下文和历史信息思考下一步应该做什么。行动根据推理结果执行一个行动Action。在Tool Calling的语境下这个行动就是“调用一个工具”。观察获取工具执行后的结果Observation将这个结果作为新的信息输入。重复上述步骤直到任务完成或无法继续。这个框架将LLM从一个单纯的文本生成器提升为一个可以与环境交互的“决策者”。我们手写Tool Calling系统很大程度上就是在实现一个ReAct循环的执行引擎。2.3 JSON Schema工具的“说明书”我们如何告诉LLM它有哪些工具可用以及每个工具该怎么用这就需要一份清晰的“说明书”而JSON Schema是当前最通用的格式。JSON Schema是一种用于描述JSON数据结构的标准。我们可以用它来精确地定义一个工具name: 工具名称。description: 工具功能的自然语言描述这是LLM决定是否调用该工具的关键。parameters: 一个JSON Schema对象严格定义参数的名称、类型、是否必填、描述以及可能的枚举值。例如定义get_weather工具{ name: get_weather, description: 获取指定城市在指定日期的天气信息。, parameters: { type: object, properties: { city: { type: string, description: 城市名称例如北京、上海。 }, date: { type: string, description: 日期格式为YYYY-MM-DD或‘today’、‘tomorrow’。, enum: [today, tomorrow] } }, required: [city] } }在对话初始化时我们将所有工具的JSON Schema描述放入系统提示词中LLM就能在需要时生成符合这些约束的调用请求。这里有一个关键细节LLM对description字段极其敏感。模糊的描述会导致错误的调用而清晰、具体、包含示例的描述能大幅提升调用的准确率。3. 从零实现构建一个最小可用的Tool Calling系统现在我们抛开所有框架只使用最基本的HTTP客户端和字符串处理来构建一个最原始的Tool Calling流程。我们以OpenAI的Chat Completion API为例但原理通用。3.1 第一步定义工具并生成系统提示词首先我们以Python字典的形式在代码中定义几个工具。tools [ { name: calculate, description: 执行一个数学计算。支持加()、减(-)、乘(*)、除(/)。, parameters: { type: object, properties: { expression: { type: string, description: 数学表达式例如3 5 * 2。请确保表达式是明确且可计算的。 } }, required: [expression] } }, { name: get_current_time, description: 获取当前的系统日期和时间。, parameters: { type: object, properties: {}, # 此工具无需参数 required: [] } } ]接下来我们需要将这些工具描述转换成LLM能理解的系统提示词。这不是简单地把JSON扔进去而是需要精心构造一段“指令”。def build_system_prompt(tools): prompt 你是一个智能助手可以调用工具来帮助用户解决问题。你可以调用的工具如下 for tool in tools: prompt f工具名称{tool[name]}\n prompt f描述{tool[description]}\n if tool[parameters][properties]: prompt 参数说明\n for param_name, param_schema in tool[parameters][properties].items(): param_desc param_schema.get(description, ) param_type param_schema.get(type, string) prompt f - {param_name} ({param_type}): {param_desc}\n prompt \n prompt 当用户的问题需要调用工具时你必须严格按照以下JSON格式回应且只输出这个JSON不要有任何其他文字 { tool_name: 工具名称, arguments: { // 具体的参数键值对 } } 如果用户的问题不需要调用任何工具或者你已经通过知识直接回答请用自然语言正常回复。 现在开始对话吧。 return prompt注意这里我们采用了“强制JSON输出”的提示策略。在实际中更鲁棒的做法是使用Chat API的function_call参数OpenAI或tools参数其他模型让模型原生支持结构化输出。但为了理解本质我们先从最“硬核”的字符串解析开始。3.2 第二步调用LLM并解析其输出我们发送请求并尝试从LLM的回复中解析出JSON。import openai import json import re client openai.OpenAI(api_keyyour-api-key) def call_llm(user_query, system_prompt): response client.chat.completions.create( modelgpt-3.5-turbo, messages[ {role: system, content: system_prompt}, {role: user, content: user_query} ], temperature0.1 # 低温度使输出更确定更适合生成结构化内容 ) return response.choices[0].message.content def parse_llm_response(response_text): # 尝试从回复中提取JSON部分 # 使用正则表达式匹配最外层的 {...} json_match re.search(r\{.*\}, response_text, re.DOTALL) if json_match: try: potential_json json_match.group() data json.loads(potential_json) # 检查是否包含必要的字段 if tool_name in data and arguments in data: return data except json.JSONDecodeError: pass # 如果没有解析出合法JSON则认为这是自然语言回复 return {type: natural_language, content: response_text}3.3 第三步执行工具并管理对话状态我们需要一个工具执行器和一个简单的对话状态管理器。import datetime import math def execute_tool(tool_name, arguments): 根据工具名称和参数执行具体的工具函数。 if tool_name calculate: # 警告直接使用eval有严重安全风险仅用于演示。 # 生产环境必须使用安全的表达式求值库如ast.literal_eval或自己解析。 try: result eval(arguments[expression]) return f计算结果为{result} except Exception as e: return f计算失败{e} elif tool_name get_current_time: now datetime.datetime.now() return f当前时间是{now.strftime(%Y-%m-%d %H:%M:%S)} else: return f错误未知的工具 {tool_name} def run_conversation(): system_prompt build_system_prompt(tools) conversation_history [] # 存储多轮对话消息 print(系统已就绪。输入‘退出’结束对话。) while True: user_input input(\n用户: ) if user_input.lower() 退出: break # 构造包含历史的对话上下文 messages [{role: system, content: system_prompt}] messages.extend(conversation_history) messages.append({role: user, content: user_input}) # 调用LLM简化版实际需按API格式 llm_response_text call_llm(user_input, system_prompt) parsed_response parse_llm_response(llm_response_text) if parsed_response.get(type) natural_language: # LLM直接回复 assistant_reply parsed_response[content] print(f助手: {assistant_reply}) conversation_history.append({role: user, content: user_input}) conversation_history.append({role: assistant, content: assistant_reply}) else: # LLM决定调用工具 tool_name parsed_response[tool_name] tool_args parsed_response[arguments] print(f助手决定调用工具: {tool_name}, 参数: {tool_args}) # 执行工具 tool_result execute_tool(tool_name, tool_args) print(f工具执行结果: {tool_result}) # 将工具结果作为新的用户消息或系统消息再次调用LLM让其总结回复 follow_up_prompt f你调用的工具 {tool_name} 返回了结果{tool_result}。请根据这个结果回复用户最初的问题“{user_input}”。 final_reply call_llm(follow_up_prompt, system_prompt) print(f助手: {final_reply}) # 更新历史 conversation_history.append({role: user, content: user_input}) # 可以选择不将中间的工具调用和结果放入历史避免历史过长 conversation_history.append({role: assistant, content: final_reply}) if __name__ __main__: run_conversation()实操心得与踩坑点安全第一上面的calculate工具使用了eval这在生产环境中是绝对禁止的会带来严重的代码注入风险。实际应用中必须使用安全的替代方案如ast.literal_eval仅支持字面量或专门的数学表达式解析库。JSON解析的鲁棒性我们的正则表达式解析非常脆弱。LLM可能会在JSON前后添加解释性文字或者JSON格式稍有瑕疵如尾随逗号。更健壮的做法是a) 利用API的原生工具调用功能b) 使用更复杂的解析器或尝试多次提取c) 在提示词中更严格地约束输出格式。上下文管理这个简单示例将整个对话历史都传给了LLM在工具调用频繁时会导致上下文迅速膨胀增加成本和可能影响模型性能。需要设计策略来压缩或总结历史。错误处理工具执行可能失败网络错误、参数无效等。系统需要能捕获这些异常并以一种LLM能理解的方式反馈给它让它决定重试、选择其他工具还是向用户求助。4. 走向抽象设计一个可扩展的Tool Calling框架我们已经实现了一个能跑通的“玩具系统”。接下来我们要把它抽象成一个结构清晰、易于扩展的小框架。一个好的框架应该做到高内聚、低耦合即核心逻辑集中而工具定义、执行器、LLM后端等可以灵活替换。4.1 核心架构设计我们设计以下几个核心模块Tool工具抽象基类。所有具体工具都继承自它实现execute方法。ToolRegistry工具注册中心。负责管理所有可用工具并能根据名称查找。LLMClientLLM客户端抽象。封装不同模型提供商OpenAI, Anthropic, 本地模型的API调用返回统一格式。Agent智能体核心。持有ToolRegistry和LLMClient驱动整个ReAct循环管理对话状态。Workflow可选工作流引擎。用于定义复杂的多步骤任务流程超越简单的单次Tool Calling。让我们先实现前四个核心部分。from abc import ABC, abstractmethod from typing import Any, Dict, List, Optional import json import inspect # ---------- 1. Tool 抽象 ---------- class Tool(ABC): 工具的抽象基类。 name: str description: str parameters_schema: Dict[str, Any] def __init__(self): # 可以通过类属性或__init__参数来设置 name, description等 pass abstractmethod def execute(self, **kwargs) - str: 执行工具的具体逻辑返回字符串格式的结果。 pass def to_json_schema(self) - Dict[str, Any]: 将工具描述转换为标准的JSON Schema格式。 return { name: self.name, description: self.description, parameters: self.parameters_schema } # 示例计算器工具 class CalculatorTool(Tool): name calculate description 执行一个数学计算。支持加()、减(-)、乘(*)、除(/)、乘方(**)。 parameters_schema { type: object, properties: { expression: { type: string, description: 数学表达式例如(3 5) * 2。请确保表达式是明确且可计算的。 } }, required: [expression] } def execute(self, **kwargs) - str: expr kwargs.get(expression, ) if not expr: return 错误未提供表达式。 # 安全计算演示简易版生产环境需强化 try: # 禁止导入模块、调用函数等只允许基本算术和math库中的安全函数 allowed_names {k: v for k, v in math.__dict__.items() if not k.startswith(_)} allowed_names.update({abs: abs, round: round}) result eval(expr, {__builtins__: {}}, allowed_names) return str(result) except Exception as e: return f计算错误{e} # ---------- 2. ToolRegistry ---------- class ToolRegistry: 工具注册表单例模式管理所有工具。 _instance None _tools: Dict[str, Tool] {} def __new__(cls): if cls._instance is None: cls._instance super(ToolRegistry, cls).__new__(cls) return cls._instance def register(self, tool: Tool): if tool.name in self._tools: raise ValueError(f工具名称 {tool.name} 已存在。) self._tools[tool.name] tool print(f[ToolRegistry] 已注册工具: {tool.name}) def get_tool(self, name: str) - Optional[Tool]: return self._tools.get(name) def get_all_tools(self) - List[Tool]: return list(self._tools.values()) def get_tools_schema(self) - List[Dict]: return [tool.to_json_schema() for tool in self._tools.values()] # ---------- 3. LLMClient 抽象 ---------- class LLMClient(ABC): LLM客户端抽象便于切换不同模型提供商。 abstractmethod def chat_completion(self, messages: List[Dict], tools_schema: List[Dict] None) - Dict: 发送聊天补全请求。 返回格式应统一为: { content: str | None, # 自然语言回复内容 tool_calls: List[Dict] | None # 工具调用列表每个元素包含 name 和 arguments } pass # OpenAI实现 class OpenAIClient(LLMClient): def __init__(self, api_key: str, model: str gpt-3.5-turbo): import openai self.client openai.OpenAI(api_keyapi_key) self.model model def chat_completion(self, messages: List[Dict], tools_schema: List[Dict] None) - Dict: api_messages [{role: m[role], content: m[content]} for m in messages] kwargs {model: self.model, messages: api_messages, temperature: 0.1} if tools_schema: # 使用OpenAI原生的tools参数这是最佳实践 kwargs[tools] [{type: function, function: schema} for schema in tools_schema] # 可以设置 tool_choiceauto 或指定某个工具 kwargs[tool_choice] auto response self.client.chat.completions.create(**kwargs) message response.choices[0].message result {content: None, tool_calls: None} if message.content: result[content] message.content if hasattr(message, tool_calls) and message.tool_calls: tool_calls [] for tc in message.tool_calls: if tc.type function: tool_calls.append({ name: tc.function.name, arguments: json.loads(tc.function.arguments) }) result[tool_calls] tool_calls return result4.2 Agent核心实现ReAct循环引擎有了基础组件我们可以构建Agent类它是整个系统的大脑。class Agent: def __init__(self, llm_client: LLMClient, tool_registry: ToolRegistry): self.llm llm_client self.tool_registry tool_registry self.conversation_history: List[Dict] [] def _build_system_message(self) - Dict: 构建系统提示消息。 # 这里可以构建更复杂的系统指令包括工具描述。 # 由于我们使用原生的tools参数系统消息可以更专注于角色设定。 tools_desc \n.join([f- {tool.name}: {tool.description} for tool in self.tool_registry.get_all_tools()]) system_content f你是一个乐于助人的AI助手可以调用工具来解决问题。你可以使用的工具有 {tools_desc} 请根据用户的问题决定是否需要调用工具。如果需要请精确地调用。如果不需要请直接回答。请一步步思考。 return {role: system, content: system_content} def run(self, user_input: str, max_turns: int 5) - str: 运行一个对话轮次可能包含多轮工具调用ReAct循环。 self.conversation_history.append({role: user, content: user_input}) full_history [self._build_system_message()] self.conversation_history for turn in range(max_turns): print(f\n[Agent] 思考轮次 {turn 1}...) # 1. 调用LLM传入工具定义 tools_schema self.tool_registry.get_tools_schema() response self.llm.chat_completion(full_history, tools_schema) # 2. 处理LLM回复 if response[content]: # LLM直接给出了最终答案 final_answer response[content] self.conversation_history.append({role: assistant, content: final_answer}) print(f[Agent] 最终回复: {final_answer}) return final_answer elif response[tool_calls]: # LLM决定调用一个或多个工具 for tool_call in response[tool_calls]: tool_name tool_call[name] tool_args tool_call[arguments] print(f[Agent] 决定调用工具: {tool_name}, 参数: {tool_args}) # 3. 查找并执行工具 tool self.tool_registry.get_tool(tool_name) if not tool: tool_result f错误未知的工具 {tool_name} else: try: tool_result tool.execute(**tool_args) except Exception as e: tool_result f工具执行出错: {e} print(f[Agent] 工具执行结果: {tool_result}) # 4. 将工具执行结果作为新的上下文信息加入历史 # 格式需符合OpenAI的tool消息角色 tool_message { role: tool, content: tool_result, tool_call_id: fcall_{turn}_{tool_name} # 简化ID实际应从response中获取 } full_history.append({role: assistant, content: None, tool_calls: [tool_call]}) # 记录模型的决定 full_history.append(tool_message) self.conversation_history.append(tool_message) # 可选是否将中间过程存入长期历史 else: # 既没有内容也没有工具调用可能是模型困惑 error_msg 模型未产生有效响应。 self.conversation_history.append({role: assistant, content: error_msg}) return error_msg # 达到最大轮次限制 timeout_msg 已达到最大思考轮次任务可能过于复杂或无法完成。 self.conversation_history.append({role: assistant, content: timeout_msg}) return timeout_msg def clear_history(self): 清空对话历史。 self.conversation_history.clear()4.3 框架的使用示例现在让我们用这个框架来跑一个完整的例子。# 初始化组件 registry ToolRegistry() registry.register(CalculatorTool()) # 可以注册更多工具比如 GetTimeTool, SearchWebTool... llm_client OpenAIClient(api_keyyour-openai-key) # 请替换为你的API Key agent Agent(llm_client, registry) # 运行一个简单对话 print( 简单计算测试 ) result agent.run(请帮我计算一下 (12 34) * 2 等于多少) print(f\n对话结束。最终结果: {result}) agent.clear_history() print(\n 复杂多轮任务测试 ) # 假设我们还有一个查询股票价格的工具模拟 class StockTool(Tool): name get_stock_price description 获取某只股票的当前价格。 parameters_schema { type: object, properties: { symbol: {type: string, description: 股票代码例如AAPL, 000001.SZ。} }, required: [symbol] } def execute(self, **kwargs): symbol kwargs.get(symbol, ) # 模拟数据 mock_data {AAPL: 185.6, 000001.SZ: 15.23, GOOGL: 152.34} price mock_data.get(symbol.upper(), 未知股票代码) return f股票 {symbol} 的当前价格是 {price} 美元。 registry.register(StockTool()) # 多轮对话先查股价再计算 result agent.run(我想知道苹果公司AAPL的股价然后计算如果我买10股需要多少钱) print(f\n对话结束。最终结果: {result})框架设计要点与心得依赖注入Agent依赖于抽象的LLMClient和ToolRegistry而不是具体实现。这使得更换模型提供商比如从OpenAI换成Claude或本地模型或动态加载工具变得非常容易。原生工具调用在OpenAIClient中我们使用了API原生的tools参数。这比我们最初手写的“强制JSON输出”提示词方法要可靠得多能极大提高工具调用的准确率和稳定性。这是生产级应用的首选。历史管理Agent维护了conversation_history。在ReAct循环中我们将工具执行结果以role: tool的消息格式追加到历史中这符合OpenAI等API的规范能让模型理解这是上一次工具调用的结果。错误处理与循环控制框架包含了基本的错误处理工具未找到、执行异常和最大轮次限制防止陷入无限循环。可扩展性Tool基类要求每个工具实现execute方法这使得添加新工具就像写一个Python类一样简单。ToolRegistry提供了集中的管理。5. 高级话题与生产环境考量我们的框架已经具备了核心功能但要用于实际项目还需要考虑更多。5.1 流式输出与用户体验对于需要长时间运行的工具如爬取网页、训练模型我们希望能边执行边给用户反馈而不是让用户干等。这需要支持流式输出。LLM响应流式大多数API支持以流式stream方式返回Tokens可以实现打字机效果。工具执行状态流式我们可以通过WebSocket或Server-Sent Events (SSE) 将工具执行的进度如“正在连接数据库...”、“已获取50%数据”实时推送给前端。实现思路Agent.run()方法可以改造成一个生成器generatoryield出不同阶段的状态“思考中”、“调用工具X”、“工具执行中进度XX%”、“工具结果”、“最终回答”。5.2 复杂工作流与规划简单的ReAct循环对于线性任务足够但现实任务往往是树状或图状的。例如“规划一次旅行”可能涉及并行查询天气、机票、酒店然后综合比较。需要工作流引擎这就是LangGraph、Dify Workflow等框架解决的核心问题。我们可以引入“状态机”或“有向无环图”的概念来定义工作流。简易实现可以在Agent基础上增加一个Plan阶段。首先让LLM根据目标生成一个步骤列表Plan然后依次或并行地执行每个步骤每个步骤本身可能又是一个Tool Calling。这需要更强大的系统提示词来让LLM进行规划。工具组合设计可以相互调用、组合的“子工具”构建更强大的复合工具。5.3 上下文管理与Token优化长对话会导致历史上下文非常长触及模型Token上限且费用高昂。策略1滑动窗口只保留最近N轮对话。策略2总结压缩当历史达到一定长度时调用LLM本身对之前的对话进行总结将总结文本作为新的系统消息或上下文的一部分替代原始冗长的历史。策略3选择性记忆将对话历史存入向量数据库在需要时进行相关性检索只注入最相关的历史片段。这就是RAG在对话历史管理中的应用。5.4 验证、安全与监控参数验证在工具execute方法被调用前必须用JSON Schema验证器如jsonschema库对输入参数进行严格校验防止无效或恶意参数。权限控制不是所有用户都能调用所有工具。需要设计一套权限体系在ToolRegistry查找工具时结合用户身份进行鉴权。监控与日志记录每一次LLM调用输入、输出、每一次工具调用参数、结果、耗时用于分析效果、排查问题和计费。限流与降级对LLM API的调用要做限流防止意外高频请求导致费用爆炸或账号被封。当主要模型不可用时应有备用模型或降级策略。6. 常见问题排查与实战技巧在实际开发和调试中你会遇到各种各样的问题。这里记录一些典型场景和解决思路。6.1 LLM不按预期调用工具症状LLM总是用自然语言回答即使问题明显需要调用工具。排查检查工具描述description是否清晰、无歧义是否准确描述了工具的功能和适用场景用更具体、场景化的语言重写描述。检查系统提示词系统提示词是否明确指令模型“可以且应该”调用工具尝试加入示例Few-shot Prompting。调整温度将temperature参数调低如0.1使输出更确定、更倾向于遵循指令。使用原生支持确保使用了API原生的工具调用功能如OpenAI的tools参数而不是依赖文本指令生成JSON。6.2 工具调用参数错误或格式不对症状LLM决定调用工具但生成的参数JSON解析失败或参数值不符合预期。排查强化JSON Schema在Schema中尽可能使用enum限定可选值使用pattern定义字符串格式如日期给出更详细的description和examples。输出格式约束在系统提示词中反复强调输出必须是合法的、无额外格式的JSON。可以要求模型“输出一个且仅一个JSON对象”。后处理与重试在解析失败时不要直接报错给用户。可以将错误信息和原始问题再次发送给LLM要求它纠正输出。实现一个简单的重试机制。6.3 多轮对话中上下文混乱症状在连续对话中Agent忘记了之前的目标或者把不同任务的历史混淆了。排查清晰的任务边界为每个独立的对话会话Session创建一个新的Agent实例或至少清空历史。避免跨会话污染。定期总结在对话轮次较多时主动插入一条系统消息让LLM对当前对话状态和待完成目标进行简要总结然后基于总结继续。设计工作流对于复杂任务使用明确的工作流Plan-Act模式而不是完全依赖自由的ReAct循环。每一步都有明确的目标和输入输出。6.4 性能与成本问题症状响应慢API调用费用高。优化缓存对具有确定性的工具调用如查询静态数据、重复计算结果进行缓存。选择合适模型对于简单的工具路由和参数提取可以使用更小、更快的模型如gpt-3.5-turbo只在需要复杂推理或生成最终答案时使用大模型如gpt-4。异步处理如果工具调用是I/O密集型如网络请求使用异步编程asyncio来并发执行减少总体等待时间。监控与告警设置成本预算和告警监控每日Token消耗和工具调用次数。从零手写Tool Calling的过程是一次对LLM应用层核心机制的深度之旅。它让你从API调用者转变为架构设计者。你不再满足于框架提供的“魔法”而是亲手掌控了让AI长出“手脚”的每一个齿轮。当你理解了消息历史的组织方式、工具描述的编写技巧、ReAct循环的驱动逻辑以及如何构建一个松耦合、易扩展的系统时无论面对多么定制化的AI Agent需求你都将拥有从底层实现和调试的能力。这份掌控感正是深入技术核心所带来的最大回报。
返回列表