Agent:原理与快速构建 | 人工智能 | Langchain | Python ——学习笔记

news2024/9/20 20:34:17

视频链接:https://www.bilibili.com/video/BV1Hz421b7ag/?spm_id_from=333.788&vd_source=90787f5794c8e73cf358973d1de2e47f

# # 将.env的信息放到环境变量
# from dotenv import load_dotenv
# load_dotenv()


''' 第一节课程:使用openai调用智谱轻言问答示例''' 
from openai import OpenAI
client = OpenAI(
    api_key="你的key",
    base_url="https://open.bigmodel.cn/api/paas/v4/"
)

completion = client.chat.completions.create(
    model = 'glm-4',        # 使用的模型
    messages = [            # 对话列表
        {'role':'system','content':"你被用于抑制用户的购买欲望。当用户说要想买什么东西的时候,你需要提供理由让用户不要买。"},
        {'role':'user','content':"我正在考虑购买一个键盘,但我想抑制这个购买欲望。你能帮我列出一些理由,让我思考一下是否真的需要这个商品嘛?"}
    ], 
    max_tokens = 400,       # max_tokens用于控制模型输出的长度,取值范围取决于模型和输入,模型有可以处理的token总数,输入和输出不能超过这个数量。像'glm-4'最多token数量为128k
    temperature = 0.5       # temperature用于控制输出的随机性,数值越高随机性越大,每次都想得到一样的输出数值可以设置低一点
)

print(completion.choices[0].message.content)


# # ######################## 以下示例是一个应用完整的调用,主要由3部分组成:Prompt Template、Model、OutputParser######################################
from langchain_openai import ChatOpenAI
from langchain.prompts import ChatPromptTemplate

# Prompt Template: 用于将Prompt不变的地方固定住,需要变的地方留空。
prompt_template = ChatPromptTemplate.from_messages(
    [
        ('system',"你被用于抑制用户的购买欲望。当用户说要想买什么东西的时候,你需要提供理由让用户不要买。"),
        ('human',"我正在考虑购买一个{product},但我想抑制这个购买欲望。你能帮我列出一些理由,让我思考一下是否真的需要这个商品嘛?")
    ]
)
prompt_template.format(product='球鞋')

# Model:用于输入Prompt回答的模型
model = ChatOpenAI(
    model = 'glm-4',
    api_key="你的key",
    base_url="https://open.bigmodel.cn/api/paas/v4/",
    max_tokens = 500,       # max_tokens用于控制模型输出的长度
    temperature = 0.7
)

# OutputParser:进一步解析模型的输出变成所需要的样子,尤其是输出与需要的不一致时,解析过程可能会再次调用模型
def output_parser(output: str):
    parser_model = ChatOpenAI(
        model = 'glm-3-turbo',
        temperature = 0.2,
        api_key="你的key",
        base_url="https://open.bigmodel.cn/api/paas/v4/"
    )
    message = "你需要将传入的文本改写,尽可能更自然,这是你需要改写的文本:{text}"
    return parser_model.invoke(message.format(text=output))


# 其实在一开始的prompt中就要求回复自然的文本也是可以的。但在工程中,想获取稳定一致的输出,最好一个步骤只做一件事。
chain = prompt_template | model | output_parser     # 这里建立一个完整的调用链
answer = chain.invoke(input={'product':'裤子'})
print(answer.content)


# # # # 一个省钱助手 # # #
# chain = prompt_template | model | output_parser     # 这里建立一个完整的调用流程
# while True:
#     product = input("Hello! 马上要双十一,你最近又想买点啥?")
#     answer = chain.invoke(input={'product':product})
#     print(answer.content)



''' 第二节课程:langchain添加memory'''
from langchain.prompts import ChatPromptTemplate

prompt_template = ChatPromptTemplate.from_messages(
    [
        ('system',"You are a chatbot."),
        ('human',"{new_messages}")
    ]
)

print(prompt_template.invoke({'new_messages':'Hello'}).messages)


# # # 同样,传入历史消息也是留空一个位置
from langchain.prompts import MessagesPlaceholder

