本文主要讨论Langchain-Chatchat
项目中自定义Agent问答的思路和实现。以"计算器工具"为例,简单理解就是通过LLM识别应该使用的工具类型,然后交给相应的工具(也是LLM模型)来解决问题。一个LLM模型可以充当不同的角色,要把结构化的Prompt模板写好,充分利用LLM的Zero/One/Few-Shot能力。
一.自定义Agent问答
1.1+1等于多少
在线模型使用百度qianfan-api的ernie-bot-turbo,问了一个简单的问题"1+1等于多少",自定义Agent问答的思考过程为:Action: 计算器工具;Action Input: 1+1;Observation: 输出结果为2;Thought: 好的,我回答完毕;Final Answer: 1+1等于2。如下所示:
{'history': [],
'model_name': 'qianfan-api',
'query': '1+1等于多少',
'stream': True,
'temperature': 0.7}
INFO: 127.0.0.1:34592 - "POST /chat/agent_chat HTTP/1.1" 200 OK
> Entering new AgentExecutor chain...
2023-10-07 13:30:04 | INFO | httpx | HTTP Request: POST http://127.0.0.1:7861/chat/agent_chat "HTTP/1.1 200 OK"
count token
{'model': 'qianfan-api', 'prompt': '\n### user: \n Answer the following questions as best you can. You have access to the following tools:\n\n 计算器工具: 进行简单的数学运算\n翻译工具: 翻译各种语言\n天气查询工具: 查询天气\nshell工具: 使用命令行工具输出\n谷歌搜索工具: 使用谷歌搜索\n Use the following format:\n\n Question: the input question you must answer\n Thought: you should always think about what to do\n Action: the action to take, should be one of [计算器工具, 翻译工具, 天气查询工具, shell工具, 谷歌搜索工具]\n Action Input: the input to the action\n Observation: the result of the action\n ... (this Thought/Action/Action Input/Observation can be repeated zero or more times)\n Thought: I now know the final answer\n Final Answer: the final answer to the original input question\n\n Begin!\n\n history:\n \n\n Question: 1+1等于多少\n Thought: \n\n### assistant:'}
2023-10-07 13:30:05 | INFO | httpx | HTTP Request: POST http://127.0.0.1:21004/worker_generate_stream "HTTP/1.1 200 OK"
2023-10-07 13:30:05 | INFO | httpx | HTTP Request: POST https://aip.baidubce.com/rpc/2.0/ai_custom/v1/wenxinworkshop/chat/eb-instant?access_token=24.14e5edb75568d4c8dc95c09ea50b5db7.2592000.1699248307.282335-39125244 "HTTP/1.1 200 OK"
{"answer": "这个问题很简单,答案是一"}{"answer": "。"}{"answer": "\n\n"}这个问题很简单,答案是一。
Action: 计算器工具
Action Input: 1+1
Observation: 输出结果为2
Thought: 好的,我回答完毕。
Final Answer: 1+1等于2
> Finished chain.
2.函数调用过程
当dialogue_mode
为"自定义Agent问答"时,调用api.agent_chat(prompt, history=history, model=llm_model, temperature=temperature)
方法,如下所示:
根据agent_chat(self, query: str, history: List[Dict] = [], stream: bool = True, model: str = LLM_MODEL, temperature: float = TEMPERATURE, no_remote_api: bool = None)
中是否为"远程api"走不同的分支。因为本文为有远程api,所有走的response = self.post("/chat/agent_chat", json=data, stream=True)
这个方法,如下所示:
然后执行app.post("/chat/agent_chat", tags=["Chat"], summary="与agent对话")(agent_chat)
,如下所示:
最后执行async def agent_chat()
中的async def agent_chat_iterator()
方法,如下所示:
拿到model、prompt_template、output_parser后,使用得到链llm_chain = LLMChain(llm=model, prompt=prompt_template)
,使用llm_chain、output_parser和tool_names
得到单个action agent,如下所示:
agent = LLMSingleActionAgent( # 得到agent
llm_chain=llm_chain, # 得到链
output_parser=output_parser, # 得到解析器
stop=["Observation:", "Observation:\n", "<|im_end|>"], # Qwen模型中使用这个
# stop=["Observation:", "Observation:\n"], # 其他模型,注意模板
allowed_tools=tool_names, # 允许的工具
)
把history转换成agent的memory,然后通过agent、tools和memory
得到agent_executor
,如下所示:
agent_executor = AgentExecutor.from_agent_and_tools(agent=agent, # 得到agent_executor
tools=tools, # 得到工具
verbose=True, # 是否显示日志
memory=memory, # 得到memory
)
二.math agent实现原理
1.Math Prompt模板
觉得实现原理主要是利用了LLM的few-shot的能力,主要是把结构化的Prompt模板写好。如下所示:
_PROMPT_TEMPLATE = """将数学问题翻译成可以使用Python的numexpr库执行的表达式。使用运行此代码的输出来回答问题。
问题: ${{包含数学问题的问题。}}
``text
${{解决问题的单行数学表达式}}
``
...numexpr.evaluate(query)...
``output
${{运行代码的输出}}
``
答案: ${{答案}}
这是两个例子:
问题: 37593 * 67是多少?
``text
37593 * 67
``
...numexpr.evaluate("37593 * 67")...
``output
2518731
答案: 2518731
问题: 37593的五次方根是多少?
``text
37593**(1/5)
``
...numexpr.evaluate("37593**(1/5)")...
``output
8.222831614237718
答案: 8.222831614237718
问题: 2的平方是多少?
``text
2 ** 2
``
...numexpr.evaluate("2 ** 2")...
``output
4
答案: 4
现在,这是我的问题:
问题: {question}
"""
2.LLMMathChain具体使用
主要是根据LLM Model和Prompt模板得到一个LLMMathChain,本质还是LLMMathChain根据Prompt模板执行Python代码进行数学计算,如下所示:
PROMPT = PromptTemplate( # 模板
input_variables=["question"], # 输入变量
template=_PROMPT_TEMPLATE, # 模板
)
def calculate(query: str): # 计算
model = get_ChatOpenAI( # 获取ChatOpenAI
streaming=False, # 是否流式
model_name=LLM_MODEL, # 模型名称
temperature=TEMPERATURE, # 温度
)
llm_math = LLMMathChain.from_llm(model, verbose=True, prompt=PROMPT) # 从llm创建LLMMathChain
ans = llm_math.run(query) # 运行
return ans # 返回答案
觉得一个落地的AI Agent产品,主要是要有一个给力的LLM来做任务的分解,通过不同工具来解决任务,并且可以利用外部的存储能力,最终有一个LLM来合并生成的方案。以一个软件开发小组为例,组长主要是根据需求拆分任务,分配给前端、后端、数据库和测试等,然后负责生成环境的工程师统一合并代码。看似简单的例子,其实里面涉及的情况可能会非常的复杂,比如组长还可以充当不同的角色,相同的角色有弱有强,强的可以接续拆分任务给弱的角色,可以审查代码等。本质上还是一个复杂逻辑推理路径的问题,可以借鉴思维链、思维树、思维图、累积推理等思想。
参考文献:
[1]https://github.com/ai408/Langchain-Chatchat/blob/master/server/agent/math.py
路由链(RouterChain)是由LLM根据输入的Prompt去选择具体的某个链。路由链中一般会存在多个Prompt,Prompt结合LLM决定下一步选择哪个链。