让GPT使用工具

‍‍

*使用DeepSeek API测试

Function Calling

让AI调用已经定义好的python 方法

Function Calling 让模型能够调用外部工具,来增强自身能力。

  • 将可以使用方法(工具)说明,随用户请求一起放在Prompt中传给GPT
  • GPT返回要调用的方法及参数值,然后在外部运行该方法获得结果
  • 将调用结果及前面的对话历史一起放入Prompt,再次调用GPT

例如:

  • 构建一个dict对象存储:{“Method1”, “Method2”, …}
  • 在Prompt中加入方法定义
  • 根据LLM的返回,决定是否调用函数(返回信息中含有”Function_call”),还是直接返回信息给用户
  • 如需调用函数,则调用LLM指定函数,并将结果及调用的函数一起放在Prompt中再次调用LLM

OpenAI GPT4o的例子

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
import openai
import json
import os
from openai import AzureOpenAI

client = AzureOpenAI(
api_key=os.getenv("OPENAI_API_KEY"),
api_version=os.getenv("OPENAI_API_VERSION"),
azure_endpoint = os.getenv("OPENAI_API_BASE")
)


funcs = {"get_current_cluster_state": get_current_cluster_state}

def get_current_cluster_state(cluster_name):
print(f"cluster:{cluster_name}")
return """ERROR: Failed to pull image "/docker/dsp:latest"""

def run(input):
msg=[{"role":"user","content":input}]
ret = run_conversation(msg)
return ret.content

def run_conversation(msg):
response = client.chat.completions.create(
model=deployment,
messages=msg,
functions=[
{
"name": "get_current_cluster_state",
"description": "Get the current state in a given cluster",
"parameters": {
"type": "object",
"properties": {
"cluster_name": {
"type": "string",
"description": "the name of the cluster",
},

},
"required": ["cluster_name"],
}

}
],
function_call="auto",
)

response_message = response.choices[0].message

function_call = response_message.function_call

# 如果不需要调用function,则直接返回结果
if not function_call:
return response_message
function_name = function_call.name
function_to_call = funcs[function_name]
function_args = json.loads(response_message.function_call.arguments)
function_response = function_to_call(**function_args)
msg.append( # adding assistant response to messages
{
"role": response_message.role,
"function_call": {
"name": function_name,
"arguments": response_message.function_call.arguments,
},
"content": None
}
)
msg.append( # adding function response to messages
{
"role": "function",
"name": function_name,
"content": function_response,
}
)

return run_conversation(msg)

在Prompt中加入方法描述

image

DeepSeek示例源代码

目前会出现空回复的bug

https://github.com/KaloSora/HelloGPT/blob/dev/code/gpt_function_calling.ipynb

使用LangChain Agent

让GPT以更简单的方式,学会使用工具。

Agent的核心思想是使用语言模型来选择要采取的一系列操作。

LangChain 工具集

https://python.langchain.com/api_reference/

测试以后可以发现,LangChain使用工具的方法更加智能、灵活

image

Wolfram Alpha API Wrapper

Wolfram Alpha​是专注于解决科学计算的工具,帮助AI更好得思考数学问题

官网

https://zh.wolframalpha.com

API ID Ceation

https://developer.wolframalpha.com

WolframAlphaAPIWrapper document

https://python.langchain.com/api_reference/community/utilities/langchain_community.utilities.wolfram_alpha.WolframAlphaAPIWrapper.html

创建账号

image

创建你的APP ID

image

复制App ID
image

参考源代码

https://github.com/KaloSora/HelloGPT/blob/dev/code/gpt_langchain_agent.ipynb

In-context learning

Zero-shot Learning

一种机器学习方法,它允许模型在没有见过任何训练样本的情况下,对新类别的数据进行分类或识别。

这种方法通常依赖于模型在训练过程中学到的知识,以及对新类别的一些描述性信息,如属性或原数据。

例如,给出一些猫的特征,然后给出一堆图片,让机器识别出其中哪些图片是与猫相关的。

Few-shot Learning

教导模型使用非常有限的训练数据来识别新的对象、类或任务。在这里是通过Prompt里加入少量示例,来实现模型学习。

应用大语言模型要从传统机器学习思维切换为上下文学习思路

上下文学习包括Zero-shot Learning 和 Few-shot Learning,两者并无明显界限,可以根据实际需要灵活运用。

源代码

