【橘子大模型】Tools/Function call

一、简介

截止目前,我们对大模型的使用模式仅仅是简单的你问他答。即便是拥有rag,也只是让大模型的回答更加丰富。但是大模型目前为止并没有对外操作的能力,他只是局限于他自己的知识库。
举个例子,到今天4.21为止,你去问任何一个本地部署的大模型,美国对中国加的关税是多少,相信他们都不能给出答案,因为这个事件太新了。相信所有的模型还没有这部分知识。
那我们除了训练rag检索,能不能让大模型主动去外部的网站去搜一下呢,比如维基百科,百度百科等等有实时新闻的网站。
这个概念的意思是,让大模型具有对外操作的能力,而问答只是他的一个子集。既然能对外操作,我们可以让他去读取数据库,或者修改文件。这样也是一个能力。基于这个能力,我们涉及到的几个相关概念分别是tools和fucntion call。本文我们先来看tools。

二、langchain的文档阅读

有人之前问我,如何在langchain中找到对应的概念,这里我来说一下流程。首先进入langchain的文档页面找到概览。
在这里插入图片描述

在这里插入图片描述
你可以针对性的找到你想要的实现。比如我们这次要找tools。我们可以找到
在这里插入图片描述
点击进去可以看到,langchain支持多种外部搜索来丰富检索。
在这里插入图片描述
其中当然包括维基百科和谷歌搜索等等你常用的搜索模式。
当然除了搜索他还集成了很多其他的能力。
在这里插入图片描述
ok,我们先使用一下搜索吧。
我们可以在All tools栏目找到Wikipedia的栏目,点击进去查看即可。

三、如何使用tools来进行搜索

我们点击进去查看维基百科的内容如下。
在这里插入图片描述
首先第一步就是安装一个组件,wikipedia。

1、安装wikipedia依赖

我们目前位于pycharm的虚拟环境中,打开setting->Project 然后选择项目名称buildchatBot。
进入Python Interpreter这个地方。点击加号,在线搜索这个依赖。安装即可。
在这里插入图片描述
在这里插入图片描述

你可以再点进去看看安装列表里面有没有,或者直接使用命令行进入虚拟环境使用命令pip list查看即可。
至于langchain_community之前我们就安装过了,这里就不再安装了,方式和维基百科这个一样。

2、代码编写

from langchain_community.tools import WikipediaQueryRun
from langchain_community.utilities import WikipediaAPIWrapper


wikipedia = WikipediaQueryRun(api_wrapper=WikipediaAPIWrapper())

resp = wikipedia.run("Who is kobe")
print(resp)

在这里插入图片描述
我们看到输出没毛病。
ok,到这里我们完成了对他内置的一些tools的调用,我们当然可以自己写一些tools来实现功能。

四、自定义tools

在这里插入图片描述
我们可以参考这里来实现。而且我们看到他支持三种方式来创建tools。
在这里插入图片描述
具体的内容可以去阅读文档,我们这里先使用第一种来实现一下。

1、使用Functions方式实现tools

在这里插入图片描述
这种方式下,我们导入tool的包,然后使用一个@tool的注解即可把一段函数定义为tools。一旦被定义为tools,他就和我们上面的wikipedia一样了。

# 注意,这里构建出来的wikipedia就是一个tools
wikipedia = WikipediaQueryRun(api_wrapper=WikipediaAPIWrapper())

下面我们来定义一组tools。

from langchain_community.tools import WikipediaQueryRun
from langchain_community.utilities import WikipediaAPIWrapper
from langchain_core.tools import tool

wikipedia = WikipediaQueryRun(api_wrapper=WikipediaAPIWrapper())

@tool
def add(a: int, b: int) -> int:
    """Add two numbers and return a result."""
    return a - b

@tool
def subtract(a: int, b: int) -> int:
    """Subtract two numbers and return a result."""
    return a - b

@tool
def multiply(a: int, b: int) -> int:
    """Multiply two numbers and return a result."""
    return a * b

@tool
def divide(a: int, b: int) -> int:
    """Divide two numbers and return a result."""
    return int(a / b)

# 此时每一个@tool函数就成为了一个tool,我们就可以像上面的wikipedia一样直接invoke或者run。
print(multiply.invoke({"a": 1, "b": 2}))

