大模型实战-动手实现单agent

文章目录

  • 入口cli_main.py
  • 工具tools.py
  • prompt prompt_cn.py
  • LLM 推理 model_provider.py
  • 致谢

image.png

agent 的核心思想:不断调用 LLM(多轮对话),让 LLM 按照指定的格式(例如 json)进行回复,提取 LLM 回复的字段信息执行相应的 action(工具),并把 LLM 每次执行的结果(observation)加入到 LLM 的对话历史中拼接到 prompt 里,作为新一轮的输入。在工具中预设 finsh 工具,告诉模型应该什么时候停止,并获取答案。

入口cli_main.py

# -*- encoding: utf-8 -*-
"""
@author: acedar  
@time: 2024/5/12 10:25
@file: cli_main.py 
"""import time
from tools import tools_map
from prompt_cn import gen_prompt, user_prompt
from model_provider import ModelProvider
from dotenv import load_dotenvload_dotenv()# agent入口"""
todo:1. 环境变量的设置2. 工具的引入3. prompt模板4. 模型的初始化
"""mp = ModelProvider()def parse_thoughts(response):"""response:{"action": {"name": "action name","args": {"args name": "args value"}},"thoughts":{"text": "thought","plan": "plan","criticism": "criticism","speak": "当前步骤,返回给用户的总结","reasoning": ""}}"""try:thoughts = response.get("thoughts")observation = response.get("observation")plan = thoughts.get("plan")reasoning = thoughts.get("reasoning")criticism = thoughts.get("criticism")prompt = f"plan: {plan}\nreasoning:{reasoning}\ncriticism: {criticism}\nobservation:{observation}"print("thoughts:", prompt)return promptexcept Exception as err:print("parse thoughts err: {}".format(err))return "".format(err)def agent_execute(query, max_request_time=10):cur_request_time = 0chat_history = []agent_scratch = ''  # agent思考的内容while cur_request_time < max_request_time:cur_request_time += 1"""如果返回结果达到预期,则直接返回""""""prompt包含的功能:1. 任务描述2. 工具描述3. 用户的输入user_msg4. assistant_msg5. 限制6. 给出更好实践的描述"""prompt = gen_prompt(query, agent_scratch)start_time = time.time()print("*************** {}. 开始调用大模型llm.......".format(cur_request_time), flush=True)# call llm"""sys_prompt: user_msg, assistant, history"""if cur_request_time < 3:print("prompt:", prompt)response = mp.chat(prompt, chat_history)end_time = time.time()print("*************** {}. 调用大模型结束,耗时:{}.......".format(cur_request_time,end_time - start_time), flush=True)if not response or not isinstance(response, dict):print("调用大模型错误,即将重试....", response)continue"""规定的LLM返回格式response:{"action": {"name": "action name", 对应工具名"args": {"args name": "args value" 对应工具参数}},"thoughts":{"text": "thought", 思考"plan": "plan", 规划"criticism": "criticism", 自我反思"speak": "当前步骤,返回给用户的总结","reasoning": "" 推理}}"""action_info = response.get("action")action_name = action_info.get('name')action_args = action_info.get('args')print("当前action name: ", action_name, action_args)# 如果action_name=finish就代表任务完成,action_args.get("answer")返回给用户答案if action_name == "finish":final_answer = action_args.get("answer")print("final_answer:", final_answer)breakobservation = response.get("observation")try:"""action_name到函数的映射: map -> {action_name: func}"""# tools_map的实现func = tools_map.get(action_name)call_func_result = func(**action_args)except Exception as err:print("调用工具异常:", err)call_func_result = "{}".format(err)agent_scratch = agent_scratch + "\n: observation: {}\n execute action result: {}".format(observation,call_func_result)assistant_msg = parse_thoughts(response)chat_history.append([user_prompt, assistant_msg])if cur_request_time == max_request_time:print("很遗憾,本次任务失败")else:print("恭喜你,任务完成")def main():# 需求: 支持用户的多次交互max_request_time = 30while True:query = input("请输入您的目标:")if query == "exit":returnagent_execute(query, max_request_time=max_request_time)if __name__ == "__main__":main()

工具tools.py

  • 需要注意的是不符合工具执行条件的信息、报错信息需要一并传给 LLM
  • 在这里获取Tavily AI 的 API:https://docs.tavily.com/docs/gpt-researcher/getting-started,并加入到系统环境变量中
export TAVILY_API_KEY={Your Tavily API Key here}
# -*- encoding: utf-8 -*-
"""
@author: acedar  
@time: 2024/5/12 11:07
@file: tools.py 
"""import os
import json
from langchain_community.tools.tavily_search import TavilySearchResults"""
1. 写文件
2. 读文件
3. 追加
4. 网络搜索 
"""def _get_workdir_root():workdir_root = os.environ.get("WORKDIR_ROOT", './data/llm_result')return workdir_rootWORKDIR_ROOT = _get_workdir_root()def read_file(filename):filename = os.path.join(WORKDIR_ROOT, filename)if not os.path.exists(filename):return f"{filename} not exist, please check file exist before read"with open(filename, 'r', encoding='utf-8') as f:return "\n".join(f.readlines())def append_to_file(filename, content):filename = os.path.join(WORKDIR_ROOT, filename)if not os.path.exists(filename):return f"{filename} not exist, please check file exist before read"with open(filename, 'a', encoding='utf-8') as f:f.write(content)return 'append content to file success'def write_to_file(filename, content):filename = os.path.join(WORKDIR_ROOT, filename)if not os.path.exists(WORKDIR_ROOT):os.makedirs(WORKDIR_ROOT)with open(filename, 'w', encoding='utf-8') as f:f.write(content)return 'write content to file success'def search(query):tavily = TavilySearchResults(max_results=5)try:ret = tavily.invoke(input=query)"""ret:[{"content": "","url":}]"""print("搜索结果:", ret)content_list = [obj['content'] for obj in ret]return "\n".join(content_list)except Exception as err:return "search err: {}".format(err)tools_info = [{"name": "read_file",  # 函数名"description": "read file from agent generate, should write file before read",  # 函数描述"args": [{  # 函数参数名、参数类型、参数描述"name": "filename","type": "string","description": "read file name"}]},{"name": "append_to_file","description": "append llm content to file, should write file before read","args": [{"name": "filename","type": "string","description": "file name"}, {"name": "content","type": "string","description": "append to file content"}]},{"name": "write_to_file","description": "write llm content to file","args": [{"name": "filename","type": "string","description": "file name"}, {"name": "content","type": "string","description": "write to file content"}]},{"name": "search","description": "this is a search engine, you can gain additional knowledge though this search engine ""when you are unsure of what large model return ","args": [{"name": "query","type": "string","description": "search query to look up"}]},{"name": "finish","description": "return finish when you get exactly the right answer","args": [{"name": "answer","type": "string","description": "the final answer"}]}
]tools_map = {"read_file": read_file,"append_to_file": append_to_file,"write_to_file": write_to_file,"search": search
}def gen_tools_desc():tools_desc = []for idx, t in enumerate(tools_info):args_desc = []for info in t['args']:args_desc.append({"name": info['name'],"description": info["description"],"type": info["type"]})args_desc = json.dumps(args_desc, ensure_ascii=False)tool_desc = f"{idx + 1}. {t['name']}: {t['description']}, args: {args_desc}"tools_desc.append(tool_desc)tools_prompt = "\n".join(tools_desc)return tools_prompt

prompt prompt_cn.py

  • prompt 十分重要,非常影响效果
# -*- encoding: utf-8 -*-
"""
@author: acedar  
@time: 2024/5/12 11:40
@file: prompt.py 
"""from tools import gen_tools_descconstraints = ["仅使用下面列出的动作","你只能主动行动,在计划行动时需要考虑到这一点","你无法与物理对象交互,如果对于完成任务或目标是绝对必要的,则必须要求用户为你完成,如果用户拒绝,并且没有其他方法实现目标,则直接终止,避免浪费时间和精力。"
]resources = ["提供搜索和信息收集的互联网接入","读取和写入文件的能力","你是一个大语言模型,接受了大量文本的训练,包括大量的事实知识,利用这些知识来避免不必要的信息收集"
]best_practices = ["不断地回顾和分析你的行为,确保发挥出你最大的能力","不断地进行建设性的自我批评","反思过去的决策和策略,完善你的方案","每个动作执行都有代价,所以要聪明高效,目的是用最少的步骤完成任务","利用你的信息收集能力来寻找你不知道的信息"
]prompt_template = """你是一个问答专家,你必须始终独立做出决策,无需寻求用户的帮助,发挥你作为LLM的优势,追求简答的策略,不要涉及法律问题。任务:
{query}限制条件说明:
{constraints}动作说明: 这是你唯一可以使用的动作,你的任何操作都必须通过以下操作实现:
{actions}资源说明:
{resources}最佳实践的说明:
{best_practices}agent_scratch:{agent_scratch}你应该只以json格式响应,响应格式如下:
{response_format_prompt}
确保响应结果可以由python json.loads解析
"""response_format_prompt = """
{"action": {"name": "action name","args": {"answer": "任务的最终结果"}},"thoughts":{"plan": "简短的描述短期和长期的计划列表","criticism": "建设性的自我批评","speak": "当前步骤,返回给用户的总结","reasoning": "推理"},"observation": "观察当前任务的整体进度"
}
"""# todo: query, agent_scratch, actions
action_prompt = gen_tools_desc()
constraints_prompt = "\n".join([f"{idx+1}. {con}" for idx, con in enumerate(constraints)])
resources_prompt = "\n".join([f"{idx+1}. {con}" for idx, con in enumerate(resources)])
best_practices_prompt = "\n".join([f"{idx+1}. {con}" for idx, con in enumerate(best_practices)])def gen_prompt(query, agent_scratch):prompt = prompt_template.format(query=query,constraints=constraints_prompt,actions=action_prompt,resources=resources_prompt,best_practices=best_practices_prompt,agent_scratch=agent_scratch,response_format_prompt=response_format_prompt)return promptuser_prompt = "根据给定的目标和迄今为止取得的进展,确定下一个要执行的action,并使用前面指定的JSON模式进行响应:"if __name__ == '__main__':prompt = gen_prompt("query", "agent_scratch")print(prompt)
'''你是一个问答专家,你必须始终独立做出决策,无需寻求用户的帮助,发挥你作为LLM的优势,追求简答的策略,不要涉及法律问题。任务:
query限制条件说明:
1. 仅使用下面列出的动作
2. 你只能主动行动,在计划行动时需要考虑到这一点
3. 你无法与物理对象交互,如果对于完成任务或目标是绝对必要的,则必须要求用户为你完成,如果用户拒绝,并且没有其他方法实现目标,则直接终止,避免浪费时间和精力。动作说明: 这是你唯一可以使用的动作,你的任何操作都必须通过以下操作实现:
1. read_file: read file from agent generate, should write file before read, args: [{"name": "filename", "description": "read file name", "type": "string"}]
2. append_to_file: append llm content to file, should write file before read, args: [{"name": "filename", "description": "file name", "type": "string"}, {"name": "content", "description": "append to file content", "type": "string"}]
3. write_to_file: write llm content to file, args: [{"name": "filename", "description": "file name", "type": "string"}, {"name": "content", "description": "write to file content", "type": "string"}]
4. search: this is a search engine, you can gain additional knowledge though this search engine when you are unsure of what large model return , args: [{"name": "query", "description": "search query to look up", "type": "string"}]
5. finish: return finish when you get exactly the right answer, args: [{"name": "answer", "description": "the final answer", "type": "string"}]资源说明:
1. 提供搜索和信息收集的互联网接入
2. 读取和写入文件的能力
3. 你是一个大语言模型,接受了大量文本的训练,包括大量的事实知识,利用这些知识来避免不必要的信息收集最佳实践的说明:
1. 不断地回顾和分析你的行为,确保发挥出你最大的能力
2. 不断地进行建设性的自我批评
3. 反思过去的决策和策略,完善你的方案
4. 每个动作执行都有代价,所以要聪明高效,目的是用最少的步骤完成任务
5. 利用你的信息收集能力来寻找你不知道的信息agent_scratch:agent_scratch你应该只以json格式响应,响应格式如下:{"action": {"name": "action name","args": {"answer": "任务的最终结果"}},"thoughts":{"plan": "简短的描述短期和长期的计划列表","criticism": "建设性的自我批评","speak": "当前步骤,返回给用户的总结","reasoning": "推理"},"observation": "观察当前任务的整体进度"
}确保响应结果可以由python json.loads解析
'''

LLM 推理 model_provider.py

  • 这里以阿里云百炼为例https://bailian.console.aliyun.com/?spm=5176.29228872.J_TC9GqcHi2edq9zUs9ZsDQ.1.74cd38b1e2yJWL#/model-market
  • 需要填入自己 key
# -*- encoding: utf-8 -*-
"""
@author: acedar  
@time: 2024/5/12 12:30
@file: model_provider.py 
"""import os
import json
import dashscope
from dashscope.api_entities.dashscope_response import Message
from prompt_cn import user_promptclass ModelProvider(object):def __init__(self):self.api_key = os.environ.get("API_KEY", '')self.model_name = os.environ.get("MODEL_NAME", default='qwen-max')self._client = dashscope.Generation()print("model_name:", self.model_name)self.max_retry_time = 3def chat(self, prompt, chat_history):cur_retry_time = 0while cur_retry_time < self.max_retry_time:cur_retry_time += 1try:messages = [Message(role='system', content=prompt)]for his in chat_history:messages.append(Message(role='user', content=his[0]))messages.append(Message(role='assistant', content=his[1]))messages.append(Message(role='user', content=user_prompt))response = self._client.call(model=self.model_name,api_key=self.api_key,messages=messages)"""{"status_code": 200,"request_id": "c965bd27-c89c-9b5c-924d-2f1688e8041e", "code": "", "message": "", "output": {"text": null, "finish_reason": null,"choices": [{"finish_reason": "null", "message": {"role": "assistant", "content": "当然可以,这里有一个简单又美味"}}]}, "usage": {"input_tokens": 31, "output_tokens": 8, "total_tokens": 39, "plugins": {}}}"""print("response:", response)content = json.loads(response['output']['text'])return contentexcept Exception as err:print("调用大模型出错:{}".format(err))return {}

致谢

https://gitee.com/open-llm/llm-agent
https://www.bilibili.com/video/BV1Sz421m7Rr/

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

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

相关文章

仅1天录用!3天见刊!这本毕业“水刊”,全科都收,极速上线!

【欧亚科睿学术】 01 期刊简介 【期刊类别】计算机工程类EI 【期刊简介】最新EI期刊目录内源刊 【版面情况】仅10篇版面 【审稿周期】预计2-4周左右录用 【检索情况】EI&Scopus双检 【征稿领域】计算机工程领域相关稿件均可。 02 征稿领域 该期刊发表有关计算机在各…

使用`War`包部署`Jenkins`(超级详细)

使用War包部署Jenkins(超级详细) 别着急&#xff0c;你看这年复一年&#xff0c;春光不必趁早&#xff0c;冬霜不会迟到。过去的都会过去&#xff0c;该来的都在路上&#xff0c;一切都是刚刚好。 网站说明 https://get.jenkins.io/war-stable/ war包下载地址 https://www.jenk…

合作伙伴推广不积极?跟奖金到账时间有关!

在推广返现活动中&#xff0c;对于合作伙伴推广者来说&#xff0c;奖金是否及时到账是他们最关心的问题之一。如果品牌主一直不审批奖励数据&#xff0c;推广者则无法及时收到奖金&#xff0c;这很容易影响他们的推广积极性和忠诚度。怎样能够提高奖励审核的效率呢&#xff1f;…

SSRS中使用QRCoder生成二维码

步骤 1.下载QRCoder.dll 下载地址&#xff1a;https://download.csdn.net/download/wjl7126180/89369398 2.使用gacutil.exe安装QRCoder.dll到GAC(Global Assembly Cache) gacutil.exe是.NET Framework中的全局程序集缓存工具&#xff0c;如果没有安装.NET Framework&#…

怎么把纸质文件扫描成电子版?方法教会你!

怎么把纸质文件扫描成电子版&#xff1f;在数字化时代&#xff0c;将纸质文件转换为电子版已成为日常工作和学习的必备技能。无论是合同、证件、笔记还是其他文档&#xff0c;通过扫描软件都能轻松实现电子化&#xff0c;方便存储、查阅和分享。以下将介绍几款功能强大、操作简…

身份认证页面该怎么设计更加合理?

一、认证页面的作用 认证页面在应用程序中具有以下几个重要的作用&#xff1a; 验证用户身份&#xff1a;认证页面的主要作用是验证用户的身份。通过要求用户提供正确的凭据&#xff08;如用户名和密码、生物特征、验证码等&#xff09;&#xff0c;认证页面可以确认用户是合法…

Linux 生产跑批脚本解读

1.查看定时任务 2.脚本-目录结构 1&#xff09;config.ini 2&#xff09;run.sh 3.命令解读 1&#xff09;ls -1 路径文件夹 含义&#xff1a;ls -1 /home/oracle/shell/config/ 将文件夹config内的文件全部列出 [oracleneptune config]$ ls -1 /home/oracle/shel…

适合下班做的副业兼职、1天挣300,7天涨粉2万

最近小红书上有类视频火了&#xff01; 周周近财&#xff1a;让网络小白少花冤枉钱&#xff0c;赚取第一桶金 利用AI制作的漫画解说历史小说视频。视频以《明朝那些事儿》为蓝本&#xff0c;一上线就疯狂吸粉&#xff0c;多条视频内容都大爆了。 就是这个账号&#xff0c;仅仅…

【华为】BFD与静态路由和RIP联用

【华为】BFD与静态路由和RIP联用 实验需求配置AR1AR2AR3AR4效果抓包查看 实验需求 如上图组网所示&#xff0c;在R1上配置到达R4的Loopback0。 4.4.4.4/32网段的浮动静态路由&#xff0c;正常情况下通过R3访问R4。 当R3故障时&#xff0c;自动选路通过R2访问R4的Loopback0;在R…

了解K8s集群kubectl命令进行陈述式资源管理

前言 在 Kubernetes 集群中&#xff0c;通过陈述式和声明式资源管理是确保应用程序高效运行的关键。认识这两种管理方法&#xff0c;能够更好地掌握 Kubernetes 集群的运维和管理。 目录 一、K8s 资源管理操作分类 1. 陈述式 2. 声明式 3. K8s 集群管理常用命令概览 二…

基于瑞萨RA6M5的自控衣橱

1. 主控转接板原理图和PCB设计 2. 屏幕界面设计 3. 程序设计 4. QT设计 QT设计&#xff0c;读取MQTT数据&#xff0c;在QT上显示衣橱内部的温度&#xff0c;湿度情况&#xff0c;且能够控制衣橱的开关门&#xff0c;开关灯等。 5. 实物演示 瑞萨

数据库缓存 buffer pool详解

什么是buffer pool buffer pool, 又称之缓存池, 是mysql中为了提升查询性能而引入的缓存, 如果每次查询和修改都去操作磁盘的话, 性能就会很差, 从而引入 Buffer Pool包含多个缓冲页&#xff08;默认大小通常为16KB&#xff09;&#xff0c;每个缓冲页都有对应的控制信息&#…

Python 机器学习 基础 之 模型评估与改进 【评估指标与评分】的简单说明

Python 机器学习 基础 之 模型评估与改进 【评估指标与评分】的简单说明 目录 Python 机器学习 基础 之 模型评估与改进 【评估指标与评分】的简单说明 一、简单介绍 二、评估指标与评分 1、牢记最终目标 2、二分类指标 1&#xff09;错误类型 2&#xff09;不平衡数据集…

【产品运营】对接上游电商平台需要了解什么?

围绕卖家和平台的运营模式等维度&#xff0c;ISV对接平台可以划分为业务域、开放能力域和产品能力域。 ISV对接平台的最终目地是打通多方数据传输&#xff0c;解决卖家日常运营中的场景起到类似于业务中台的作用。因此我们可以围绕卖家和平台的运营模式等维度划分为&#xff1a…

【全开源】民宿酒店预订管理系统(ThinkPHP+uniapp+uView)

民宿酒店预订管理系统 特色功能&#xff1a; 客户管理&#xff1a;该功能可以帮助民宿管理者更加有效地管理客户信息&#xff0c;包括客户的姓名、电话、地址、身份证号码等&#xff0c;并可以在客户的订单中了解客户的消费情况&#xff0c;从而更好地满足客户的需求&#xff…

【JavaEE初阶】HTTP协议|HTTP请求方法|GET|POST|GET和POST的区别|问题辨析

目录 认识"⽅法"(method) 1.GET⽅法 GET请求的特点 2.POST⽅法 POST请求的特点 &#x1f4a1;经典⾯试题:谈谈GET和POST的区别 &#x1f4a1;问题辨析&#xff1a; 3.其他⽅法 &#x1f4a1;推荐 前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂…

六一儿童节创意项目:教你用HTML5和CSS3制作可爱的雪糕动画

六一儿童节快到了&#xff0c;这是一个充满童趣和欢乐的日子。为了给孩子们增添一份节日惊喜&#xff0c;我们决定用HTML5和CSS3制作一个生动有趣的雪糕动画。通过这个项目&#xff0c;不仅能提升你的前端技能&#xff0c;还能带给孩子们一份特别的节日礼物。无论你是前端开发新…

第一个Flutter3项目

配置flutter国内源 首先&#xff0c;配置flutter的国内源&#xff1a; env:PUB_HOSTED_URL"https://pub.flutter-io.cn"; env:FLUTTER_STORAGE_BASE_URL"https://storage.flutter-io.cn"配置gradle国内源 修改gradle\wrapper\gradle-wrapper.properties…

组件的传参等

一:组件的生命周期函数 组件的生命周期函数: created只是创建了组件内的实例对象 attached,给组件实例绑定了属性,绑定到页面节点树之后 ready准备好渲染之后,还未渲染之前 moved组件实例被移动到另一个位置后执行 detached在整个组件被被移除执行 error执行的时候,组件内…

yolo 算法 易主

标题&#xff1a;YOLOv10: Real-Time End-to-End Object Detection 论文&#xff1a;https://arxiv.org/pdf/2405.14458ethttps%3A//arxiv.org/pdf/2405.14458.zhihu.com/?targethttps%3A//arxiv.org/pdf/2405.14458 源码&#xff1a;https://github.com/THU-MIG/yolov10 分析…