prompt_template = ChatPromptTemplate.from_messages(
    [
        ('system',"You are a chatbot."),
        # ('system', "你是一个聊天机器人"),
        MessagesPlaceholder(variable_name="chat_history"),
        ('human',"{new_messages}")
    ]
)

print(prompt_template.invoke({'chat_history':[('human','Hello'),('ai','Hi'),], 'new_messages':'How old are you?'}).messages)


from langchain_openai import ChatOpenAI

model = ChatOpenAI(
    model = 'glm-3-turbo',
    api_key="你的key",
    base_url="https://open.bigmodel.cn/api/paas/v4/",
    max_tokens = 500,       # max_tokens用于控制模型输出的长度
    temperature = 0.7
)

# # 添加memory步骤:首先用prompt_template和model组成chain,然后定义列表来存储对话记录
chain = prompt_template | model
chat_history = []

# 每次调用chain函数时,将传给模型的话和模型返回的话放入chat_history列表,下次调用的时候再作为历史信息传进去
def chat(new_messages):
    response = chain.invoke({'chat_history': chat_history, 'new_messages': new_messages})
    chat_history.extend([
        ('human', new_messages),
        ('ai', response.content)
        ])
    return response.content

print(chat('你好,我是ysn,今年72岁,已经退休了,正在学习AI知识'))
print(chat('请你阐述一下你了解关于我的个人信息'))


# 在实际应用中用langchain的component来实现,对开发一致性和扩展性都更好
from langchain_community.chat_message_histories import ChatMessageHistory

chat_history = ChatMessageHistory()

chat_history.add_user_message('你好,我是ysn,今年72岁,已经退休正在学习AI知识')
chat_history.add_ai_message('你好,我是AI')


from langchain_core.runnables.history import RunnableWithMessageHistory

chain_with_memory = RunnableWithMessageHistory(
    chain,
    lambda x: chat_history,
    input_messages_key = 'new_messages',
    history_messages_key = 'chat_history'
)

print(chain_with_memory.invoke({'new_messages': '请你阐述一下你了解关于我的个人信息'}, config={"configurable":{"session_id": "unused"}}).content)
print(chat_history.messages)


# 这个函数接受传入chain的东西然后修剪记忆,再将传入chain的东西返回去。
def trim_messages(chain_input):
    '''修剪记忆'''
    stored_messages = chat_history.messages
    # 当大于两条时就清空记忆保留最后两条
    if len(stored_messages) > 2:
        chat_history.clear()
        for message in stored_messages[-2:]:
            chat_history.add_message(message)
    return chain_input

chain_with_trimming = trim_messages | chain_with_memory

print(chain_with_trimming.invoke({'new_messages': '请你阐述一下你了解关于我的个人信息'}, config={"configurable":{"session_id": "unused"}}).content)
print(chat_history.messages)


def summarize_messages(chain_input):
    '''总结记忆,需要调用模型来总结'''
    stored_messages = chat_history.messages
    # 当信息数大于等于6条时进行总结
    if len(stored_messages)>=6:
        summarization_prompt = ChatPromptTemplate.from_messages(
            [
                MessagesPlaceholder(variable_name="chat_history"),
                ("user","将上述聊天信息提炼为一条摘要信息。尽可能多的包含具体细节。")
            ]
        )
        summarization_chain = summarization_prompt | model
        summary_message = summarization_chain.invoke({"chat_history": stored_messages})
        chat_history.clear()
        chat_history.add_message(summary_message)
    return chain_input

chain_with_summarization = summarize_messages | chain_with_memory

chat_history.clear()
chat_history.add_message(('human','你好,我是ysn,我今年72岁,已经退休正在学习AI知识'))
chat_history.add_message(('ai','你好,我是AI,请问有什么可以帮你'))
chat_history.add_message(('human','你觉得我适合做AI工程师嘛'))
chat_history.add_message(('ai','适合'))
chat_history.add_message(('human','为什么'))
chat_history.add_message(('ai','因为你在学习AI知识'))

print(chain_with_summarization.invoke({'new_messages': '你觉得我适合干什么'}, config={"configurable":{"session_id": "unused"}}).content)
print(chat_history.messages)



