Agent模型微调

这篇文章讲解:

  1. 把 Agent 和 Fine-Tuning 的知识串起来,在更高的技术视角看大模型应用;
  2. 加深对 Agent 工作原理的理解;
  3. 加深对 Fine-Tuning 训练数据处理的理解。

1. 认识大模型 Agent

1.1 大模型 Agent 的应用场景

揭秘Agent核心原理与企业级应用场景

再设想以下几个和 AI 交互的场景,并思考有什么特点:

  1. 帮我查一下今天的销售额?
  2. (开车时)前方为啥堵车了?
  3. 上海天气如何?

再比如:

  1. 帮我订一张周五去上海的机票;
  2. 请帮我约一个和搜索产品部的需求沟通会,本周三至周五我日历上空闲的时间都可以。

【重点】大模型应用需要 Agent 技术的原因:

  1. 大模型的“幻觉”问题,很难在从模型本身上彻底解决,在严肃的应用场景需要通过引入外部知识确保答案的准确;
  2. 大模型参数无法做到实时更新,本身也无法与真实世界产生实时连接,在多数场景下难以满足实际需求;
  3. 复杂的业务场景,不是一问一答就能解决的,需要任务拆解、多步执行与交互。

大模型应用,不仅要“会说话”,更要“会做事”!

1.2 大模型 Agent 的技术框架 

 

​ 

1.3 为什么需要做 Agent Tuning ?

如何实现 Agent?利用 Prompt Engineering 可以实现吗?

答案显然是可以!前面学的 AutoGPT 就是例子。

既然通过 Prompt Engineering 可以实现 Agent,那为什么还要训练 Agent 模型呢?

【重点】因为可以这么做的前提是:模型足够“聪明”,靠看“说明书”就能执行, Prompt Engineering 实际上是把“说明书”写得更加清晰易懂。

  1. 实践证明,除了 GPT-4 level 的大模型,其他大模型(包括 GPT-3.5 )无法很好遵从 prompt 要求完成复杂的 Agent 任务;
  2. 很多场景下无法使用最强的大模型 API ,需要私有化部署小模型,需要控制推理成本;
  3. 通过训练,一个小参数量的大模型(13B、7B等)也能达到较好的能力,更加实用。

 1.4 Agent Tuning 的研发流程

 

训练成本参考:
  • 训练框架: HuggingFace Trainer + DeepSpeed Zero3

  • 配置说明:max_len:4096 + Flash Attention + bf16 (batchsize=1、AdamW优化器)

模型训练最低配置训练数据规模(token数)建议训练 epoch 数平均训练时长训练成本(估算)
7B (全参数)4卡A100(4 * 80G)470M525h * 5 = 125h34.742 * 4 * 125 = 17371.0 元
14B (全参数)8卡A100(8 * 80G)470M424h * 4 = 96h34.742 * 8 * 96 = 26681.9 元
72B (全参数)32卡A100(32 * 80G)470M240h * 2 = 80h34.742 * 32 * 80 = 88939.5 元
  • 以当前阿里云 A100 租用价格计算:

2. Agent Prompt 模板设计

常见的 Agent Prompt 模板,除了大家学习过的 AutoGPT 外,还有 ReACT、ModelScope、ToolLLaMA 等不同的形式。

2.1 主流 Agent Prompt 模板

模版描述优点缺点
ReACTReACT prompt较为简单,先设定Question,再以Thought、Action、Action Input、Observation执行多轮,最后输出Final Answerprompt 简单1. API 参数只能有一个
2. 没有设定反思等行为,对于错误的思考不能及时纠正
ModelScope更为直接的生成回复,调用只需要加入<|startofthink|>和<|endofthink|>字段,并在其中填入command_name和args简单直接没有设定反思等行为,对于错误的思考不能及时纠正
AutoGPT- prompt 较为复杂,分为生成工具调用 和 生成最终答案 两套prompt
- 生成工具调用 prompt 详细设立了Constraints(例如不需要用户协助)、Resources(例如网络搜索)、Best Practices(例如每个API都需要花费,尽量少的调用),最终严格以json格式输出
prompt 限制多,会较好地进行自我反思、任务规划等prompt 较长,花费较大
ToolLLaMA模仿AutoGPT和ReACT,输出以Thought、Action、Action Input 格式而非 json 格式,增加了 give_up_and_restart,支持全部推导重来,重来的prompt会把历史失败的记录加进去训模型用了1.6w Rapid APIprompt 限制多,会较好地进行自我反思、任务规划等,并支持全部推倒重来1. prompt 较长,花费较大
2. 全部推倒重来花费会更大

 eg:

