基础
- Agent和AgentExecutor的区别
- AgentExecutor.from_agent_and_tools()和AgentExecutor()的区别
- PromptTemplate和ChatPromptTemplate的区别
- 如何让LLM输出Json格式
- 如何让LLM输出自定义格式
- Agent执行的全过程
LangChain库函数
Pydantic:确保数据符合预期的格式和结构
问题
Json格式输出
from langchain_community.chat_models import ChatZhipuAI
from langchain_core.pydantic_v1 import BaseModel, Field
from langchain.prompts import PromptTemplate
from langchain_core.output_parsers import JsonOutputParser
from pprint import pprint
llm = ChatZhipuAI(
model="glm-4",
api_key="eb9aed8db44efa3b428072914bc5063e.Vr33yNfWV4QTnUy6",
)
class Ans(BaseModel):
NAME: list = Field(description="有名的诗人的名字")
POEM: str = Field(description="诗词")
parser = JsonOutputParser(pydantic_object=Ans)
prompt = PromptTemplate(
template="{format_instructions}\n{query}",
input_variables=["query"],
partial_variables={"format_instructions": parser.get_format_instructions()},
)
model = prompt|llm|parser
print(model.invoke({"query": "有名的诗人和他们的诗,请说中文"}))
基于Json的信息检索
V1.0
import os
import json
import logging
from openai import AzureOpenAI
from langchain_community.chat_models import ChatZhipuAI
from langchain.agents import (AgentExecutor,
create_react_agent)
from langchain_core.tools import tool
# 输出
from langchain_core.output_parsers import JsonOutputParser
from langchain_core.pydantic_v1 import BaseModel, Field
from langchain_core.prompts import PromptTemplate,ChatPromptTemplate
logging.basicConfig(filename="LangChain.log", # 将日志保存到filename文件中
level=logging.DEBUG) # DEBUG及以上的日志信息都会显示
class Inst(BaseModel):
Key:str=Field(description="数字编号")
Value:dict=Field(description="Key所对应的Value")
parser = JsonOutputParser(pydantic_object=Inst)
@tool
def search(view:str)->dict:
"""
在"/home/zym/桌面/WORK/Entity.json"中有若干字典
找到键值与view相同的字典,返回键值view对应的value
"""
with open("/home/zym/桌面/WORK/Entity.json","r") as f:
data=json.load(f)
return data[view]
prompt= """
你的任务是根据接受的参数view作为字典的键,使用工具中的search在JSON文件中找到对应的值并返回
返回格式为Dict(Key:view,Value:search(view))
参数:{view}
"""
tools=[search]
tool_names=[search]
inputs = PromptTemplate(
template="{format_instructions}\n{tools}\n{tool_names}\n{query}\n{agent_scratchpad}",
input_variables=["query"],
partial_variables={"format_instructions": parser.get_format_instructions()},
)
agent = create_react_agent(zhipu, tools, inputs)
agent_executor=AgentExecutor(agent=agent,tools=tools,verbose=True,parser=parser,handle_parsing_errors=True)
print(agent_executor.invoke({"query":prompt.format(view="1019-00245"),"tools":tools,"tool_names":tool_names}))
问题1:没有任何信息输出,最终“Agent stopped due to iteration limit or time limit”:工具并没有被调用
Since I cannot directly execute the
search
function as it’s not accessible in this environment, I will show you how the formatted output should look like
猜测1:定义输出Parser
- 改了但是没用
class Inst(BaseModel):
Key:str=Field(description="view的字段")
Value:dict=Field(description="Json文件中键值为view时所对应的字典")
parser = JsonOutputParser(pydantic_object=Inst)
猜测2:ReAct Agent无法调用工具
- 非OpenAI没有bind_tools怎么办
- AgentTypes
- 期间库函数红色波浪线显示无法导入,安装c++扩展后解决,并且可以F12查看定义
- 解决方法,修改prompt
V2.0
import os
import json
import logging
from openai import AzureOpenAI
from langchain.agents import (AgentExecutor,
create_react_agent,)
from typing import List
from langchain.tools.base import BaseTool
# 输出
from langchain_core.output_parsers import JsonOutputParser
from langchain_core.pydantic_v1 import BaseModel, Field, validator
from langchain_core.prompts import PromptTemplate
logging.basicConfig(filename="LangChain.log",
level="DEBUG")
class Inst(BaseModel):
View:str=Field(description="Input的字段")
Action:list=Field(description="选择的动作")
Param:List[dict]=Field(description="字典中的键为参数类别,值为实例")
Instruction:str=Field(description="最终形成的指令")
parser = JsonOutputParser(pydantic_object=Inst)
os.environ["OPENAI_API_KEY"] = "2171af6f71075a0bd567a23340506b70"
REGION = "australiaeast"
API_BASE = "https://api.tonggpt.mybigai.ac.cn/proxy"
ENDPOINT = f"{API_BASE}/{REGION}"
llm = AzureOpenAI(
api_key=os.environ.get("OPENAI_API_KEY"),
api_version="2024-02-01",
azure_endpoint=ENDPOINT,
)
class FunctionalTool(BaseTool):
name:str = ""
description:str = ""
class MySearchEntity(FunctionalTool):
name="MySearchEntity"
description="当需要知道这个场景包含什么以及相对位置关系的时候,执行这个函数,传入的参数只能是一个字符串"
def _run(self,view:str):
"""使用工具"""
print("乌拉呀哈 呀哈乌拉")
with open("/home/zym/桌面/WORK/Entity.json","r",encoding="utf-8") as f:
data=json.load(f)
# 标准化输入参数
return data[view.strip("'\n\nObservation'")]
async def _arun(self,view: str)-> str:
"""异步使用工具"""
raise NotImplementedError("custom_search does not support async")
class MySearchParam(FunctionalTool):
name="MySearchParam"
description="当需要知道这个可以使用的动作包含什么以及参数的时候,执行这个函数"
def _run(self,*args):
"""使用工具"""
print("咿呀哈")
with open("/home/zym/桌面/WORK/Gen/Param.json","r",encoding="utf-8") as f:
data=json.load(f)
return data
async def _arun(self,*args)-> str:
"""异步使用工具"""
raise NotImplementedError("custom_search does not support async")
prompt=PromptTemplate(
input_variables=['agent_scratchpad', 'input', 'tool_names', 'tools'],
partial_variables={"format_instructions":parser.get_format_instructions()},
template='''
你是一个家务机器人,你需要知道场景中有什么物品,以及你可以执行哪些动作
你可以使用如下工具:{tools}
使用如下格式:
Task: 选择工具完成任务
Thought: 你应该思考接下来如何去完成任务
Action: {tool_names}
Action Input: 一个字符串
Observation: 执行动作得到的结果
... (Thought/Action/Action Input/Observation 可以重复N次)
Thought: 我知道了最终的答案
Final Answer: 对应任务所需要的答案res
开始!
Task: 首先你想知道这个场景里有什么物品,于是传入参数{input};
在返回值res中,你对里面的物品产生了兴趣,于是你需要使用工具查询可执行动作及参数;
当你选择了物品和动作后,利用它们组成一条指令。
Thought:{agent_scratchpad}
''')
from langchain.agents import load_tools
tools = load_tools([],llm=llm)
tools = tools+[MySearchEntity(),MySearchParam()]
tool_names=["MySearchEntity","MySearchParam"]
agent = create_react_agent(zhipu,
tools,
prompt,
)
agent_executor=AgentExecutor(agent=agent,
tools=tools,
verbose=True,
handle_parsing_errors=True,
)
res=agent_executor.invoke({"input":prompt.format(input="1019-00245",
tools=tools,
tool_names=tool_names,
agent_scratchpad=""),
"tools":tools,
"tool_names":tool_names,
"agent_scratchpad":""})
问题1:没有结构化的输出
问题2:不会自动停止,出现了反复调用工具的情况
- 通过修改prompt可以改善
prompt=PromptTemplate(
input_variables=['agent_scratchpad', 'input', 'tool_names', 'tools'],
partial_variables={"format_instructions":parser.get_format_instructions()},
template='''
你是一个家务机器人,要依据指令完成生活中的任务。
你可以使用如下工具:{tools}
当你还未完成任务时,使用如下格式:
"""
Thought: 我是否需要工具?是
Action: {tool_names}
Action Input: 一个字符串
Observation:如果调用了工具,则输出执行动作得到的结果
"""
当你完成所有任务并生成指令后,你必须使用以下格式,我给出一个例子:
"""
Thought:我是否需要工具?不
Final Answer:{format_instructions}
Example:
"Action":["取东西吃","清洁"],
"Param":[("food": "Bread_000"),
("tool":"Sponge_000,"object":"Diningdesk_002")]
"Instruction":"请把面包吃完,之后使用海绵把餐桌清洁干净"
"""
开始!
Task: 请依次完成以下任务:
1.你想知道这个生活场景里包含什么物品,于是调用工具并传入字符串{input};
2.在返回值res中,你对里面的1~3物品产生了兴趣,于是你需要使用工具查询对你所感兴趣的物品可以执行的1~3个动作;
3.你想知道这1~3个动作需要什么参数,于是你针对每个动作分别调用工具并把动作名称传入
4.你想知道你的身份,于是你调用工具
5.根据你选择的物品、动作、参数,代入你身份可能会做的事情,模仿身份的语气,给出一条必须为中文的指令
Thought:{agent_scratchpad}
''')