侧边栏壁纸
博主头像
MobotStone AI

行动起来,活在当下

  • 累计撰写 16 篇文章
  • 累计创建 4 个标签
  • 累计收到 0 条评论

目 录CONTENT

文章目录

2025年你必须知道如何利用工具提升大模型效果

Administrator
2025-05-07 / 0 评论 / 6 点赞 / 167 阅读 / 0 字

欢迎回到AI智能体系列文章。在上一篇文章中,我们探讨了智能体系统的三大核心要素:大语言模型(LLM)、工具调用能力和推理决策机制。今天我们将深入解析这一架构中最基础的实现形态——LLM+工具的简易组合系统。

首先,我将带您从系统架构层面理解这类方案的运行原理,然后通过OpenAI智能体开发工具包(Agents SDK)的具体实现示例,手把手演示构建过程。这种"模型+工具"的基础架构不仅是理解复杂系统的起点,更是实践中快速验证想法的有效方案。

在常规的软件开发中,解决一个问题通常需要将任务拆解为明确的步骤,并用代码实现这些步骤的逻辑。这种方法适用于输入稳定、流程可预测的场景,但现实中并非所有问题都能如此清晰地定义。

以客服机器人为例,规则化的实现方式可能是:接收用户输入→匹配预设问题→返回对应解决方案。但实际使用时,这种机械式交互往往效果不佳,原因在于用户反馈的多样性和不可预测性——没有人能预先穷举所有可能的提问方式和故障场景。

当传统规则系统遇到开放式需求时,其局限性就暴露无遗。那么,是否存在更灵活的问题解决思路?

AI 智能体的核心理念

传统软件开发依赖于明确定义的规则和业务逻辑,而智能体(AI Agents)提供了一种全新的思路:不必硬编码每一种可能的处理流程,而是为大型语言模型(LLM)提供必要的工具,使其能自主完成任务。

以客服场景为例,传统方法往往试图定义固定的流程来处理各种情况,但智能体的做法不同。它只需要:

  • 业务背景知识(公司政策、产品信息)

  • 可调用的工具(搜索支持文档、查询用户订单)

  • 问题升级能力(转接人工、提交工单)

模型本身会根据实际输入动态决定如何处理,而不是机械匹配预设规则。这种方式的灵活性使得系统能适应更复杂的真实场景。

解锁LLM的自主解题能力

这个思路让我联想到"授人以鱼,不如授人以渔"的古老智慧。关键在于:解锁对象必要的工具和能力,它就能自立解决问题——这正是我对智能体的理解核心。

传统开发模式要求工程师预先构建完整解决方案并编码实现。而智能体的范式则是:为LLM配备明确的指导说明和工具集,使其能够自主寻找多样化问题的解决方案。

LLM工具调用机制解析

大型语言模型本质上只是文本生成器,它们本身不具备直接调用工具的能力。要实现工具调用功能,需要在外围构建额外的软件层来处理以下三个关键环节:

  • 实时检测模型输出的特殊标记:系统持续监控模型生成的内容,当识别到预定义的工具调用标记时触发处理机制

  • 中断生成并执行调用:在检测到工具调用请求后,系统暂时中止文本生成过程,通过外部代码执行具体的工具操作

  • 反馈处理结果:工具执行完成后,系统将返回的数据重新注入模型的上下文环境,让模型继续基于这些信息进行后续生成

不同模型采用的具体标记和处理流程可能有所差异。以下是一个简化版的类GPT模型调用示例...

image-KcCI.png

实现LLM工具调用的两种方法

虽然通过代码执行工具调用本身并不复杂,但关键问题在于如何让具有不确定性的LLM主动发起这些调用。在实际应用中,主要有两种实现方式:

方法一:提示词引导

最直接的方式是通过系统提示词明确指示LLM进行工具调用。有效的提示词应包含以下关键要素:

  • 工具功能描述

  • 输入参数说明

  • 预期输出格式

  • 特殊标识字符串(便于代码检测)

理论上,经过指令微调的普通模型配合精心设计的提示词也能实现这一功能。不过,专门针对工具调用优化的模型在可靠性和准确率上表现更好。如果通过API访问这类专用模型,操作会更加简便——开发者只需提供工具定义的JSON Schema(如下例所示),大部分API会自动处理底层提示词生成。

{
  "type": "function",
  "function": {
    "name": "transcribe_youtube_video",
    "description": "Transcribes the audio from a YouTube video into text.",
    "parameters": {
      "type": "object",
      "properties": {
        "video_url": {
          "type": "string",
          "description": "The full URL of the YouTube video to transcribe."
        }
      },
      "required": ["video_url"],
      "additionalProperties": false
    },
    "strict": true
  }
}

基于OpenAI Agents SDK的YouTube视频处理实例

几个月前,我开发了一款AI应用,将国外的YouTube视频转化为博客文章。虽然使用了大型语言模型,但最初采用的是传统的软件开发思路——将博客创作过程拆解为离散步骤,LLM仅负责其中的一部分文本生成工作。

这种架构存在明显局限:每次需要新增功能(比如视频内容摘要或时间戳提取)都必须专门开发对应的处理流程。而如果采用智能体(Agent)架构,这些功能(包括尚未设想的扩展功能)都能自动获得支持。

本文将演示如何用OpenAI Agents SDK重构这个系统。通过为LLM配置YouTube转录工具,最终实现的智能体可以:

  • 撰写视频内容相关的博客文章

  • 回答关于视频内容的提问

  • 自动生成关键时间戳

  • 实现其他衍生功能

引入必要的Python库

在项目的初始阶段,我们需要导入几个关键的Python库来构建应用基础。考虑到开发安全性,将通过dotenv库从.env配置文件中读取OpenAI API密钥。这样的设计既保证了密钥的安全性,又便于在不同环境间切换。