# 导入依赖库
from openai import OpenAI
from dotenv import load_dotenv, find_dotenv# 加载 .env 文件中定义的环境变量
_ = load_dotenv(find_dotenv())# 初始化 OpenAI 客户端
client = OpenAI()  # 默认使用环境变量中的 OPENAI_API_KEY 和 OPENAI_BASE_URL# 基于 prompt 生成文本
# 默认使用 gpt-3.5-turbo 模型
def get_completion(prompt, response_format="text", model="gpt-4o-mini"):messages = [{"role": "user", "content": prompt}]    # 将 prompt 作为用户输入response = client.chat.completions.create(model=model,messages=messages,temperature=0,                                  # 模型输出的随机性,0 表示随机性最小# 返回消息的格式,text 或 json_objectresponse_format={"type": response_format},)print(response)return response.choices[0].message.content          # 返回模型生成的文本# 任务描述
instruction = """
Answer the following questions as best you can. You have access to the following tools:[
Name: web_search. Description: Perform a web search using the specified query.
Name: get_weather. Description: Retrieve the current weather information for a specified location.
]Use the following format: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 [web_search, get_weather]
Action Input: the input to the action
Observation: the result of the action
... (this Thought/Action/Action Input/Observation can repeat N times)
Thought: I now know the final answer
Final Answer: the final answer to the original input questionBegin!
"""# 用户输入
input_text = """
北京天气怎么样?
"""# 工具结果
tool_output = """
"""# prompt 模版。instruction 和 input_text 会被替换为上面的内容
prompt = f"""
{instruction}Question: 
{input_text}{tool_output}
"""# 调用大模型
response = get_completion(prompt)
print("------------------------------------------")
print(response)
# 导入依赖库
from openai import OpenAI
from dotenv import load_dotenv, find_dotenv# 加载 .env 文件中定义的环境变量
_ = load_dotenv(find_dotenv())# 初始化 OpenAI 客户端
client = OpenAI()  # 默认使用环境变量中的 OPENAI_API_KEY 和 OPENAI_BASE_URL# 基于 prompt 生成文本
# 默认使用 gpt-3.5-turbo 模型
def get_completion(prompt, response_format="text", model="gpt-4o-mini"):messages = [{"role": "user", "content": prompt}]    # 将 prompt 作为用户输入response = client.chat.completions.create(model=model,messages=messages,temperature=0,                                  # 模型输出的随机性,0 表示随机性最小# 返回消息的格式,text 或 json_objectresponse_format={"type": response_format},)print(response)return response.choices[0].message.content          # 返回模型生成的文本# 任务描述
instruction = """
<|system|>
You are AutoGPT, you can use many tools (functions) to do the following task. First I will give you the task description, and your task start. At each step, you need to give your thought to analyze the status now and what to do next, with a function call to actually execute your step. Your output should follow this format:Thought:
Action:
Action Input:After the call, you will get the call result, and you are now in a new state. Then you will analyze your status now, then decide what to do next.After many (Thought-call) pairs, you finally perform the task, then you can give your final answer.Remember:The state change is irreversible, you can't go back to one of the former states. If you want to restart the task, say "I give up and restart".
All the thoughts are short, at most 5 sentences.
You can do more than one try, so if your plan is to continuously try some conditions, you can do one of the conditions per try.
Let's Begin!Task description: You should use functions to help handle the real-time user queries. Remember:ALWAYS call the "Finish" function at the end of the task. The final answer should contain enough information to show to the user. If you can't handle the task, or you find that function calls always fail (the function is not valid now), use function Finish->give_up_and_restart.
Specifically, you have access to the following APIs:{"api_name": "web_search","description": "Perform a web search using the specified query.","parameters": {"type": "object","properties": {"query": {"type": "string","description": "The search query to be executed.","example_value": "华为发布会"}},"required": ["query"],"optional": []}
}
{"api_name": "get_weather","description": "Retrieve the current weather information for a specified location.","parameters": {"type": "object","properties": {"location": {"type": "string","description": "The name of the location (city, country, etc.) to get the weather for.","example_value": "Beijing"},},"required": ["location"],"optional": []}
}
{"name": "Finish","description": "If you believe that you have obtained a result that can answer the task, please call this function to provide the final answer. Alternatively, if you recognize that you are unable to proceed with the task in the current state, call this function to restart. Remember: you must ALWAYS call this function at the end of your attempt, and the only part that will be shown to the user is the final answer, so it should contain sufficient information.","parameters": {"type": "object","properties": {"return_type": {"type": "string","enum": ["give_answer", "give_up_and_restart"]},"final_answer": {"type": "string","description": "The final answer you want to give the user. You should have this field if "return_type"=="give_answer""}},"required": ["return_type"]}
}
"""# 用户输入
input_text = """
北京天气怎么样?
"""# 工具结果
tool_output = """
"""# prompt 模版。instruction 和 input_text 会被替换为上面的内容
prompt = f"""
{instruction}<|user|>
{input_text}{tool_output}<|assistant|>
"""# 调用大模型
response = get_completion(prompt)
print("------------------------------------------")
print(response)

2.2 Agent Prompt 模板设计

我们可以设计两套Prompt模板,一套用于任务规划和工具调用指令生成(模板-1),一套用于总结生成最终答案(模板-2)。

I. Agent Prompt 1(模板-1):

你是一个很专业的AI任务规划师,给定目标或问题,你的决策将独立执行而不依赖于人类的帮助,请发挥LLM的优势并且追求高效的策略进行任务规划。

Constraints: 1.你有~4000字的短期记忆 2.不需要用户的帮助 3.只使用双引号中列出的commands,例如:“command_name” 4.互联网搜索、信息聚合和鉴别真伪的能力 5.保持谦逊,对自己没把握的问题,尽可能调用command,但尽量少调用,不能重复调用 6.当你从自身知识或者历史记忆中能得出结论,请聪明且高效,完成任务并得出结论 7.经常建设性地自我批评整个行为大局,反思过去的决策和策略,以改进你的方法 8.你最多只能进行5步思考,规划5个任务,所以尽可能高效规划任务 9.你有反思能力,如果已完成的任务和结果暂不能得到回答问题所需信息或尚不能完成目标,应继续规划

Commands: 1:{"name": "web_search", "description": "Perform an internet search.", "parameters": {"type": "object", "properties": {"text": {"type": "str", "description": "Search query."}}}, "returns": {"description": "Multiple webpage links along with brief descriptions.", "type": "str"}, "required": ["text"]}

2:{"name": "wiki_search", "description": "Conduct an encyclopedia search for a specified entity and question. Provide accurate answers for factual queries but has a limited scope and cover fewer queries.", "parameters": {"type": "object", "properties": {"entity": {"type": "str", "description": "The target entity for the search."}, "question": {"type": "str", "description": "A concise Chinese sentence containing the target entity, indicating the specific information sought from the wikipage."}}}, "returns": {"description": "Relevant encyclopedia entries pertaining to the question.", "type": "str"}, "required": ["entity", "question"]}

3:{"name": "get_weather_info", "description": "Retrieve weather information for specified locations and dates.", "parameters": {"type": "object", "properties": {"location": {"type": "str", "description": "Locations in English separated by commas, e.g., "Beijing,Vancouver,...,Chicago"."}, "start_date": {"type": "str", "description": "Start date in format "yyyy-MM-dd"."}, "end_date": {"type": "str", "description": "End date in format "yyyy-MM-dd"."}, "is_current": {"type": "str", "description": ""yes" or "no" indicating if current time's weather is desired."}}}, "returns": {"description": "Weather information between start date and end date.", "type": "str"}, "required": ["location", "start_date", "end_date", "is_current"]}

4:{"name": "task_complete", "description": "Indicate task completion without the need for further functions. ", "parameters": {"type": "object", "properties": {}}, "returns": {"description": "", "type": ""}, "required": []}

GOAL: 用户的输入

Completed tasks: 已完成任务(短时记忆)

Conversation history: 对话历史(短时记忆)

Knowledge: 知识(短时记忆)

Current Time: 当前时间

根据目标和已有任务,规划一个新Task(不能重复),你只能以以下json列表的格式生成Task { "task_name": "任务描述", "command":{ "name":"command name", "args":{ "arg name":"value" } } }