https://github.com/KaloSora/HelloGPT/blob/dev/code/gpt_in-ontext_learning.ipynb

ReAct模式

大语言模型具有推理能力,因为它们通过学习大量的文本数据,捕捉语言中的模式和结构。这些模型在训练过程中,会学习到各种知识、逻辑关系和推理方法。当它们遇到新的问题时,可以根据已经学到的知识和推理方法,生成有意义的回答。

image

通过获取当前环境信息(观察),进一步思考,采取行动

image

LangChain ReAct Agent

image

构建GPT,可以使用如下范式

Question: the input question you must answer

Thought: you should always think about what to do

Action: the action to take, should be one of [{tool_names}]

Action Input: the input to the action

Observation: the result of thr action… (Though/Action/Action Input/Observation repeat N times)

Thought: Now I know the answer

Final Answer: the answer to the input question

AutoGPT - 针对某个解决方案的循环自执行GPT

如果可以,配合短期和长期记忆保证上下文效果。

image

Plan: 设计实现预期结果的计划,将复杂的任务分解为较小的步骤。

Criticize: 评估计划的可行性和效率,识别潜在问题和改进领域

Act: 使用其多功能的能力执行计划的操作,例如网络搜索和数据检索

Observe:分析从Act中生成的反馈,从以前的性能中学习以改善未来的结果

Plan(修改):根据反馈,修改初始计划,允许持续改进问题解决策略

源代码

https://github.com/KaloSora/HelloGPT/blob/dev/code/gpt_autogpt_example.ipynb

文本分片与向量化

让大模型应用企业内部数据

大量文档和数据的挑战:如果使用prompt的方式来传递数据或上下文,会面临以下挑战:

  • Prompt的内容大小限制
  • 使用大量数据的成本
  • 并非所有数据都会用于解决当前问题

image

一种可能的处理方式关键词检索:通过Elaticsearch、Lucene等类似搜索引擎的方式,根据文本建立索引,通过关键词严格匹配到对应的文本内容。但是这种方式会丢失很多上下文的信息,会让相同语意的文本丢失。

更好的方法是让关键词检索变为语义检索

语义检索是一种基于文本内容和意义的信息检索方法,它试图理解查询和文档的语义,以便更准确地找到与查询相关的文档。

向量化(embedding)是将文本数据转为数值向量的过程。向量化后的文本可以用于计算文本之间的相似性,如余弦相似度、欧几里德距离等度量。这使得语义检索能够根据查询和文档之间的语义相似性来对文档进行排序和检索,从而提高检索的准确性和效率

我们可以把字符块进行向量化,通过向量间的距离来求解这些向量之间的相似性。也就是说,语义越相近的向量,它的距离就越短。

参考阅读

Word2Vec相关的一些机器学习的理论

实现流程

image

代码示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
# 向量化简单示例

from langchain.embeddings.openai import OpenAIEmbeddings
import numpy as np

# embedding = OpenAIEmbeddings() #如果直接使用OpenAI的GPT服务
embedding = OpenAIEmbeddings(deployment=embedding_deployment) #deployment是你在Azure中的 embedding 模型的部署名字
sentence1 = "我是一名软件工程师"
sentence2 = "小张从事法律工作"
sentence3 = "我是一名程序员"

embedding1 = embedding.embed_query(sentence1)
embedding2 = embedding.embed_query(sentence2)
embedding3 = embedding.embed_query(sentence3)

# 点集计算向量间的距离
print(np.dot(embedding1,embedding2))
print(np.dot(embedding2,embedding3))
print(np.dot(embedding1,embedding3))

文本向量化

1
2
3
4
5
6
7
8
9
from langchain.embeddings.openai import OpenAIEmbeddings

def embed(chunks):
# embedding = OpenAIEmbeddings()#如果直接使用OpenAI的GPT服务
embedding = OpenAIEmbeddings(deployment=embedding_deployment)
return [embedding.embed_query(chunk) for chunk in chunks]

chunks = split_file_into_chunks("spotmax_intro.txt",100)
embeddeds = embed(chunks)

向量检索

1
2
3
4
5
6
7
8
9
10
11
12
13
14
def find_k_largest_indices(input_list, k):
sorted_indices = sorted(range(len(input_list)), key=lambda i: input_list[i], reverse=True)
print(input_list)
print(sorted_indices)
return sorted_indices[:k]