''' 第三节课程:Agent原理与快速构建'''
# agent 是一种结合了大模型推理能力和实际操作能力的智能体
# 通常我们使用模型是通过问答模式,比如我想实现数据库查询,模型可以告诉我一个Sql语句,然后需要自己粘贴这个语句到数据库中执行,来获取这个查询结果。
#  agent 可以接受我们的自然语言,直接修改数据库,还可以上网查找资料,回答最近发生的事情。

# 定义模型
from langchain_openai import ChatOpenAI

model = ChatOpenAI(
    model = 'glm-4-flash',      # 完全免费且响应速度很快
    openai_api_base = "https://open.bigmodel.cn/api/paas/v4/",
    api_key="你的key",
)

# 定义 tools    
from langchain_community.tools import DuckDuckGoSearchRun       # DuckDuckGo 搜索引擎免费

# 操作数据库的 tool
import pandas as pd
from pandasql import sqldf


def simulate_database_operation(sql):
	my_table = pd.DataFrame({
	    'name': ['Henry Myers', 'Martha Hawkins', 'Kelsey Lutz', 'Jonathan Fowler', 'Jonathan Young', 'Autumn Johnson', 'Kimberly Macias', 'Jared Mccormick', 'Casey Hoover', 'Erica Morse'],
	    'age': [60, 44, 54, 46, 76, 22, 69, 33, 23, 35],
	    'sex': ['F', 'M', 'M', 'F', 'F', 'M', 'M', 'F', 'F', 'M']
	})
	result = sqldf(sql)
	return result
# 正常的查询
print(simulate_database_operation('SELECT * FROM my_table WHERE age > 50'))
# # 错误的查询
# print(simulate_database_operation('SELECT * FROM my_table WHERE id > 50'))


# 如何把函数包装成tool? 只要加装饰器和docstring(即使用说明)即可
from langchain.tools import tool

@tool   
def simulate_database_operation(sql: str):
	'''根据sql语句操作数据库'''
	my_table = pd.DataFrame({
	    'name': ['Henry Myers', 'Martha Hawkins', 'Kelsey Lutz', 'Jonathan Fowler', 'Jonathan Young', 'Autumn Johnson', 'Kimberly Macias', 'Jared Mccormick', 'Casey Hoover', 'Erica Morse'],
	    'age': [60, 44, 54, 46, 76, 22, 69, 33, 23, 35],
	    'sex': ['F', 'M', 'M', 'F', 'F', 'M', 'M', 'F', 'F', 'M']
	})
	result = sqldf(sql)
	return result


# 模型调用 tool
tools = [DuckDuckGoSearchRun(), simulate_database_operation]
model_with_tools = model.bind_tools(tools)


from pprint import pprint as pp

# 不需要调用tool的问题
response = model_with_tools.invoke('印度的首都是哪里?')
pp(dict(response))

# 不需要调用tool的问题
search_response = model_with_tools.invoke('最近有什么新鲜事?搜索之后告诉我')
pp(dict(search_response))

fetch_response = model_with_tools.invoke('现在是北京时间几点?查询之后告诉我')
pp(dict(fetch_response))

# 需要操作数据库的问题
db_response = model_with_tools.invoke('帮我往数据库的my_table表中插入一条数据,name是张三,age是18,sex是male')
pp(dict(db_response))


######################### 手动实现agent ################################
# from icecream import ic

def call_tool(model_output, tools):
    tools_map = {tool.name.lower(): tool for tool in tools}
    tools_response = {}
    for tool in model_output.tool_calls:
        tool_name = tool['name']
        tool_args = tool['args']
        tool_instance = tools_map[tool_name]
        tool_response = tool_instance.invoke(*tool_args.values())
        tools_response[tool_name] = tool_response
    return tools_response


def manual_agent(query: str, model: ChatOpenAI, tools: list[tool]):
    '''①模型和工具绑定、②调用绑定的模型查询、③调用tool ④用tool_response和一开始的询问query获取最终的回答final_response'''
    model_with_tools = model.bind_tools(tools)
    model_output = model_with_tools.invoke(query)
    tool_response = call_tool(model_output, tools)
    final_response = model.invoke(
        f'original query: {query} \n\n\n tool response: {tool_response}',
    )
    return final_response


