AutoGen: Enabling Next-Gen LLM Applications via Multi-Agent Conversation
本笔记本的灵感来自Wu等人的论文AutoGen:通过多代理对话启用下一代LLM应用程序。在本笔记本的其余部分,您将:
Define the agents’ tools to access the web and write files定义代理访问Web和写入文件的工具Define some utilities to help create the graph and agents定义一些实用程序来帮助创建图和代理Create and define each team (web research + doc writing)创建和定义每个Team (网络研究+文档编写)Compose everything together.把一切组合在一起。
from langchain_community.document_loaders import WebBaseLoader
from langchain_community.tools.tavily_search import TavilySearchResults
from langchain_core.tools import tool
tavily_tool = TavilySearchResults(max_results=5)@tooldefscrape_webpages(urls: List[str])->str:"""Use requests and bs4 to scrape the provided web pages for detailed information."""
loader = WebBaseLoader(urls)
docs = loader.load()return"\n\n".join([f'<Document name="{doc.metadata.get("title","")}">\n{doc.page_content}\n</Document>'for doc in docs
])
复制代码
API Reference:WebBaseLoaderTavilySearchResultstool 文档编写Team 工具
接下来,我们将提供一些工具供文档编写Team 使用。我们在下面定义了一些基本的文件访问工具。
请注意,这使代理可以访问您的文件系统,这可能是不安全的。我们也没有优化工具描述以提高性能。
from pathlib import Path
from tempfile import TemporaryDirectory
from typing import Dict, Optional
from langchain_experimental.utilities import PythonREPL
points: Annotated[List[str],"List of main points or sections."],
file_name: Annotated[str,"File path to save the outline."],)-> Annotated[str,"Path of the saved outline file."]:"""Create and save an outline."""with(WORKING_DIRECTORY / file_name).open("w")asfile:for i, point inenumerate(points):file.write(f"{i +1}. {point}\n")returnf"Outline saved to {file_name}"@tooldefread_document(
file_name: Annotated[str,"File path to save the document."],
start: Annotated[Optional[int],"The start line. Default is 0"]=None,
end: Annotated[Optional[int],"The end line. Default is None"]=None,)->str:"""Read the specified document."""with(WORKING_DIRECTORY / file_name).open("r")asfile:
content: Annotated[str,"Text content to be written into the document."],
file_name: Annotated[str,"File path to save the document."],)-> Annotated[str,"Path of the saved document file."]:"""Create and save a text document."""with(WORKING_DIRECTORY / file_name).open("w")asfile:file.write(content)returnf"Document saved to {file_name}"@tooldefedit_document(
file_name: Annotated[str,"Path of the document to be edited."],
inserts: Annotated[
Dict[int,str],"Dictionary where key is the line number (1-indexed) and value is the text to be inserted at that line.",],)-> Annotated[str,"Path of the edited document file."]:"""Edit a document by inserting text at specific line numbers."""with(WORKING_DIRECTORY / file_name).open("r")asfile:
lines =file.readlines()
sorted_inserts =sorted(inserts.items())for line_number, text in sorted_inserts:if1<= line_number <=len(lines)+1:
lines.insert(line_number -1, text +"\n")else:returnf"Error: Line number {line_number} is out of range."with(WORKING_DIRECTORY / file_name).open("w")asfile:file.writelines(lines)returnf"Document edited and saved to {file_name}"# Warning: This executes code locally, which can be unsafe when not sandboxed
repl = PythonREPL()@tooldefpython_repl(
code: Annotated[str,"The python code to execute to generate your chart."],):"""Use this to execute python code. If you want to see the output of a value,
you should print it out with `print(...)`. This is visible to the user."""try:
result = repl.run(code)except BaseException as e:returnf"Failed to execute. Error: {repr(e)}"returnf"Successfully executed:\n\`\`\`python\n{code}\n\`\`\`\nStdout: {result}"
复制代码
API Reference:PythonREPL 四、Helper Utilities
当我们想要时,我们将创建一些实用函数以使其更加简洁:
创建一个工作代理。为子图创建主管。
这些将为我们简化最后的图形组合代码,以便更容易看到发生了什么。
from typing import List, Optional
from langchain.output_parsers.openai_functions import JsonOutputFunctionsParser
from langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholder
from langchain_openai import ChatOpenAI
from langgraph.graph import END, StateGraph, START
from langchain_core.messages import HumanMessage, trim_messages
result = agent.invoke(state)return{"messages":[HumanMessage(content=result["messages"][-1].content, name=name)]}defcreate_team_supervisor(llm: ChatOpenAI, system_prompt, members)->str:"""An LLM-based router."""
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"],},}
MessagesPlaceholder(variable_name="messages"),("system","Given the conversation above, who should act next?"" Or should we FINISH? Select one of: {options}",),]).partial(options=str(options), team_members=", ".join(members))return(
llm,"You are a supervisor tasked with managing a conversation between the"" following workers: Search, WebScraper. 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,"" respond with FINISH.",["Search","WebScraper"],)
复制代码
API Reference:BaseMessageHumanMessageChatOpenAIcreate_react_agent 现在我们已经创建了必要的组件,定义它们的交互很容易。将节点添加到团队图中,并定义确定转换标准的边。
chain = research_graph.compile()# The following functions interoperate between the top level graph state# and the state of the research sub-graph# this makes it so that the states of each graph don't get intermixeddefenter_chain(message:str):
# Document writing team graph stateclassDocWritingState(TypedDict):# This tracks the team's conversation internally
messages: Annotated[List[BaseMessage], operator.add]# This provides each worker with context on the others' skill sets
team_members:str# This is how the supervisor tells langgraph who to work nextnext:str# This tracks the shared directory state
current_files:str# This will be run before each worker agent begins work# It makes it so they are more aware of the current state# of the working directory.defprelude(state):
f.relative_to(WORKING_DIRECTORY)for f in WORKING_DIRECTORY.rglob("*")]except Exception:passifnot written_files:return{**state,"current_files":"No files written."}return{**state,"current_files":"\nBelow are files your team has written to the directory:\n"+"\n".join([f" - {f}"for f in written_files]),}
llm = ChatOpenAI(model="gpt-4o")
doc_writer_agent = create_react_agent(
llm, tools=[write_document, edit_document, read_document])# Injects current directory working state before each call
llm,"You are a supervisor tasked with managing a conversation between the"" following workers: {team_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,"" respond with FINISH.",["DocWriter","NoteTaker","ChartGenerator"],)
复制代码
通过创建对象本身,我们可以形成图形。
# Create the graph here:# Note that we have unrolled the loop for the sake of this doc
chain = authoring_graph.compile()# The following functions interoperate between the top level graph state# and the state of the research sub-graph# this makes it so that the states of each graph don't get intermixeddefenter_chain(message:str, members: List[str]):
for s in authoring_chain.stream("Write an outline for poem and then write the poem to disk.",{"recursion_limit":100},):if"__end__"notin s:print(s)print("---")
复制代码
{'supervisor':{'next':'NoteTaker'}}---{'NoteTaker':{'messages':[HumanMessage(content='The poem has been written and saved to "poem.txt".', name='NoteTaker')]}}---{'supervisor':{'next':'FINISH'}}---
from langchain_openai.chat_models import ChatOpenAI
llm = ChatOpenAI(model="gpt-4o")
supervisor_node = create_team_supervisor(
llm,"You are a supervisor tasked with managing a conversation between the"" following teams: {team_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,"" respond with FINISH.",["ResearchTeam","PaperWritingTeam"],)
content="Write a brief research report on the North American sturgeon. Include a chart.")],},{"recursion_limit":150},):if"__end__"notin s:print(s)print("---")