def search(chunks,embeddeds,top_k, txt):
embedding = OpenAIEmbeddings(deployment="embedding",chunk_size=1)
embedded_txt = embedding.embed_query(txt)
distances = [np.dot(embedded_txt,embedded) for embedded in embeddeds]
ret_idx = find_k_largest_indices(distances, top_k)
return [chunks[i] for i in ret_idx]

search(chunks,embeddeds,2, "提高系统可用性")

向量检索 + GPT

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
import openai
import numpy as np
def anwser_question_with_doc(question, chunks, embeddeds):
relevent_chunks = search(chunks,embeddeds,2, question)
prompt = """
仅通过总结以下的文字片段回答用户问题, 注意保持回答的语言通顺(字数在30字以内)
---
"""
for rchunks in relevent_chunks:
prompt = prompt + "\n'" + rchunks + "'"

response = openai.ChatCompletion.create(
engine=deployment, # engine = "deployment_name".
messages=[
{"role": "system", "content": prompt},
{"role": "user", "content": question}
],
temperature = 0.9,
max_tokens = 200
)
return response.choices[0].message.content

print(anwser_question_with_doc("如何提高可用性", chunks,embeddeds))

*也可以使用embedding模型辅助实现,embedding model使用nomic-embed-text

Ollama embedding model

https://ollama.com/blog/embedding-models

nomic-embed-text model

https://ollama.com/library/nomic-embed-text

通过ollama安装模型

复制命令

image

在命令行安装

image

image

LangChain Retrieval

通过LangChain连接大模型和内部文本

上面使用了chroma向量数据库,在这一节配合LangChain使用实现分片向量化的整个工作流

image

LangChain Document Loader加载数据

支持CSV,文件目录,HTML,JSON,PDF,Markdown等多种格式

https://python.langchain.com/docs/integrations/document_loaders/

LangChain Retrievers

更好的文档分片工具

https://python.langchain.com/docs/integrations/retrievers/

最后把分片好的数据embed到向量数据库

image

LangChain提供了RetrievalQA​的方法直接查询向量数据库(Vectordb)

用户提问 -> 向量数据库检索 -> 构成新的prompt -> 大模型回答

这里使用md文档为例

image

1
2
3
4
retriever=vectordb.as_retriever(
search_type="mmr", search_kwargs={"k": 3}
#search_type="similarity", search_kwargs={"k": 3}
)

search_type:根据场景选择适合的参数

  • similarity:根据相似性查找,最多查找3个
  • mmr(max marginal):找到三个最相似的,然后根据这三个数据库之间差别最大的,但是跟用户问题又有关联性的问题

1
2
qa = RetrievalQA.from_chain_type(llm=llm, chain_type="refine", retriever=retriever,
return_source_documents=False, verbose=True)

chain_type: 可选值 stuff / refine / map reduce / map re-rank

  • 要根据企业内部的实际情况和数据特性,尽可能多地测试
  • 适当做一些定制化的改动以满足需求

image

image

源代码

https://github.com/KaloSora/HelloGPT/blob/dev/code/gpt_langchain_retrieval.ipynb

参考阅读

https://medium.com/@rahul.dusad/run-rag-pipeline-locally-with-ollama-embedding-model-nomic-embed-text-generate-model-llama3-e7a554a541b3

构建多模态Chatbot

image

图形生成能力:openai可以使用DALL E2,或者是Stable Diffusion

Openai api示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
import os
import http.client
import requests
import time

def create_image(prompt):
api_base = os.getenv("OPENAI_API_BASE")
api_key = os.getenv("OPENAI_API_KEY")
api_version = api_version = '2022-08-03-preview'

url = "{}dalle/text-to-image?api-version={}".format(api_base, api_version)
headers= { "api-key": api_key, "Content-Type": "application/json" }
body = {
"caption": prompt,
"resolution": "512x512"
}
submission = requests.post(url, headers=headers, json=body)
operation_location = submission.headers['Operation-Location']
retry_after = submission.headers['Retry-after']
status = ""
while (status != "Succeeded"):
time.sleep(int(retry_after))
response = requests.get(operation_location, headers=headers)
status = response.json()['status']
image_url = response.json()['result']['contentUrl']
#display(Image(url=image_url))
return "\n![image]("+image_url+")"

print (create_image("A dog on the street."))

Openai 代码示例

https://github.com/KaloSora/HelloGPT/blob/dev/code/gpt_all_in_one_example.ipynb

0%