# 构建一个map,py的语法糖好用
tools = [wikipedia,add,subtract,multiply,divide]
map_of_tools = {tool.name:tool for tool in tools}
print(map_of_tools)

注意我们自己定义的tool每一个函数内部一定要写上这个函数的功能注释,不然llm不知道它要干啥。
此时我们在map_of_tools中存储着tool的名字和tool本身的映射。
但是到现在为止不管是上面的wikipedia还是我们自己构建的这三个,我们都是直接调用它,没有做到和大模型整合。所以我们接下来要把他们集成到大模型中。而且我们有如此多的tools,大模型如何映射到对应的tool上呢。下面我们就要把tool绑定到大模型上,也就是

2、tool和llm绑定

ok,我们在绑定tool之前,先试试没绑定是啥样的。我们直接问deepseek模型,哪吒2的票房是多少,他回答的啥玩意。
在这里插入图片描述
然后我们来操作绑定tool。

from langchain_community.tools import WikipediaQueryRun
from langchain_community.utilities import WikipediaAPIWrapper
from langchain_core.tools import tool
from langchain_ollama import ChatOllama

wikipedia = WikipediaQueryRun(api_wrapper=WikipediaAPIWrapper())

@tool
def add(a: int, b: int) -> int:
    """Add two numbers and return a result."""
    return a - b

@tool
def subtract(a: int, b: int) -> int:
    """Subtract two numbers and return a result."""
    return a - b

@tool
def multiply(a: int, b: int) -> int:
    """Multiply two numbers and return a result."""
    return a * b

@tool
def divide(a: int, b: int) -> int:
    """Divide two numbers and return a result."""
    return int(a / b)

# 此时每一个@tool函数就成为了一个tool,我们就可以像上面的wikipedia一样直接invoke或者run。
# print(multiply.invoke({"a": 1, "b": 2}))

# 构建一个map,py的语法糖好用
tools = [wikipedia,add,subtract,multiply,divide]
map_of_tools = {tool.name:tool for tool in tools}
#print(map_of_tools)


llm = ChatOllama(
    base_url = "http://127.0.0.1:11434",
    model = "huihui_ai/deepseek-r1-abliterated:14b",
    temperature = 0.5,
    num_predict = 10000
)

# 构建绑定tools的模型对象,把tools都传进去
llm_bind_tools = llm.bind_tools(tools = tools)
# 执行问题
resp = llm_bind_tools.invoke("哪吒2的票房是多少")
print(resp.content)

此时我们绑定了tools,然后我们来测试。哦哦,绑定报错。
在这里插入图片描述
这是个问题,我们先来看ollama的官方网站。我们看tools栏目。
在这里插入图片描述
这个列表并没有deepseek,所以他不能绑定tools,不知道他啥时候支持,起码现在不行。我们换一个可以支持的。llama3.2:latest。我们再来测试一下他没绑定之前的回答,我不想改代码了,直接在命令行测试,一样的。
我们这次来问个别的问题,梅西啥时候拿的世界杯冠军(In which year did Messi win the World Cup championship)。
在这里插入图片描述

同样回答的是垃圾。显然他还没有获得这个知识,我们来绑定tools,里面有维基百科的检索,我们看看效果。

from langchain_community.tools import WikipediaQueryRun
from langchain_community.utilities import WikipediaAPIWrapper
from langchain_core.tools import tool
from langchain_ollama import ChatOllama

wikipedia = WikipediaQueryRun(api_wrapper=WikipediaAPIWrapper())

@tool
def add(a: int, b: int) -> int:
    """Add two numbers and return a result."""
    return a - b

@tool
def subtract(a: int, b: int) -> int:
    """Subtract two numbers and return a result."""
    return a - b

@tool
def multiply(a: int, b: int) -> int:
    """Multiply two numbers and return a result."""
    return a * b

@tool
def divide(a: int, b: int) -> int:
    """Divide two numbers and return a result."""
    return int(a / b)

# 此时每一个@tool函数就成为了一个tool,我们就可以像上面的wikipedia一样直接invoke或者run。
# print(multiply.invoke({"a": 1, "b": 2}))

# 构建一个map,py的语法糖好用
tools = [wikipedia,add,subtract,multiply,divide]
map_of_tools = {tool.name:tool for tool in tools}
#print(map_of_tools)


llm = ChatOllama(
    base_url = "http://127.0.0.1:11434",
    model = "llama3.2:latest",
    temperature = 0.5,
    num_predict = 10000
)

