← All AI Engineer talks

AI Engineer World's Fair 2025

Building Multimodal AI Agents (From Scratch)

Apoorva Joshi· Senior AI Developer Advocate, MongoDB36:58

Read the talk

Building a Multimodal Agent in Plain Python

A document assistant needs more than a vision model: it needs a tool loop, retrieval that preserves visual context, and memory that carries the conversation forward.

From a talk by Apoorva Joshi

Before you start: Basic Python and familiarity with LLM prompts are sufficient; prior experience with retrieval-augmented generation will help with the retrieval sections.

What makes an assistant an agent?

What does it take to build an assistant that can reason about a request, use tools, and work with images as well as text? Apoorva Joshi’s workshop approaches that question in plain Python, starting with the components before assembling a multimodal agent. Joshi is an AI-focused developer advocate at MongoDB, with a background in cybersecurity data science. The workshop moves from agent fundamentals to multimodality, then into a hands-on implementation.

Agenda slide listing AI agents, components of an AI agent, multimodality, building a multimodal AI agent, and Q&A.
Workshop agenda: AI agents, their components, multimodality, and building a multimodal agent.

An agent uses an LLM to reason through a problem, create a plan, and execute and revise that plan with tools. The useful distinction is how much responsibility the application gives the model for deciding what happens next.

0:161:09
Suggest correction

This note stays in this page until you copy or download it. Nothing is submitted; reloading clears the draft.

0:16 · section reference included

Choose how much autonomy the task needs

Joshi distinguishes three interaction patterns:

PatternInformation availableHow work proceeds
Simple promptingPretrained, parametric knowledgeAnswer the supplied prompt
Retrieval-augmented generationExternal information added as contextRetrieve information, then answer
AgentTools, their results, and past interactionsSelect actions and revise the next step

In the simple prompting baseline, the model has no external source for missing information. RAG supplies that information and can support light personalization when the retrieved sources contain relevant user context. In Joshi’s comparison, neither baseline supplies the autonomous, multistep feedback loop that lets an agent change its approach after seeing a result. The agent makes those sequencing decisions itself.

Use agents when the task warrants their additional cost and latency. Planning, tool use, and correction can require repeated model calls. Good candidates include workflows whose steps are difficult to predict, tasks that tolerate slower responses and variable outputs, and applications that benefit from personalization over time. The same input need not produce the same result; Joshi notes that an agent’s sequence of decisions amplifies this variability. The workshop deliberately uses a simple problem to make the machinery understandable, even though a production version might need less autonomy.

AI agents slide showing tools and memory connected to an LLM, an action-result feedback loop, three benefits, and higher cost and latency.
AI agents combine tools, memory, and an action-result loop, with higher cost and latency.
3:253:44
Suggest correction

This note stays in this page until you copy or download it. Nothing is submitted; reloading clears the draft.

3:25 · section reference included

Inputs, plans, and feedback

The agent has four components: perception gathers information, planning and reasoning determine an approach, tools act on the outside world, and memory retains past interactions. The resemblance to human problem-solving is intentional: these components give the software enough autonomy to carry out a task.

Perception begins with inputs. A person might submit a query, or an email or Slack message might trigger the application. Text is one input format; images, voice, and video expand what the agent can observe. This implementation limits its scope to text and images.

The LLM supplies planning and reasoning, guided by a prompt. Joshi first describes planning without feedback: the model forms a plan from its initial understanding without revising it in response to tool outcomes. She presents chain-of-thought prompting in this category. A zero-shot instruction asks the model to work step by step; a few-shot prompt supplies worked examples that guide its approach to the next problem.

Planning with feedback lets new observations change the next action. The workshop uses ReAct, which interleaves reasoning and acting:

  1. Determine an action that could advance the task.
  2. Execute the selected tool.
  3. Return the result as an observation.
  4. Use that observation to decide what to do next.
  5. Continue until the model can produce a final answer.

The operational difference is the return path: tool results become inputs to another decision, rather than merely outputs of a fixed plan.

7:127:22
Suggest correction

This note stays in this page until you copy or download it. Nothing is submitted; reloading clears the draft.

7:12 · section reference included

The model requests a tool; Python executes it

Tools can expose weather and search APIs, vector stores, or specialized machine-learning models. They are usually represented as functions. A tool-capable LLM can select a function and supply its arguments, but the application must execute the function. A generated tool call is a request for an action, not evidence that the action happened.

The model also needs a tool schema: the function’s name, a description of its purpose, and its parameters with types and descriptions. Joshi mentions JSON schemas and MCP as ways of exposing tool definitions. Her weather example accepts a city as a string. In Python, that contract can be represented directly:

python

weather_schema = {
    "name": "get_weather",
    "description": "Get today's weather for a city.",
    "parameters": {
        "type": "object",
        "properties": {
            "city": {
                "type": "string",
                "description": "The city to get weather for.",
            }
        },
        "required": ["city"],
    },
}

This describes the available operation. The weather client and the code that dispatches a model’s request to it remain separate responsibilities.

Tools slide with a weather function on the left and a schema defining its name, description, and city parameter on the right.
A weather tool function alongside its tool schema.
11:2111:46
Suggest correction

This note stays in this page until you copy or download it. Nothing is submitted; reloading clears the draft.

11:21 · section reference included

Follow a weather question through the loop

Memory completes the component model. Short-term memory stores and retrieves information within one conversation. Long-term memory stores, updates, and retrieves information across conversations, supporting personalization over time. The lab implements short-term memory; cross-conversation learning is outside its scope.

Consider the workshop’s weather question: what is the weather in San Francisco today? The agent is the surrounding software system, which forwards that query to an LLM. The model has descriptions of weather and search tools, along with past interactions. It selects the weather tool and extracts San Francisco as the city argument.

Python then calls the weather API with the selected arguments and returns the API’s response to the model. At that point, the model can request another tool if it still needs information, or generate a natural-language answer from the returned temperature. This is the complete feedback loop: request, execution, observation, and a new decision. The model never has to be the component that performs the network request.

12:5012:55
Suggest correction

