wird teilen, wie man ein AI -Journal mit dem baut Llamaindex. Wir werden eine wesentliche Funktion dieses AI -Journals abdecken: um Rat fragen. Wir werden mit der grundlegendsten Implementierung beginnen und von dort aus iterieren. Wir können signifikante Verbesserungen für diese Funktion sehen, wenn wir Entwurfsmuster wie anwenden Agentenlappen und Multi-Agent-Workflow.

Sie finden den Quellcode dieses AI -Journals in meinem Github Repo Hier. Und ungefähr wer ich bin.

Überblick über AI Journal

Ich möchte meine Prinzipien aufbauen, indem ich Ray Dalios Praxis befolgt. Ein Ai Das Journal wird mir helfen, mich selbst zu reflektieren, meine Verbesserung zu verfolgen und mir sogar Ratschläge zu geben. Die Gesamtfunktion eines solchen AI -Journals sieht folgendermaßen aus:

AI Journalübersicht. Bild des Autors.

Heute werden wir nur die Umsetzung des Such-Advise-Flusses abdecken, der durch mehrere lila Zyklen im obigen Diagramm dargestellt wird.

Einfachste Type: LLM mit großem Kontext

Bei der einfachsten Implementierung können wir alle relevanten Inhalte in den Kontext übergeben und die Frage beibringen, die wir stellen möchten. Wir können das in tun Llamaindex mit ein paar Codezeilen.

import pymupdf
from llama_index.llms.openai import OpenAI

path_to_pdf_book = './path/to/pdf/e book.pdf'
def load_book_content():
    textual content = ""
    with pymupdf.open(path_to_pdf_book) as pdf:
        for web page in pdf:
            textual content += str(web page.get_text().encode("utf8", errors='ignore'))
    return textual content

system_prompt_template = """You might be an AI assistant that gives considerate, sensible, and *deeply personalised* ideas by combining:
- The consumer's private profile and ideas
- Insights retrieved from *Rules* by Ray Dalio
Ebook Content material: 
```
{book_content}
```
Person profile:
```
{user_profile}
```
Person's query:
```
{user_question}
```
"""

def get_system_prompt(book_content: str, user_profile: str, user_question: str):
    system_prompt = system_prompt_template.format(
        book_content=book_content,
        user_profile=user_profile,
        user_question=user_question
    )
    return system_prompt

def chat():
    llm = get_openai_llm()
    user_profile = enter(">>Inform me about your self: ")
    user_question = enter(">>What do you wish to ask: ")
    user_profile = user_profile.strip()
    book_content = load_book_summary()
    response = llm.full(immediate=get_system_prompt(book_content, user_profile, user_question))
    return response

Dieser Ansatz hat Nachteile:

  • Niedrige Präzision: Das Laden des gesamten Buchkontexts könnte LLM dazu veranlassen, den Fokus auf die Frage des Benutzers zu verlieren.
  • Hohe Kosten: Das Senden von erheblichen Inhalten in jedem LLM-Anruf bedeutet hohe Kosten und schlechte Leistung.

Wenn Sie mit diesem Ansatz den gesamten Inhalt von Ray Dalios Prinzipienbuch vergeben, Antworten auf Fragen wie „Wie Sie mit Stress umgehen?“ sehr allgemein werden. Solche Antworten, ohne sich auf meine Frage zu beziehen, ließen mich das Gefühl haben, dass die KI mir nicht zuhörte. Obwohl es viele wichtige Konzepte wie abdeckt Realität umarmenAnwesend Der 5-Stufen-Prozess, um das zu bekommen, was Sie wollenUnd radikal aufgeschlossen sein. Ich magazine den Rat, den ich auf die Frage, die ich aufgeworfen habe, mehr gezielt sein muss. Mal sehen, wie wir es mit Lappen verbessern können.

Verbesserte Type: Agentenlappen

Additionally, was ist Agentenlag? Agentenlag kombiniert dynamische Entscheidungsfindung und Datenabnahme. In unserem AI -Journal sieht der Agentenlappen wie folgt aus:

Stadien des Agentenlappen. Bild des Autors
  • Fragenbewertung: schlecht gerahmte Fragen führen zu schlechten Abfragenergebnissen. Der Agent bewertet die Abfrage des Benutzers und klärt die Fragen, wenn der Agent der Ansicht ist, dass dies erforderlich ist.
  • FRAGE RE-WRITE: Schreiben Sie die Benutzeranfrage um, um sie auf den indizierten Inhalt im semantischen Raum zu projizieren. Ich fand diese Schritte für die Verbesserung der Präzision während des Abrufs wesentlich. Nehmen wir an, wenn Ihre Wissensbasis ein Q/A -Paar ist und Sie den Fragen Teil indizieren, um nach Antworten zu suchen. Wenn Sie die Abfrageanweisung des Benutzers in eine ordnungsgemäße Frage umschreiben, können Sie den relevantesten Inhalt finden.
  • Abfragevektorindex: Viele Parameter können beim Erstellen eines solchen Index abgestimmt werden, einschließlich der Größe, Überlappung oder einem anderen Index. Der Einfachheit halber verwenden wir VectorStoreIndex hier, das eine Customary -Chunking -Strategie hat.
  • Filter & Artificial: Anstelle eines komplexen Neuausstattungsprozesses wende ich LLM explizit an, in der Eingabeaufforderung relevante Inhalte zu filtern und zu file. Ich sehe, dass LLM den relevantesten Inhalt aufnimmt, obwohl es manchmal eine geringere Ähnlichkeitsbewertung hat als andere.

Mit diesem Agentenlappen können Sie hochrelevante Inhalte zu den Fragen des Benutzers abrufen und zielgerichtete Ratschläge generieren.

Lassen Sie uns die Implementierung untersuchen. Mit dem Llamaindex SDK ist es unkompliziert, einen Index in Ihrem lokalen Verzeichnis zu erstellen und zu behalten.

from llama_index.core import Doc, VectorStoreIndex, StorageContext, load_index_from_storage

Settings.embed_model = OpenAIEmbedding(api_key="ak-xxxx")
PERSISTED_INDEX_PATH = "/path/to/the/listing/persist/index/domestically"

def create_index(content material: str):
    paperwork = (Doc(textual content=content material))
    vector_index = VectorStoreIndex.from_documents(paperwork)
    vector_index.storage_context.persist(persist_dir=PERSISTED_INDEX_PATH)

def load_index():
    storage_context = StorageContext.from_defaults(persist_dir=PERSISTED_INDEX_PATH)
    index = load_index_from_storage(storage_context)
    return index

Sobald wir einen Index haben, können wir darüber hinaus eine Abfrage -Engine erstellen. Die Abfrage -Engine ist eine leistungsstarke Abstraktion, mit der Sie die Parameter während der Abfrage (z. B. Prime Ok) und dem Syntheseverhalten nach dem Abrufen von Inhalten einstellen können. In meiner Implementierung überschreibe ich den Response_Mode NO_TEXT Da der Agent den vom Funktionsaufruf zurückgegebenen Buchinhalt verarbeitet und das Endergebnis synthetisiert. Es wäre überflüssig, dass die Abfrage -Engine das Ergebnis synthetisiert.

from llama_index.core.indices.vector_store import VectorIndexRetriever
from llama_index.core.query_engine import RetrieverQueryEngine
from llama_index.core.response_synthesizers import ResponseMode
from llama_index.core import  VectorStoreIndex, get_response_synthesizer

def _create_query_engine_from_index(index: VectorStoreIndex):
    # configure retriever
    retriever = VectorIndexRetriever(
        index=index,
        similarity_top_k=TOP_K,
    )
    # return the unique content material with out utilizing LLM to synthesizer. For later analysis.
    response_synthesizer = get_response_synthesizer(response_mode=ResponseMode.NO_TEXT)
    # assemble question engine
    query_engine = RetrieverQueryEngine(
        retriever=retriever,
        response_synthesizer=response_synthesizer
    )
    return query_engine

Die Eingabeaufforderung sieht aus wie folgt:

You might be an assistant that helps reframe consumer questions into clear, concept-driven statements that match 
the type and subjects of Rules by Ray Dalio, and carry out search for precept e book for related content material. 

Background:
Rules teaches structured enthusiastic about life and work choices.
The important thing concepts are:
* Radical reality and radical transparency
* Resolution-making frameworks
* Embracing errors as studying

Activity:
- Activity 1: Make clear the consumer's query if wanted. Ask follow-up questions to make sure you perceive the consumer's intent.
- Activity 2: Rewrite a consumer’s query into a press release that might match how Ray Dalio frames concepts in Rules. Use formal, logical, impartial tone.
- Activity 3: Lookup precept e book with given re-wrote statements. You need to present no less than {REWRITE_FACTOR} rewrote variations.
- Activity 4: Discover essentially the most related from the e book content material as your fina solutions.

Schließlich können wir den Agenten mit den definierten Funktionen aufbauen.