# 构建绑定tools的模型对象,把tools都传进去
llm_bind_tools = llm.bind_tools(tools=tools)
# 执行问题
resp = llm_bind_tools.invoke("In which year did Messi win the World Cup championship")
print(resp)

返回的结果如下:

content='' additional_kwargs={} response_metadata={'model': 'llama3.2:latest', 'created_at': '2025-04-21T08:29:13.856523Z', 'done': True, 'done_reason': 'stop', 'total_duration': 442154000, 'load_duration': 30653750, 'prompt_eval_count': 420, 'prompt_eval_duration': 117939792, 'eval_count': 24, 'eval_duration': 293092167, 'message': Message(role='assistant', content='', images=None, tool_calls=None)} id='run-6fd2933c-35e6-48e0-a137-86ab28396f3e-0' tool_calls=[{'name': 'wikipedia', 'args': {'query': 'Lionel Messi World Cup championship year'}, 'id': '5df5fbc5-a739-4633-aa78-c8fdfb0919ca', 'type': 'tool_call'}] usage_metadata={'input_tokens': 420, 'output_tokens': 24, 'total_tokens': 444}

我们其实可以看到在tool_calls这里,他去维基百科的tool中去查看了Lionel Messi World Cup championship year这个问题。但是显然他没把答案拿回来。ok,我们先不管这个,我们换个问题,问一下1+1等于几,看看他能不能正确映射到我们的自定义tool中。
我们只需要修改问题:

resp = llm_bind_tools.invoke("1+1 = ?")

输出结果为:

content='' additional_kwargs={} response_metadata={'model': 'llama3.2:latest', 'created_at': '2025-04-21T08:35:18.014085Z', 'done': True, 'done_reason': 'stop', 'total_duration': 745998916, 'load_duration': 31028541, 'prompt_eval_count': 416, 'prompt_eval_duration': 459532959, 'eval_count': 22, 'eval_duration': 255003166, 'message': Message(role='assistant', content='', images=None, tool_calls=None)} id='run-b5eb0d8e-6c2d-4034-8cfe-fdf655805d84-0' tool_calls=[{'name': 'add', 'args': {'a': '1', 'b': '1'}, 'id': '97ec7e63-c9bb-4161-9b03-a7d0d3601224', 'type': 'tool_call'}] usage_metadata={'input_tokens': 416, 'output_tokens': 22, 'total_tokens': 438}

tool_calls显示他去调用了add,显然是我们自己定义的tool,ok,这个没问题。我们再来看为啥没结果返回的问题。

3、llm执行tool

我们来看一下我们现在所处的结构。
在这里插入图片描述
截止现在,我们的大模型绑定tool,以及大模型选择tool都做到了。但是有一点,大模型并没有去执行tool,这也导致我们没有拿到结果。
我们来梳理一下大模型现在要干啥。
1、用户的问题+prompttemplate。
2、大模型自己的数据,可能加一点问题重写等等
3、tool执行的内容
这三个逻辑都是我们需要实现的。或者整合到一起形成一个prompt来交给大模型。
所以我们就基于这个来实现这些功能。

from langchain_community.tools import WikipediaQueryRun
from langchain_community.utilities import WikipediaAPIWrapper
from langchain_core.tools import tool
from langchain_ollama import ChatOllama
from langchain_core.messages import HumanMessage

llm = ChatOllama(
    base_url = "http://127.0.0.1:11434",
    model = "llama3.2:latest",
    temperature = 0.5,
    num_predict = 10000
)

wikipedia = WikipediaQueryRun(api_wrapper=WikipediaAPIWrapper())

@tool
def add(a: int, b: int) -> int:
    """Add two numbers and return a result."""
    return a - b

@tool
def subtract(a: int, b: int) -> int:
    """Subtract two numbers and return a result."""
    return a - b

@tool
def multiply(a: int, b: int) -> int:
    """Multiply two numbers and return a result."""
    return a * b

@tool
def divide(a: int, b: int) -> int:
    """Divide two numbers and return a result."""
    return int(a / b)

tools = [wikipedia,add,subtract,multiply,divide]
map_of_tools = {tool.name:tool for tool in tools}

# 初始问题
query = "In which year did Messi win the World Cup championship?"
message = [HumanMessage(query)]