This note stays in this page until you copy or download it. Nothing is submitted; reloading clears the draft.

12:50 · section reference included

Retrieve documents and interpret figures

Multimodality extends the inputs a model can process and, depending on the model, the outputs it can generate. Research papers, financial reports, organizational reports, and healthcare documents routinely mix prose with graphs, images, and tables. Understanding these documents requires preserving relationships across those forms of information.

Two model roles matter:

  • Multimodal embedding models turn different input types into vectors for retrieval through methods such as vector search, hybrid search, or graph-based retrieval.
  • Multimodal LLMs interpret those inputs and generate responses. Joshi cites DeepSeek, Claude, and ChatGPT voice mode as examples of the broader multimodal model landscape; supported input and output formats depend on the particular model.

Give a multimodal LLM tools for searching multimodal data, then let it use the results to solve a problem, and the tool loop becomes a multimodal agent.

The Python assistant has two objectives: answer questions over a large document corpus, and explain or analyze a chart or diagram supplied by the user. Joshi’s everyday example is taking a screenshot of an equation in a research paper and asking Claude to explain it. The additional challenge for this agent is searching a corpus where text, images, and tables are interleaved. Before the agent can reason about a relevant figure, the retrieval system has to find it without stripping away its context.

Objectives slide with two bullets, green emphasis on mixed modalities, and an arrow pointing to a reaction image.
Answer questions about documents with mixed modalities and explain charts and diagrams.
15:5716:08
Suggest correction

This note stays in this page until you copy or download it. Nothing is submitted; reloading clears the draft.

15:57 · section reference included

What extraction pipelines lose

A text-only RAG pipeline typically chunks documents, embeds the chunks, and retrieves relevant chunks as context. Mixed documents require additional handling. Joshi names LlamaParse and Unstructured as tools for extracting text, images, and tables, then describes two ways to make the extracted elements searchable.

PipelineText handlingImage and table handling
Convert to textChunk and embed textSummarize, then embed summaries
Embed multiple modalitiesChunk and embed textEmbed visual elements directly

The first path brings everything into the text domain, using a text embedding model for both prose and visual summaries. The second uses a multimodal embedding model for the extracted elements. Both still depend on separating the document into pieces.

That separation creates two costs. Context can disappear at boundaries: a caption, chart, and explanatory paragraph may no longer travel together. Parent-document retrieval and metadata pre-filtering can help reintroduce relevant context during retrieval or generation. Preprocessing gains more stages: element detection and extraction come before chunking and embedding, and the summary-based path may add another LLM call. Each stage becomes another part of the pipeline to maintain.

19:3919:54
Suggest correction

This note stays in this page until you copy or download it. Nothing is submitted; reloading clears the draft.

19:39 · section reference included

Embed the page with its layout intact

There is also a representation problem. CLIP uses separate networks to encode text and images. Joshi describes a modality gap in which unrelated items of the same modality can be closer in vector space than related items across modalities. An irrelevant text item may therefore be closer to a text query than a relevant image is.

The alternative is to embed a screenshot containing the text and visual elements together. Joshi motivates this with VLM-based embeddings and a more unified representation. The chosen model, Voyage Multimodal 3, uses shared-transformer vectorization. That model-specific architecture should not be read as a guarantee that every VLM eliminates modality separation. The practical benefit here is concrete: the embedding input retains the page’s text, figures, tables, and their visible arrangement. Joshi argues that this simplifies preprocessing and improves retrieval, but supplies no workshop-specific retrieval measurement.

The ingestion pipeline becomes:

  1. Render each document page as a separate screenshot.
  2. Save the screenshot locally for the lab; use blob storage such as S3 or Google Cloud Storage for a production deployment.
  3. Generate a multimodal embedding of the screenshot.
  4. Store that embedding and the image’s path or reference in MongoDB.

The vector database stores the embedding and the reference, not the raw screenshot. Rendering a PDF page means capturing the complete page, rather than extracting only the figures embedded within it. The file remains in local or blob storage, ready to be fetched after retrieval.

21:5722:12
Suggest correction

This note stays in this page until you copy or download it. Nothing is submitted; reloading clears the draft.

21:57 · section reference included

A page preserves local context, not the whole document

Why take a screenshot of every page? The purpose is to preserve continuity between prose and visual elements so they can be retrieved together, rather than to save storage space. An audience question exposes the remaining boundary: a page is still only part of a document. Joshi favors a complete page over a small paragraph chunk, while recommending metadata pre-filtering and other familiar retrieval techniques when more context is needed. The lab uses distinct pages; overlapping captures are a possible extension.

Why not pass the entire PDF to the model? Joshi invokes the lost-in-the-middle problem: a large context window does not ensure that the model will find and use relevant information buried inside it. That motivates selective retrieval without establishing that page screenshots always outperform whole-document input. To preserve continuity across retrieved pages, store page numbers and document metadata, then expand a match to nearby pages—for example, the previous two and next two pages.

The choice of Voyage Multimodal 3 is not essential to the agent loop. Asked why that model was selected, Joshi points to the VLM-based embedding approach and avoiding the CLIP-style modality gap she described. Another suitable model could fill the retrieval role. Audio and video require their own representations and processing; screenshots fit this workshop because text and figures naturally coexist on document pages.

A second question asks whether VLM embeddings must be less accurate than embeddings from Ada 002 because of presumed model-size differences. No such comparison is established. Joshi notes that VLMs can also be large and offers to point participants toward benchmarks, without giving a measured result. Running a model locally has the same practical constraint as running an LLM locally: select one that fits the machine’s hardware.

Finally, an audience member asks about combining text, images, and a time series that is weakly aligned with the other modalities. A shared vector space may not make those records meaningfully close. Joshi suggests treating the time series as features and using a different retrieval strategy. This is a design direction for disparate data, not an implemented time-series solution or a claim that time series cannot be embedded.

26:0126:08
Suggest correction

This note stays in this page until you copy or download it. Nothing is submitted; reloading clears the draft.

26:01 · section reference included

Search for references, then fetch the images