def get_principle_rag_agent():
    index = load_persisted_index()
    query_engine = _create_query_engine_from_index(index)

    def look_up_principle_book(original_question: str, rewrote_statement: Record(str)) -> Record(str):
        consequence = ()
        for q in rewrote_statement:
            response = query_engine.question(q)
            content material = (n.get_content() for n in response.source_nodes)
            consequence.prolong(content material)
        return consequence

    def clarify_question(original_question: str, your_questions_to_user: Record(str)) -> str:
        """
        Make clear the consumer's query if wanted. Ask follow-up questions to make sure you perceive the consumer's intent.
        """
        response = ""
        for q in your_questions_to_user:
            print(f"Query: {q}")
            r = enter("Response:")
            response += f"Query: {q}nResponse: {r}n"
        return response

    instruments = (
        FunctionTool.from_defaults(
            fn=look_up_principle_book,
            identify="look_up_principle_book",
            description="Lookup precept e book with re-wrote queries. Getting the ideas from the Precept e book by Ray Dalio"),
        FunctionTool.from_defaults(
            fn=clarify_question,
            identify="clarify_question",
            description="Make clear the consumer's query if wanted. Ask follow-up questions to make sure you perceive the consumer's intent.",
        )
    )

    agent = FunctionAgent(
        identify="principle_reference_loader",
        description="You're a useful agent will primarily based on consumer's query and search for essentially the most related content material in precept e book.n",
        system_prompt=QUESTION_REWRITE_PROMPT,
        instruments=instruments,
    )
    return agent

rag_agent = get_principle_rag_agent()
response = await agent.run(chat_history=chat_history)

Es gibt einige Beobachtungen, die ich während der Implementierungen hatte:

  • Eine interessante Tatsache, die ich gefunden habe, ist, dass die Bereitstellung eines nicht verwendeten Parameters, original_question in der Funktionssignatur hilft. Ich habe festgestellt, dass LLM, wenn ich keinen solchen Parameter habe rewrote_statement der Parameter. Haben original_question Parameter betont irgendwie die Umschreibungsmission in LLM.
  • Verschiedene LLMs verhalten sich bei der gleichen Aufforderung ganz anders. Ich fand Deepseek V3 viel mehr, um Funktionsaufrufe auszulösen als andere Modellanbieter. Dies bedeutet nicht unbedingt, dass es nicht nutzbar ist. Wenn ein funktionaler Aufruf 90% der Fälle eingeleitet werden sollte, sollte er Teil des Workflows sein, anstatt als Funktionsaufruf registriert zu werden. Außerdem fand ich im Vergleich zu OpenAIs Modellen Gemini intestine darin, die Quelle des Buches zu zitieren, wenn es die Ergebnisse synthetisiert.
  • Je mehr Inhalte Sie in das Kontextfenster laden, desto mehr Inferenzfähigkeit benötigt das Modell. Ein kleineres Modell mit weniger Inferenzleistung verliert eher im großen Kontext.

Um die Such-Recommendation-Funktion jedoch zu vervollständigen, benötigen Sie jedoch mehrere Agenten anstelle eines einzelnen Agenten. Lassen Sie uns darüber sprechen, wie Sie Ihre Agenten zu Arbeitsabläufen zusammenfassen können.

Endgültige Type: Agent Workflow

Bevor wir beginnen, empfehle ich diesen Artikel von Anthropic, Aufbau effektiver Agenten. Die Ein-Liner-Zusammenfassung der Artikel ist das Sie sollten immer priorisieren, wenn möglich einen Workflow anstelle eines dynamischen Agenten zu erstellen. In Llamaindex können Sie beides tun. Sie können einen Agenten -Workflow mit automatischeren Routing oder einen angepassten Workflow mit expliziter Kontrolle über den Übergang von Schritten erstellen. Ich werde ein Beispiel für beide Implementierungen geben.

Workflow erklären. Bild des Autors.

Schauen wir uns an, wie Sie einen dynamischen Workflow erstellen können. Hier ist ein Code -Beispiel.

interviewer = FunctionAgent(
        identify="interviewer",
        description="Helpful agent to make clear consumer's questions",
        system_prompt=_intervierw_prompt,
        can_handoff_to = ("retriver")
        instruments=instruments
)
interviewer = FunctionAgent(
        identify="retriever",
        description="Helpful agent to retrive precept e book's content material.",
        system_prompt=_retriver_prompt,
        can_handoff_to = ("advisor")
        instruments=instruments
)
advisor = FunctionAgent(
        identify="advisor",
        description="Helpful agent to advise consumer.",
        system_prompt=_advisor_prompt,
        can_handoff_to = ()
        instruments=instruments
)
workflow = AgentWorkflow(
        brokers=(interviewer, advisor, retriever),
        root_agent="interviewer",
    )
handler = await workflow.run(user_msg="Methods to deal with stress?")

Es ist dynamisch, weil der Agentenübergang auf dem Funktionsaufruf des LLM -Modells basiert. Lamaindex Workflow liefert Agentenbeschreibungen als Funktionen für LLM -Modelle. Wenn das LLM -Modell einen solchen „Agentenfunktionsaufruf“ auslöst, wird LlamaNdex für die nachfolgende Schrittverarbeitung zu Ihrem nächsten entsprechenden Agenten überfliegen. Die Ausgabe Ihres vorherigen Agenten wurde dem internen Standing des Workflows hinzugefügt, und Ihr folgender Agent wird den Standing als Teil des Kontextes in seinem Aufruf zum LLM -Modell aufnehmen. Sie nutzen auch state Und reminiscence Komponenten zum Verwalten des internen Zustands des Workflows oder laden externe Daten (verweisen Sie auf das Dokument Hier).