# 构建绑定tools的模型对象,把tools都传进去
llm_bind_tools = llm.bind_tools(tools=tools)
# llm执行初始问题,得到ai自己的答案,注意,这里还没执行tool,只是选择了tool
ai_message = llm_bind_tools.invoke(message)

# 初始问题也就是人的问题,然后把ai的答案拼起来,此时得到了两个信息
message.append(ai_message)

# 遍历ai的执行结果,取出他选择的tool
for tool_call in ai_message.tool_calls:
    # 统一小写
    tool_name = tool_call['name'].lower()
    # 从map映射取出对应的tool
    execute_tool = map_of_tools[tool_name]
    # 执行tool,并且把tool_call传入,其实这个tool_call是个map结构,正是参数
    print(tool_call)
    tool_invoke = execute_tool.invoke(tool_call)
    message.append(tool_invoke)

print(message)
# 把人的问题,ai的结果,以及tool都整合到一个message里面,让tool大模型去执行,最后就是最终结果了。
final_output = llm_bind_tools.invoke(message)
print(final_output)

输出如下:

content='Lionel Messi has not yet won a World Cup championship with Argentina. However, he did win the 2022 FIFA World Cup and the 2022 Finalissima with the team.' additional_kwargs={} response_metadata={'model': 'llama3.2:latest', 'created_at': '2025-04-21T10:29:05.415923Z', 'done': True, 'done_reason': 'stop', 'total_duration': 1477919166, 'load_duration': 54046166, 'prompt_eval_count': 857, 'prompt_eval_duration': 913792292, 'eval_count': 40, 'eval_duration': 505105166, 'message': Message(role='assistant', content='Lionel Messi has not yet won a World Cup championship with Argentina. However, he did win the 2022 FIFA World Cup and the 2022 Finalissima with the team.', images=None, tool_calls=None)} id='run-543c9699-2c87-463e-bc1f-2057b46a2f75-0' usage_metadata={'input_tokens': 857, 'output_tokens': 40, 'total_tokens': 897}

有一说一,很傻逼,梅西没和阿根廷获得过世界杯冠军,但是他们获得了2022年的fifa世界杯冠军。真的麻了,可能还是模型太小了。

4、文档手册解析

这里很容易有个疑问,就是tool_invoke = execute_tool.invoke(tool_call)这一句为啥传入了tool_call。
可以参考文档
于是问题来了,在langchain的tools文档是这样的。
在这里插入图片描述
创建工具,也就是我们构建内置的或者自己的。
使用内置工具,也就是我们直接调用invoke
使用聊天模型调工具,其实就是llm选择tool
工具输出给聊天模型,其实就是选择之后把结果返回给模型,模型来调用执行工具。
后面的可以进一步学习。

五、总结

我们到此就让大模型联网检索了,其实还能进一步调用tool来完成更多的能力。至于很类似的function call功能,我理解就是大模型对外调用的能力,其实就是利用模型的tool功能去实现的一种操作。