print(manual_agent("帮我查询数据库my_table表中有多少人年龄大于60", model, tools).content)


# 使用 langgraph 定义 agent
from langgraph.prebuilt import create_react_agent
agent = create_react_agent(model, tools)


from langchain_core.messages import HumanMessage

response = agent.invoke({'messages': [HumanMessage(content="帮我查询数据库my_table表中有多少人年龄大于60")]})
print(response)

response = agent.invoke({'messages': [HumanMessage(content="今天在北京的天气怎么样")]})
print(response)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2150003.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Jboss CVE-2017-7504 靶场攻略

漏洞介绍 JBoss AS 4.x及之前版本中,JbossMQ实现过程的JMS over HTTP Invocation Layer的 HTTPServerILServlet.java⽂件存在反序列化漏洞,远程攻击者可借助特制的序列化数据利⽤该漏洞执⾏ 任意代码执⾏ 影响范围 JBoss 4.x 以及之前的所有版本 环…

2024 中秋盛景:数据璀璨,文旅辉煌

2024 年的中秋假期,文旅市场热闹非凡。看这一组组令人惊叹的数据,感受中秋旅游的火爆魅力。国内出游人次高达 1.07 亿,相比 2019 年同期增长了 6.3%,这意味着无数人踏上旅途,追寻着心中的诗和远方。国内游客出游总花费…

揭开 Vue 3 中大量使用 ref 的隐藏危机

在 Vue 3 中,ref 是用来创建响应式的引用,它能够追踪和管理单一的变量或对象。当代码中大量使用 ref 时,虽然可以实现对各个状态或数据的精细控制,但也会带来一些问题和潜在影响。 1. 大量使用 ref 带来的问题 1、代码冗长与维护…

超强提分神器:大模型+RAG!新SOTA性能提升50%+,实现计算资源动态分配

现在的大模型因为“幻觉”问题,已经离不开“外挂”检索增强生成RAG了,而且很多大模型应用几乎完全基于RAG构建,可以说决定了大模型生成的天花板。 这是因为RAG可以将外部数据检索集成到生成过程中,不仅确保了大模型生成的内容具有…

微服务保护详细笔记(一):雪崩问题--Sentinel

目录 1.雪崩问题 1.1.雪崩问题产生原因: 1.2.雪崩问题解决方案 1.2.1.请求限流 1.1.2.线程隔离 1.1.3.服务熔断 1.3.微服务保护技术对比 1.4.Sentinel 1.4.1.介绍与安装 1.4.2.微服务整合 1.雪崩问题 1.1.雪崩问题产生原因: 比如查询购物车的…

【省时省力】告别 Node.js 安装配置的繁琐!国内镜像源加速,版本切换轻松搞定

前言 最近电脑开发环境又意外出现了异常,每次更新系统都是冒着很大的风险,这次最直接的影响就是一些基于nodejs的前端项目. 不同项目的版本环境要求不一致,最新的nodejs并不总是满足项目要求,因此为了重新部署自己开发的以及别人开发的项目,需要根据项目随时切换到相应的版本.…

git使用“保姆级”教程2——初始化及工作机制解释

1、设置用户签名 解释: 签名的作用就是用来:标识用户,以区分不同的开发人员简单来说:用来标识"你是谁",在提交代码时,会显示提交代码的是谁,把设置的信息一起提交上去 设置&#xff…

sqoop的安装与简单使用

文章目录 一、安装1、上传,解压,重命名2、修改环境变量3、修改配置文件4、上传驱动包5、拷贝jar包 二、import命令1、将mysql的数据导入到hdfs上2、将mysql的数据导入到hive上3、增量导入数据 三、export命令1、从hdfs导出到mysql中2、从hive导出到mysql…

【JPCS出版】第二届应用统计、建模与先进算法国际学术会议(ASMA2024,9月27日-29)

第二届应用统计、建模与先进算法国际学术会议 2024 2nd International Conference on Applied Statistics, Modeling and Advanced Algorithms(ASMA2024) 会议官方 会议官网:www.icasma.org 2024 2nd International Conference on Applied …

