Find answers from the community

Updated 8 months ago

Router

Hello. Has anyone an example of a querypipeline to build a chat (with memory) that use router query engine to select the right index?
L
H
23 comments
It's basically a context chat engine from scratch
Yes but to that i need to add routing. So the pipeline will be like this: condense the question with chat history -> use routing to choose a tool -> query to the index -> response
Idk really if its possible to merge routing with chat history. Maybe there is a better way to solve the issue that im facing. I have a large database index. So i wanted a chat engine which can select the right index to search because if a compact all the information in one index, the engine returns inaccurate answers
Why is it not possible? Chat history is just used to rewrite the query
It's definitely possible
I have this example:
Plain Text
def get_query_pipeline_router():
    standalone_question = """\
    Given the following conversation between a user and an AI assistant and a follow up question from user,
    rephrase the follow up question to be a standalone question.

    Chat History:
    {chat_history}

    Follow Up Input: {question}
    Standalone question:
    """
    standalone_question_prompt = PromptTemplate(standalone_question)
    text_qa_template = PromptTemplate(CHAT_SYSTEM_PROMPT)
    llm = OpenAI(model="gpt-3.5-turbo-0125")
    llm_s = llm.as_query_component(streaming=True)

    teg_query_engine = get_index(dir=STORAGE_DIR_DEHYDRATION_TEG).as_query_engine(
        text_qa_template=text_qa_template
    )
    teg_chain = QueryPipeline(chain=[teg_query_engine])

    dessicants_query_engine = get_index(
        dir=STORAGE_DIR_DEHYDRATION_SOLID_DESSICANTS
    ).as_query_engine(text_qa_template=text_qa_template)
    dessicants_chain = QueryPipeline(chain=[dessicants_query_engine])

    router_c = RouterComponent(
        selector=LLMMultiSelector.from_defaults(),
        choices=[
            "Useful for retrieving information about TEG (Glycol) systems. Useful keywords: TEG, Contactor tower, absorber tower, TEG Reboiler, TEG Regenerator, Regeneration Tower, HTU packed towres",
            "Useful for retrieving information about solid dessicants. Useful keywords: Gels, Alumina, Molecular Sieves, Bed, MTZ, Calcium Chloride, Membrane Permeation, Bed Regeneration",
        ],
        components=[teg_chain, dessicants_chain],
        verbose=True,
    )

    qp = QueryPipeline(chain=[standalone_question_prompt, llm, router_c], verbose=True)
    return qp

response = get_query_pipeline_router.run("Here goes the question")
how can i pass the "chat_history" string into the template?
chat history would have to be an input to the pipeline
This is what the example I linked above actually does
Do you mean this example? using the module.add_link syntax?
Because if i use this example and try to add the memory as a second parameter i get an error
Can i just simply pass chat_history (as a string) as a get_query_pipeline_router parameter directly? Or is not recommendable?
yea using the add_link syntax -- you'll need an InputComponent

Something like

Plain Text
pipline = QueryPipeline(
  modules={"input": InputComponent(), "prompt": standalone_question_prompt, "llm": llm, "router": router_c}
)

pipeline.add_line("input", "prompt", src_key="question", dest_key="question")
pipeline.add_link("input", "prompt" src_key="chat_history", dest_key="chat_history")
pipeline.add_link("prompt", "llm")
pipeline.add_link("llm", "router")

pipeline.run(question="question", chat_history="...")
Great! That works. Thank you very much
Hello. Sorry to bother you. How can i add memory to a custom agent? For example this worker:
Plain Text
class CustomAgentWorker(CustomSimpleAgentWorker):
    prompt_str: str = Field(default=DEFAULT_PROMPT_STR)
    max_iterations: int = Field(default=10)

    _router_query_engine: RouterQueryEngine = PrivateAttr()

    def __init__(self, tools: List[BaseTool], **kwargs: Any) -> None:
        """Init params."""
        # validate that all tools are query engine tools
        for tool in tools:
            if not isinstance(tool, QueryEngineTool):
                raise ValueError(
                    f"Tool {tool.metadata.name} is not a query engine tool."
                )
        self._router_query_engine = RouterQueryEngine(
            selector=PydanticSingleSelector.from_defaults(),
            query_engine_tools=tools,
            verbose=kwargs.get("verbose", False),
        )
        super().__init__(
            tools=tools,
            **kwargs,
        )

    def _initialize_state(self, task: Task, **kwargs: Any) -> Dict[str, Any]:
        """Initialize state."""
        return {"count": 0, "current_reasoning": []}

    def _run_step(
        self, state: Dict[str, Any], task: Task, input: Optional[str] = None
    ) -> Tuple[AgentChatResponse, bool]:
        """Run step.

        Returns:
            Tuple of (agent_response, is_done)

        """
        if "new_input" not in state:
            new_input = task.input
        else:
            new_input = state["new_input"]

        # first run router query engine
        response = self._router_query_engine.query(new_input)

        if response:
            is_done = True

        # return response
        return AgentChatResponse(response=str(response)), is_done
 
@Harez you put the agent worker into an agent runner

Plain Text
from llama_index.core.agent import AgentRunner

agent = AgentRunner(agent_worker)
I did that, but the memory doesnt seem to be working. Using the CustomAgentWorker from above, I continue the code with this:

Plain Text
agent_worker = CustomAgentWorker.from_tools(
        tools=query_engine_tools,
        llm=llm,
        verbose=True,
        callback_manager=callback_manager,
    )
agent = AgentRunner(agent_worker)
response: AgentChatResponse = agent.chat(lastMessage.content, messages) 

with "messages" as the chat history
I see in your custom agent worker you aren't using any memory at all actually
The memory is managed by the top level agent-runner, which is available under task.memory()

At the same time, you have the current reasoning, which could contain the reasoning for the current step, assuming you properly merge the memory in finalize_task
Can you provide me a quick example on how can i use the memory of the agent runner? Or maybe do you know a repository that i can take as an example for makinc custom workers with memory
Add a reply
Sign up and join the conversation on Discord