129 lines
4.4 KiB
Python
129 lines
4.4 KiB
Python
from langchain_openai import ChatOpenAI
|
||
from langchain_core.tools import tool
|
||
from langchain_core.prompts import ChatPromptTemplate
|
||
from langchain_core.output_parsers import StrOutputParser
|
||
from langchain.agents import AgentExecutor, create_react_agent
|
||
from conf import settings
|
||
|
||
# 创建模型
|
||
llm = ChatOpenAI(
|
||
base_url=settings.base_url,
|
||
api_key=settings.api_key,
|
||
model=settings.model_name,
|
||
temperature=0.1
|
||
)
|
||
|
||
|
||
# 2.定义工具
|
||
@tool
|
||
def multiply(numbers_str: str) -> int:
|
||
"""用于计算两个整数的乘积。
|
||
|
||
参数:
|
||
numbers_str (str): 包含两个整数的字符串,用逗号分隔,例如:"100,25"。
|
||
返回:
|
||
int: 两个整数的乘积。
|
||
"""
|
||
print(f"正在执行乘法: {numbers_str}")
|
||
try:
|
||
a_str, b_str = numbers_str.split(',')
|
||
a = int(a_str.strip())
|
||
b = int(b_str.strip())
|
||
return a * b
|
||
except ValueError:
|
||
return "输入的格式不正确,请确保是两个用逗号分隔的整数,例如:'100,25'"
|
||
|
||
|
||
@tool
|
||
def search_weather(city: str) -> str:
|
||
"""用于查询指定城市的实时天气。"""
|
||
print(f"正在查询天气: {city}")
|
||
if "北京" in city:
|
||
return "北京今天是晴天,气温25摄氏度。"
|
||
elif "上海" in city:
|
||
return "上海今天是阴天,有小雨,气温22摄氏度。"
|
||
else:
|
||
return f"抱歉,我没有'{city}'的天气信息。"
|
||
|
||
|
||
# 将工具列表放入一个变量
|
||
tools = [multiply, search_weather]
|
||
|
||
# 3.定义规划器 (Planner) 和执行者 (Executor) 的 Prompt
|
||
# 3.1 规划器的 Prompt
|
||
# 规划器的职责是分析用户任务,并将其分解成一系列简单的、可执行的子任务。
|
||
planner_prompt = ChatPromptTemplate.from_template(
|
||
"""你是一个任务规划师,你的工作是将用户提出的一个复杂任务分解成一系列清晰、可执行的步骤。
|
||
你的输出应该是一个简单的任务列表,每行一个任务。
|
||
|
||
例子:
|
||
用户任务: "请先查上海的天气,然后计算20乘以30。"
|
||
任务列表:
|
||
- 查找上海的天气
|
||
- 计算20乘以30的结果
|
||
|
||
用户任务: {user_input}
|
||
任务列表:
|
||
"""
|
||
)
|
||
# 规划器链,它只负责生成文本化的任务列表
|
||
planner_chain = planner_prompt | llm | StrOutputParser()
|
||
|
||
# 3.2 执行者的 Prompt
|
||
# 执行者的职责是执行单个任务。在这里,我们使用 ReAct 模式作为执行者,因为它能根据任务描述选择并调用正确的工具。
|
||
# 注意:我们使用一个简化版的 ReAct Prompt,因为它只需要处理单个任务。
|
||
executor_react_prompt_template = """你是一个专业的工具执行者,可以访问以下工具:
|
||
|
||
{tools}
|
||
|
||
根据你的思考(Thought)决定下一步的行动(Action)。你的行动必须遵循以下格式:
|
||
Thought: 我需要思考如何完成任务。
|
||
Action: [工具名称]
|
||
Action Input: [工具的输入参数,对于multiply工具,请使用'100,25'这样的格式]
|
||
|
||
可用的工具名称有: {tool_names}
|
||
|
||
当你获取了所有必要信息并可以给出最终答案时,请以以下格式结束:
|
||
Thought: 我已经有了最终答案。
|
||
Final Answer: [最终答案]
|
||
|
||
请执行以下任务:
|
||
{input}
|
||
{agent_scratchpad}
|
||
"""
|
||
executor_prompt = ChatPromptTemplate.from_template(executor_react_prompt_template)
|
||
|
||
# 4.创建 ReAct Agent 作为执行者
|
||
executor_agent = create_react_agent(llm, tools, executor_prompt)
|
||
executor_executor = AgentExecutor(
|
||
agent=executor_agent,
|
||
tools=tools,
|
||
verbose=True,
|
||
handle_parsing_errors=True # 启用错误处理,自动重试解析错误
|
||
)
|
||
|
||
|
||
# 5.定义并运行规划模式的工作流
|
||
def execute_planning_pattern(query: str):
|
||
print("--- 启动规划模式 ---")
|
||
|
||
# 规划器分解任务
|
||
print("\n规划器正在分解任务...")
|
||
plan = planner_chain.invoke({"user_input": query})
|
||
tasks = [task.strip() for task in plan.split('\n') if task.strip()]
|
||
print("规划器生成的任务列表:")
|
||
for i, task in enumerate(tasks):
|
||
print(f" {i + 1}. {task}")
|
||
|
||
# 执行者逐一执行任务
|
||
print("\n执行者正在逐一执行任务...")
|
||
for i, task in enumerate(tasks):
|
||
print(f"\n--- 执行任务 {i + 1}: {task} ---")
|
||
executor_executor.invoke({"input": task})
|
||
|
||
print("\n--- 所有任务执行完毕!---")
|
||
|
||
|
||
if __name__ == "__main__":
|
||
test_query = "请先计算 50 乘以 60 的结果,然后告诉我上海的天气怎么样?"
|
||
execute_planning_pattern(test_query) |