第四届计算机、信息工程与电子材料国际学术会议 (CTIEEM 2024)

目录 重要信息 大会简介 出版信息 大会组委 会议征稿主题 会议议程 参会须知 重要信息 大会时间:2024年11月15-17日 大会地点:中国-郑州 大会官网:www.ctieem.org 收录检索:EI Compendex,Scopus 大会简介 随着信…

XXL-JOB 漏洞大全

一、前言 在当今的数字化时代,任务调度平台对于企业级应用来说至关重要。它们负责自动化和协调各种时间敏感或周期性的任务,确保业务流程的顺畅运行。XXL-JOB作为一款流行的分布式任务调度平台,因其强大的功能和易用性,被广泛部署…

【4.3】图搜索算法-DFS和BFS解被围绕的区域

一、题目 给定一个二维的矩阵,包含 X 和 O ( 字母 O )。 找到所有被 X 围绕的区域,并将这些区域里所有的 O 用 X 填充。 示例 : X X X X X O O X X X O X X O X X 运行你的函数后,矩阵变为…

uniapp H5 打开地图 并选中标记点

uniapp H5 打开地图 并选中标记点 先上代码 //打开地图 显示景区位置openMap() {// 支付宝// #ifdef MP-ALIPAYmy.openLocation({longitude: Number(this.detailObj.longitude), // 经度latitude: Number(this.detailObj.latitude), // 纬度name: this.detailObj.scenicName, …

C++速通LeetCode中等第10题-轮转数组(四种方法)

方法一&#xff1a;巧用deque双向队列容器 class Solution { public:void rotate(vector<int>& nums, int k) {deque<int> q;int tmp;if(nums.size() > 1){for(auto num:nums) q.push_back(num);for(int i 0;i < k;i){tmp q.back();q.pop_back();q.pu…

dgl库安装

此篇文章继续上一篇pytorch已经安装成功的情况 &#xff08;python3.9&#xff0c;pytorch2.2.2&#xff0c;cuda11.8&#xff09; 上一篇pytorch安装教学链接 选择与之匹配的版本 输入下方代码进行测试 import dgl.data dataset dgl.data.CoraGraphDataset() print(‘Numb…

24 小时不关机的挂机云电脑,还能这么玩?

云电脑技术为我们提供了无限可能。特别是对于游戏爱好者&#xff0c;挂机云电脑不仅解决了传统电脑的局限性&#xff0c;还带来了更为便利的游戏体验。除此之外云电脑还有什么其他玩法呢&#xff1f; 01 挂机云电脑的优势 首先要知道&#xff0c;什么是挂机云电脑&#xff1f…

局域网变压器市场价值

2024 年全球局域网变压器市场价值为 3.056 亿美元&#xff0c;预计到 2030 年将达到 4.426 亿美元&#xff0c;2024-2030 年的复合年增长率为 5.4%。 局域网变压器市场包括用于改变电信号电压或格式的产品&#xff0c;以改善和简化局域网 (LAN) 上的数据传输。这些变压器对于保…

【JavaScript】数据结构之链表(双指针、滑动窗口)

什么是链表&#xff1f; 多个元素存储的列表链表中的元素在内存中不是顺序存储的&#xff0c;而是通过“next”指针联系在一起的&#xff0c;这个“next”可以自定义。JS中的原型链原理就是链表结构&#xff0c;是通过__proto__指针联系在一起的。 双指针形式 对撞指针&am…

分布式事务一致性:本地消息表设计与实践

概念 本地消息表是一种常见的解决分布式事务问题的方法。其核心思想是将分布式事务拆分成本地事务来处理&#xff0c;通过消息队列来保证各个本地事务的最终一致性。 实现步骤 创建本地消息表&#xff1a;在数据库中创建一个本地消息表&#xff0c;用于存储待发送的消息以及消…

【图像检索】基于灰度共生矩的纹理图像检索,matlab实现

博主简介&#xff1a;matlab图像代码项目合作&#xff08;扣扣&#xff1a;3249726188&#xff09; ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 本次案例是基于灰度共生矩的纹理图像检索&#xff0c;用matlab实现。 一、案例背景和算法介绍 …