LangChain使用函数调用的技巧与流程

  • 01. bind()与bind_tools()

    我们在 OpenAI 的 GPT 模型如何添加工具的描述参数,即在实例化的时候传递多一个 tools 参数,如下:

    completion = client.chat.completions.create(

    model="gpt-3.5-turbo-16k",

    messages=messages,

    tools=tools,

    tool_choice="auto"

    )

    其实除了上面的这些参数,我们还可以传递 temperature 温度参数,这些参数本质上都是模型生成内容时传递的 运行时参数,所以在 LangChain 中,我们可以使用 convert_to_openai_tool 将自定义工具转换成符合 GPT 模型的参数格式,使用 .bind() 函数来传递对应的 tools 和 tool_choice,从而完成对大语言模型函数的绑定。

    运行流程如下:

  • 不过由于上述的步骤太过于常见,所以 LangChain 团队单独对支持 函数调用 的大语言模型添加了 .bind_tools() 函数,可以快捷地完成此操作,例如 GPT 模型的 .bind_tools() 函数的核心代码如下

    def bind_tools(

    self,

    tools: Sequence[Union[Dict[str, Any], Type[BaseModel], Callable, BaseTool]],

    *,

    tool_choice: Optional[

    Union[dict, str, Literal["auto", "none", "required", "any"], bool]

    ] = None,

    **kwargs: Any,

    ) -> Runnable[LanguageModelInput, BaseMessage]:

    formatted_tools = [convert_to_openai_tool(tool) for tool in tools]

    if tool_choice:

    if isinstance(tool_choice, str):

    tool_choice is a tool/function name

    if tool_choice not in ("auto", "none", "any", "required"):

    tool_choice = {

    "type": "function",

    "function": {"name": tool_choice},

    }

    'any' is not natively supported by OpenAI API.

    We support 'any' since other models use this instead of 'required'.

    if tool_choice == "any":

    tool_choice = "required"

    elif isinstance(tool_choice, bool):

    tool_choice = "required"

    elif isinstance(tool_choice, dict):

    tool_names = [

    formatted_tool["function"]["name"]

    for formatted_tool in formatted_tools

    ]

    if not any(

    tool_name == tool_choice["function"]["name"]

    for tool_name in tool_names

    ):

    raise ValueError(

    f"Tool choice {tool_choice} was specified, but the only "

    f"provided tools were {tool_names}."

    )

    else:

    raise ValueError(

    f"Unrecognized tool_choice type. Expected str, bool or dict. "

    f"Received: {tool_choice}"

    )

    kwargs["tool_choice"] = tool_choice

    return super().bind(tools=formatted_tools, **kwargs)

    02. LLM绑定天气预报与谷歌实时搜索

    例如要将前两节课实现的 天气预报 与 谷歌实时搜索 接入到 GPT 模型中,其实只需要创建好自定义工具后,将自定义工具组装成列表,然后调用 .bind_tools() 函数即可完成 LLM 对函数的绑定,当大语言模型返回的内容携带 函数调用参数 时,可以通过 .tool_calls 属性来获取对应的信息。

    例如:将 GPT 模型绑定 天气预报 与 谷歌实时,并且当执行工具调用时,将 工具结果 附加到历史消息列表中,再次传递给大语言模型,让其生成对应的内容,完整代码如下

    import json

    import os

    from typing import Type, Any

    import dotenv

    import requests

    from langchain_community.tools import GoogleSerperRun

    from langchain_community.utilities import GoogleSerperAPIWrapper

    from langchain_core.messages import ToolMessage

    from langchain_core.prompts import ChatPromptTemplate

    from langchain_core.pydantic_v1 import Field, BaseModel

    from langchain_core.runnables import RunnablePassthrough

    from langchain_core.tools import BaseTool

    from langchain_openai import ChatOpenAI

    dotenv.load_dotenv()

    class GaodeWeatherArgsSchema(BaseModel):

    city: str = Field(description="需要查询天气预报的目标城市,例如:广州")

    class GoogleSerperArgsSchema(BaseModel):

    query: str = Field(description="执行谷歌搜索的查询语句")

    class GaodeWeatherTool(BaseTool):

    """根据传入的城市名查询天气"""

    name = "gaode_weather"

    description = "当你想询问天气或与天气相关的问题时的工具。"

    args_schema: Type[BaseModel] = GaodeWeatherArgsSchema

    def _run(self, *args: Any, **kwargs: Any) -> str:

    """运行工具获取对应城市的天气预报"""

    try:

    1.获取高德API秘钥,如果没有则抛出错误

    gaode_api_key = os.getenv("GAODE_API_KEY")

    if not gaode_api_key:

    return f"高德开放平台API秘钥未配置"

    2.提取传递的城市名字并查询行政编码

    city = kwargs.get("city", "")

    session = requests.session()

    api_domain = "https://restapi.amap.com/v3"

    city_response = session.request(

    method="GET",

    url=f"{api_domain}/config/district?keywords={city}&subdistrict=0&extensions=all&key={gaode_api_key}",

    headers={"Content-Type": "application/json; charset=utf-8"},

    )

    city_response.raise_for_status()

    city_data = city_response.json()

    3.提取行政编码调用天气预报查询接口

    if city_data.get("info") == "OK":

    if len(city_data.get("districts")) > 0:

    ad_code = city_data["districts"][0]["adcode"]

    weather_response = session.request(

    method="GET",

    url=f"{api_domain}/weather/weatherInfo?city={ad_code}&extensions=all&key={gaode_api_key}&output=json",

    headers={"Content-Type": "application/json; charset=utf-8"},

    )

    weather_response.raise_for_status()

    weather_data = weather_response.json()

    if weather_data.get("info") == "OK":

    return json.dumps(weather_data)

    session.close()

    return f"获取{kwargs.get('city')}天气预报信息失败"

    4.整合天气预报信息并返回

    except Exception as e:

    return f"获取{kwargs.get('city')}天气预报信息失败"

    1.定义工具列表

    gaode_weather = GaodeWeatherTool()

    google_serper = GoogleSerperRun(

    name="google_serper",

    description=(

    "一个低成本的谷歌搜索API。"

    "当你需要回答有关时事的问题时,可以调用该工具。"

    "该工具的输入是搜索查询语句。"

    ),

    args_schema=GoogleSerperArgsSchema,

    api_wrapper=GoogleSerperAPIWrapper(),

    )

    tool_dict = {

    gaode_weather.name: gaode_weather,

    google_serper.name: google_serper,

    }

    tools = [tool for tool in tool_dict.values()]

    2.创建Prompt

    prompt = ChatPromptTemplate.from_messages([

    ("system", "你是由OpenAI开发的聊天机器人,可以帮助用户回答问题,必要时刻请调用工具帮助用户解答"),

    ("human", "{query}"),

    ])

    3.创建大语言模型并绑定工具

    llm = ChatOpenAI(model="gpt-3.5-turbo-16k", temperature=0)

    llm_with_tool = llm.bind_tools(tools=tools)

    4.创建链应用

    chain = {"query": RunnablePassthrough()} | prompt | llm_with_tool

    5.解析输出

    query = "广州现在天气怎样,有什么适合穿的衣服呢"

    resp = chain.invoke(query)

    tool_calls = resp.tool_calls

    6.判断是工具调用还是正常输出结果

    if len(tool_calls) <= 0:

    print("生成内容:", resp.content)

    else:

    7.将历史的系统消息、人类消息、AI消息组合

    messages = prompt.invoke(query).to_messages()

    messages.append(resp)

    8.循环遍历所有工具调用信息

    for tool_call in tool_calls:

    tool = tool_dict.get(tool_call.get("name"))

    print("正在执行工具: ", tool.name)

    id = tool_call.get("id")

    content = tool.invoke(tool_call.get("args"))

    print("工具输出: ", content)

    messages.append(ToolMessage(

    content=content,

    tool_call_id=id,

    ))

    print("输出内容: ", llm.invoke(messages))

    到这里,你已经构建出了第一个用程序实现的 Agent,这个 Agent 拥有 实时信息搜索 和 天气预报查询 功能,但是有没有发现一个问题,原本我们使用 LECL 表达式构建的链应用是非常优雅的,但是加入了 判断、循环、工具调用 等模块后,维护起来也相对吃力,不过这个问题很快就会解决,在 LangChain 中针对 Agent 应用的创建,目前有两种封装好的策略,一种使用传统 Agent,另外一种使用 LangGraph。