At runtime, the agent sends the query to a multimodal LLM. The embedding model finds relevant pages; this second model interprets their text and images. Joshi tentatively names Gemini 2.0 Flash Experimental for this role. The historical experimental endpoint is now shut down, so reproducing the architecture requires an available model with image input and tool-calling support.

The assistant exposes one tool: vector search. Its retrieval branch follows a specific sequence:

  1. The LLM requests vector search and supplies arguments.
  2. Application code executes the search.
  3. The search returns references to matching screenshots.
  4. Application code loads those screenshots from local or blob storage.
  5. The next model call includes the images, original query, and conversation history.
  6. The model produces an answer or continues the tool loop.

The extra image-loading step is essential. Returning a file reference does not give the model the image’s contents. Images already available to the conversation accompany subsequent calls, whether the model is choosing another tool or generating its answer.

Retrieval is optional. If the user supplies an image and asks for a summary, the model may already have everything needed to respond. It can answer directly without calling vector search. The same assistant therefore supports both corpus questions that require retrieval and image questions that do not.

31:3831:51
Suggest correction

This note stays in this page until you copy or download it. Nothing is submitted; reloading clears the draft.

31:38 · section reference included

Persist the conversation around the tool loop

Short-term memory makes the assistant coherent across turns. Each query carries a session ID that identifies its conversation. Before asking the model what to do, the application retrieves previous turns for that session and includes them alongside the current query and any retrieved context. History can change the tool decision itself: the answer may already be available from an earlier exchange.

After generating an answer, the application appends the current user query and response to the same session. The essential database operations can be expressed with a MongoDB collection passed into two Python functions:

python

def load_history(collection, session_id: str) -> list[dict]:
    session = collection.find_one({"_id": session_id})
    return session["turns"] if session else []


def save_turn(
    collection,
    session_id: str,
    query: str,
    response: str,
) -> None:
    collection.update_one(
        {"_id": session_id},
        {
            "$push": {
                "turns": {
                    "$each": [
                        {"role": "user", "content": query},
                        {"role": "assistant", "content": response},
                    ]
                }
            }
        },
        upsert=True,
    )

Call load_history before the model loop and save_turn after an answer has been generated. User queries and model responses are the minimum persisted history. Tool calls and their outcomes can also be retained; Joshi additionally mentions recording reasoning traces where available.

34:0234:14
Suggest correction

This note stays in this page until you copy or download it. Nothing is submitted; reloading clears the draft.

34:02 · section reference included

Build the loop in the notebook

The hands-on portion begins with the lab’s GitHub README: open the lab on a laptop and follow its setup instructions. Then choose how to work through the implementation:

  • lab.ipynb: fill in the code exercises, using the inline reference documentation marked with a books emoji.
  • solutions.ipynb: work through the prefilled code and explanatory comments.

The solutions are also available to consult while completing the exercises. The final slide shows the lab entry point and code-placeholder guidance.

Slide showing mdb.link/multimodal-lab above a QR code, plus notes for reference documentation, CODE_BLOCK_N placeholders, and solutions.ipynb.
Hands-on lab link and guidance for reference documentation, code placeholders, and the solutions notebook.

Joshi closes by encouraging participants to ask the instructor team for help and use the solutions when stuck. The next step is to connect the pieces in Python: page ingestion, tool dispatch, image loading, and session persistence. The recording hands that implementation work to the reader at the notebooks.

35:2335:37
Suggest correction

This note stays in this page until you copy or download it. Nothing is submitted; reloading clears the draft.

35:23 · section reference included

Resources

From the talk

  • Python workshop materials with exercise and solution notebooks, screenshot assets, and a Codespaces setup guide.

  • Mind the GapPaper

    Research on why image and text representations can occupy separated regions within a shared embedding space.

  • Lost in the MiddlePaper

    Experiments showing how relevant information’s position affects question answering and retrieval from long contexts.

Updates since the talk

