Open weatherbetter opened 3 weeks ago
Hi @weatherbetter, I'm assuming you are using the multi-agent notebook for this?
For vertex or other model providers, I'd replace the system messages with human messages with the contetn wrapped in XM, since they don't support the full openai API
Hi @hinthornw First of all, thank you for your reply.
I tried using 'convert_system_message_to_human'. But it still doesn't work. Am I using the wrong method? What should I do?
llm = ChatVertexAI(model_name="gemini-pro", convert_system_message_to_human=True )
I was thinking more along the lines of this:
def sanitize(messages: list):
return [HumanMessage(content=f"<system-message>{m.content}</system-message>") if m.type == "system" else m for m in messages]
llm = sanitize | ChatVertexAI(model_name="gemini-pro")
Same issue with my code
@chocky18 did you try a suggested fix?
@hinthornw i tried But it still doesn't work. Same error occurs.
import functools import operator from typing import Sequence, TypedDict, List, Optional, Any, Dict from langchain_core.pydantic_v1 import BaseModel, Field, validator from langchain_google_vertexai import create_structured_runnable import json import google.generativeai as genai import os from typing import ( Any, AsyncIterator, Callable, Dict, Iterator, List, Optional, Sequence, Type, Union, cast, Literal, TypedDict, overload, ) from langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholder from langchain_core.messages import BaseMessage, HumanMessage, SystemMessage, AIMessage, FunctionMessage, ToolMessage
os.environ["GOOGLE_APPLICATION_CREDENTIALS"] = "json key" os.environ["GENAI_API_KEY"] = "API key" class AgentState(TypedDict): messages: Sequence[BaseMessage] next: str
def setup_supervisor_chain(members: List[str], options: List[str], prompt: str): """ Setup the supervisor chain using LangChain libraries.
Args:
- members (List[str]): List of members/workers.
- options (List[str]): List of options including 'FINISH' and members.
- prompt (str): Prompt template for the supervisor chain.
Returns:
- Any: Supervisor chain instance configured with the given parameters.
"""
# Ensure GOOGLE_APPLICATION_CREDENTIALS is set
import os
if 'GOOGLE_APPLICATION_CREDENTIALS' not in os.environ:
raise EnvironmentError("GOOGLE_APPLICATION_CREDENTIALS environment variable is not set.")
# llm = ChatGoogleGenerativeAI(temperature=0, model="gemini-pro", convert_system_message_to_human=True)
# llm = ChatVertexAI(model="gemini-pro",project="agents")
genai.configure(api_key=os.environ['GENAI_API_KEY'])
# llm = genai.GenerativeModel(name='gemini-1.5-flash')
llm = ChatVertexAI(
model="gemini-1.5-flash-001",
temperature=0,
max_tokens=None,
max_retries=6,
stop=None,
# other params...
)
class Route(BaseModel):
"""Select the next role."""
next: Literal["Researcher", "Coder", "FINISH"] = Field(..., description="Select the next agent to execute the pending task or message")
supervisor_chain = create_structured_runnable([Route], llm, prompt=prompt)
return supervisor_chain
members = ["Researcher", "Coder"] options = ["FINISH"] + members
prompt = ChatPromptTemplate.from_messages([ ("You are a supervisor tasked with managing a conversation between the" " following workers: {members}. Given the following user request," " respond with the worker to act next. Each worker will perform a" " task and respond with their results and status. When finished," " if a message or result contains the word FINISH,respond with FINISH,again if a message or result contains the word FINISH your output must be FINISH " "Given the following query: {messages}, Make calls to the relevant function to tell us who should execute the inputed query or messages? you should only Select one of of: {options}," "Or should we FINISH? " "Tip: Make sure to answer in the correct format, and output absolutely nothing else") ]).partial(options=str(options), members=", ".join(members))
supervisor_chain = setup_supervisor_chain(members, options, prompt)
# # print("chain1",chain)
# # Assuming `state['input']` contains the input message for the supervisor chain
# input_message = state['messages']
# print("input_message",input_message)
# # Run the supervisor chain with the input message
# output = chain.invoke(input_message)
# print("output",output)
# # Update the state with the output's next step
# state['next'] = output.get('next', 'FINISH')
# return state
def _convert_to_prompt(part: str) -> Dict[str, Any]: return {"text": part}
research_agent = create_agent(llm, [tavily_tool], "You are a web researcher.") research_node = functools.partial(agent_node, agent=research_agent, name="Researcher")
code_agent = create_agent( llm, [python_repl_tool], "You may generate safe python code to analyze data and generate charts using matplotlib.", ) code_node = functools.partial(agent_node, agent=code_agent, name="Coder")
workflow = StateGraph(AgentState) workflow.add_node("Researcher", research_node) workflow.add_node("Coder", code_node) workflow.add_node("supervisor", supervisor_chain) # Use the placeholder supervisor_chain
members = ["Researcher", "Coder"] for member in members: workflow.add_edge(member, "supervisor")
conditional_map = {k: k for k in members} conditional_map["FINISH"] = END workflow.add_conditional_edges("supervisor", lambda x: x["next"], conditional_map)
workflow.set_entry_point("supervisor")
graph = workflow.compile()
def _convert_to_parts(message: BaseMessage) -> List[Dict[str, Any]]: raw_content = message.content if isinstance(raw_content, str): raw_content = [raw_content] return [_convert_to_prompt(part) for part in raw_content]
def convert_messages_to_vertex_format(history: List[BaseMessage], convert_system_message_to_human: bool = False): vertex_messages: List[Dict[str, Any]] = [] system_parts: Optional[List[Dict[str, Any]]] = None system_instruction = None prev_ai_message: Optional[AIMessage] = None
for i, message in enumerate(history):
if isinstance(message, SystemMessage):
prev_ai_message = None
if i != 0:
raise ValueError("SystemMessage should be the first in the history.")
if system_instruction is not None:
raise ValueError(
"Detected more than one SystemMessage in the list of messages. "
"Gemini APIs support the insertion of only one SystemMessage."
)
if convert_system_message_to_human:
system_parts = _convert_to_parts(message)
continue
system_instruction = {"role": "user", "parts": _convert_to_parts(message)}
elif isinstance(message, HumanMessage):
prev_ai_message = None
role = "user"
parts = _convert_to_parts(message)
if system_parts is not None:
if i != 1:
raise ValueError(
"System message should be immediately followed by HumanMessage"
)
parts = system_parts + parts
system_parts = None
vertex_messages.append({"role": role, "parts": parts})
elif isinstance(message, AIMessage):
prev_ai_message = message
role = "model"
parts = _convert_to_parts(message) if message.content else []
for tc in message.tool_calls:
function_call = {"name": tc["name"], "args": tc["args"]}
parts.append({"function_call": function_call})
vertex_messages.append({"role": role, "parts": parts})
elif isinstance(message, FunctionMessage):
prev_ai_message = None
role = "function"
part = {"function_response": {"name": message.name, "response": {"content": message.content}}}
prev_content = vertex_messages[-1]
if prev_content and prev_content["role"] == "function":
parts = list(prev_content["parts"])
parts.append(part)
vertex_messages[-1] = {"role": role, "parts": parts}
continue
vertex_messages.append({"role": role, "parts": [part]})
elif isinstance(message, ToolMessage):
role = "function"
name = message.name or next(
(t["name"] for t in prev_ai_message.tool_calls if t["id"] == message.tool_call_id), None
)
if not name:
raise ValueError("Message name is empty and can't find corresponding tool call")
content = _parse_tool_message_content(message.content)
part = {"function_response": {"name": name, "response": content}}
prev_content = vertex_messages[-1]
if prev_content and prev_content["role"] == "function":
parts = list(prev_content["parts"])
parts.append(part)
vertex_messages[-1] = {"role": role, "parts": parts}
continue
vertex_messages.append({"role": role, "parts": [part]})
else:
raise ValueError(f"Unexpected message type {type(message)} at position {i}.")
return system_instruction, vertex_messages
def _parse_tool_message_content(content: Any) -> Dict[Any, Any]: if isinstance(content, list): parsed_content = [_parse_content(c) for c in content] if len(parsed_content) > 1: merged_content = {} for content_piece in parsed_content: for key, value in content_piece.items(): if key not in merged_content: merged_content[key] = [] merged_content[key].append(value) return {k: "".join(v) for k, v in merged_content.items()} return parsed_content[0] return _parse_content(content)
def _parse_content(raw_content: Any) -> Dict[Any, Any]: if isinstance(raw_content, dict): return raw_content if isinstance(raw_content, str): try: content = json.loads(raw_content) if isinstance(content, dict): return content except json.JSONDecodeError: pass return {"content": raw_content}
initial_message = SystemMessage(content="Starting the workflow") human_message = HumanMessage(content="Code hello world and print it to the terminal")
system_instruction, vertex_messages = convert_messages_to_vertex_format( [initial_message, human_message] )
input_messages = [initial_message, human_message]
try: for s in graph.stream(
{"messages": input_messages},
{"recursion_limit": 100},
):
if "__end__" not in s:
print(s)
print("----")
except ValueError as e: print(f"Error: {e}")
check this, its working
check this, its working
Hey! I got your code, but it doesn't worked. Can you help me?
import os import functools import json from typing import Any, Dict, List, Optional, Sequence, Literal, TypedDict from langchain_core.pydantic_v1 import BaseModel, Field, validator
from langchain_core.prompts import ChatPromptTemplate from langchain_core.messages import BaseMessage, HumanMessage, SystemMessage, AIMessage, FunctionMessage, ToolMessage from langchain_google_vertexai import ChatVertexAI, create_structured_runnable
class AgentState(TypedDict): messages: Sequence[BaseMessage] next: str
def setup_supervisor_chain(members: List[str], options: List[str], prompt: str): llm = ChatVertexAI( model="gemini-1.5-pro-001", model_kwargs=model_kwargs, )
class Route(BaseModel):
"""Select the next role."""
next: Literal["Components", "Records", "Details", "FINISH"] = Field(..., description="Selecione o próximo agente para executar a tarefa.")
supervisor_chain = create_structured_runnable([Route], llm, prompt=prompt)
return supervisor_chain
def create_agent(llm, tools, system_message): prompt = ChatPromptTemplate.from_messages([ ("system", ai_prompt), ("human", "{input}"), ]) return prompt | llm.bind_tools(tools)
def agent_node(state, agent, name): result = agent.invoke(state) if isinstance(result, ToolMessage): pass else: result = AIMessage(**result.dict(exclude={"type", "name"}), name=name) return { "messages": [result], "sender": name, }
from langchain_core.output_parsers import StrOutputParser from langchain_core.output_parsers.openai_functions import JsonOutputFunctionsParser from langgraph.graph import END, StateGraph from langgraph.prebuilt import ToolNode
members = ["Components", "Records", "Details"]
options = ["FINISH"] + members
prompt = ChatPromptTemplate.from_messages([ ("Você é um supervisor encarregado de gerenciar uma conversa entre" "seguintes trabalhadores: {members}. Dada a seguinte solicitação do usuário," "responda com o trabalhador para agir em seguida. Cada trabalhador executará um" "tarefa e responda com seus resultados e status. Quando terminar," "se uma mensagem ou resultado contiver a palavra FINISH, responda com FINISH. Novamente, se uma mensagem ou resultado contiver a palavra FINISH, sua saída deverá ser FINISH." " Dada a seguinte consulta: {messages}, faça chamadas para a função relevante para nos informar quem deve executar a consulta ou mensagens de entrada. Você deve selecionar apenas um de: {options}," "ou devemos TERMINAR?" "Dica: certifique-se de responder no formato correto e não produza absolutamente mais nada.") ]).partial(options=str(options), members=", ".join(members))
supervisor_chain = setup_supervisor_chain(members, options, prompt)
llm = ChatVertexAI(model=model, model_kwargs=model_kwargs, safety_settings=safety_settings)
def supervisor_chain(state): state['next'] = 'FINISH' return state
def _convert_to_prompt(part: str) -> Dict[str, Any]: return {"text": part}
def create_and_bind_agent(llm, tools, system_message, name): agent = create_agent(llm, tools, system_message) return functools.partial(agent_node, agent=agent, name=name)
components_agent = create_and_bind_agent(llm, [list_components], "Você é o Agente de Componentes da uMov.me. Você deve fornecer informações sobre os componentes disponíveis no catálogo uMov.me.", "Components") records_agent = create_and_bind_agent( llm, [list_component_records], "Você é o Agente de Registros da uMov.me. Você deve fornecer informações sobre os registros de cada componente disponível no catálogo uMov.me.", "Records" ) details_agent = create_and_bind_agent( llm, [get_component_details], "Você é o Agente de Detalhes da uMov.me. Você deve fornecer informações sobre os detalhes da estrutura de cada componente disponível no catálogo uMov.me.", "Details" )
tools = [get_component_details, list_components, list_component_records]
workflow = StateGraph(AgentState) workflow.add_node("Components", components_agent) workflow.add_node("Records", records_agent) workflow.add_node("Details", details_agent) workflow.add_node("supervisor", supervisor_chain)
for member in members:
workflow.add_edge(member, "supervisor")
conditional_map = {k: k for k in members} conditional_map["FINISH"] = END workflow.add_conditional_edges("supervisor", lambda x: x["next"], conditional_map)
workflow.set_entry_point("supervisor")
graph = workflow.compile()
from typing import Sequence, TypedDict, List, Optional, Any, Dict from langchain_core.messages import ( AIMessage, AIMessageChunk, BaseMessage, FunctionMessage, HumanMessage, InvalidToolCall, SystemMessage, ToolCall, ToolCallChunk, ToolMessage, ) from langchain_core.output_parsers import StrOutputParser from langchain_core.output_parsers.openai_functions import JsonOutputFunctionsParser from langgraph.graph import END, StateGraph from langgraph.prebuilt import ToolNode import os import functools import json from typing import Any, Dict, List, Optional, Sequence, Literal, TypedDict from langchain_core.pydantic_v1 import BaseModel, Field, validator
from langchain_core.prompts import ChatPromptTemplate from langchain_core.messages import BaseMessage, HumanMessage, SystemMessage, AIMessage, FunctionMessage, ToolMessage from langchain_google_vertexai import ChatVertexAI, create_structured_runnable
def _convert_to_prompt(part: str) -> Dict[str, Any]: return {"text": part}
def _convert_to_parts(message: BaseMessage) -> List[Dict[str, Any]]: raw_content = message.content if isinstance(raw_content, str): raw_content = [raw_content] return [_convert_to_prompt(part) for part in raw_content]
def convert_messages_to_vertex_format(history: List[BaseMessage], convert_system_message_to_human: bool = False): vertex_messages: List[Dict[str, Any]] = [] system_parts: Optional[List[Dict[str, Any]]] = None system_instruction = None prev_ai_message: Optional[AIMessage] = None
for i, message in enumerate(history):
if isinstance(message, SystemMessage):
prev_ai_message = None
if i != 0:
raise ValueError("SystemMessage should be the first in the history.")
if system_instruction is not None:
raise ValueError(
"Detected more than one SystemMessage in the list of messages. "
"Gemini APIs support the insertion of only one SystemMessage."
)
if convert_system_message_to_human:
system_parts = _convert_to_parts(message)
continue
system_instruction = {"role": "user", "parts": _convert_to_parts(message)}
elif isinstance(message, HumanMessage):
prev_ai_message = None
role = "user"
parts = _convert_to_parts(message)
if system_parts is not None:
if i != 1:
raise ValueError(
"System message should be immediately followed by HumanMessage"
)
parts = system_parts + parts
system_parts = None
vertex_messages.append({"role": role, "parts": parts})
elif isinstance(message, AIMessage):
prev_ai_message = message
role = "model"
parts = _convert_to_parts(message) if message.content else []
for tc in message.tool_calls:
function_call = {"name": tc["name"], "args": tc["args"]}
parts.append({"function_call": function_call})
vertex_messages.append({"role": role, "parts": parts})
elif isinstance(message, FunctionMessage):
prev_ai_message = None
role = "function"
part = {"function_response": {"name": message.name, "response": {"content": message.content}}}
prev_content = vertex_messages[-1]
if prev_content and prev_content["role"] == "function":
parts = list(prev_content["parts"])
parts.append(part)
vertex_messages[-1] = {"role": role, "parts": parts}
continue
vertex_messages.append({"role": role, "parts": [part]})
elif isinstance(message, ToolMessage):
role = "function"
name = message.name or next(
(t["name"] for t in prev_ai_message.tool_calls if t["id"] == message.tool_call_id), None
)
if not name:
raise ValueError("Message name is empty and can't find corresponding tool call")
content = _parse_tool_message_content(message.content)
part = {"function_response": {"name": name, "response": content}}
prev_content = vertex_messages[-1]
if prev_content and prev_content["role"] == "function":
parts = list(prev_content["parts"])
parts.append(part)
vertex_messages[-1] = {"role": role, "parts": parts}
continue
vertex_messages.append({"role": role, "parts": [part]})
else:
raise ValueError(f"Unexpected message type {type(message)} at position {i}.")
return system_instruction, vertex_messages
def _parse_tool_message_content(content: Any) -> Dict[Any, Any]: if isinstance(content, list): parsed_content = [_parse_content(c) for c in content] if len(parsed_content) > 1: merged_content = {} for content_piece in parsed_content: for key, value in content_piece.items(): if key not in merged_content: merged_content[key] = [] merged_content[key].append(value) return {k: "".join(v) for k, v in merged_content.items()} return parsed_content[0] return _parse_content(content)
def _parse_content(raw_content: Any) -> Dict[Any, Any]: if isinstance(raw_content, dict): return raw_content if isinstance(raw_content, str): try: content = json.loads(raw_content) if isinstance(content, dict): return content except json.JSONDecodeError: pass return {"content": raw_content}
initial_message = SystemMessage(content="Starting the workflow") human_message = HumanMessage(content="Quais são os componentes do catálogo?")
system_instruction, vertex_messages = convert_messages_to_vertex_format( [initial_message, human_message] )
print("System instruction:", system_instruction) print("Vertex messages:", vertex_messages) input_messages = [initial_message, human_message]
try: for s in graph.stream(
{"messages": input_messages},
{"recursion_limit": 100},
):
if "__end__" not in s:
print(s)
print("----")
except ValueError as e: print(f"Error: {e}")
Answer: {'supervisor': {'messages': [SystemMessage(content='Starting the workflow'), HumanMessage(content='Quais são os componentes do catálogo?')], 'next': 'FINISH'}}
@chocky18 did you try a suggested fix?
Can you help me? Please, i got the same error. I'm using ChatVertexAI.
from langchain.agents import AgentExecutor, create_openai_tools_agent from langchain_core.messages import BaseMessage, HumanMessage from langchain_core.output_parsers.openai_functions import JsonOutputFunctionsParser from langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholder from langchain_google_vertexai import ChatVertexAI, create_structured_runnable from langchain.agents.format_scratchpad.tools import format_to_tool_messages from langchain.agents.output_parsers.tools import ToolsAgentOutputParser from langchain.tools.base import StructuredTool
def create_agent(llm: ChatVertexAI, tools: list, system_prompt: str):
prompt = ChatPromptTemplate.from_messages(
[
(
"system",
system_prompt,
),
MessagesPlaceholder(variable_name="messages"),
MessagesPlaceholder(variable_name="agent_scratchpad"),
]
)
llm = llm.bind_tools(tools=tools)
agent_executor = AgentExecutor(
agent=prompt | llm | ToolsAgentOutputParser(),
tools=[StructuredTool.from_function(tool) for tool in tools],
)
return agent_executor
def agent_node(state, agent, name): result = agent.invoke(state) return {"messages": [HumanMessage(content=result["output"], name=name)]}
from langchain_core.output_parsers.openai_functions import JsonOutputFunctionsParser from langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholder from typing import Any, Dict, List, Optional, Sequence, Literal, TypedDict from langgraph.graph import END, StateGraph
class AgentState(TypedDict): messages: Sequence[BaseMessage] next: str
members = ["Components", "Records", "Details"] system_prompt = ( "Você é um supervisor encarregado de gerenciar uma conversa entre" "seguintes trabalhadores: {members}. Dada a seguinte solicitação do usuário," "responda com o trabalhador para agir em seguida. Cada trabalhador executará um" "tarefa e responda com seus resultados e status. Quando terminar," "se uma mensagem ou resultado contiver a palavra FINISH, responda com FINISH." )
options = ["FINISH"] + members
function_def = { "name": "route", "description": "Select the next role.", "parameters": { "title": "routeSchema", "type": "object", "properties": { "next": { "title": "Next", "anyOf": [ {"enum": options}, ], } }, "required": ["next"], }, } prompt = ChatPromptTemplate.from_messages( [ ("system", system_prompt), MessagesPlaceholder(variable_name="messages"), ( "system", "Dada a conversa acima, quem deve agir em seguida?" "Ou devemos FINISH? Selecione uma de: {options}", ), ] ).partial(options=str(options), members=", ".join(members))
llm = ChatVertexAI(model_name="gemini-1.5-pro-001", convert_system_message_to_human=True)
supervisor_chain = ( prompt | llm.bind(functions=[function_def], function_call="route") | JsonOutputFunctionsParser() )
components_agent = create_agent(llm, [list_components], "Você é o Agente de Componentes da uMov.me. Você deve fornecer informações sobre os componentes disponíveis no catálogo uMov.me.") records_agent = create_agent( llm, [list_component_records], "Você é o Agente de Registros da uMov.me. Você deve fornecer informações sobre os registros de cada componente disponível no catálogo uMov.me." ) details_agent = create_agent( llm, [get_component_details], "Você é o Agente de Detalhes da uMov.me. Você deve fornecer informações sobre os detalhes da estrutura de cada componente disponível no catálogo uMov.me." )
tools = [get_component_details, list_components, list_component_records]
workflow = StateGraph(AgentState) workflow.add_node("Components", components_agent) workflow.add_node("Records", records_agent) workflow.add_node("Details", details_agent) workflow.add_node("supervisor", supervisor_chain)
for member in members:
workflow.add_edge(member, "supervisor")
conditional_map = {k: k for k in members} conditional_map["FINISH"] = END workflow.add_conditional_edges("supervisor", lambda x: x["next"], conditional_map)
workflow.set_entry_point("supervisor")
graph = workflow.compile()
def sanitize(messages: list):
return [HumanMessage(content=f"
messages = [HumanMessage(content="Quais são os componentes disponíveis no catálogo?", type="human")]
sanitized_messages = sanitize(messages)
input_dict = {"messages": sanitized_messages} # Encapsulando as mensagens em um dicionário
for s in graph.stream(input_dict): # Passando o dicionário como argumento if "end" not in s: print(s) print("----")
Error:
ValueError: SystemMessage should be the first in the history.
I really need this code as soon as possible, thanks anyway!
@hinthornw
@chocky18 did you try a suggested fix?
Can you help me? Please, i got the same error. I'm using ChatVertexAI.
from langchain.agents import AgentExecutor, create_openai_tools_agent from langchain_core.messages import BaseMessage, HumanMessage from langchain_core.output_parsers.openai_functions import JsonOutputFunctionsParser from langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholder from langchain_google_vertexai import ChatVertexAI, create_structured_runnable from langchain.agents.format_scratchpad.tools import format_to_tool_messages from langchain.agents.output_parsers.tools import ToolsAgentOutputParser from langchain.tools.base import StructuredTool
def create_agent(llm: ChatVertexAI, tools: list, system_prompt: str): # Each worker node will be given a name and some tools. prompt = ChatPromptTemplate.from_messages( [ ( "system", system_prompt, ), MessagesPlaceholder(variable_name="messages"), MessagesPlaceholder(variable_name="agent_scratchpad"), ] ) llm = llm.bind_tools(tools=tools)
agent_executor = AgentExecutor( agent=prompt | llm | ToolsAgentOutputParser(), tools=[StructuredTool.from_function(tool) for tool in tools], ) return agent_executor
def agent_node(state, agent, name): result = agent.invoke(state) return {"messages": [HumanMessage(content=result["output"], name=name)]}
from langchain_core.output_parsers.openai_functions import JsonOutputFunctionsParser from langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholder from typing import Any, Dict, List, Optional, Sequence, Literal, TypedDict from langgraph.graph import END, StateGraph
class AgentState(TypedDict): messages: Sequence[BaseMessage] next: str
members = ["Components", "Records", "Details"] system_prompt = ( "Você é um supervisor encarregado de gerenciar uma conversa entre" "seguintes trabalhadores: {members}. Dada a seguinte solicitação do usuário," "responda com o trabalhador para agir em seguida. Cada trabalhador executará um" "tarefa e responda com seus resultados e status. Quando terminar," "se uma mensagem ou resultado contiver a palavra FINISH, responda com FINISH." )
Our team supervisor is an LLM node. It just picks the next agent to process
and decides when the work is completed
options = ["FINISH"] + members
Using openai function calling can make output parsing easier for us
function_def = { "name": "route", "description": "Select the next role.", "parameters": { "title": "routeSchema", "type": "object", "properties": { "next": { "title": "Next", "anyOf": [ {"enum": options}, ], } }, "required": ["next"], }, } prompt = ChatPromptTemplate.from_messages( [ ("system", system_prompt), MessagesPlaceholder(variable_name="messages"), ( "system", "Dada a conversa acima, quem deve agir em seguida?" "Ou devemos FINISH? Selecione uma de: {options}", ), ] ).partial(options=str(options), members=", ".join(members))
llm = ChatVertexAI(model_name="gemini-1.5-pro-001", convert_system_message_to_human=True)
supervisor_chain = ( prompt | llm.bind(functions=[function_def], function_call="route") | JsonOutputFunctionsParser() )
components_agent = create_agent(llm, [list_components], "Você é o Agente de Componentes da uMov.me. Você deve fornecer informações sobre os componentes disponíveis no catálogo uMov.me.") records_agent = create_agent( llm, [list_component_records], "Você é o Agente de Registros da uMov.me. Você deve fornecer informações sobre os registros de cada componente disponível no catálogo uMov.me." ) details_agent = create_agent( llm, [get_component_details], "Você é o Agente de Detalhes da uMov.me. Você deve fornecer informações sobre os detalhes da estrutura de cada componente disponível no catálogo uMov.me." )
tools = [get_component_details, list_components, list_component_records]
workflow = StateGraph(AgentState) workflow.add_node("Components", components_agent) workflow.add_node("Records", records_agent) workflow.add_node("Details", details_agent) workflow.add_node("supervisor", supervisor_chain)
for member in members: # We want our workers to ALWAYS "report back" to the supervisor when done workflow.add_edge(member, "supervisor")
The supervisor populates the "next" field in the graph state
which routes to a node or finishes
conditional_map = {k: k for k in members} conditional_map["FINISH"] = END workflow.add_conditional_edges("supervisor", lambda x: x["next"], conditional_map)
Finally, add entrypoint
workflow.set_entry_point("supervisor")
graph = workflow.compile()
def sanitize(messages: list): return [HumanMessage(content=f"{m.content}", type="system") if m.type == "system" else m for m in messages]
messages = [HumanMessage(content="Quais são os componentes disponíveis no catálogo?", type="human")]
sanitized_messages = sanitize(messages)
input_dict = {"messages": sanitized_messages} # Encapsulando as mensagens em um dicionário
for s in graph.stream(input_dict): # Passando o dicionário como argumento if "end" not in s: print(s) print("----")
Error:
ValueError: SystemMessage should be the first in the history.
I really need this code as soon as possible, thanks anyway!
@hinthornw
@hinthornw Can you help me? Pleaase, thanks anyway!
Checked other resources
Example Code
Description
After changing chat_models from ChatOpenAI to ChatVertexAI, i get a error 'ValueError: SystemMessage should be the first in the history.' file : LLMCompiler.ipynb
System Info
python -m langchain_core.sys_info