分享一个langchain开发中的免费搜索工具duckduckgo,@tool修饰的使用

注意@tool 修饰在langchainV0.2支持

什么是@tool修饰?

from langchain_core.tools import tool

@tool
def add(a: int, b: int) -> int:
    """Adds a and b."""
    return a + b

from langchain_openai import ChatOpenAI

tool = [add]

model = ChatOpenAI(model="gpt-4o-2024-08-06")

prompt = "5+6等于多少?"

model_with_tool = model.bind_tools(tools=tool, tool_choice="add")

model_with_tool.invoke(prompt).tool_calls

return如下,可见返回的消息中已经有函数调用信息,但是现在还没有进行函数调用

[{'name': 'add',
  'args': {'a': 5, 'b': 6},
  'id': 'call_UXCUvL7VpFJKhFmGEmfGiOlX',
  'type': 'tool_call'}]

经过@tool修饰就可以令自定义的函数像langchain预定义的工具(tool)一样被支持工具调用的模型(例如OpenAI的GPT系列)调用

下面我们根据模型生成的参数和调用信息来调用工具

# 将用户输入和准备调用工具的信息转换为列表作为下一步给模型的输入
tool_invoke = add.invoke(model_with_tool.invoke(prompt).tool_calls[0])
tool_invoke

输出

ToolMessage(content='11', name='add', tool_call_id='call_3EzfZjrkTYMYwssYEInaloDY')

这样就实现了一次完整的工具调用,那么后续我们就可以根据执行的结果来进行模型的自然语言回答,这里不做介绍

duckduckgo是一个完全免费的搜索工具,调用也是免费的不同于Tavily和Google有免费额度的搜索限制,开发阶段(对于资金不充裕的我)非常友好

langchain中的duckduckgo工具的文档给定的示例 DuckDuckGoSearchResults 这个接口我认为已经过时,可以直接用 @tool 来自己实现修饰一个duckduckgo搜索工具的实现,duckduckgo_search这个链接是python包的地址,在用langchain官方示例
DuckDuckGoSearchResults.invoke(“what is openai?”)
如图1它不能给我返回有效的例如官网或者wiki的介绍

如图2直接调用duckduckgo_search sdk中的函数返回的内容确是非常精准的有wiki和官网的内容,还有一些额外的功能可以自己进行实现,所以我推荐自己制作一个tool来调用,这样的体验和可控性会更好

那么如何实现我们可以仿照上述@tool来实现,注意实现函数的时候里面的描述也会传递给模型所以大家写描述的时候要写清楚

from langchain_core.tools import tool
from duckduckgo_search import DDGS
@tool
def duckduckgo(query: str) -> list:
    """
    Invoke DuckDuckGo's service to retrieve the latest information from the internet.
    
    Args:
        query: The query.

    Returns:
        search_results: The search results.
    """
    search_results = DDGS().text(keywords=query, region="wt-wt", safesearch="on", max_results=2)
    return search_results

from langchain_openai import ChatOpenAI
tool = [duckduckgo]
model = ChatOpenAI(model="gpt-4o-2024-08-06")
prompt = "what is openai?"
model_with_tool = model.bind_tools(tools=tool, tool_choice="duckduckgo")

model_with_tool.invoke(prompt).tool_calls

return

[{'name': 'duckduckgo',
  'args': {'query': 'OpenAI'},
  'id': 'call_2buAM5HatlN9MwhS3wV6qIdH',
  'type': 'tool_call'}]
tool_invoke = duckduckgo.invoke(model_with_tool.invoke(prompt).tool_calls[0])
tool_invoke

return

ToolMessage(content='[{"title": "OpenAI", "href": "https://openai.com/", "body": "Instant answers. Greater productivity. Endless inspiration. We believe our research will eventually lead to artificial general intelligence, a system that can solve human-level problems. Building safe and beneficial AGI is our mission."}, {"title": "ChatGPT | OpenAI", "href": "https://openai.com/chatgpt/", "body": "Get started with ChatGPT today. View pricing plans. Free. Assistance with writing, problem solving and more. Access to GPT-4o mini. Limited access to GPT-4o. Limited access to advanced data analysis, file uploads, vision, web browsing, and image generation. Use custom GPTs. $0/ month."}]', name='duckduckgo', tool_call_id='call_Uz2bxRlaORAgH5UtTyIctIj1')

返回的内容是OpenAI官网,可见搜索的还是很精准的

那么你也可以自己来定义自己的工具来给LLM使用,像定义函数一样容易

10 Likes

langchain 对比 dify这种工作流最主要的差别在哪

2 Likes

dify我具体没特别用过,我之前用过字节的coze感觉dify跟那个很像,我自己感觉langchain更加的可以定制化吧,因为可以操作的地方很多比如自定义各种工具或者嫁接其他的产品或者服务

来吧上代码玩玩

感谢大佬分享

感谢大佬分享

感谢大佬分享

好像挺有用,在具体一点就好

搞了一段可以查看一下更新了post

现在具体了一些

能用真不错 哈哈哈哈