Wie ich jedoch vorgeschlagen habe, können Sie die Schritte in Ihrem Workflow explizit steuern, um mehr Kontrolle zu erhalten. Mit llamaNdex kann es durch Erweiterung des Workflow -Objekts erfolgen. Zum Beispiel:

class ReferenceRetrivalEvent(Occasion):
    query: str

class Recommendation(Occasion):
    ideas: Record(str)
    profile: dict
    query: str
    book_content: str

class AdviceWorkFlow(Workflow):
    def __init__(self, verbose: bool = False, session_id: str = None):
        state = get_workflow_state(session_id)
        self.ideas = state.load_principle_from_cases()
        self.profile = state.load_profile()
        self.verbose = verbose
        tremendous().__init__(timeout=None, verbose=verbose)

    @step
    async def interview(self, ctx: Context,
                        ev: StartEvent) -> ReferenceRetrivalEvent:
        # Step 1: Interviewer agent asks inquiries to the consumer
        interviewer = get_interviewer_agent()
        query = await _run_agent(interviewer, query=ev.user_msg, verbose=self.verbose)

        return ReferenceRetrivalEvent(query=query)

    @step
    async def retrieve(self, ctx: Context, ev: ReferenceRetrivalEvent) -> Recommendation:
        # Step 2: RAG agent retrieves related content material from the e book
        rag_agent = get_principle_rag_agent()
        book_content = await _run_agent(rag_agent, query=ev.query, verbose=self.verbose)
        return Recommendation(ideas=self.ideas, profile=self.profile,
                      query=ev.query, book_content=book_content)

    @step
    async def recommendation(self, ctx: Context, ev: Recommendation) -> StopEvent:
        # Step 3: Adviser agent supplies recommendation primarily based on the consumer's profile, ideas, and e book content material
        advisor = get_adviser_agent(ev.profile, ev.ideas, ev.book_content)
        advise = await _run_agent(advisor, query=ev.query, verbose=self.verbose)
        return StopEvent(consequence=advise)

Die Rückgabe des spezifischen Ereignisstyps steuert den Schrittübergang des Workflows. Zum Beispiel, retrieve Schritt Gibt ein zurück Recommendation Ereignis, das die Ausführung des recommendation Schritt. Sie können das auch nutzen Recommendation Ereignis, um die erforderlichen Informationen zu übergeben Du brauchst.

Wenn Sie während der Implementierung verärgert sind, wenn Sie über den Workflow beginnen müssen, um einige Schritte in der Mitte zu debuggen, ist die Kontextobjekt ist unerlässlich, wenn Sie die Ausführung der Workflow -Ausführung fixieren möchten. Sie können Ihren Zustand in einem serialisierten Format speichern und Ihren Workflow wiederherstellen, indem Sie ihn in einem Kontextobjekt unverzweigt. Ihr Workflow wird weiterhin basierend auf dem Staat ausführen, anstatt von vorne zu beginnen.

workflow = AgentWorkflow(
    brokers=(interviewer, advisor, retriever),
    root_agent="interviewer",
)
strive:
    handler = w.run()
    consequence = await handler
besides Exception as e:
    print(f"Error throughout preliminary run: {e}")
    await fail_over()
    # Non-obligatory, serialised and save the contexct for debugging 
    ctx_dict = ctx.to_dict(serializer=JsonSerializer())
    json_dump_and_save(ctx_dict)
    # Resume from the identical context
    ctx_dict = load_failed_dict()
    restored_ctx = Context.from_dict(workflow, ctx_dict,serializer=JsonSerializer())
    handler = w.run(ctx=handler.ctx)
    consequence = await handler

Zusammenfassung

In diesem Beitrag haben wir diskutiert, wie Lamaindex verwendet wird, um die Kernfunktion eines AI -Journals zu implementieren. Das Schlüssellernen umfasst:

  • Verwenden von Agentenlappen, um die LLM -Fähigkeit zu nutzen, um das ursprüngliche Ergebnis der Abfrage- und Synthese dynamisch neu zu schreiben.
  • Verwenden Sie einen individuellen Workflow, um eine explizite Kontrolle über Schrittübergänge zu erhalten. Bauen Sie bei Bedarf dynamische Agenten auf.

Der saureCE -Code dieses AI -Journals befindet sich in meinem Github Repo Hier. Ich hoffe, Sie genießen diesen Artikel und diese kleine App, die ich gebaut habe. Prost!

Von admin

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert