Spaces:
Sleeping
Sleeping
| # LangGraph è un framework che consente di creare applicazioni pronte per la produzione offrendo strumenti di controllo sul flusso del proprio agente. | |
| # LangGraph è un framework sviluppato da LangChain per gestire il flusso di controllo delle applicazioni che integrano un LLM. | |
| # https://www.langchain.com/ | |
| # LangChain fornisce un'interfaccia standard per interagire con modelli e altri componenti, utile per il recupero, le chiamate LLM e le chiamate agli strumenti. | |
| # Le classi di LangChain possono essere utilizzate in LangGraph, ma non è obbligatorio. | |
| # Quando usare LangGraph? Quando si progettano applicazioni di intelligenza artificiale, ci si trova di fronte a un compromesso fondamentale tra controllo e libertà: | |
| # Gli agenti, come quelli che si possono trovare in smolagents, sono molto liberi. Possono richiamare più strumenti in un'unica fase di azione, creare i propri strumenti, ecc. | |
| # Tuttavia, questo comportamento può renderli meno prevedibili e meno controllabili di un normale agente che lavora con JSON! | |
| # LangGraph è all'altro estremo dello spettro, ed è utile quando hai bisogno di "controllo" sull'esecuzione del tuo agente. | |
| # In parole povere, se la tua applicazione prevede una serie di passaggi che devono essere orchestrati in un modo specifico, con decisioni prese a ogni punto di congiunzione, LangGraph fornisce la struttura di cui hai bisogno. | |
| # Come funziona LangGraph? | |
| # Nodes : I nodi rappresentano singole fasi di elaborazione (come la chiamata di un LLM, l'utilizzo di uno strumento o la presa di una decisione). | |
| # Edges : definiscono le possibili transizioni tra i passaggi. | |
| # State : È definito e gestito dall'utente e trasmesso tra i nodi durante l'esecuzione. Quando decidiamo quale nodo indirizzare successivamente, questo è lo stato attuale che prendiamo in considerazione. | |
| # Building Blocks of LangGraph | |
| # Per creare applicazioni con LangGraph, è necessario comprenderne i componenti principali. Esploriamo gli elementi fondamentali che compongono un'applicazione LangGraph. | |
| #Un'applicazione in LangGraph inizia da un punto di ingresso e, a seconda dell'esecuzione, il flusso può passare a una funzione o all'altra fino a raggiungere la FINE. | |
| # 1. State Lo stato è il concetto centrale di LangGraph. Rappresenta tutte le informazioni che fluiscono attraverso l'applicazione. | |
| # 2. Nodes I nodi sono funzioni Python. Ogni nodo: Accetta lo stato come input Esegue un'operazione Restituisce aggiornamenti allo stato | |
| # Ad esempio, i nodi possono contenere: Chiamate LLM: generare testo o prendere decisioni Chiamate strumenti: interagire con sistemi esterni Logica condizionale: determinare i passaggi successivi Intervento umano: ottenere input dagli utenti | |
| # 3. Edges collegano i nodi e definiscono i possibili percorsi attraverso il grafico | |
| # 4. StateGraph è il contenitore che contiene l'intero flusso di lavoro dell'agente: | |
| # Esempio: https://huggingface.co/agents-course/notebooks/blob/main/unit2/langgraph/mail_sorting.ipynb | |
| # pip install langgraph langchain_openai | |
| import datasets | |
| from langchain.docstore.document import Document | |
| from langchain_community.retrievers import BM25Retriever | |
| from langchain.tools import Tool | |
| from typing import TypedDict, Annotated | |
| from langgraph.graph.message import add_messages | |
| from langchain_core.messages import AnyMessage, HumanMessage, AIMessage | |
| from langgraph.prebuilt import ToolNode | |
| from langgraph.graph import START, StateGraph | |
| from langgraph.prebuilt import tools_condition | |
| #from langchain_huggingface import HuggingFaceEndpoint, ChatHuggingFace | |
| from langchain_huggingface import HuggingFaceEndpoint | |
| from langchain_community.tools import DuckDuckGoSearchRun | |
| import gradio as gr | |
| import os | |
| ####################################### | |
| ## Give Your Agent Access to the Web ## | |
| ####################################### | |
| search_tool = DuckDuckGoSearchRun() | |
| # results = search_tool.invoke("Who's the current President of France?") | |
| # print(results) | |
| ########################################## | |
| ## Step 1: Load and Prepare the Dataset ## | |
| ########################################## | |
| # Per prima cosa, dobbiamo trasformare i dati grezzi dei nostri ospiti in un formato ottimizzato per il recupero. | |
| # Utilizzeremo la libreria di set di dati Hugging Face per caricare il set di dati e convertirlo in un elenco di oggetti Document dal modulo langchain.docstore.document. | |
| # Load the dataset | |
| guest_dataset = datasets.load_dataset("agents-course/unit3-invitees", split="train") | |
| # Convert dataset entries into Document objects | |
| docs = [ | |
| Document( | |
| page_content="\n".join([ | |
| f"Name: {guest['name']}", | |
| f"Relation: {guest['relation']}", | |
| f"Description: {guest['description']}", | |
| f"Email: {guest['email']}" | |
| ]), | |
| metadata={"name": guest["name"]} | |
| ) | |
| for guest in guest_dataset | |
| ] | |
| # Nel codice sopra: Carichiamo il dataset Convertiamo ogni voce ospite in un oggetto Documento con contenuto formattato Memorizziamo gli oggetti Documento in un elenco | |
| # Ciò significa che tutti i nostri dati sono prontamente disponibili e possiamo iniziare a configurare il recupero. | |
| ########################################## | |
| ## Step 2: Create the Retriever Tool ## | |
| ########################################## | |
| # Ora creiamo uno strumento personalizzato che Alfred potrà utilizzare per cercare le informazioni sui nostri ospiti. | |
| # Utilizzeremo BM25Retriever dal modulo langchain_community.retrievers per creare uno strumento di recupero. | |
| # BM25Retriever è un ottimo punto di partenza per il recupero, ma per una ricerca semantica più avanzata, potresti prendere in considerazione l'utilizzo di retriever basati sull'incorporamento come quelli di sentence-transformers. | |
| bm25_retriever = BM25Retriever.from_documents(docs) | |
| def extract_text(query: str) -> str: | |
| """Retrieves detailed information about gala guests based on their name or relation.""" | |
| results = bm25_retriever.invoke(query) | |
| if results: | |
| return "\n\n".join([doc.page_content for doc in results[:3]]) | |
| else: | |
| return "No matching guest information found." | |
| guest_info_tool = Tool( | |
| name="guest_info_retriever", | |
| func=extract_text, | |
| description="Retrieves detailed information about gala guests based on their name or relation." | |
| ) | |
| # Analizziamo questo strumento passo dopo passo. | |
| # Il nome e la descrizione aiutano l'agente a capire quando e come utilizzare questo strumento. | |
| # I decoratori di tipo definiscono i parametri che lo strumento si aspetta (in questo caso, una query di ricerca). | |
| # Utilizziamo BM25Retriever, un potente algoritmo di recupero del testo che non richiede incorporamenti. | |
| # Il metodo elabora la query e restituisce le informazioni più rilevanti sull'ospite. | |
| ############################################ | |
| ## Step 2: Integrate the Tool with Alfred ## | |
| ############################################ | |
| # Infine, mettiamo insieme il tutto creando il nostro agente e dotandolo del nostro strumento personalizzato: | |
| # Generate the chat interface, including the tools | |
| llm = HuggingFaceEndpoint( | |
| repo_id="Qwen/Qwen2.5-Coder-32B-Instruct", | |
| huggingfacehub_api_token=os.getenv("HF_TOKEN"), | |
| ) | |
| #chat = ChatHuggingFace(llm=llm, verbose=True) | |
| #tools = [guest_info_tool,search_tool] | |
| tools = [search_tool] | |
| #chat_with_tools = chat.bind_tools(tools) | |
| # Generate the AgentState and Agent graph | |
| class AgentState(TypedDict): | |
| messages: Annotated[list[AnyMessage], add_messages] | |
| # def assistant(state: AgentState): | |
| # return { | |
| # "messages": [chat_with_tools.invoke(state["messages"])], | |
| # } | |
| def assistant(state: AgentState): | |
| # Prendi l'ultimo messaggio umano | |
| human_msg = [msg for msg in state["messages"] if isinstance(msg, HumanMessage)][-1] | |
| # Chiama il modello LLM direttamente con il testo | |
| response_text = llm.invoke(human_msg.content) | |
| # Crea una risposta AIMessage | |
| ai_message = HumanMessage(content=response_text) # o AIMessage se preferisci | |
| return { | |
| "messages": state["messages"] + [ai_message] | |
| } | |
| ## The graph | |
| builder = StateGraph(AgentState) | |
| # Define nodes: these do the work | |
| builder.add_node("assistant", assistant) | |
| builder.add_node("tools", ToolNode(tools)) | |
| # Define edges: these determine how the control flow moves | |
| builder.add_edge(START, "assistant") | |
| builder.add_conditional_edges( | |
| "assistant", | |
| # If the latest message requires a tool, route to tools | |
| # Otherwise, provide a direct response | |
| tools_condition, | |
| ) | |
| builder.add_edge("tools", "assistant") | |
| alfred = builder.compile() | |
| # Funzione Gradio | |
| def run_agent(input_text): | |
| try: | |
| response = alfred.invoke({"messages": input_text}) | |
| return response['messages'][-1].content | |
| except Exception as e: | |
| return f"Errore: {str(e)}" | |
| iface = gr.Interface( | |
| fn=run_agent, | |
| inputs="text", | |
| outputs="text", | |
| title="Wikipedia AI Agent", | |
| description="Scrivi un argomento, l'agente recupera un riassunto da Wikipedia e lo spiega usando un LLM." | |
| ) | |
| iface.launch() | |
| # messages = [HumanMessage(content="Tell me about our guest named 'Lady Ada Lovelace'.")] | |
| # response = alfred.invoke({"messages": messages}) | |
| # print("🎩 Alfred's Response:") | |
| # print(response['messages'][-1].content) |