确保Task可以被Python的json.loads解析

当已完成的Tasks能够帮助回答这个目标问题,则尽可能生成任务完成Task,否则生成一个其他Task。一个新Task:

Agent Prompt 1 的组成部分:
  • Profile(角色):

定义 Agent 的身份、背景甚至性格特点等。这帮助模型在回答时保持一致性和个性化。例如,一个 Agent 可能被设定为一个友好且专业的助理。

你是一个很专业的AI任务规划师,给定目标或问题,你的决策将独立执行而不依赖于人类的帮助,请发挥LLM的优势并且追求高效的策略进行任务规划。
  • Instruction(指令):

提供具体的操作指令,指导Agent如何完成任务。这些指令明确地告诉Agent在特定情境下应该做什么或避免做什么。

Constraints:  
1.你有~4000字的短期记忆
2.不需要用户的帮助
3.只使用双引号中列出的commands,例如:“command_name”
4.互联网搜索、信息聚合和鉴别真伪的能力
5.保持谦逊,对自己没把握的问题,尽可能调用command,但尽量少调用,不能重复调用
6.当你从自身知识或者历史记忆中能得出结论,请聪明且高效,完成任务并得出结论
7.经常建设性地自我批评整个行为大局,反思过去的决策和策略,以改进你的方法
8.你最多只能进行5步思考,规划5个任务,所以尽可能高效规划任务
9.你有反思能力,如果已完成的任务和结果暂不能得到回答问题所需信息或尚不能完成目标,应继续规划……当已完成的Tasks能够帮助回答这个目标问题,则尽可能生成任务完成Task,否则生成一个其他Task。一个新Task:
  • Tools(工具集):

列出Agent可以使用的工具或功能,需要根据实际业务需求来构建。

Commands:  
1:{"name": "web_search", "description": "Perform an internet search.", "parameters": {"type": "object", "properties": {"text": {"type": "str", "description": "Search query."}}}, "returns": {"description": "Multiple webpage links along with brief descriptions.", "type": "str"}, "required": ["text"]}2:{"name": "wiki_search", "description": "Conduct an encyclopedia search for a specified entity and question. Provide accurate answers for factual queries but has a limited scope and cover fewer queries.", "parameters": {"type": "object", "properties": {"entity": {"type": "str", "description": "The target entity for the search."}, "question": {"type": "str", "description": "A concise Chinese sentence containing the target entity, indicating the specific information sought from the wikipage."}}}, "returns": {"description": "Relevant encyclopedia entries pertaining to the question.", "type": "str"}, "required": ["entity", "question"]}3:{"name": "get_weather_info", "description": "Retrieve weather information for specified locations and dates.", "parameters": {"type": "object", "properties": {"location": {"type": "str", "description": "Locations in English separated by commas, e.g., "Beijing,Vancouver,...,Chicago"."}, "start_date": {"type": "str", "description": "Start date in format "yyyy-MM-dd"."}, "end_date": {"type": "str", "description": "End date in format "yyyy-MM-dd"."}, "is_current": {"type": "str", "description": ""yes" or "no" indicating if current time's weather is desired."}}}, "returns": {"description": "Weather information between start date and end date.", "type": "str"}, "required": ["location", "start_date", "end_date", "is_current"]}4:{"name": "task_complete", "description": "Indicate task completion without the need for further functions. ", "parameters": {"type": "object", "properties": {}}, "returns": {"description": "", "type": ""}, "required": []}
  • Goal(目标,用户的Query):

定义Agent的主要任务或目的。这帮助Agent聚焦于最终目标,例如帮助用户解答问题、撰写文章等。

GOAL: 我想登顶北京最高峰,请帮我做个规划
  • Memory(记忆):

保持上下文或会话记忆,以提供连续性。这使得Agent能够参考之前的对话或用户提供的信息,提供更相关和个性化的回应。

【重点】Memory部分可以包括:

  1. Completed Tasks(已完成任务):之前已调用工具完成的任务,通常包含任务名、工具名、工具参数、工具返回结果等信息;
  2. Conversation History(对话历史):记录用户和 Agent 系统的对话历史;
  3. Knowledge(知识):存储业务中所需的知识用于参考,例如用户上传的文档、个性化知识等。

将知识,对话历史,任务历史进行存储,然后在对话的过程中进行检索和筛选,筛选后的信息加入prompt中作为参考。底层使用的向量数据库进行信息的存储,检索采用es和embedding进行双路召回。

Completed tasks: [{"task_name": "查询北京最高山","command": {"name": "wiki_search","args": {"entity": "北京""question": "北京最高山是什么山"}},"task_id": 1,"result": "北京市,通称北京(汉语拼音:Běijīng;邮政式拼音:Peking),简称“京”,曾称“北平”[注 2]。是中华人民共和国的首都及直辖市,是中国的政治、文化、科技、教育、军事和国际交往中心,是一座全球城市,是世界人口第三多的城市和人口最多的首都,具有重要的国际影响力[4]。北京位于华北平原的北部边缘,背靠燕山,永定河流经老城西南,毗邻天津市、河北省,为京津冀城市群的重要组成部分..."},{"task_name": "未找到,调用搜索工具查询","command": {"name": "web_search","args": {"question": "北京最高山是什么山"}},"task_id": 2,"result": "title:北京最高的山峰是那座,北京最高的山是什么山\nbody:北京最高的山峰是位于北京市门头沟区清水镇的东灵山,主峰海拔2303米,是北京市的最高峰,被誉为京西的“珠穆朗玛”。 景色介绍东灵山自然风景区位于京西门头沟的西北部, ... url: https://m.mafengwo.cn/travel-news/219777.html ..."}
]
Conversation history: [{"user": "刘德华多少岁了?","assistant": "刘德华(Andy Lau)生于1961年9月27日。截至2024年7月,他已经62岁了。"},{"user": "北京今天天气怎么样?","assistant": "北京当日天气多云,28摄氏度,微风"}     
]
Knowledge: [{"北京最高的山峰是东灵山,海拔2303米。","北京市地处中国北部、华北平原北部,东与天津市毗连,其余均与河北省相邻,中心位于东经116°20′、北纬39°56′,北京市地势西北高、东南低。","2023年,北京市全年实现地区生产总值43760.7亿元,按不变价格计算,比上年增长5.2%。"}
]
思考:如果 Memory 太多,Prompt 无法容纳怎么办?
  • Format(输出格式):