Read the complete timestamped transcript
  1. 0:00

    [upbeat music] Hi, everyone.

  2. 0:16

    Um, thanks for taking the time to be here today. Um, welcome to this workshop where you will learn about agents, multimodality, and hopefully get to build... Not hopefully, you will build, uh, a multimodal agent of your own from scratch.

  3. 0:32

    Uh, whose first workshop of the day? How many? Show of hands. Okay, first workshop. How many people already been in a workshop? Oh, wow. Like really proactive, overachieving crowd.

  4. 0:44

    Great to see that. All right. Um, with that, here's a little bit about me. I'm Apoorva. Uh, I'll be your lead instructor for today. I'm also joined by, um, my awesome team here.

  5. 0:57

    We have Richmond. He's waving at you. There's Rafa back there. He's waving at you as well. There's Thibaut, and we have Makiko. Um, but yeah, g- here's a bit about me.

  6. 1:09

    Uh, I'm Apoorva. I'm currently an AI-focused developer advocate at MongoDB, which means I spend a lot of my time building, uh, workshops like this one for AI developers like you, uh, to help them build AI applications of their own.

  7. 1:24

    Uh, prior to this role, I spent about six years working as, uh, a data scientist in the cybersecurity space. And outside of work, I like to read a lot.

  8. 1:33

    I try to yoga pretty regularly, or used to try to till I, uh, [laughs] busted my knee a while ago. Uh, and I'm always on a mission to, um, visit as many local coffee shops as I can in whichever city I'm in.

  9. 1:46

    So this is what the next hour and twenty minutes is going to look like. Uh, we'll be going over key concepts of AI agents, discuss what multimodality is, and finally, we are gonna put the two together and build a multimodal AI agent from scratch using good old Python.

  10. 2:04

    And since this is a relatively short workshop session, um, this is what you can expect. Uh, we are going to focus on getting concepts down, um, and we'll see what we have time for.

  11. 2:15

    Based on my practice sessions, uh, I believe you get about fifty-five minutes to an hour to actually take your time to write code or just, like,

  12. 2:26

    get a really good understanding of how, uh, multimodal agents work in code. So just wanted to, uh, set that expectation there.

  13. 2:35

    And with that, let's get started. So let's first answer two questions. What are AI agents, and why do we need them? But even before I get into that, uh, how many of you already have some experience with AI agents?

  14. 2:50

    Okay, there's some of you. Hopefully, there'll be something new for you, uh, at this workshop. And for those of you who are new to the concept, there's a lot of stuff coming your way.

  15. 2:59

    So, uh, apologies for that, or not. Okay, so here's my definition of an AI agent. Um, I like to define an AI agent as a system that uses a large language model, I'll be referring to this as an LLM, uh, to reason through a problem, create a plan to solve, uh, the problem, and execute and iterate on

  16. 3:21

    the plan with the help of a set of tools.

  17. 3:25

    So in the past two years or so, uh, we have seen three main paradigms for interacting with LLMs. There's simple prompting, RAG, and agents. So let's briefly, uh, talk about each of these because this will help us build an intuition for, uh, when you want to use an AI agent versus something else.

  18. 3:44

    So with simple prompting, you're simply asking, uh, the LLM questions and expecting the LLM to rely on its pre-trained, or as we call it, parametric knowledge, uh, to answer these questions.

  19. 3:55

    So this means the LLM cannot answer questions, um, if the information required to answer them is not present in its pre-trained knowledge. It cannot really handle complex queries, and it cannot provide personalized responses or even refine its responses.

  20. 4:12

    With RAG, uh, how many of you have built a RAG application? Okay, some of you. So, you know, with RAG, you take this up a notch. You augment the LLM's knowledge with information from external data sources.

  21. 4:25

    And as you can imagine, this solves some problems where you can now be, uh, reasonably certain that the LLM has, uh, the information required to, uh, answer user questions and also incorporate some basic light personalization if it's given access to the right sources of information.

  22. 4:43

    But this still doesn't equip the LLM with the ability to handle, uh, complex, uh, multi-step tasks or to self-refine its responses, but that's okay because not all tasks might require this capability.

  23. 4:58

    And finally, uh, 2025 is the year of agents. So if you need-- uh, if you have complex multi-step tasks or need, uh, deep personalization, any sort of adaptive learning in your applications, then you'd want to use AI agents.

  24. 5:13

    So with AI agents, what we've done is given LLM the agency to determine the sequence of steps required to, uh, complete a particular task. And they do this by taking actions with the help of tools that you provide them and reasoning through the result-results of these tool executions and also its past interactions, um, to inform what to

  25. 5:36

    do next. And this is what makes agents extremely flexible and capable of handling a wide variety of complex tasks. But the... Yeah. Sorry, will you share these, uh, the presentation?

  26. 5:47

    Yes, it will be shared. The you- uh, recordings will be up on YouTube as well. So yeah. Uh, the one thing to note here, though, is that agents come with, uh, higher cost and latency.

  27. 5:58

    After all, you're expecting LLMs to do all the heavy lifting of, uh, thinking through the problem, coming up with a plan of action, uh, executing, um, the actions, rectifying its responses.

  28. 6:09

    So my word of caution here is only use agents if you need to. Don't complicate whatever it is you're trying to build. But we are building an AI agent today, so for today, let's just throw an agent at the problem, a simple problem.

  29. 6:24

    Okay. So to summarize, use agents for complex tasks that don't have a structured workflow, or where the series of steps required to solve the problem is hard to predict, or tasks that have a high latency tolerance, as I was just mentioning, or for tasks where it's acceptable for, uh, your application or system to return non-deterministic outputs, which

  30. 6:47

    means, um, the same, uh, result is not guaranteed for the same out- inputs. And this is true for any application that uses LLMs, but this effect is especially amplified, uh, in agentic workflows.

  31. 7:00

    And finally, tasks that might benefit from any sort of personalization or adaptive behavior over a long period of time, all of these are fair game for AI agents.

  32. 7:12

    Now let's talk about the different components of AI agents, just to get a better understanding of, uh, how these systems work.

  33. 7:22

    So an agent typically has four main components. There's perception, which is how, uh, agents gather information about their environment. Planning and reasoning, which helps, um, the agent reason through a problem and come up with a plan to solve it.

  34. 7:38

    Then there's tools, which are external interfaces that help the agent act upon and solve a problem.

  35. 7:45

    And memory, which helps agents learn from past interactions. And if you are passionate about memory, we have Rich Wind, who knows a lot about this topic, so definitely, uh, catch him, um, after or during the presentation.

  36. 8:00

    So all of this sounds a bit like a human, doesn't it? But that's the whole goal of agents. The goal with, uh, LLM-based agents is to give, uh, these systems the autonomy to carry out complex tasks, much like we humans do.

  37. 8:12

    So it's not a surprise that the components kind of resemble how we, um, think through problems and go about the world.

  38. 8:21

    So let's dive a bit deeper into each of these components.

  39. 8:25

    Let's talk about perception first. So perception, as I said, is the mechanism by which agents gather information about their environment. And this happens via some form of inputs, whether it's, uh, a user like you interacting with the agent or triggered by something else, like an email or a, a Slack message.

  40. 8:43

    And text inputs have been the most common form of, uh, interacting with LLMs and agents so far. But over the past few months, we've seen, um, images, voice, video also being part of this, uh, perception mechanism for agents.

  41. 8:57

    And in today's workshop, we'll be working with two of these, which is text and images.

  42. 9:03

    The next component we have is planning and reasoning.

  43. 9:07

    And shocker, [chuckles] the component that helps, uh, agents plan and reason is LLMs. So given a user query, it's the LLM's job to determine how to go about, uh, solving the problem.

  44. 9:19

    But they can't do all of this on their own. They need some guidance, and the way to provide guidance, uh, at this point is to, um, prompt the LLM.

  45. 9:29

    And you can start simple by prompting the LLM to create a plan of action based on its initial understanding of the problem, and this is what we call planning without feedback, since the LLM doesn't really modify, uh, its initial plan of action based on information gathered from tool outcomes or its own reasoning traces.

  46. 9:48

    And a common design pattern for this kind of planning is chain of thought.

  47. 9:54

    And chain of thought is as simple as prompting the LLM to think through a problem step by step without, um, directly jumping to, uh, giving the user an answer.

  48. 10:04

    And you can do this in two ways, uh, in a zero-shot manner, where you literally prompt the LLM, like, tell it, like, "Let's think step by step," or you can do this in a few shot manner, where you're providing examples of how the LLM should go about thinking through a problem, so that the next time you give

  49. 10:19

    it another problem, it'll, uh, use your examples to guide its reasoning process.

  50. 10:26

    Then there's planning with feedback, where you can prompt the LLM to, uh, adjust and refine its, uh, initial plan based on new information, again, obtained from, uh, tool outcomes or based on its own, uh, previous reasoning.

  51. 10:40

    And a common design pattern that you will implement today is, uh, ReAct, which is short for reasoning and act. And what we do in this pattern is you prompt the LLM to generate

  52. 10:53

    verbal reasoning, uh, traces and also, uh, tell you the actions that it'll take to solve the task. And then after each action, we ask the LLM to make an observation based on, uh, the information that it gathered from that tool execution and think through that and plan what to do next.

  53. 11:10

    And this continues until the LLM determines that, "I have the final answer," and that's when it'll exit that execution loop and provide the answer to the user.

  54. 11:21

    Then the next thing we have is tools. And tools are essentially interfaces for, uh, agents to interact with their external world in order to, uh, achieve their objectives. And these tools can range from simple APIs such as, I'm sure you've seen, uh, examples of weather and search APIs, to, uh, vector stores, to even specialized machine learning models.

  55. 11:46

    And tools for LLMs are typically defined as functions. And most recent LLMs have been trained to identify... Uh, when a function should be called, and also the arguments for a function call.

  56. 11:57

    But the one thing to note is, um, the LLM doesn't actually execute the function. This is something, uh, we will have to implement in our code.

  57. 12:07

    And in addition to actually defining the function, uh, you typically also need to provide, uh, the LLM a function or tool schema. And this basically is just a JSON file, or with, um, MCP servers, you might have seen a different way of, uh, defining, uh, tools.

  58. 12:24

    But essentially, you're providing, um, the name of the tool to call, a description of what the tool does, and the pa-parameters that the tool takes, and also their types and descriptions.

  59. 12:35

    So, for example, I have a weather tool here, and in my tool schema, I'm saying, uh, the name of the tool, the description, I'm saying, uh, the input that it takes as a city, the type is string, and, uh, the description of that parameter.

  60. 12:50

    And finally, uh, the last component is memory.

  61. 12:55

    This component is what allows AI agents to store and recall past conversations, uh, and enables them to learn from these interactions. And memory, if you think of human memory, it's a pretty nebulous concept.

  62. 13:06

    There's so many different types of memory. If you ask a psychologist, they'll tell you, uh, all about that. But, uh, I'm not a psychologist, so [chuckles] uh, I think of it in pretty primitive terms.

  63. 13:16

    Uh, I think of it in as two broad categories. Uh, one is short-term, which deals with storing and retrieving information from a single conversation, and then there's long-term, which deals with storing, updating, and retrieving information, um, ha- obtained over multiple conversations had with the agent over a longer period of time.

  64. 13:38

    And this is really what, um, enables agents to personalize their responses over a long period of time. But in today's lab, we'll implement short-term memory for our multimodal agent.

  65. 13:50

    And again, if you wanna learn more about this, uh, nebulous and extensive topic, then here's a talk that I gave a few months ago. Uh, so I'll leave this here for a few seconds, but if you wanna talk to someone live, then talk to me, Richmond, Mikiko, uh, anyone from our team.

  66. 14:11

    Moving on. Okay. So let's take an example and understand how, how all of these components work together, right? So the first thing that happens is a query comes into the agent here.

  67. 14:23

    Uh, I'm asking this agent what's the weather in San Francisco today?

  68. 14:28

    The agent forwards the query to an LLM. So think of agent, uh, agents as a software application or system with different components, one of them being, uh, one or more LLMs.

  69. 14:41

    And the LLM, in this case, has access to a set of tools. In this case, it has access to a weather and search API and also its past interactions or memories.

  70. 14:50

    So based on the tools it has access to, in this case, for this query, the LLM might, uh, decide that the weather API would be the most suitable to get information about this query, and it'll also parse out the arguments for this tool from the user query.

  71. 15:07

    And like I mentioned, the-- your agent also needs to have code to actually execute the tools, so we have that in our agent. It's going to make a call to the weather API, uh, with the arguments extracted by the LLM, get a response back from the API, forward that to the LLM.

  72. 15:25

    And at this point, the LLM has two options. It can either decide that it needs to-- needs more information and decide to call more tools, or it can be like, "I have the final answer.

  73. 15:35

    Uh, I'm gonna generate that now." So in this case, it has the temperature in San Francisco, so it might be like, "I know the answer." It generates a natural language response, and that gets forwarded to, uh, the user.

  74. 15:47

    So that's kind of the full flow of how, uh, a tool calling, simple tool calling agent works.

  75. 15:57

    The other thing we need to talk about today, which is the more interesting part, uh, I believe, is multimodality b-because we are, after all, building a multimodal agent.

  76. 16:08

    So what is multimodality? Multimodality in the context of machine learning or AI is the ability of machine learning models to process, understand, and at this point, uh, even generate different types of, uh, data, such as text, images, audio, video, et cetera.

  77. 16:26

    And like I mentioned, in today's lab, we'll be working with two of these modalities, which is text and images.

  78. 16:33

    So here are some real-world examples of data that contains a combination of, uh, images and text, just to give you some inspiration for, uh, the kind of problems and domains you can apply your learnings from today too.

  79. 16:45

    So there's graphs, tables, and then there's these types of data interweaved with text. So think of research papers, financial reports, any sort of organizational reporting, uh, which typically has, like, some graphs, analysis, and text, um, all combined together or healthcare documents.

  80. 17:05

    The list is virtually endless. There's a lot of, uh, a lot of real-world, um, data looks something like this.

  81. 17:13

    So to make sense of this type of data, we currently have two classes of multimodal machine learning models. And the first type of models we see are multimodal embedding models.

  82. 17:23

    And the job of these models is essentially to take, uh, multiple types of data as input and generate embeddings for them so that all of these diverse data types can be searched and retrieved together using techniques like vector search, hybrid search, graph-based retrieval, whatever retrieval mechanism you want.

  83. 17:43

    And the other class of models is multimodal LLMs, which can, um, be... DeepSeek does that at this point, Claude, uh, OpenAI, um, like ChatGPT has a voice mode. So- The job of these LLMs is to take all of these different data types as input and also generate, uh, outputs in these different data formats.

  84. 18:04

    Now, if you give a multimodal LLM tools to search through multimodal data and use its reasoning capabilities to make sense of this information and to solve, uh, complex problems, what you have at your hands is a multimodal agent.

  85. 18:20

    So let's build that. Enough talk. Let's actually talk about the agent that we are going to build today.

  86. 18:27

    So we are gonna start with something simple. Uh, we are gonna,

  87. 18:31

    um, remove as many abstractions as possible, uh, start with very simple objectives, uh, and build an agent from scratch. You get a really good understanding of what it really takes to, uh, build a multimodal agent in practice.

  88. 18:46

    So our agent has two simple objectives, the first one being answer questions about a large corpus of documents, and then also given a chart or diagram, help the user, uh, make sense of it by explaining and analyzing that, uh, figure.

  89. 19:00

    I do this all the time when I'm reading research papers. I'll just take a screenshot, pass it to Claude, and be like, "Explain that equation," especially with all those, like, mathematical symbols and whatnot.

  90. 19:10

    Sounds pretty reasonable, easy. Not quite. There's a small catch, and the catch is we want to search our documents with mixed modalities. So in our case, our corpus is going to be, uh, documents that have text interleaved with things like images and tables.

  91. 19:30

    And that complicates things because, uh, retrieving the right information from mixed modality documents is not a trivial problem.

  92. 19:39

    The challenge lies in actually preparing the corpus of documents for search and retrieval. So typically, for text-based documents, if you've built a RAG application, you chunk up those documents, embed those chunks, and then, uh, retrieve relevant chunks to pass as context to an LLM.

  93. 19:54

    But you can't really do this when you have images and tables in your documents. And one way to do this, there's so many tools out in the market. There's like LlamaParse, Unstructured, that use, uh, vision transformers or object recognition models to first identify and extract the different elements.

  94. 20:11

    Like they'll extract text, images, tables separately. Then you chunk the text as usual, but you summarize the images and tables instead, and then basically convert everything to the text domain by, uh, creating embeddings of the text chunks and summaries using a text embedding model.

  95. 20:28

    I know that's already a mouthful, but you'll see how to simplify this process using a new type of models. I'll just get to that in just a little bit.

  96. 20:38

    Another technique similar to the previous one is that you still extract the text and non-text elements, you chunk the text, but instead of summarizing the images and tables, you would embed all of these, like the text chunks, images, and tables using a multimodal embedding model because, uh, it has the capacity to, um, understand and embed all of

  97. 20:59

    these different data types. I already see some, some of you losing me because these, uh, pro-data processing pipelines are pretty complex, and they ha- they come with their own limitations, right?

  98. 21:12

    They sound promising, but they have, um, mainly these two limitations. So the first one is that they face the same drawbacks, uh, that you see with chunking. So to me, the biggest problem with chunking is, uh, the loss of context at the chunk boundaries, which is why techniques like parent document retrieval, metadata pre-filtering are becoming popular, where

  99. 21:31

    you add back context that was lost during chunking at either retrieval or generation time. Also notice how complex these, uh, processing pipelines were, right? You need an object recognition model, uh, to extract the elements.

  100. 21:46

    Another, potentially another LLM call to, um, actually summarize these elements in addition to chunking and embedding, which is already one too many steps.

  101. 21:57

    Another limitation with a lot of, uh, multimodal embedding models lies in the architecture of, uh, the models themselves. So until recently, the architecture of most multimodal embedding models, at least for text and images, was based on OpenAI's CLIP model.

  102. 22:12

    Um, and what happens in this architecture is text and images are, um, passed through separate networks for generating the embeddings of these data types.

  103. 22:24

    And this results in something, uh, we call a modality gap, where irrelevant items of the same modality end up, uh, close to each other rather than, uh, relevant items of different modalities.

  104. 22:36

    So in a CLIP model, for example, text vectors of irrelevant text might appear close together in vector space rather than, uh, text and images corresponding to related subjects, and that's a problem.

  105. 22:50

    But this has changed with the advent of, uh, vision language model or VLM-based, uh, architectures. So in this architecture, both moda-modalities are vectorized using the same encoder, and this ensures that both text and visual features are treated as part of a more unified representation than as distinct components.

  106. 23:13

    So with these models, all you really need is a screenshot of documents containing whether it's purely images, purely text, or an, a combination of text, images, tables, et cetera.

  107. 23:25

    And this is what, uh, because of that unified architecture, it ensures that the contextual relationships between, uh, text and visual data is preserved. So as you can imagine, this greatly simplifies the data processing pipeline for multimodal data and also ensures that you get, uh, better retrieval quality, uh, because you're no longer separating these texts and images.

  108. 23:47

    So basically, given a document containing a combination of text and images, you simply take a screenshot of it, pass it through a multimodal embedding model, and the embedding that you get from that makes this data ready for retrieval.

  109. 24:01

    Pretty straightforward process there. So let's quickly look at some of the... how some of the key features of the agent that we are going to build is work, and then we can go implement these in code.

  110. 24:14

    So let's talk about the dep- data preparation pipeline for, uh, the corpus of documents that our agent is going to use to answer questions. So, like I mentioned, the first thing we are going to do is, um, for each document in our corpus, we are gonna convert that into a set of screenshots, and in our case, each,

  111. 24:33

    uh, screenshot is going to represent a page in the document.

  112. 24:38

    We'll then store the screenshots locally, but if you were to do this in production, then you might want to store them to some form of blob storage, like S3, uh, Google Cloud Storage, whatever, uh, your preferred cloud provider is.

  113. 24:51

    And we'll also note the path to where the image is stored,

  114. 24:56

    and then store this as metadata along with the embeddings of the screenshots generated using a multimodal embedding model, and store these into a vector database.

  115. 25:08

    So in our lab, we'll use the latest multimodal, uh, embedding model from Voyage AI, and we'll use MongoDB as a vector database, because I work at MongoDB. [laughs] Uh, not that... [laughs]

  116. 25:20

    So one thing to... important thing to note here that we are not storing the raw screenshots. Yes.

  117. 25:26

    Yeah, one quick question.

  118. 25:27

    Yeah.

  119. 25:27

    Um, so you are retrieving the documents into screenshots. There are screenshots or you're picking up the screenshots from your document and sending into the...

  120. 25:45

    So, okay, so say I have a PDF containing multiple pages. Each page in the PDF, I'm going to take a screenshot of it, and each screenshot is going to be saved separately in blob storage, and references will be stored as metadata along with embeddings in the vector database.

  121. 26:01

    Okay. And why do you have to take the screenshot of each page? Is it to save the space or?

  122. 26:08

    Uh, so like I showed you two methods before, right? Like, to be able to use the image and table data, uh, for reasoning, you need to, uh, be able to retrieve that document that contains all of that together.

  123. 26:21

    And the reason I'm taking a screenshot is to preserve, like the continuity between the text elements and the image elements, so all of them can be retrieved together as context.

  124. 26:30

    So this is, is worse than chunk- chunks, uh-

  125. 26:32

    What's that?

  126. 26:33

    I mean, a screenshot for each page-

  127. 26:36

    Mm-hmm

  128. 26:36

    ... loses the context of, of the whole, I mean, document.

  129. 26:39

    But then with chunking it's worse because you have like a very, uh... usually you're keeping like two paragraphs together or something. So, like slightly better, you would alway... of course, maybe want to augment this method with metadata pre-filtering, other methods that you use for traditional chunking.

  130. 26:55

    But I still think one page is better than two paragraphs or a small paragraph of text. Yeah. Do you want overlapping segments here as well, just like you do with text chunking?

  131. 27:04

    Uh, yes. Yeah. So when you... So here, we'll take screenshots of like distinct pages, but, uh, if you want that continuity, you might want to like keep some overlap as well.

  132. 27:14

    Yeah.

  133. 27:14

    How is this-

  134. 27:15

    Good point

  135. 27:15

    ... better than giving it the full PDF at once?

  136. 27:18

    Uh, because LLMs have like that lost in the middle problem. So if you give it... Like just because you have a large context window doesn't mean you should flood it, because they still have the problem of searching through like the full...

  137. 27:30

    a large document to find the right, uh, information. So you're trying to-

  138. 27:34

    Is the relation between these different screens shortly maintained after the

  139. 27:38

    Uh-

  140. 27:38

    ... after the

  141. 27:39

    Yeah. I think as, as she was pointing out, either you'd have to like, uh, maybe structure it a little differently to have some overlap or store some additional metadata to maintain that continuity, like page numbers or...

  142. 27:51

    And whenever you're retrieving a page, you could do something like retrieve the previous two, next two pages, things like that. Yeah.

  143. 27:59

    Thank you.

  144. 27:59

    Any more questions?

  145. 28:01

    Yes.

  146. 28:01

    Yeah.

  147. 28:02

    Uh, you talked about Voyage Multimodal 3. Like why-

  148. 28:04

    Mm-hmm

  149. 28:05

    ... why that one versus others?

  150. 28:07

    Uh, any VLM based model really. Like the whole point is to show you that clip-based models have that. I'm not using a clip-based model because it has a modality ga- uh, yeah, modality gap.

  151. 28:16

    But any VLM based model is very good. Yeah. So this works for text and image. Yeah. Are there more like video- Right. Yeah ... voice? Like, uh, yep, 100%.

  152. 28:29

    So this doesn't really deal with that, but essentially you could, um, extend this concept to different modalities. It's just I typically don't see like video or audio occurring with text.

  153. 28:43

    Like I just chose this because, uh, like images, uh, figures typically, uh, occur with text, but... So yeah, screenshots might not apply to other modalities. There are different ways to handle it.

  154. 28:55

    Today we are only focusing on images and text. Uh, okay, two more questions. [laughs] Okay. Yeah.

  155. 29:00

    So VLM, um, I, I guess this, uh, is different from the large language model, right? So it has, I guess, smaller parameters than large language model, then-

  156. 29:10

    Yeah

  157. 29:10

    ... performance is a bit less, I guess. Is it-

  158. 29:12

    Um, it's just, it's still a large-

  159. 29:16

    It depends on language to language.

  160. 29:17

    Mm-hmm.

  161. 29:17

    For example, like we make an embedding from the VLM-

  162. 29:20

    Mm-hmm

  163. 29:20

    ... text, and then if you make an embedding from the, um, uh, let's say, um, Ara 002, which is bigger parameters, then performance probably, accuracy probably less.

  164. 29:32

    VLMs tend to get pretty big too. So they're basically-

  165. 29:35

    Oh, okay

  166. 29:35

    ... still large models. They just can handle like images and text, but they're still gr- pretty sizable models. [laughs] Yeah. And I could point you to s- to some benchmarks that show that they're still good at even purely text or purely image data, and then a combination of both.

  167. 29:50

    How to run it on local?

  168. 29:51

    What's that?

  169. 29:52

    How to run it, uh, run in the local machine, I guess.

  170. 29:55

    Um, like you'd find a model that works with your hardware specifications, just like a, an LLM, right? Like, not all LLMs can be run on your machine. So it would be similar to those.

  171. 30:05

    Yeah Um, no, that was one

  172. 30:09

    Let's skip one

  173. 30:09

    Okay. One more.

  174. 30:11

    Yeah, so in this case, you're using multimodal retrieval, right?

  175. 30:14

    Mm-hmm.

  176. 30:15

    It is true that your image and text is strongly aligned to the modalities. But what if you have a modality that's really weakly aligned to the time series, right?

  177. 30:23

    So which means your latent space, they're not really close. How do you handle those?

  178. 30:26

    Sorry, can you say that again?

  179. 30:27

    If you have a modality that's, kind of, not strongly aligned with the rest of the modalities, like for the whole time series, right?

  180. 30:34

    Mm-hmm.

  181. 30:34

    If you embed it into the same latent space, they are not, like, really close to each other.

  182. 30:39

    Yeah.

  183. 30:40

    So in those situations, how do you handle it?

  184. 30:43

    Um, so like time series data with text? Like, I'm, I'm trying to understand, like, a situation where you would have totally disparate-

  185. 30:50

    So it could be like you have like a text, um, image and a time series too.

  186. 30:53

    Mm-hmm.

  187. 30:53

    And that time series data may not be really aligned with the rest.

  188. 30:55

    Yeah.

  189. 30:56

    And that means when you retrieve them-

  190. 30:58

    Yeah

  191. 30:59

    ... they don't really go very well. So how do you handle those?

  192. 31:02

    Yeah, I think time series data, typically you don't even, like, use embeddings for it. It's to... It's just like you treat them like any other features like you would for traditional ML models.

  193. 31:11

    You definitely want like a different, uh, retrieval strategy for those. It'd be hard to put them in the same, uh, yeah, vector space as text and images. So you might need to work with like different retrieval methodologies.

  194. 31:23

    Okay.

  195. 31:24

    Yeah. All right. Uh, I'm gonna move, uh, forward here very... Like, in a few minutes, we will hit the hands-on portion. So if we have more questions, just, um, call out to our team, and we'll take more questions then.

  196. 31:38

    Cool? All right. Um, okay. Okay, let's quickly talk about the workflow of our agent. We looked at a random example before, but let's talk about the agent you are buil- you're going to build.

  197. 31:51

    So query comes in, agent forwards the query to a multimodal LLM. So note we are going to use a multimodal embedding model for retrieval, but we also need a multimodal LLM.

  198. 32:01

    We are going to use, I think, Gemini 2.0 Flash Experimental, some long name. Uh, but yeah, basically we need that LLM because once we give it like, um, that interleaved document with text and images, we need, uh, an LLM that can make sense of both these modalities.

  199. 32:19

    So that's why I'm using that LLM. It has, uh, just one tool, which is a vector search tool to, uh, retrieve those multimodal documents and also its past interactions and memory.

  200. 32:31

    So based on the query, the LLM can decide to call the vector search tool, and if it does that, it'll return the name of the tool and the arguments, um, to use to call the tool.

  201. 32:42

    Again, the agent has code to actually call the tool, so it calls the vector search tool. And typically, if you're working with text-based data, you get the, uh, documents back directly from, uh, vector search.

  202. 32:55

    But in this case, what we are gonna get back is references to the screenshots. Remember, we didn't store those in the vector database. Those are in our local or blob storage.

  203. 33:05

    So then our agent needs to have that additional step of using those image references to actually get the screenshots from blob storage, and then it's going to pass those images along with the original user query and, uh, any past conversational history to the multimodal LLM.

  204. 33:21

    So each time an LLM call is made, whether it's to determine what tools to call or generate the final answer, uh, the images are also going to be passed along with the query and conversation history to the LLM.

  205. 33:35

    Then it generates an answer, and that gets, uh, returned back to the user.

  206. 33:41

    And finally, depending on the query, the LLM might also decide that it doesn't need to call a tool. So for example, if the user is simply asking like, "Hey, summarize this image," it might not need to, uh, call a tool.

  207. 33:53

    So in that case, it'll say, "I don't need to call tools." It'll simply generate an answer, and that gets forwarded to the user.

  208. 34:02

    Um, and the final thing, um, let's talk about the memory management mechanism for our agent because this is important for it to actually have, uh, coherent multi-turn conversations with the user.

  209. 34:14

    So like I mentioned before, we'll be implementing short-term memory for the agent, and the way this works is each user query is associated with a session ID, just as some identifier to distinguish between different conversations.

  210. 34:29

    So given a user query, we obtain its session or conversation ID, and we query a database consisting of previous turns in the conversation to get that, uh, chat history for that session.

  211. 34:41

    And each time, again, in addition to, like, the context, we also pass in that, uh, chat history just so the LLM can use that as additional context to determine if it need, it even needs to call tools or not.

  212. 34:55

    And then when the LLM generates a response, the other thing that happens is we add, uh, this current response and the current, um, query back to the database to add on to, uh, the history for that session.

  213. 35:08

    Now, you can also log, uh, tool call, their outcomes, any, um, reasoning traces from the LLM, but at a minimum you at least want to be logging, uh, the LLM's response and the user queries themselves.

  214. 35:23

    And finally, that is enough talking from me. You... I'll be quiet for the rest of, uh, the workshop. We have about forty-five or s- forty-five-ish minutes. So head over to that link, uh, to access the hands-on lab.

  215. 35:37

    Recommend running that on your laptop. So instead of QR, that QR code, uh, actually type in that URL. This should take you to a GitHub repo. Uh, follow the instructions in the Read Me to get set up for the lab.

  216. 35:49

    That should take about ten minutes, and then you have two options. Um, you can either... There are two notebooks in there. One is called lab.ipynb. And if you actually want to, if you're in the mood to actually write code right now, that's the notebook you'll be using.

  217. 36:05

    You'll have, you'll see reference documentation in line in the notebook indicated by that books emoji that tells you, "Use this documentation, fill in your code." You can do that.

  218. 36:15

    If that sounds too daunting, there's also a notebook called, called solutions.ipynb that has all the code prefilled. So you can just run through that notebook, read the comments to get an understanding of, uh, how the agent works.

  219. 36:29

    But whichever option you use, I'm here, my team is here. Just call on us to, uh, if you have any questions. And yeah, for anyone actually filling in the code, you can also refer to the solutions.

  220. 36:41

    Don't get too frustrated if you get stuck. Uh, we don't want that. All right. So

  221. 36:47

    I'm shutting up now. Um, let's go ahead and build that agent. [clapping] [outro music]