相关推荐
九.九9 小时前
ops-transformer:AI 处理器上的高性能 Transformer 算子库
人工智能·深度学习·transformer
春日见9 小时前
拉取与合并:如何让个人分支既包含你昨天的修改,也包含 develop 最新更新
大数据·人工智能·深度学习·elasticsearch·搜索引擎
小高不会迪斯科9 小时前
CMU 15445学习心得(二) 内存管理及数据移动--数据库系统如何玩转内存
数据库·oracle
恋猫de小郭9 小时前
AI 在提高你工作效率的同时,也一直在增加你的疲惫和焦虑
前端·人工智能·ai编程
YJlio9 小时前
1.7 通过 Sysinternals Live 在线运行工具:不下载也能用的“云端工具箱”
c语言·网络·python·数码相机·ios·django·iphone
deephub9 小时前
Agent Lightning:微软开源的框架无关 Agent 训练方案,LangChain/AutoGen 都能用
人工智能·microsoft·langchain·大语言模型·agent·强化学习
e***8909 小时前
MySQL 8.0版本JDBC驱动Jar包
数据库·mysql·jar
l1t9 小时前
在wsl的python 3.14.3容器中使用databend包
开发语言·数据库·python·databend
大模型RAG和Agent技术实践9 小时前
从零构建本地AI合同审查系统:架构设计与流式交互实战(完整源代码)
人工智能·交互·智能合同审核
老邋遢9 小时前
第三章-AI知识扫盲看这一篇就够了
人工智能