Skip to content

Commit

Permalink
Refactor agent_nickname to agent_name, update system_message
Browse files Browse the repository at this point in the history
  • Loading branch information
coolbeevip committed Jul 17, 2024
1 parent 06c08af commit 541e215
Show file tree
Hide file tree
Showing 5 changed files with 119 additions and 139 deletions.
87 changes: 57 additions & 30 deletions src/langchain_lab/core/conference.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,17 +15,33 @@
from langgraph.graph.graph import CompiledGraph
from langgraph.prebuilt import ToolInvocation, ToolExecutor

lang_prompts = {
"en": {
"agent_system_prompt_prefix": ("You are a helpful AI assistant, collaborating with other assistants."
" Use the provided tools to progress towards answering the question."
" If you are unable to fully answer, that's OK,"
" another assistant with different tools "
" will help where you left off. Execute what you can to make progress."
" If you or any of the other assistants have the final answer or deliverable,"
" prefix your response with FINAL ANSWER so the team knows to stop.")
},
"zh": {
"agent_system_prompt_prefix": ("你是一个乐于助人的人工智能助手,正在与其他助手合作。"
"如果你无法完全回答,没关系,另一个助手会帮助你完成你未完成的任务。尽你所能取得进展。"
"如果你或任何其他助手有最终答案或可交付成果,"
"在你的回答前面加上 'FINAL ANSWER',这样团队就知道该停下来了。")
}
}


class AgentRunnableSequence:
id: str
nickname: str
name: str
next_agent_name: str
agent: RunnableSequence
entry_point: bool = False

def __init__(self, id, nickname, next_agent_name, agent, entry_point):
self.id = id
self.nickname = nickname
def __init__(self, name, next_agent_name, agent, entry_point):
self.name = name
self.next_agent_name = next_agent_name
self.agent = agent
self.entry_point = entry_point
Expand All @@ -47,33 +63,38 @@ class AgentState(TypedDict):

class Conference:

def __init__(self, llm: BaseChatModel = None, python_repl: bool = False):
def __init__(self, llm: BaseChatModel = None, python_repl: bool = False, lang: str = "en"):
self.tool_executor: ToolExecutor = None
self.graph: CompiledGraph = None
self.agents: List[AgentRunnableSequence] = []
self.tools: List[Tool] = []
self.python_repl = python_repl
self.default_llm = llm
if lang not in lang_prompts:
raise ValueError(f"Language {lang} not supported. Only support {', '.join(lang_prompts.keys())}.")
self.lang = lang

def add_tool(self, *tools):
for t in tools:
self.tools.append(t)
self.tool_executor = ToolExecutor(self.tools)

