-: Hey there, Idan here, and in this video,
we are going to be implementing the retrieval part.
And let's go to the code.
So I'm going to go to the backend directory here.
Let's go and create here a Dundas core init file,
just to turn it into a package.
And let's go and let me go and create a core.py file.
And here we're going to implement the retrieval part.
All right, let's start with the imports.
Let's import OS to handle environment variables.
Let's go and import from typing,
type Any and Dict,
and those are going to be type-ins
for our function declarations.
We want to import load_dotenv
to load environment variables.
We saw all of this before.
We want to import the create_agent function,
which we saw before as well.
And now we're introducing something new, the initChatModel.
And the initChatModel is a very convenient way
which we are going to use to initialize
very quickly a chat client to make the LLM request.
Now, this is a general function
which is going to receive a string
and it's going to return us the correct chat model.
We're going to see it,
it's very cool and it's very convenient to use.
All right, let's go and also use ToolMessage.
and we're going to be implementing everything,
the entire retrieval pipeline,
with an agent which is going to have a retrieval tool.
So it's going to retrieve the relevant content,
the document,
and this retrieval is going to be marked as a tool message.
So I remind you, a tool message
is going to be a type of message
that is containing tool execution,
and in our case, it's going to be the retrieval tool,
which we're going to implement.
Let's import also tool, because we want to create this tool.
And we want to use the PineconeVectorStore.
You can use Chroma.
I'm going to use in this video PineconeVectorStore
for the retrieval itself.
And of course, we need an embeddings model
because we want to embed the query
and turn it into a vector
before we get the relevant context.
All right. So now we want to load the environment variables,
and up until now was just the inputs.
So now we want to initialize the embeddings model,
and I'm going to use text embedding 3 small.
And I remind you, this must correlate
and this must match the size of the vectors
when you initialize your vector store in Pinecone.
So make sure you're going to be using
the same embedding model.
And now we want to initialize the vector store,
so we want to give it the index name.
And here I re-recorded this video,
so I gave it the langchain-docs-2026.
And we want to pass the vector store,
just like in the earlier video,
an embeddings object.
So it will know how to embed the text
and work with the embedding.
We want to also now init a chat model.
And here, look how easy it is.
We're simply going to tell that the model provider
is going to be OpenAI
and that we're going to be wanting to use GPT-5.2.
So you can see here in the actual implementation itself,
all of the strings, right?
So you can see in order to use OpenAI,
this is the string we need to write.
Cool. So here you can see
all of the supported models
because it doesn't support all of the models,
but the major ones are here.
And it's very easy to use.
If you wanted to use Gemini,
we'd simply need to change this string
to represent a Google gen AI
and to write the Gemini version that we want
according to the function implementation here.
All right, so let's now go and implement our function.
And our function is going to be called retrieve_context,
and it's going to receive a query
and this query is going to be the user query.
Now this function is going to be a tool.
So let's go and use the tool decorator.
And we want to have the response format
as content and artifact.
So the response format,
you can see it right over here,
it can be either content or content_and_artifact,
where the default is content.
If it's going to be content,
then this tool should only return one value.
And if it's going to be content_and_artifact,
this tool should return two values.
Now this is going to be very convenient
to mark other information
which we want to downstream to the application
and not send to the LLM.
So I know you're probably not making any sense of it,
but trust me, once we're going to debug it,
you'll see the difference
between content and between artifact.
Anyways, just to summarize, this response format
simply is going to mean that
this tool is going to return two return values.
All right.
So the description is going to be as follows.
"Retrieve relevant documentation
to help answer user queries about LangChain"
'cause it's going to be a LangChain retrieval tool.
So this is going to help the agent
determine whether to use this tool or not.
And notice here that I didn't mention even the return values
because it's going to be derived
from this content and artifact.
All right, so let's go do the implementation.
So we want to take the vector, we want to embed it,
then we want to find all its relevant documents
that are most relevant to that vector,
and then we want to return it.
So let's go and do it.
And we're going to take the vector store,
we're going to use the as_retriever function
like we saw in the previous section,
and we're going to be using the invoke method here.
Now I remind you, for a retriever,
so this entire thing is a retriever,
an invoke method is going to perform similarity search.
And in similarity search, we can provide the query.
So this is the question string
that we want to embed and find the relevant documents.
Here, we can also provide the number of documents
we want to get at most.
So this is the k=4 here.
So this finally is going to give us
a list of documents we can augment our prompt here.
And now we want to go and we want to serialize everything.
Just like we saw in the previous section,
we want to go and to iterate over the documents.
And we want to take the content of the documents
and we want to take the sources of the documents
which we indexed before.
And eventually you want to get a big string
that we want to attach to our prompt
and this is the prompt augmentation here.
So this is going to be the serialized context
which we're going to pass
and downstream eventually to the LLM.
Amazing.
And lastly, now, all we want to do
is to return also the serialized content.
So this is going to be the content
from the content and artifact,
and also the retrieved docs.
So this is going to be an artifact.
Now, why I am making this distinction?
Now, notice what's going to happen now.
We are going to be downstreaming
the serialized documents here to the LLM.
However, I want to downstream to the application
and not the LLM,
the retrieved documents in their LangChain documents form.
So this is why we have here a distinction,
because if we were to return only the serialized documents,
then I wouldn't have this document object I can work with.
So I want to keep that so I can work with.
And eventually, this is going to go to the LLM,
and this is not going to go to the LLM.
This is going to stay in the application.
And once we debug it,
we're going to be seeing this in the traces.
So this is the entire RetrieveContext tool here.
So now we want to create an agent
which is going to be using that tool.
All right, so let me define a wrapper function
because I want to wrap everything under a function.
I'm going to call this function run_llm.
It's going to receive a query
and it's going to return us a dictionary.
This function is going to run the RAG retrieval pipeline
to answer a question.
It's going to receive the user query
and it's going to return a dictionary,
which is going to have the answer,
which is the generated answer by the LLM,
and it's going to return context.
So it's going to be the list of retrieved documents.
And I'm going to give you a quick hint.
This context here is going to be derived here
from this retrieved_docs here.
So this is why we need it and we'll soon go and see it.
All right, so let's start create the agent
with one retrieval tool
and let's start with the system prompt.
And the system prompt is going to go as follows.
"You are a helpful AI assistant
that answers questions about LangChain documentation.
You have access to a tool
that retrieves relevant documentation.
Use the tool to find relevant information
before answering questions.
Always cite the sources you use in your answers.
If you cannot find the answer
in the retrieved documentation, say so."
Cool. So the last part
is actually very, very important
because if the documentation helper
doesn't know how to answer, we don't want it to hallucinate.
So this is going to be helping with that.
So let's go now and use the create_agent function
like we saw before.
We're going to give it the model.
We're going to give it the tools of the retrieve_context.
And we're going it the system_prompt we saw before.
So this is going to run langref under the hood,
I remind you.
And now let's go and build this message list
and this invocation from the query.
So we want to take this query,
which is a string right here,
and we want to create a message,
which is going to have the role of the user
and the content is going to be the user query,
simply building a message object.
And now we want to invoke the graph
and we want to give it the list of messages
of this list over here.
So I remind you, the create agent function,
when you invoke it,
it expects to receive a dictionary with a messages key.
And we're going to get back a response,
and the response,
because we're going to run a lot of tool calls,
and we're going to have tool messages,
who are going to sit in the trace,
we want to take from the response,
we're going to have all the messages history,
want to take the last message and to access its content.
So far, we created a very simple agent,
we invoke it, we got here the response.
And now we want to also,
we want to return the documents
that help the agent answer the question,
because we want to show the user
where the answer was grounded for.
So it's going to create trust with the user
because they can go to the link
where the answer was generated from.
So this concept of showing the user
where does the answer come from
really creates trust,
and it's a really important part
of the agentic user experience.
So we want now to take, I remind you,
this tool which ran,
it also returned the documents themselves.
So we want now to access that, right?
So I told you earlier
that we used the content_and_artifact here.
So in fact, we can go and access this variable here
of retrieved_docs.
We can access the value here from the tool message.
And I'm going to show it in debug mode.
So now I want to extract the context documents
from the tool message artifacts here.
So I'm going to initialize an empty list
and I'm going to iterate through all the messages here.
And I'm going to search for all the messages
which are type ToolMessage
and are going to have the attribute of artifact.
So this means that this tool message
is going to have an artifact field
which is not going to be empty.
So this is going to be only for the result
of this tool execution right over here.
So if that is the case,
I want to go and I want to take the context docs,
which is an empty list right now,
and I want to append to it this entire list here,
because the value of artifact is going to be a list.
And finally, let's finish this function
by returning an answer and a context.
So the answer is going to be the LLM response.
And the context now is going to be a list of documents
which we took from the artifact of the tool execution.
So this is the entire function.
Now, let me go and implement an example
so you can see everything I talked about
and let's go and debug it.
So I created if __name == '__main__':,
and I'm going to run the LLM function
with the query of "what are deep agents?"
and I'm going to be printing the result.
So let me now run it in debug.