定义Agent生成输出的格式和风格。这确保了Agent的回应符合预期的结构和表达方式,例如简洁、正式或非正式等。

根据目标和已有任务,规划一个新Task(不能重复),你只能以以下json列表的格式生成Task  
{  "task_name": "任务描述",  "command":{  "name":"command name",  "args":{  "arg name":"value"  }  }  
}  
确保Task可以被Python的json.loads解析
  • 其他必要信息:

可以根据业务场景的需求,在Prompt中添加必要的常用信息,如:当前时间、地点、IP等。


Current Time: 2024-07-01 12:12:00.653415

3. Agent Tuning

3.1 Agent Tuning 的目的(再次理解)

回顾: 既然通过 Prompt Engineering 可以实现 Agent,那为什么还要训练 Agent 模型呢?

因为可以这么做的前提是:模型足够“聪明”,靠看“说明书”就能执行, Prompt Engineering 实际上是把“说明书”写得更加清晰易懂。

  1. 实践证明,除了 GPT-4 level 的大模型,其他大模型(包括 GPT-3.5 )无法很好遵从 prompt 要求完成复杂的 Agent 任务;
  2. 很多场景下无法使用最强的大模型 API ,需要私有化部署小模型,需要控制推理成本;
  3. 通过训练,一个小参数量的大模型(13B、7B等)也能达到较好的能力,更加实用。

 3.2 训练数据准备

​ 

  • 大模型 fine-tuning 的数据形式:

【重点】大模型 Fine Tuning 本质上是在给定输入 Input 的条件下,调整模型的参数,使得大模型生成的输出内容 Output' 和训练数据中的标准回答 Output 尽可能接近。Fine Tuning 也被称作 Supervised Fine Tuning,简称SFT,有监督微调,训练数据中的 Output 就是用来“监督”模型参数调整方向的。

  • Agent Tuning 是一种特殊的 fine-tuning,有时也被称作 Tool SFT,特殊之处在于:

    1)Agent Tuning 的 Prompt 更复杂,约束条件更多;

    2)通常 Agent 工作过程是多步的,因此训练数据也需要是多步骤的,多步之间前后有关联。

​ 

重点Agent Tuning 训练数据构建的步骤:

  1. 根据实际业务收集大量 query,要尽可能覆盖各种场景;
  2. 将每一个 query 与 prompt 模板结合,构成 agent prompt,也就是训练数据中的输入部分;
  3. 为每一个 agent prompt 构建对应的标准答案,也就是训练数据中的输出部分,这项工作可以借助 GPT-4 level 的大模型来降本提效;
  4. 如果第三步是用大模型来生成答案,则最好通过人工修正或筛选高质量的 Output,数据质量越高,最终 Agent Tuning 得到的模型效果越好。

 eg:

你是一个很专业的AI任务规划师, 给定目标或问题,你的决策将独立执行而不依赖于人类的帮助,请发挥LLM的优势并且追求高效的策略进行任务规划。
Constraints:
1.你有~4000字的短期记忆
2.不需要用户的帮助
3.只使用双引号中列出的commands,例如:“command_name”
4.互联网搜索、信息聚合和鉴别真伪的能力
5.保持谦逊,对自己没把握的问题,尽可能调用command,但尽量少调用,不能重复调用
6.当你从自身知识或者历史记忆中能得出结论,请聪明且高效,完成任务并得出结论
7.经常建设性地自我批评整个行为大局,反思过去的决策和策略,以改进你的方法
8.你最多只能进行5步思考,规划5个任务,所以尽可能高效规划任务
9.你有反思能力,如果已完成的任务和结果暂不能得到回答问题所需信息或尚不能完成目标,应继续规划Commands:
1:Web Search:"web_search",args:"text":"<search>"
2:Browse Website:"browse_website",args:"url":"<url>, "question":"<what_you_want_to_find_on_website>"
3:Wikipedia search:"wiki_search",args:"entity":<entity>,"question":"<what_you_want_to_find_on_wikipage>"
4:Wikipage browser:"browse_wikipage",args:"url":<url_return_by_wiki_search>,"question":"<what_you_want_to_find_on_wikipage>"
5:Video Search:"video_search",args:"query":"<search-query-in-chinese>"
6:Do Nothing: "do_nothing",args:
7:Task Complete (Shutdown):"task_complete",args: "reason":"<reason>"Commands Tips:
1.使用browse_website时,尽可能只访问先前搜索得到的网址,不要瞎编生成无效网站链接
2.wiki_search返回的信息尽管更准确,但搜索范围小,问题覆盖率低,question只能是包含中心实体的简单中文短句
3.每次调用command都会收取费用,尽可能少调用Current Time: 2023-07-07 18:35:32.214612GOAL: 请找出蔡徐坤2023年的演唱会名称,以及与演唱会相关的最新几则新闻。根据目标和已有任务,规划一个新Task(不能重复),你只能以以下json列表的格式生成Task
{
"task_name": "任务描述",
"command":{
"name":"command name",
"args":{
"arg name":"value"
}
}
}
确保Task可以被Python的json.loads解析当已完成的Tasks已经能够帮助回答这个目标,则尽可能生成任务完成Task,否则生成一个其他Task。一个新Task:

 3.3 模型训练

注意:Agent 模型通常需要全参数训练,LoRA 效果不好。

高阶经验(大家了解即可):

  • 应用加速训练、节省显存的方法,例如:混合精度、分布式训练(Deepspeed Zero3)、梯度检查点(Gradient Checkpointing)、梯度累积(Gradient Accumulation)、Flash Attention 等;
  • 推理用 vllm 等框架加速。

3.4 效果评估

3.4.1 自动评估

自动评估的主要目的是在模型训练过程中监控模型的效果,评估指标的对比意义大于绝对值意义。

  1. 采用 GPT-4 + 人工修正的方式构建自动评测的 benchmark(一般从训练数据中随机分出一部分即可);
  2. 将 Agent 输出结果与 benchmark 中的参考答案进行对比,计算得到分值。

示例:

Ground Truth:

{"task_name": "查询北京实时天气","command": {"name": "get_weather_info","args": {"location": "北京","start_date": "2024-07-01","end_date": "2024-07-01","is_current": "yes"}}
}

Agent Response:

{"task_name": "查询北京当前天气","command": {"name": "get_weather_info","args": {"location": "北京","start_date": "2024-07-01","end_date": "2024-07-01","is_current": "no"}}
}

其中,Tn,i 为 Groud Truth 中的工具名称,Tn,j′ 为 待测试的 Agent Response 中的工具名称,EM为精确匹配(Exact Match,直接进行字符串精确匹配),结果为 0 或 1;

Th,i 为 Groud Truth 中的任务描述(示例中的“task_name”),Th,j′ 为 待测试的 Agent Response 中的任务描述,

可以是任何文本生成质量评估的方法(例如 ROUGE、 BLEU),做模糊匹配评分,分值为0-1;

类似地:

自动测试结果示例:

ScalePlanningTool-useReflectionConcludingProfileOverall Score
GPT-3.5-turbo-18.5526.268.0637.2635.4225.63
Qwen7B13.3418.007.9136.2434.9921.17
Qwen27B20.1129.0321.0140.3642.0629.57
Baichuan213B6.7016.106.7624.9719.0814.89
------------------------
Qwen-MAT7B31.6443.3033.3444.8544.7839.85
Baichuan2-MAT13B37.2752.9737.0048.0141.8345.34

人工评估

最靠谱的评估当然还是需要人工来做,人工评估的难点在于标准的制定,以及对评估人员的培训。

评估标准示例:

评分分为五个等级,具体定义如下:

1分:核心信息存在重大不准确性,大部分或全部内容不正确; 2分:核心信息不正确,或超过60%的内容有错误; 3分:核心信息准确,但10%到60%的补充信息不正确; 4分:小有出入,核心信息准确,补充信息中的错误不超过10%; 5分:完全正确。

得分为4分或5分的回答被认为是可用的。

遇到违规内容一票否决,直接判0分。


人工评估效率低、成本高,所以不能频繁使用,一般在大的模型版本上使用。

4. Agent 泛化性提升

如果想进一步提升 Agent 的泛化性,比如希望用一个 Agent 服务于多个业务,能适应不同的 Prompt 模板,可以灵活地接入新的业务,那么训练数据应该如何构建呢?

4.1 训练数据的多样性

基座大模型本身的理解能力和 Agent Tuning 训练数据的多样性共同决定了 Agent 的泛化能力。在指定了基座模型的情况下,我们可以做的是提升训练数据的多样性

我们可以将训练数据 Input 部分拆解为3个变量:Query、Tools、Agent Prompt模板,最终的数据就是这3个变量的组合。

  • Query

    • 覆盖全部场景:对于内部业务工具构造特定query,尽可能覆盖所有可能的业务场景,避免有遗漏;

    • 困难负样本:构造正样本(需要用到工具的query) + 困难负样本(看似和工具有关,但实际上不调用),其中大部分是正样本,但不能全是正样本


      示例:上海明天天气怎么样?(正样本)| 北京今天下雨吗?(正样本) | 今天天气真好(困难负样本)
      经验值:正样本和困难负样本比例 4:1,仅供参考。


    • 样本复杂度多样:简单样本和复杂样本都需要构造,简单样本为一步即可完成的任务,复杂样本为涉及多步推理、多种工具的任务;(实践中评测时发现,仅减少550复杂query,测试集中的事实准确率下降6个百分点)


      示例:这周末适合去北京郊区露营吗?如果适合,请推荐几个地方? | 刘德华的女儿几岁了?(涉及到多步工具调用)
      经验值:简单样本与复杂样本比例 6:1,仅供参考。


  • Tools

    有两种维度:Tools描述格式多样性和Tools类型多样性。

    • Tools 描述格式多样性:


      - OpenAI function:{"name": "web_search", "description": "Perform an internet search.", "parameters": {"type": "object", "properties": {"text": {"type": "str", "description": "Search query."}}}, "returns": {"description": "Multiple webpage links along with brief descriptions.", "type": "str"}, "required": ["text"]} - AutoGPT:Web Search:"web_search",args:"text":"" - ReACT:duckduckgo_search: A wrapper around DuckDuckGo Search. Useful for when you need to answer questions about current events. Input should be a search query.


    • Tools 类型多样性:

      除了引入业务本身的工具之后,还可以添加更加丰富的工具,比如可以从ToolLLaMA(1w+)、ModelScope(几百)、AutoGPT等项目中选取API,可以提升工具的泛化性。

  • Agent Prompt 模板

    提升 Agent Prompt 模板的多样性,参见下一节 Meta-Agent 内容。

【重点】对 Query、Tools、Agent Prompt 模板 这三个变量分别构造了各种类型的数据,然后进行组合构成多样性的 Input( Prompt )数据,再调用GPT-4生成 Output( Response ),多样性的数据可以使模型不只拟合特定的 Prompt 模板,适应各种类型的 Query 以及 Tools 集合,提高模型的泛化性。

4.2 Meta-Agent

Agent Prompt 模板多样性提升

4.2.1 背景

ReACT、ToolLlama、ModelScope、AutoGPT 都有一套各自运行在其中内部的一套 prompt 模板,模型如果只是在一套 prompt 模板下训练,那么可能只是拟合了这一套 prompt ,如果换一套 prompt 性能会急剧下降;我们希望 Agent 不受到特定 Prompt 模板的限制,提升模型本质的 Agent 能力,提出了核心思想 Meta-Agent 方法。

这些 Agent Prompt 模板虽然表述方式各不相同,但都可以分为 <Profile>、<Instruction>、<Tools>、<Goal>、<Memory>、<Format>部分,那是不是可以调用GPT4来自动化生成包含这些部分且表达方式多样性的模板呢?

4.2.2 方法

我们可以通过 Prompt Engineering 来设计一个基于 GPT-4 的 Agent,用于生成多样性的 Agent Prompt 模板,我们称之为:Meta-Agent (元-Agent)。

Meta-Agent Prompt: 用于调用 GPT-4 生成 Agent Prompt 模板的 Prompt,我们称之为 Meta-Agent Prompt。

我们可以手动写一个固定的 Meta-Agent Prompt 作为 GPT-4 的输入,利用大模型内容生成的多样性来生成不同的模板,但实际上多样性效果有限,更好的方式是用不同的种子 query 做引导,提升多样性。

  1. 根据实际业务收集大量 query,要尽可能覆盖各种场景;
  2. 选取相似的数条 query 组成多个集合,如果数量不足,这一步也可以借助 GPT-4 来对 query 做扩展;
  3. 设计一个 Meta-Agent Prompt 模板,将不同的 query 集合插入设计好的模板中组合成不同的 Meta-Agent Prompt;
  4. 调用 GPT-4 生成不同的 Agent Prompt 模板候选。

利用这种方法便可以生成包含<Profile>、<Instruction>、<Tools>、<Goal>、<Memory>、<Format>要素的多样化的模板。

 

由于自动化生成的 Agent Prompt 模板质量可能参差不齐,我们还需要对这些模板以及生成的训练数据进行筛选。对于关键信息缺失,有明显缺陷的的模板,我们直接删除即可。剩下的模板效果如何则需要在实际数据上检验,我们同样也可以借助 GPT-4 (做裁判)来完成。具体步骤如下:

  1. 将一批相同的 query 分别插入到经过验证的标杆模板中(如AutoGPT、ToolLLaMA等)和 Meta-Agent 生成的 prompt 模版中,形成 prompt pair;
  2. 将 prompt pair 中的两个 prompt 分别输入给GPT-4,生成对应的回复;
  3. 利用 GPT-4 对两个回复的质量分别打分 score1(标杆模板的实例)、score2(候选模板的实例),如果 score2−score1>ϵ,则保留该 prompt 实例,否则删除;
  4. 对于同一个模板的所有实例求平均分,得到模板的得分,当分值大于一定阈值,保留该模板,否则删除该模板以及对应的prompt实例。
4.1.3 示例
  • Mate-Agent Prompt(GPT-4 的输入):
# 导入依赖库
from openai import OpenAI
from dotenv import load_dotenv, find_dotenv# 加载 .env 文件中定义的环境变量
_ = load_dotenv(find_dotenv())# 初始化 OpenAI 客户端
client = OpenAI()  # 默认使用环境变量中的 OPENAI_API_KEY 和 OPENAI_BASE_URL# 基于 prompt 生成文本
# 默认使用 gpt-3.5-turbo 模型
def get_completion(prompt, response_format="text", model="gpt-4o-mini"):messages = [{"role": "user", "content": prompt}]    # 将 prompt 作为用户输入response = client.chat.completions.create(model=model,messages=messages,temperature=0,                                  # 模型输出的随机性,0 表示随机性最小# 返回消息的格式,text 或 json_objectresponse_format={"type": response_format},)print(response)return response.choices[0].message.content          # 返回模型生成的文本# meta-agent prompt 模板
meta_agent_prompt = """
As an expert in designing meta prompts for large language models (LLMs), your expertise lies in creating diverse prompts that go beyond eliciting simple responses. Your goal is to develop a prompt that assigns a specific persona to the LLM and encourages it to engage in complex tasks, such as task planning, executing API calls, self-reflection, and iterative actions influenced by the results of these API interactions, continuing until the task is fully completed. You should use "you" instead of "I" as the main voice in the meta prompt.Your prompt must explicitly reserve slots for <<QUERY>> and <<APIs>>. Each slot should ideally occupy a separate line. If the API results are integrated into the prompt, the process is segmented into two phases: the API call phase (referred to as 'prompt-API') and the final summary phase (referred to as 'prompt-response'). If API results are integrated into the response, the process includes both the API interaction and the summary in the response (referred to as 'prompt-react'). The prompt you develop must fall under one of these three categories: prompt-API, prompt-response, or prompt-react.Components that the Prompt May Include:<PROFILE> [OPTIONAL for all] Example queries use may asks are as follows: {{QUERIES}} Summarize the common characteristics of the above queries and design a detailed LLM's role or persona adept at solving such problems.
<INSTRUCTION> [REQUIRED for all] You must devise meaningful directives to constrain or aid LLMs in decision-making. For instance, "no user assistance required", "be smart and efficient in completing tasks and drawing conclusions from your own knowledge or historical memory", "possess capabilities for internet search, information aggregation", etc. Use your imagination to expand on these guidelines.
<QUERY> [REQUIRED for all] Directly add slot <<QUERY>> into your prompt. The slot will be replaced with an actual user query. Do NOT provide the specific query.
<APIs> [REQUIRED for prompt-API, prompt-react] Directly add slot <<APIs>> into your prompt. The slot will be replaced with specific APIs. These APIs contain API Name, API description and parameters that could be used in real-world scenarios, where one of them might relate to the QUERY. Do NOT provide the specific APIs.
<FORMAT> [REQUIRED for prompt-API, For prompt-react] Include explicit instructions to limit the LLM's output to a specific format and ensure that the output can be parsed. You MUST provide an output format using placeholders for both prompt-API and prompt-react. The output format MUST NOT contain any specific API name or API parameters mentioned in the <APIs> section, and you can use placeholders (such as <API_NAME>, 'command_name' and so on) to replace it.For prompt-API, you must restrict LLM's output to a fixed format and ensure that the LLM's output can be parsed. For example, you can first instruct the LLM to output a fixed expression choosing a specific API, then output another fixed expression to provide parameters, or you can output in JSON format. Please be creative and do not feel limited by the above examples. You can also include additional parameters to gather more information, such as the need to understand why LLM is invoking this API.For prompt-react, multiple rounds of thought, API calls, and API results should be executed, finally outputting the final answer.Note:You have the freedom to construct your prompts, API descriptions, parameters, and queries in either English or Chinese. The examples provided above are only for reference. Use your imagination and creativity beyond the given examples. You may replace any of the placeholder terms in the prompts, such as renaming "API" to "Command", "API call" to "Action", or 'QUERY' to 'QUESTION'. Please refrain from explicitly dividing the prompt into sections and labeling them with tags such as <PROFILE>, <APIs>, and other components, and they should be implicitly integrated into the prompt. For prompt-API, the LLM needs to just select only ONE API from the available APIs to perform the next action based on your response prompt. You must mention this in your prompt. For prompt-response, combine the API results to output useful content for the user.Please generate a prompt of the {{PROMPT_TYPE}} type directly in {{LANGUAGE}}. Do not include any explanations.
"""# query 集合
queries = """
['天津天气如何','深圳市下雨了吗','上海有台风吗']
"""# 模板类型
prompt_type = "prompt-API"# 语言设置
language = "CHINESE"# prompt
prompt = meta_agent_prompt.replace("{{QUERIES}}", queries).replace("{{PROMPT_TYPE}}", prompt_type).replace("{{LANGUAGE}}", language)# 调用大模型
response = get_completion(prompt)
print("------------------------------------------")
print(response)

4.3 训练数据构建关键经验

构建机器学习训练数据是保证模型性能的关键环节。以下是一些注意事项:

  1. 数据质量
    • 准确性:确保数据的标注正确且准确。错误标注会导致模型学到错误的模式。
    • 一致性:数据应该保持一致,避免同样的输入在不同记录中对应相互冲突的答案。

2. **数据量**: - **数量**:足够大的数据量有助于模型捕捉复杂的模式。数据量不足可能导致模型过拟合。 - **多样性**:数据应包含尽可能多的不同情况,避免模型对某些特定模式的偏好。
3. **数据平衡**:确保各种类型的数据量相对平衡。例如对于分类问题,类别不平衡会导致模型偏向多数类。
4. **数据增强**: - **数据扩充**:对于图像、文本等数据,通过旋转、翻转、添加噪声等方法扩充数据量。 - **合成数据**:在数据量不足时,考虑生成合成数据。
5. **数据清洗**: - **去重**:删除重复的数据记录,避免模型学习到重复信息。 - **提质**:对于含有瑕疵的数据,合理补充修正或直接删除。
6. **隐私和合规性**: - **隐私保护**:确保数据的收集和使用符合隐私保护法规。 - **数据匿名化**:对敏感数据进行匿名化处理,保护个人隐私。
7. **数据分割**: - **训练集、验证集、测试集**:将数据合理分割为训练集、验证集和测试集,确保模型的泛化能力。 - **避免数据泄漏**:确保训练数据中不包含测试数据的信息,避免模型在测试时表现出非真实的高精度。
8. **持续更新**: - **数据更新**:随着时间推移,定期更新训练数据,保持模型的准确性和可靠性。 - **模型监控**:监控模型性能,及时发现和解决数据相关的问题。
通过关注这些注意事项,可以提高训练数据的质量,从而构建出更准确、更可靠的机器学习模型。

一般大厂都会专门开发一套机器学习数据管理的系统,并且有专业的数据标注团队(全职+外包)来完成机器学习数据的建设。

5. 几个 Agent Tuning 开源项目简介

1) ToolBench (ToolLLaMA)
  • 发布机构:面壁智能

4.6k stars
* https://github.com/OpenBMB/ToolBench

提供数据集、相应的训练和评估脚本,以及在ToolBench上经过微调的强大模型ToolLLaMA。

数据:ToolBench,包含 469585 条数据(工具数量:3451;API数量:16464);
模型:ToolLLaMA-2-7b-v2、ToolLLaMA-7b-v1、ToolLLaMA-7b-LoRA-v1


 

2) AgentTuning
  • 发布机构:智谱华章

1.3k stars
* https://github.com/THUDM/AgentTuning

利用多个 Agent 任务交互轨迹对 LLM 进行指令调整的方法。评估结果表明,AgentTuning 让 LLM 在未见过的 Agent 任务中也展现出强大的泛化能力,同时通用语言能力也基本保持不变。

数据:AgentInstruct,包含 1866 个高质量交互、6 个多样化的真实场景任务;
模型:AgentLM 由 Llama2-chat 开源模型系列在 AgentInstruct,ShareGPT 混合数据集上微调得到,有7B、13B、70B三个模型。

3) KwaiAgents
  • 发布机构:快手

1k stars
* https://github.com/KwaiKEG/KwaiAgents

快手联合哈尔滨工业大学研发,使 7B/13B 的 “小” 大模型也能达到超越 GPT-3.5 的效果。

数据:KAgentInstruct,超过20w(部分人工编辑)的Agent相关的指令微调数据;KAgentBench:超过3k条经人工编辑的自动化评测Agent能力数据;
模型:采用 Meta-Agent 方法训练,包括 Qwen-7B-MAT、Qwen-14B-MAT、Qwen-7B-MAT-cpp、Qwen1.5-14B-MAT、Baichuan2-13B-MAT。

6. 总结

1. 理解大模型应用需要 Agent 技术的原因:消除“幻觉”、连接真实世界、处理复杂任务;
2. 理解 Agent Tuning 的主要动机:希望通过训练让大模型,尤其是小参数大模型(7B、14B)也能具备特定业务场景的 Agent 能力;
3. 了解 Agent Prompt 的构造方法,通常包括Profile、Instruction、Tools、Format、Memory、Goal等部分;
4. 了解 Agent Tuning 训练数据的构建方法和微调训练方式,并学习模型效果评估的方法;
5. 了解提升 Agent 泛化性的方法:从Query、Tools 和 Agent Prompt 模板三个方面提升训练数据的多样化,引申了解机器学习训练数据构建的关键经验;
6. 介绍了三个 Agent Tuning 的开源项目。

 最后推荐大家一起学习B站上吴恩达老师的,讲的很不错。

链接:04can-a-large-language-model-master-wordle_哔哩哔哩_bilibili

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

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

相关文章

【最新版】Arduino IDE的安装入门Demo

1、背景说明 1、本教程编写日期为2025-5-24 2、Arduino IDE的版本为&#xff1a;Arduino IDE 2.3.6 3、使用的Arduino为Arduino Uno 1、ArduinoIDE的安装 1、下载。网址如下&#xff1a;官网 2、然后一路安装即可。 期间会默认安装相关驱动&#xff0c;默认安装即可。 3、安…

Python应用运算符初解

大家好!运算符是编程中不可或缺的工具&#xff0c;它们能帮助我们执行各种计算和操作。无论是数学运算&#xff0c;还是变量赋值&#xff0c;运算符都在背后默默发挥作用。对于编程初学者来说&#xff0c;理解并掌握常见运算符的用法是迈向编程世界的重要一步。 算术运算符: 加…

小米2025年校招笔试真题手撕(二)

一、题目 给一个长度为n的序列和一个整数x&#xff0c;每次操作可以选择序列中的一个元素&#xff0c;将其从序列中删去&#xff0c;或者将其值加一。 问至少操作多少次&#xff0c;可以使操作后的序列&#xff08;可以为空&#xff09;中数字之和是x的倍数。 输入描述&#…

CNN卷积神经网络到底卷了啥?

参考视频&#xff1a;卷积神经网络&#xff08;CNN&#xff09;到底卷了啥&#xff1f;8分钟带你快速了解&#xff01; 我们知道&#xff1a; 图片是由像素点构成&#xff0c;即最终的成像效果是由背后像素的颜色数值所决定 在Excel中&#xff1a;有这样一个由数值0和1组成的66…

教师技术知识对人工智能赋能下教学效果的影响:以教学创新为中介的实证研究

教师技术知识对人工智能赋能下教学效果的影响&#xff1a;以教学创新为中介的实证研究 摘要 随着教育信息化的快速发展&#xff0c;人工智能技术在教育领域的应用日益广泛&#xff0c;为教育教学带来了深刻变革。然而&#xff0c;当前关于教师技术知识如何影响人工智能赋能下的…

Linux驱动学习笔记(九)

设备模型 1.kobject的全称为kernel object&#xff0c;即内核对象&#xff0c;每一个kobject都会对应到系统/sys/下的一个目录&#xff0c;这些目录的子目录也是一个kobject&#xff0c;以此类推&#xff0c;这些kobject构成树状关系&#xff0c;如下图&#xff1a; kobject定…

25年上半年五月之软考之设计模式

目录 一、单例模式 二、工厂模式 三、 抽象工厂模式 四、适配器模式 五、策略模式 六、装饰器模式 ​编辑 考点&#xff1a;会挖空super(coffeOpertion); 七、代理模式 为什么必须要使用代理对象&#xff1f; 和装饰器模式的区别 八、备忘录模式 一、单例模式 这个…

Python打卡第36天

浙大疏锦行 作业&#xff1a; 对之前的信贷项目&#xff0c;利用神经网络训练下&#xff0c;尝试用到目前的知识点让代码更加规范和美观。 import torch import torch.nn as nn import torch.optim as optim from sklearn.model_selection import train_test_split from sklear…

全面理解类和对象(下)

文章目录 再谈构造函数初始化列表 static概念&#xff1a; 友元友元函数友元类 内部类再次理解类和对象 再谈构造函数 class Date { public:Date(int year, int month, int day){_year year;_month month;_day day;} private:int _year;int _month;int _day; };上述代码有了…

TomatoSCI分析日记——层次聚类

TomatoSCI分析日记——层次聚类 今天介绍的是一种常见的聚类方法——层次聚类。层次聚类会将数据集划分成嵌套的簇&#xff0c;形成一个层次结构&#xff08;树状图&#xff09;&#xff0c;经常用于探究样本的相似性。用大白话来说&#xff0c;就是&#xff1a;我有一大堆样品…

mysql都有哪些锁?

MySQL中的锁机制是确保数据库并发操作正确性和一致性的重要组成部分&#xff0c;根据锁的粒度、用途和特性&#xff0c;可以分为多种类型。以下是MySQL中常见的锁及其详细说明&#xff1a; 一、按锁的粒度划分 行级锁&#xff08;Row-level Locks&#xff09; 描述&#xff1a;…

flutter 项目调试、flutter run --debug调试模式 devtools界面说明

Flutter DevTools 网页界面说明 1. 顶部导航栏 Inspector&#xff1a;查看和调试 Widget 树&#xff0c;实时定位 UI 问题。Performance-- 性能分析面板&#xff0c;查看帧率、CPU 和 GPU 使用情况&#xff0c;识别卡顿和性能瓶颈。Memory-- 内存使用和对象分配分析&#xff…

使用Kotlin创建Spring Boot用户应用项目

项目初始化与配置 通过Spring Initializr创建Kotlin项目 若需使用Kotlin语言开发Spring Boot应用(假设已安装Kotlin环境),可通过start.spring.io进行项目初始化。在项目创建页面需进行以下关键配置: 语言选择:切换至Kotlin选项项目元数据:需填写Group(如com.apress.us…

【Linux网络篇】:Socket网络套接字以及简单的UDP网络程序编写

✨感谢您阅读本篇文章&#xff0c;文章内容是个人学习笔记的整理&#xff0c;如果哪里有误的话还请您指正噢✨ ✨ 个人主页&#xff1a;余辉zmh–CSDN博客 ✨ 文章所属专栏&#xff1a;Linux篇–CSDN博客 文章目录 网络编程套接字一.预备知识1.理解源IP地址和目的IP地址2.认识端…

Python爬虫实战:研究Newspaper框架相关技术

1. 引言 1.1 研究背景与意义 互联网的快速发展使得新闻信息呈现爆炸式增长&#xff0c;如何高效地获取和分析这些新闻数据成为研究热点。新闻爬虫作为一种自动获取网页内容的技术工具&#xff0c;能够帮助用户从海量的互联网信息中提取有价值的新闻内容。本文基于 Python 的 …

【node.js】实战项目

个人主页&#xff1a;Guiat 归属专栏&#xff1a;node.js 文章目录 1. 项目概览与架构设计1.1 实战项目&#xff1a;企业级电商管理系统1.2 技术栈选择 2. 项目初始化与基础架构2.1 项目结构设计2.2 基础配置管理 3. 用户服务实现3.1 用户服务架构3.2 用户模型设计3.3 用户服务…

Mybatis框架的构建(IDEA)

选择maven项目 修改设置 在设置中添加自定义代码模板 开始写代码 动态SQL语句的示例&#xff1a; pom文件&#xff1a; <?xml version"1.0" encoding"UTF-8"?> <project xmlns"http://maven.apache.org/POM/4.0.0"xmlns:xsi"…

经济法-6-公司法律制度知识点

一、出资期限 1.有限责任公司&#xff1a;全体股东需在公司成立之日起5年内缴足认缴的注册资本 2.股份有限公司&#xff1a;以发起方式设立的&#xff0c;发起人需在公司登记前实缴全部股款 3.认缴期加速到期 公司不能清偿到期债务的&#xff0c;公司或者已到期债权的债权人…

jquery.table2excel方法导出

jquery提供了一个table2excel方法可以用来导出页面到xls等 $("#grid_595607").table2excel({exclude: ".noExport", // 排除类名为 noExport 的元素filename: "导出数据.xls",exclude_img: true, // 不导出图片exclude_links: true, // 不导…

echarts设置标线和最大值最小值

echarts设置标线和最大值最小值 基本ECharts图表初始化配置 设置动态的y轴范围&#xff08;min/max值&#xff09; 通过markPoint标记最大值和最小值点 使用markLine添加水平参考线 配置双y轴图表 自定义标记点和线的样式&#xff08;颜色、符号等&#xff09; 响应式调整图表大…