def add_agent(self, agent_id, agent_nickname: str, system_message: str, next_agent_name: str,
def add_agent(self, agent_name: str, system_message: str, next_agent_name: str,
entry_point: bool = False, llm: BaseChatModel = None):
functions = [convert_to_openai_function(t) for t in self.tools]

system_content = lang_prompts[self.lang]["agent_system_prompt_prefix"]

if len(self.tools) > 0:
system_content = system_content + " You have access to the following tools: {tool_names}."

system_content = system_content + "\n{system_message}"

prompt = ChatPromptTemplate.from_messages(
[
(
"system",
"You are a helpful AI assistant, collaborating with other assistants."
" Use the provided tools to progress towards answering the question."
" If you are unable to fully answer, that's OK, another assistant with different tools "
" will help where you left off. Execute what you can to make progress."
" If you or any of the other assistants have the final answer or deliverable,"
" prefix your response with FINAL ANSWER so the team knows to stop."
" You have access to the following tools: {tool_names}.\n{system_message}",
system_content
),
MessagesPlaceholder(variable_name="messages"),
]
Expand All @@ -89,8 +110,7 @@ def add_agent(self, agent_id, agent_nickname: str, system_message: str, next_age
raise ValueError("No language model provided.")

self.agents.append(
AgentRunnableSequence(id=agent_id,
nickname=agent_nickname,
AgentRunnableSequence(name=agent_name,
next_agent_name=next_agent_name,
agent=agent,
entry_point=entry_point))
Expand All @@ -100,34 +120,41 @@ def build_graph(self):

# Add Agents
for agent in self.agents:
workflow.add_node(agent.nickname,
functools.partial(self.graph_node_agent, agent=agent.agent, name=agent.nickname))
workflow.add_node(agent.name,
functools.partial(self.graph_node_agent, agent=agent.agent, name=agent.name))

# Add ToolKit
workflow.add_node("ToolKit", self.graph_node_tool_kit)
if len(self.tools) > 0:
workflow.add_node("ToolKit", self.graph_node_tool_kit)

# Add Edges
for agent in self.agents:
path_map = {"continue": agent.next_agent_name, "end": END}
if len(self.tools) > 0:
path_map["ToolKit"] = "ToolKit"
workflow.add_conditional_edges(
agent.nickname,
agent.name,
self.graph_node_router,
{"continue": agent.next_agent_name, "ToolKit": "ToolKit", "end": END},
path_map
)

if len(self.tools) > 0:
path_map = {agent.name: agent.next_agent_name for agent in self.agents}
workflow.add_conditional_edges(
source="ToolKit",
path=lambda x: x["sender"],
path_map=path_map
)

path_map = {agent.nickname: agent.next_agent_name for agent in self.agents}
workflow.add_conditional_edges(
source="ToolKit",
path=lambda x: x["sender"],
path_map=path_map
)
entry_point_agents = [agent for agent in self.agents if agent.entry_point]
if len(entry_point_agents) > 1:
raise ValueError("Only one agent can be an entry point.")
elif len(entry_point_agents) == 0:
raise ValueError("At least one agent must be an entry point.")
else:
workflow.set_entry_point(entry_point_agents[0].nickname)
workflow.set_entry_point(entry_point_agents[0].name)
self.graph = workflow.compile()
self.graph.get_graph().print_ascii()

def graph_node_tool_kit(self, state: AgentState):
last_message = state["messages"][-1]
Expand Down Expand Up @@ -185,8 +212,8 @@ def python_repl_tool(code: Annotated[str, "The python code to execute to generat
return f"Failed to execute. Error: {repr(e)}"
return f"Successfully executed:\n```python\n{code}\n```\nStdout: {result}"

def invoke(self, humanMessage: HumanMessage, recursion_limit: int = 20):
output_role = [agent.nickname for agent in self.agents]
def invoke(self, humanMessage: HumanMessage, recursion_limit: int = 5):
output_role = [agent.name for agent in self.agents]
output_role.append("ToolKit")
for s in self.graph.stream(
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@
from typing import Annotated, Sequence

import pandas as pd
from langchain_core.messages import BaseMessage, FunctionMessage, HumanMessage
from langchain_community.chat_models import ChatTongyi
from langchain_core.messages import BaseMessage, FunctionMessage, HumanMessage, ToolMessage
from langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholder
from langchain_core.runnables import RunnableSequence
from langchain_core.tools import tool
Expand All @@ -32,8 +33,9 @@ class NetworkOperationsAnalysisAssistant:
def __init__(self, openai_api_base: str, openai_api_key: str, model_name: str, recursion_limit: int = 20):
self.model_name = model_name
self.recursion_limit = recursion_limit
self.llm = ChatOpenAI(model_name=model_name, openai_api_base=openai_api_base, openai_api_key=openai_api_key,
temperature=0.000000001, request_timeout=600, streaming=True)
self.llm = ChatTongyi(model_name=model_name, openai_api_base=openai_api_base, dashscope_api_key=openai_api_key)
# self.llm = ChatOpenAI(model_name=model_name, openai_api_base=openai_api_base, openai_api_key=openai_api_key,
# temperature=0.000000001, request_timeout=600, streaming=True)

# 网络运营经理
networkOpsManager = self.create_agent(
Expand Down Expand Up @@ -203,7 +205,7 @@ def graph_node_agent(state: AgentState, agent: RunnableSequence, name: str):
if isinstance(result, FunctionMessage):
pass
else:
result = HumanMessage(**result.dict(exclude={"type", "name"}), name=name)
result = HumanMessage(**result.dict(exclude={"type", "name"}))
return {
"messages": [result],
# 由于有严格的工作流程,可以追踪发件人。
Expand All @@ -216,7 +218,7 @@ def graph_node_router(state: AgentState):
messages = state["messages"]
last_message = messages[-1]

if "function_call" in last_message.additional_kwargs:
if "tool_calls" in last_message.additional_kwargs:
return "data_tool"

if "FINAL ANSWER" in last_message.content:
Expand All @@ -232,11 +234,13 @@ def graph_node_data_tool(self, state: AgentState):

last_message = messages[-1]
# 从function_call创建ToolInvocation
tool_input = json.loads(last_message.additional_kwargs["function_call"]["arguments"])
# tool_input = json.loads(last_message.additional_kwargs["tool_calls"]["arguments"])
tool_input = json.loads(last_message.additional_kwargs["tool_calls"][0]["function"]["arguments"])
# 传递单个参数
if len(tool_input) == 1 and "__arg1" in tool_input:
tool_input = next(iter(tool_input.values()))
tool_name = last_message.additional_kwargs["function_call"]["name"]
# tool_name = last_message.additional_kwargs["function_call"]["name"]
tool_name = last_message.additional_kwargs["tool_calls"][0]["function"]["name"]
action = ToolInvocation(
tool=tool_name,
tool_input=tool_input,
Expand All @@ -245,7 +249,9 @@ def graph_node_data_tool(self, state: AgentState):
# 调用tool_executor,并返回响应。
response = self.tool_executor.invoke(action)
# 利用响应创建FunctionMessage。
function_message = FunctionMessage(content=f"{tool_name} response: {str(response)}", name=action.tool)
# function_message = FunctionMessage(content=f"{tool_name} response: {str(response)}", name=action.tool)
# function_message = ToolMessage(content=f"{tool_name} response: {str(response)}", tool_call_id=action.tool)
function_message = HumanMessage(content=f"{tool_name} response: {str(response)}")
# 将现有列表添加
return {"messages": [function_message]}

Expand All @@ -255,7 +261,7 @@ def create_agent(llm, tools, system_message: str):
prompt = ChatPromptTemplate.from_messages(
[
(
"system",
"user",
"您是一个精通电信网络知识的AI助手,与其他助手合作。"
"使用提供的工具来逐步回答问题。"
"如果您无法完全回答,没关系,另一个使用不同工具的助手将继续帮助您完成。尽力取得进展。"
Expand All @@ -268,7 +274,7 @@ def create_agent(llm, tools, system_message: str):
)
prompt = prompt.partial(system_message=system_message)
prompt = prompt.partial(tool_names=", ".join([tool.name for tool in tools]))
return prompt | llm.bind_functions(functions)
return prompt | llm.bind_tools(functions)

def run(self):
agent_names = {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,82 +0,0 @@
## Sales_Staff

原始数据:

| | Year | Product_A | Product_B | Product_C |
|---:|-------:|------------:|------------:|------------:|
| 0 | 2019 | 1091 | 540 | 802 |
| 1 | 2020 | 979 | 527 | 782 |
| 2 | 2021 | 970 | 521 | 816 |
| 3 | 2022 | 1070 | 559 | 752 |
| 4 | 2023 | 1059 | 533 | 730 |

## Sales_Manager

描述性统计:

| | Year | Product_A | Product_B | Product_C |
|:------|-----------:|------------:|------------:|------------:|
| count | 5 | 5 | 5 | 5 |
| mean | 2021 | 1033.8 | 536 | 776.4 |
| std | 1.58114 | 55.4319 | 14.6629 | 35.3667 |
| min | 2019 | 970 | 521 | 730 |
| 25% | 2020 | 979 | 527 | 752 |
| 50% | 2021 | 1059 | 533 | 782 |
| 75% | 2022 | 1070 | 540 | 802 |
| max | 2023 | 1091 | 559 | 816 |

相关性矩阵:

| | Year | Product_A | Product_B | Product_C |
|:----------|-----------:|------------:|------------:|------------:|
| Year | 1 | 0.0770147 | 0.194099 | -0.777903 |
| Product_A | 0.0770147 | 1 | 0.749269 | -0.43633 |
| Product_B | 0.194099 | 0.749269 | 1 | -0.464733 |
| Product_C | -0.777903 | -0.43633 | -0.464733 | 1 |

## Sales_Staff

根据数据分析工具提供的分析结果,我们可以看到以下关键信息:

- 产品A在过去5年的平均销量为1033.8,标准差为55.43,最低销量为970,最高销量为1091。
- 产品B在过去5年的平均销量为536,标准差为14.66,最低销量为521,最高销量为559。
- 产品C在过去5年的平均销量为776.4,标准差为35.37,最低销量为730,最高销量为816。

此外,相关性矩阵显示了各产品之间的相关性。我们可以看到产品A和产品B之间有较强的正相关关系(相关系数为0.749),而产品A和产品C之间则呈现负相关关系(相关系数为-0.436)。

基于以上分析结果,我们可以制定以下销售策略:
- 由于产品A和产品B之间存在较强的正相关关系,可以考虑将它们作为搭配销售,推出套餐优惠,以促进销量增长。
- 鉴于产品A和产品C之间的负相关关系,可以尝试调整市场定位或推出新的营销策略,以提高产品C的销量。
- 针对产品B的销量波动较小,可以继续保持稳定的市场定位和销售策略,但也需要不断创新以留住现有客户并吸引新客户。

Sales_Staff,您对以上销售策略有什么想法或建议吗?

## Sales_Manager

销售策略看起来很合理和有针对性。我认同将产品A和产品B作为搭配销售,并推出套餐优惠的想法,这样可以提高销量并增加客户的购买意愿。对于产品C的销量,需要进一步研究消费者需求和市场定位,确保推出的营销策略能够有效提升销量。另外,为了保持产品B的稳定销量,可以考虑增加客户忠诚度计划或定期推出新的促销活动以吸引更多消费者。综合来看,这些策略应该能够帮助公司实现更好的销售业绩。

## Sales_Staff

根据Sales_Staff和Sales_Manager的讨论,他们就过去5年的产品销量数据进行了详细分析,并制定了针对产品A、B、C的销售策略。销售策略包括搭配销售、套餐优惠、调整市场定位、推出新的营销策略、客户忠诚度计划和促销活动等。这些策略旨在提高销量、增加客户购买意愿并改善公司的销售业绩。

由于销售团队已经就销售策略达成一致,Sales_Manager可以总结这些重要要点,并结束会话。接下来,我将总结这些要点。
**重要要点总结:**

1. 产品A和产品B可以作为搭配销售,并推出套餐优惠,以增加销量和客户购买意愿。
2. 针对产品C的销量,需要进一步研究消费者需求和市场定位,确保推出的营销策略能有效提升销量。
3. 为保持产品B的稳定销量,可以考虑增加客户忠诚度计划或定期推出新的促销活动以吸引更多消费者。

Sales_Manager,您可以在实施销售策略时重点关注以上要点,确保团队的努力能够有效提升销售业绩。如有需要,可以随时进行进一步讨论或调整销售策略。如果没有其他问题,可以结束本次会话。

## Sales_Manager

**FINAL ANSWER**

重要要点总结:

1. 产品A和产品B可以作为搭配销售,并推出套餐优惠,以增加销量和客户购买意愿。
2. 针对产品C的销量,需要进一步研究消费者需求和市场定位,确保推出的营销策略能有效提升销量。
3. 为保持产品B的稳定销量,可以考虑增加客户忠诚度计划或定期推出新的促销活动以吸引更多消费者。

销售团队已经就销售策略达成一致,Sales_Manager可以在实施销售策略时重点关注以上要点,确保团队的努力能够有效提升销售业绩。如有需要,可以随时进行进一步讨论或调整销售策略。如果没有其他问题,可以结束本次会话。

Original file line number Diff line number Diff line change
Expand Up @@ -53,12 +53,12 @@ def test_conference(self):
conference = Conference(llm=llm)
conference.add_tool(load_sales_data_tool, data_analysis_tool)
conference.add_agent(agent_id="Sales_Staff",
agent_nickname="Sales_Staff",
agent_name="Sales_Staff",
system_message="负责客户服务和产品、服务提案。回答客户问题,推荐适当的产品、服务,并记录商谈数据、销售预定数据到系统中。",
next_agent_name="Sales_Manager",
entry_point=True)
conference.add_agent(agent_id="Sales_Manager",
agent_nickname="Sales_Manager",
agent_name="Sales_Manager",
system_message="负责团队管理和指导。设定销售目标,制定销售策略,监控绩效,并向团队成员提供反馈。",
next_agent_name="Sales_Staff")
conference.build_graph()
Expand Down
Loading

0 comments on commit 541e215

Please sign in to comment.