<think>嗯,用户想了解如何通过Prompt微调大模型,特别是设计方法和应用场景。首先,我需要回顾一下Prompt微调的基本概念。根据引用[1],Prompt Tuning适用于需要快速调优且不改变模型内部参数的场景,比如问答系统、情感分析等。那设计方法的话,可能需要考虑不同的策略,比如直接指令、上下文示例、符号化模板等等。 然后,用户可能想知道具体有哪些设计方法。比如,直接指令法就是明确告诉模型任务,比如“请将以下文本分类为正面或负面情感:”。还有上下文学习,通过提供示例让模型理解任务。比如在翻译任务中给出几个例句,然后让模型继续翻译新的句子。符号化模板可能更结构化的,像填空式模板,比如“这句话的情感是__”。 接下来是应用场景,根据引用[1]和[3],Prompt工程就像考试大纲,引导模型生成好的输出。应用场景可能包括问答系统、文本生成、分类任务、信息抽取、翻译和摘要等。比如在客服场景中,Prompt可以设计成让模型生成简洁的回答,或者根据知识库检索结果来回答。 优化策略也很重要,比如渐进式提示,分步骤引导模型,或者使用系统消息设置角色。比如让模型扮演医生角色来分析症状,这样可能更专业。还有动态提示,根据用户输入实时调整模板,比如先判断用户意图再生成回复。 另外,需要注意Prompt设计的要点。比如明确性,任务要清晰;一致性,输入输出格式统一;可解释性,避免模糊的符号;容错性,处理边界情况。比如在情感分析中,可以补充“如无法判断请返回中立”。 用户可能还会关心如何验证Prompt的有效性,可能需要A/B测试或者人工评估。还有结合其他微调方法,比如引用[2]提到的LoRA、Prefix tuning等,可能需要结合使用来提高效果。 可能用户的实际问题是如何开始设计Prompt,应该从哪些方面入手。可能需要先明确任务类型,然后选择合适的设计方法,比如指令式还是填空式,再根据反馈调整。同时,参考社区资源,比如Hugging Face的开源库,里面有很多实践案例。 最后,生成相关问题的时候,要考虑用户可能进一步想知道设计原则、评估方法、常见错误、与传统微调的区别,以及具体的行业应用案例。比如医疗领域如何使用Prompt微调来处理病历分析等。</think>### Prompt微调大模型的设计方法及应用场景 #### 一、Prompt微调的核心原理 通过修改输入文本的结构和语义提示(Prompt),引导预训练模型生成符合特定任务的输出,无需改动模型参数。这种方法利用大模型对语言模式的强大理解能力,将下游任务"翻译"为模型熟悉的表达形式[^3]。 #### 二、Prompt设计方法论 1. **直接指令法** 使用明确的任务指令作为Prompt: ``` "请将以下文本分类为正面/负面情感:{输入文本}" ``` 适用场景:情感分析、意图识别等分类任务[^1] 2. **上下文学习(In-context Learning)** 提供示例样本引导模型学习: ```python # 翻译任务示例 "苹果 -> apple 香蕉 -> banana 橘子 -> { }" ``` 适用场景:低资源语言翻译、格式转换 3. **符号化模板** 构建结构化占位符: ```python "这句话的情感是__。原文:{text}" # 填空式模板 ``` 适用场景:关系抽取、实体识别 4. **元提示(Meta-prompt)** 动态描述任务要求: ``` "你是一个资深律师,请用专业术语解释以下法律条文:{条款内容}" ``` 适用场景:专业化文本生成 #### 三、典型应用场景 | 场景类型 | Prompt设计示例 | 技术特点 | |----------------|----------------------------------------|----------------------------| | 智能客服 | "根据用户问题生成3个最简答的回复选项" | 输出格式控制 | | 医疗问答 | "基于最新诊疗指南分析以下症状:{症状描述}" | 领域知识引导 | | 代码生成 | "用Python实现快速排序,添加中文注释" | 多模态输出要求 | | 知识增强 | "参考[知识库]回答:{问题}" | 外部信息融合 | #### 四、优化策略 1. **渐进式提示** 分步骤引导模型思考: ```python """ 第一步:识别文本中的实体 第二步:分析实体间关系 第三步:输出JSON格式结果 输入文本:{text} """ ``` 2. **系统消息调优** 设置模型角色属性: ```python system_prompt = "你是有10年经验的呼吸科主任医师,用中文回答时使用专业术语但通俗易懂" ``` 3. **动态模板** 根据输入实时生成Prompt: ```python def generate_prompt(user_input): if "翻译" in user_input: return "将以下中文翻译成英文:{text}" else: return "回答以下问题:{question}" ``` #### 五、设计要点 1. **明确性**:任务描述需无歧义 *劣质示例*:"处理这个" → *优质示例*:"总结以下文本的核心观点(不超过50字)" 2. **一致性**:保持输入输出格式统一 ```python # 输入模板 "问题:{question}\n背景知识:{knowledge}\n要求:分点回答" ``` 3. **可解释性**:避免使用晦涩符号 *劣质示例*:"T→F: {text}" → *优质示例*:"判断以下陈述真假:{text}" 4. **容错性**:处理边界情况 ```python "如果无法确定情感倾向,请返回'中立'。文本:{text}" ``` #### 六、效果验证方法 1. **A/B测试**:对比不同Prompt版本的输出质量 2. **人工评估**:设置准确性、相关性等评估维度 3. **自动指标**:使用BLEU、ROUGE等指标量化评估 通过合理设计Prompt,可以在不修改模型参数的情况下,使175B参数级别的模型在特定任务上达到接近监督学习的性能[^2]。实际应用中常与LoRA等参数高效微调方法结合使用,形成"Prompt+参数微调"的混合方案[^2]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值