以下是核心依赖库的导入说明:

  • os:用于处理系统环境变量

  • dotenv:安全加载.env配置文件

  • openai:接入OpenAI的API服务

典型导入方式如下:

from youtube_transcript_api import YouTubeTranscriptApi
import re
from agents import Agent, function_tool, Runner, ItemHelpers, RunContextWrapper
from openai.types.responses import ResponseTextDeltaEvent
from dotenv import load_dotenv
import asyncio

# import environment variables from .env file
load_dotenv()

构建指令与工具集

根据OpenAI的定义,一个智能体(Agent)由大语言模型(LLM)及其配套的指令集和工具组成。我们需要先建立这两个核心组件。

# define instructions
instructions = "You provide help with tasks related to YouTube videos."
# define tool
@function_tool
def fetch_youtube_transcript(url: str) -> str:
    """
    Extract transcript with timestamps from a YouTube video URL and format it 
    for LLM consumption
    
    Args:
        url (str): YouTube video URL
        
    Returns:
        str: Formatted transcript with timestamps, where each entry is on a 
        new line in the format: "[MM:SS] Text"
    """
    # Extract video ID from URL
    video_id_pattern = r'(?:v=|\/)([0-9A-Za-z_-]{11}).*'
    video_id_match = re.search(video_id_pattern, url)
    
    if not video_id_match:
        raise ValueError("Invalid YouTube URL")
    
    video_id = video_id_match.group(1)
    
    try:
        transcript = YouTubeTranscriptApi.get_transcript(video_id)
        
        # Format each entry with timestamp and text
        formatted_entries = []
        for entry in transcript:
            # Convert seconds to MM:SS format
            minutes = int(entry['start'] // 60)
            seconds = int(entry['start'] % 60)
            timestamp = f"[{minutes:02d}:{seconds:02d}]"
            
            formatted_entry = f"{timestamp} {entry['text']}"
            formatted_entries.append(formatted_entry)
        
        # Join all entries with newlines
        return "\n".join(formatted_entries)
    
    except Exception as e:
        raise Exception(f"Error fetching transcript: {str(e)}")

Agents SDK提供了一个非常实用的功能:只需在Python函数前添加@function_tool装饰器,就能将其快速转化为LLM工具。这个过程会自动解析函数的结构和文档字符串(docstring),生成符合OpenAI API要求的JSON结构。

更令人省心的是,Agents SDK会全权处理函数的调用过程,开发者无需再编写解析LLM输出和执行函数调用的代码。

创建Agent实例

Agents SDK提供了一个核心类Agent(),使得创建新agent变得异常简单。以下是基本使用示例:

# define agent
agent = Agent(
    name="YouTube Transcript Agent",
    instructions=instructions,
    tools=[fetch_youtube_transcript],
)

开发Agent交互系统

到目前为止,构建Agent的逻辑代码非常简单。但因为这个系统是异步的(即不按照预设步骤顺序执行),实现其交互界面就变得不那么容易了。

这主要涉及两个技术难点:

  1. 模型生成的文本需要实时流式输出,让用户感受到即时交互

  2. 函数调用可能存在延迟,在此期间仍需保持应用其他功能的运行(比如界面更新或处理用户中断操作)

为简化实现过程,我们选择在命令行环境中构建这个聊天系统。

# define main chat function
async def main():
    input_items = []

    print("=== YouTube Transcript Agent ===")
    print("Type 'exit' to end the conversation")
    print("Ask me anything about YouTube videos!")

    while True:
        # Get user input
        user_input = input("\nYou: ").strip()
        input_items.append({"content": user_input, "role": "user"})
        
        # Check for exit command
        if user_input.lower() in ['exit', 'quit', 'bye']:
            print("\nGoodbye!")
            break
            
        if not user_input:
            continue

        print("\nAgent: ", end="", flush=True)
        result = Runner.run_streamed(
            agent,
            input=input_items,
        )

        async for event in result.stream_events():
            # We'll ignore the raw responses event deltas
            if event.type == "raw_response_event" and isinstance(event.data, ResponseTextDeltaEvent):
                print(event.data.delta, end="", flush=True)
            elif event.type == "agent_updated_stream_event":
                continue
            elif event.type == "run_item_stream_event":
                if event.item.type == "tool_call_item":
                    print("\n-- Fetching transcript...")
                elif event.item.type == "tool_call_output_item":
                    input_items.append({"content": f"Transcript:\n{event.item.output}", "role": "system"})
                    print("-- Transcript fetched.")
                elif event.item.type == "message_output_item":
                    input_items.append({"content": f"{event.item.raw_item}", "role": "assistant"})
                else:
                    pass  # Ignore other event types

        print("\n")  # Add a newline after each response

# run main
if __name__ == "__main__":
    asyncio.run(main())

# note: if running in Jupyter lab simply run "await main()"

以下展示最终实现的效果:

1_u67FBWhfnFUPQo4r_aXYLA.gif

后续发展方向

AI Agent技术正在重新定义软件的可能性——开发者无需预先明确所有功能细节,就能创建出高度灵活的应用程序。通过本文的实践,我们看到只需为大型语言模型(LLM)提供工具调用能力,它就能即时生成针对任意用户请求的解决方案

不过这种灵活性也带来了不可预测性的代价,可能影响用户体验。此外,依赖单一LLM在处理复杂任务时会显现局限性。

本系列的下一篇文章将探讨如何通过智能工作流实现两大目标:

  • 构建更可靠的AI Agent;

  • 通过协同多个LLM来处理更复杂的任务系统。

6
博主关闭了所有页面的评论