Transcript#
This transcript was generated automatically and may contain errors.
Okay, welcome everyone. Today you are here for the workshop on LLMs for Data Analysis in R with Sarah Altman from Posit. And Sarah, we're so happy to have you here giving this workshop and I will let you take it from here.
Great, yeah, thanks. Happy to be here. I'm going to send some links in the chat and then I'll share my screen. This is the website for the workshop and then the repository. You don't need to clone the repo or anything. We'll get set up in a minute, but just so you have that. And then let me share my slides. Okay. Can you see that, Garrett? Okay, great.
I was going to show this while we were getting ready, but we're going to do all these instructions in a second, so don't worry about this. We have everything set up for you in an environment, so you're not going to need to install anything locally or anything. But welcome to LLMs for Data Analysis in R.
Just a little bit about this workshop before we get started. So like Emily said, I'm Sarah. I work on the AI team at Posit and I'm also joined by Garrett. Garrett, do you want to briefly introduce yourself? Hi, everyone. I'm Garrett. I work with Sarah at Posit. I'm on the education team.
Yeah. Do you also want to maybe talk about your workshop that's in a month really quickly? Yes. I believe on June 11th we're scheduling a workshop that's very similar to this topic. It will be about how to use AI to develop everything from R code to Python code to dashboards to shiny apps to apps that use AI as a chatbot inside the app and how to deploy those. So look for that.
Yeah. I think at the end we'll talk, maybe overlap a little bit with that workshop, but I just wanted to mention that in case we get to the end of this workshop and you wanted to hear more about those topics. Yeah. Check out Garrett's workshop.
Okay. I pasted this in the chat. Maybe Garrett, you could resend that in case anyone joined after that. But this is where all of the slides and information is going to live. You might want to open this just because sometimes there's things that you'll need to click and it's going to be easier to click it from there than to type the links yourselves. And you can follow along with the slides. Sorry. We're now joined by my cat. And there are set up instructions, but we're going to give you some time in just a minute to do that.
Workshop overview
Okay. So workshop format at high level, we're going to have slides. I'll show some demos where I'm going to run some code and we'll talk about how it works. And then there will also be interactive exercises in a platform called instruct where you'll do some coding for these and we've set everything up for you. You're not going to have to install anything locally or anything like that.
If you have questions, you can put them in the chat at any time, but you're also welcome to come off mute and ask me. Feel free to ask questions like throughout the workshop any time. But maybe especially during the exercise portions if you get stuck.
Yeah. Ask questions at any time. Okay. Great. So we're going to start the set up process just because it takes a few minutes to get going. So you're going to go to this link and click start. And that's it. It's going to say it's going to take a couple minutes. And we're going to talk and then come back. So I'm just going to give you a minute to do that. Again, you just need to click start. It's going to say it's going to take a couple minutes and then we'll come back. But please let me know if the link isn't working.
Great. So we're going to have like three maybe two main parts of this. The first thing we're going to do is talk about how to call LLM APIs from R and sort of the basics of how LLMs work. We're going to take a really brief break and talk about tool calling which is how you give additional abilities to LLMs. And so this whole that whole section is going to be like how LLMs work, how to call them from R. Then we're going to talk about making apps with Shiny apps with LLMs and using coding agents. And then finally we'll talk a little bit about privacy and security. That part will be pretty short.
Okay. So when you look at your environment, which will get set up in a minute, you're going to see a couple folders. And this is replicated in the repository link that I shared. You're going to mostly be working in the exercises folder for the your turns. The main repo also has solutions which are solutions to those exercises. So if we might not go over the solution for every exercise, but you can always find them in there. And then you'll also have access to the demos. And these are the code that like bits of code that I'm going to run and then we'll talk about it.
Calling LLM APIs from R
Okay. So let's get started. So again, I said like first part of this, we're going to talk about working with LLM APIs from R. And so generally to use an LLM API, you typically need an API key. And beyond this workshop, if you want to rerun these exercises or experiment on your own, you will probably need an API key. There are some providers that you might connect to that authenticate a different way, which is why I say generally. But if you're doing this on your own to get an API key, you would sign up for an account with your model provider, add a payment method if you're doing this on your own, and then they'll give you an API key and you would store it in your R environment file. This is going to look really similar to like getting an API key for any API that you might have used in the past, maybe with the exception that you need to pay for it, pay for the tokens. But you might also have access to these models through your organization, and maybe they're providing you with API keys. So Posit provides us with API keys. And then we're able to work with LLMs using those.
But today, we're going to give you API keys to use, you don't have to worry about any of the setup. I'm just mentioning this, because if you try to run this code on your own, and you don't have this setup, nothing will work because you don't actually have access to the LLM. So what's up next? And you're going to use all these keys for all the activities today. Feel free to like go beyond the exercises if you want, but just don't run like massive amounts of stuff with them. Please be generally considerate. It is pretty hard to wrap up large charges, but we want you to explore, but just be considerate. And then we're going to turn them off the end of the workshop, so you won't be able to use these keys afterwards.
Okay, so hopefully, Instruct should now be ready to open for you. We're going to do this part together. So I'm going to share that screen instead. And if you just follow along for the setup process. So at this point, you should have clicked Start, and then open an external window. And then you should see something like this. Okay, is everyone, do you see the message? Yeah, sorry about that. I had the wrong link in one location.
Okay, if you use the new link and weren't able to open it, the estimated time, two minutes, is good. Yeah, sorry about that. That was the old link.
I wonder, could you just open a new tab next to that one and paste in the new link, and then maybe people will see. Yes. Let's put the link in the chat.
Okay. So it sounds like the instruct, the workshop environment is experiencing service interruptions. So we're going to try the second link again. I'm sorry, everyone. And we know about the API issue. I have a workaround for that. But let's see. Yes, there will be everything should be working. Hopefully.
Sorry. Do you have access to Rick's chat? He's provided a new API key for us. Okay. Yeah. I see. Sorry about that.
If you are in an environment like Elizabeth, stay there. You're doing great. And don't mess it up. Yeah. And we'll get you the new the new key. Yeah. Apparently it's gone. And just in my defense, IT says it doesn't make any sense.
Okay. Let me I'm just going to open this. And then I will get you the key. So again, hopefully you can get to this place and then launch RStudio.
If you see this, if you see this, you're in the right place. We have a folder for our exercises, and you just click that, we're going to go into that folder. There were some complications with the platform, and it's not going to work if you create a project, so don't do that. Just click into the folder. This was the easiest way for now. And if you've gotten there, just make sure you have all the exercises. I'm going to get you the key in one second.
So we're going to use a different key. The good news is you don't have to do anything to set it up. The bad news is that open AI won't work, but that's not particularly... we don't necessarily need that for the workshop. Just know that if you see anything like this, it's not going to run. During one of the exercise times, I'll try to take a minute to fix it. Something is going wrong with the new sets of keys. We have another one in here that should work. So just a known issue that this code will not work. Any Anthropic API code should work with no setup. If you've already done something to paste in new keys or something, try to go back and make a new session.
Okay. Yeah, again, apologies. We had two colliding problems. Everyone should be able to run the second bit of code. Now, if anyone is still not able to do that, please let me know.
Okay. We will just do the second exercise together to save a bit of time. So if you have everything working, you can open this O2 conversation.R. Okay. Great. Please let me know if it's not working.
Conversations with ellmer
Okay. So we have been talking about creating conversations with ellmer. The point of this exercise is to dig a little deeper into how this works. And so the first exercise that we're going to do is just fill this in to get the chat to work. And here we want to make a system prompt so that it answers in as few words as possible. So, again, that's the system prompt exercise or argument. And run this.
And now when we call the chat method on that chat object to send a request to the LLM, we should get a response back that obeys that system prompt. So the little zoom icon that's blocking this. But it's telling us that there's an ellmer function called models anthropic which tells us which models are available. This is a helpful function. We'll use this in a little bit as well. And it is answering in as few words as possible. Ordinarily, Claude Opus is pretty verbose.
Okay. So now what happens if we ask a follow-up question? Like, what about open AI models? And notice that it is giving us a succinct answer. One word answer. One function answer. And it knows what we're talking about. So, before we asked what ellmer function tells me what models are available, it gave us an answer saying what about open AI models and it's giving us a really short answer. So, it is taking the context from the entire conversation to form this answer.
If we make a new chat. So, let's say we make a fresh chat. This does not have the history of this one. You can take a look at it. There's no conversation history. If we use that to ask what about open AI models, it's not going to have any idea what we're talking about. It thinks this is the start of the conversation because we made a new chat object. So, we're going to ask what chat object. So, then the question is how do the answers to three and four differ? Again, if we make a new chat object, it doesn't have the context from the previous one. It doesn't know what we're talking about when we ask follow-up questions. And if we don't put a system prompt, it's going to answer very verbosely.
I realize that was sort of a demo, but I'm going to do a more formal demo now and we're going to take a look at something called ClearBot. Okay. So, this is an app that I have running. And the point of this app is to just show us a little bit more about the internals of the APIs and give us a clue about how they're working. I'm just going to switch this model. Okay. So, before we asked it a question about an ellmer function. So, I'm going to ask it the same question.
What ellmer function can tell me what models are available? Okay. There's something going on with the APIs. Okay. The APIs are down. Okay. We're going to move on from that and I'll come back and see. I think this is using the same key. Yes.
Okay. I was trying to figure out what's going on in a little bit. This was just running literally five minutes before the workshop started. I will try to explain in words the
takeaways. We already saw these a little bit in the conversation. But when you send a request to the LLM, you have to send the entire conversation history each time. I'll try to do this in the slides. The demo is very helpful for seeing this. But basically, when you have a conversation with an LLM, each time you send a request, it sends the entire conversation history to the LLM. So, it does not have a memory of your conversation before. You have to send the entire conversation each time. And this is because LLMs are stateless. They do not remember or have a state where they store your conversation for you. So, you have to send the entire thing each time.
It's kind of like it has amnesia. It forgets everything after each response. Each request is completely independent. And then it's going to construct the conversation from what you send. So, it's not really like you're talking to a person where the person remembers what you said before and then generates a response. It would be like if you had to tell the person the entire history of the conversation each time you wanted to tell them something new.
How LLMs work
We've talked a bit about how conversations work with LLMs, statelessness, and sending this full history. So, we're going to talk really briefly at a high level about how they actually work, how they understand what you're saying, and how they construct responses.
So, LLMs, you might know, are trained on this huge corporate data, essentially everything that's been written on the internet, books they have access to, all of this text and information. They extract the patterns from that and through that develop the ability to simulate, understand a context, generating text that matches your request. And they kind of understand how language works. So, they can do things like answer your questions, write code, and translate.
But LLMs don't generate whole sentences at once, and they also don't generate necessarily whole words at once. Instead, they work token by token. So, they think in tokens, which are these fundamental units of LLMs. You can kind of think of a token like a word, but it is not necessarily a word. So, for example, hello is one token, but the word unconventional, which is a bit longer, the word unconventional, which is a bit longer, is split into three tokens.
And it's important to know about tokens because this defines their input and output limits for individual requests, as well as API pricing, which is usually broken down by millions of tokens. And tokens are just for words. So, images can also be tokenized as well.
So, this is an app that helps us understand how token generation works. So, we'll keep this prompt here to rate a limerick. It's going to generate the response, and then this is showing us both how the text is broken into tokens. So, you see they kind of map to words, but some things are split up. And if we click on each of these, we can see the token probabilities. This demo is in your directory. This should work, hopefully, if you run it.
Hopefully, if you run it. So, if we click on each one, we can see that it chose their token, because it has the highest probability, but there was other options with different probabilities. And then to follow there, once has the highest probability, and then cat, or sorry, was, and eventually cat. And this is just helpful. This just gives us a basic understanding of how these tokens are generated. It's choosing the next token with the highest probability, at sort of a high level.
How to think about working with LLMs
So, we talked about, at a high level, how LLMs work, how they generate tokens, that they are stateless. And I just want to talk really briefly about how to think about working with LLMs.
And in general, I think the best approach is to think about them empirically instead of theoretically. You really don't need to understand their internals or the details of how they work. I think it's mostly okay to treat them as black boxes. And instead of, you know, theorizing, if it can do something, just try it out and experiment. I think you might find that there are things that you think they almost certainly could not do that they clearly can do today. And then there's things that you think surely they can do, and it turns out they're terrible at.
And this is partially because you might think that the plot of model performance and task difficulty looks something like this, where really easy tasks, models are great at, really hard tasks, they're really bad at. But it doesn't really work like that. Instead, LLMs are very jagged. They have very jagged performance. So, there's some easy tasks they're great at, there's easy tasks they're terrible at, and there's hard tasks that they're good at, hard tasks that they're bad at. So, for example, I think like coding, some coding tasks are very hard. LLMs are generally great at writing code. However, if you give it a vector, an R, and ask it to count the number of elements above a certain number, they're actually very bad at this, and will not give you an accurate count of the elements in a vector, which you might think is a very easy task. Their ability is very jagged.
They have very jagged performance. So, there's some easy tasks they're great at, there's easy tasks they're terrible at, and there's hard tasks that they're good at, hard tasks that they're bad at.
And so, because of that, I think in general, just embrace the experimental process with LLMs. We will talk about a way to formally run experiments for LLMs in the next section. But in general, just try things out, explore, try and reason about their behavior from observing it, instead of thinking through, okay, I know this is how transformers work, so this is going to happen.
But we're going to just transition really quickly to one other point, which is that we saw how to use the chat method to send one request and get one response back. If you want to keep chatting back and forth, ellmer also has built in functions for that. You would either start an ongoing back and forth chat in the console with live console, or in the browser with live browser.
Programming with LLMs
So, now we're going to talk about programming with LLMs. So far, we've really just done basic chat, and there's lots more that you can do. So, you learned how to use ellmer. The next step is really thinking about which model and provider you want to use. There are a lot of providers and many models to choose from. First, I just want to clarify the provider is going to be the company that hosts and serves your model. So, this is something like Anthropic or OpenAI. If you're using something like Hugging Face, that might be your provider.
This is the company that hosts and serves the models. And then a model is a specific LLM with particular capabilities. And models can vary across several dimensions. One is the amount of content you can give them. So, how many tokens can you give the model in a single request? This might range from like 200,000 to 1 million tokens, which is actually generally quite a lot. Speed. So, this is how many tokens per second they can generate and intake. Cost. How much does it cost to use the model? At this point, it's usually about like $1 to $5 per million input tokens for the major frontier models, maybe less than one for smaller models. And input tokens are usually priced less than output tokens. Those are the tokens the model is sending back to you. There's intelligence. How smart or how good is the model at tasks you want to use it for? And then additional capabilities. So, many models can also do things like that. They have vision capabilities. They can do reasoning, extended reasoning or thinking. They have tools, all that. And we'll talk about tools in a bit.
Model naming conventions
I find the naming conventions really confusing. So, we just go through that really quickly. There are many models. If you pay attention to like news at all about LLMs, there's like new models coming out all the time, and the naming conventions can be opaque. So, the Anthropic models, which is what we're going to be using today, have three. So, Anthropic has Claude models, the three model families. It took me a really long time to realize that they are named after types of poetry. So, Haiku is a small poem. The Haiku model is the smallest, fastest, and cheapest model line. Sana is a larger model or larger poem. So, it's the sort of larger, more expensive. And then Opus is a very long poem. So, this is the largest, most expensive, most intelligent model. And then the number that you might see after this, like Opus 7, that is the version. So, a higher number means a more recent version.
For OpenAI, they have GPT models. The GPT with no suffix or GPT Pro is the most expensive, smartest, slowest model, and then you have Mini and Nano.
There are also local or open weights models. So, these might be things that you personally could download and run locally on your computer, or maybe your organization has a server that it runs these models on for you. I think these naming schemes can be even more confusing. I'll just go over this really quickly. So, for example, Quen 3.6 and Jemma 4 are two recent local models. And these, I just took a picture of the various options you have for each of these models, which I find opaque and confusing. Generally, how these are named is you have the model name. It's like Quen 3.6. The number of parameters, for example, would be like 35B. That means there's 35 billion parameters. This is the model size, how big the model is. And then you might have an additional suffix with an A that's the number of activated parameters. This is like the number of parameters that are actually in use anytime you send a query.
So, for example, Jemma 4.31B has 31 billion parameters. If it has that A3B at the end, that means there's 3 billion active parameters. This isn't necessary for today, so to speak, but I think it can be confusing and sort of be a barrier to using the models. And so, I find it helpful to understand their names.
Okay. People often want to know what model to use, and I think it can really vary on your needs, your organization's needs, and what models you have access to. Generally, we recommend picking a recent frontier model from one of the big labs because they tend to be best performing models and then move to a cheaper one if you need. But you don't always have your pick of model. Your organization might constrain you to only a particular provider or only local models. So, it really can depend on where you work, what kind of data you use, and what you have access to.
Using different providers and models in ellmer
Okay. So, let's take a look at how to actually use different providers and models in ellmer. So, ellmer supports all of the major providers plus local models and enterprise options. And you can access models from these various providers by using the chat function that corresponds to the provider.
So, we have the major paid providers, open weights, models, and enterprise options like AWS Bedrock. You might have noticed that earlier we were using just a function called chat. instead of these chat underscore functions. And you can do that too. You can use either one. So, LLM has a shortcut where you just call chat and then pass the provider name as a string. If you just pass the provider name, it's going to pick a reasonable model for you to use. It has a default built-in. Same thing for OpenAI. If you want to specify a particular model with the chat function, use the format provider slash model name. So, again, you can use either chat or the chat underscore functions. It's really the same thing. In the exercises today, we tend to use chat just because it's easier to swap things out with that.
Multimodal input and structured output
So, far we've just been sending text back and forth to the LLM, but you can also send other types of information. This is called multimodal input. So, images get tokenized just like text. For an LLM, a picture is roughly 227 words or maybe 170 tokens. And so, in ellmer, we pass other types of input with content underscore functions. So, for images, we use content image file. This passes an image from your local file system to the chat. You can also do the same thing if you have an image at a particular URL with content image URL. Or if you have a PDF, you want to extract information from that PDF using an LLM, transform it into something else, you can use content PDF file to pass a PDF from your file system.
Okay. So, now we're going to talk about structured output. And this is how you can get LLMs to return data in a particular structured format instead of free text, which is really useful if you are doing, you know, any kind of data analysis.
So, here's a common problem. You might have some messy text data and you need to extract specific fields like name and age. You can definitely do this by writing R code. It might involve a complex regular expression, a lot of string parsing, but you can do it. And it might look something like this. And it works. But we have to write a lot of code. And this is actually something that LLMs are really good at, generally. And it's, like, easy to use for this use case. And we can just ask it to extract the name and age. And it can reason flexibly about what those values are. So, we don't have to write those complicated regular expressions.
So, here we've just set up a basic chat. This is in prompt to extract the name and age. And now when we ask it to extract that from two of those elements in the vector, those free text elements, it gives us back a name and age. So, this is great. But this is still just free text. It would probably be better if we could get it into some kind of R object, like a list or a data frame. So, something like this, where you have a list with the name and the age, like an object that we're used to working with in R. And you can pretty easily do this with ellmer with the chat structured function or method. So, this returns a piece of structured data instead of just free text. The trick is that we first have to tell it what structure we want.
So, to do so, we use these type functions to define a structure with its types. So, here we use type object to make a list. This is going to specify that we need a list. And then name should be a string and age should be an integer. There are type functions for all the types. Now, we can give chat structured, again, that bit of free text, our type specification. And it'll give us the data back in the format that we requested. And this is now ready for use in your analysis. If we wanted to do it over all of those free text entries, we could. And then we would have data that would be ready to use.
So, notice that we did type string for name. And so, name is a string. And type integer for age. And so, age comes back as an integer. And we're going to see these type functions again later. There's, and again, yeah, there's one for every type. If you want to see all of them, you can just do, you know, ellmer colon colon type underscore and see all of the type functions there are to choose from. You can also add descriptions to help an LLM understand what each field means.
Okay. So, now you're going to try this out yourself. So, in the 04 folder, there's some notes. This is just the wrong file path. You're going to extract data from those notes using the method we just saw. And I've given you scaffolding for the expected structure. You just need to fill it in with those type functions and then write a little bit more code.
If, did anyone have particular questions about this exercise or difficulties? Otherwise, I think we'll move on. I'm not going to go over it. But let me know if you have, if you ran into problems. The question about recommending checks to extract the corrected data, I think in general, like the model seeing information where there is none is a problem. And can be sort of difficult to get around if it really thinks there's going to be information when it is in fact not there. But I think you could try to fix it with better prompting. Or you might have like, you know, some kind of deterministic check either before it gets to the model or after. Like you might have if you're writing a general normal R function, even if there is no LLM. But I would say in general we sometimes run into problems where if information does not match the model's expectation or information isn't there and it thinks it's going to, that can be a problem for LLMs.
So, it's about an hour and a half. We're just going to take a three minute break before we get to the next section in case you want to stand. Yeah, it's almost been an hour and a half. Stand up or get some water or anything. I'll be answering questions in the chat, though. Or you're welcome to come off mute and ask questions during this time. We'll come back at 1253.
So, next we're going to talk about prompt writing or prompt engineering. So, prompt writing is a large part of working with LLMs because many times the work of getting
LLMs to do what you want them to do is figuring out how to give them the context they need in order to be useful. And so, one of those bits of context that you can give them is written information in the form of prompts. We already did this a little bit. So, we're just going to talk about it in a little bit more detail.
Okay. Just as a reminder, you can use the system prompt argument to pass system prompts to the chat object in ellmer. So, here we just put some prompt in a string and then we pass it to the system prompt argument of chat.
And usually you'll want to actually put your prompt in an external file, probably a markdown file, and then read it in and pass that to the system prompt instead of putting everything as a string and storing it in an object.
Exercise five: prompt design
Okay. So, in the fifth exercise, there are some note files stored in an object and your job is to edit the prompt MD file to instruct the model to organize the notes in a certain way each time. You can make up a format that you want, but it might be something like, you know, always with the date at the top, have a summary sentence at the top, put everything in bullets, something like that. So, play around with the prompt in order to get it to organize the notes in the way that you want and run all of the notes through the system prompt.
I looked away. Did my R session? Okay. I think it worked. I think I just restarted R and it it worked. So, I've seen this before. That means that you got disconnected from instruct, but to get reconnected, you have to go to the screen where it said open external window. Okay. Maybe try refreshing that, though. Yeah. Thanks.
I'll just I'll try reopening from the link.
Sorry. Do you mind resending the new new instruct link?
Everyone else, I'm monitoring the stats for instruct, but we really have no control over it, but it says their performance is yellow out of green, yellow, red.
Working for you. I just sent you another link that I think will work for you. Thanks.
You'll have to manually clone in the git repo. Yeah, I also have, I have everything locally too, so I can, I can do that.
Did anyone have any particular problems with the prompting?
I think I have an environment that's working. Will this have keys built in?
Yes, but now that I think about it, they're through Amazon Bedrock, so you might want to paste in an API key. I'll work on that when we do the next exercise, as long as no one had particular questions about getting this going.
Tips for getting LLMs to do what you want
So, in general, if you're trying to get an LLM to do what you want it to do, sometimes it's just not possible to get it to fully do what you want it to do. But to start, you might ask yourself three questions, which is, one, do you use the best model or the best model for your use case? And if not, try using a better or more recent model, because they really can vary a lot. In the prompt, did you really clearly explain what you want the model to do?
And into this process, is very similar in many ways to explaining how to do something to another person or documenting a process. And so you can kind of evaluate if you clearly explained, in much the same way as you would evaluate if you clearly explained to another person.
And then the third question is, did you provide examples of what you want? Generally, it's very helpful to add examples into the system prompt.
Okay, if you've done those three things and it is still not doing what you want, you might need to look into something else or it might not be really possible to get it to perform as you want it to do. Okay, but these, if you answer these three questions, you've done these three things, that can really help a lot and take care of a lot of the sort of model misbehaving that people often see.
Okay, and you might ask, like, what you should put in the system prompt versus the user prompt, meaning, like, the prompt that you're sending to the model, you know, each time you send a request. And the short answer is that if you have any instructions or background knowledge, put that in the system prompt. This is going to be something that guides the entire conversation, and so you want to put that in the system prompt. You don't have to send it each time.
Okay, a couple other tips. You can use LLMs to help you draft or improve your prompts. Cloud is a prompt generator. This can generally be helpful if you're new to prompt writing. Structure is also really helpful. Again, this is not that different from, you know, writing a set of instructions for another person. So you can use markdown headings or XML tags to give structure to your prompts. You can also use variables to insert dynamic content into your prompt. So, for example, like, if you have content in another file where that file is changing or you want to conditionally read something, you can use variables. You do need to be aware of something called prompt injection, which is where you could insert malicious information into a prompt, get the LLM to do stuff you don't want. In general, you want to make sure you're doing this with files that you trust and have, you know, verified do not have anything malicious in them. And you often generally need to be aware of what files your LLM has access to.
Okay. A couple other tips. Like I said, generally you want to get prompts out of your code and into separate files. This is easier for you to read. It's easier to read diffs if you're using version control. It's easier to organize. It might not make that much difference with the LLM, but it's going to make a difference for you as the person and anyone you're collaborating with.
It can also be really helpful to force the model to say things out loud. We're going to talk about tool calling in a bit, but you might only want it to do three rounds of that. And if you force it to say that out loud to itself or to add it in a memo to itself, it's sort of like its internal monologue, it can help it actually obey the rules that you're telling it to obey. On the ellmer website, there's a vignette about prompt design. And this is really helpful if you're thinking about running prompt. So, I encourage you to take a look at that.
Tool calling
Okay. Any questions about prompt writing? Cool. So, now we're going to talk about tool calling.
And we just saw how to add knowledge with prompting. And so, now we're going to talk about how to add abilities with tools. And this is another way to make LLMs useful for you. So, prompting is generally for adding knowledge. Tools are for adding abilities that LLMs don't have out of the box. So, before we talk about tool calling, we're going to take a look at how LLMs actually work and clarify what they actually can and can't do because it can be a little confusing.
So, on their own, do you think LLMs can access the internet, run code, or send an email? We can try it out. Here's a chat where we're just asking Claude Haiku what the weather is like. I think the implication is that right now in San Francisco.
And we're going to get a response where it basically says, I don't have access to that, and I can't tell you. And that's because LLMs don't actually have access to real time data. They don't have a built in internet connection. They were trained up until a particular date, and that is the boundary of their knowledge. And anything past that, they don't know about.
And what about doing something to affect the world, like writing a file to your computer? So, what if we ask it to write a data frame to a CSV file? Again, it's going to say, I can't really do that. Because LLMs can't affect the world. They can't change your environment or any environment. And at this point, you might be thinking, like, this can't possibly be true. I know that these things can do it. I'm told they can do everything for me. And you're saying they can't even tell me the current weather. And the distinction is that on their own, LLMs cannot do this. But they can if you give them the right tools. So, we're going to see how to do that with ellmer.
And the distinction is that on their own, LLMs cannot do this. But they can if you give them the right tools.
A tool is essentially a function and metadata. And if you've ever written in R function and then documented it, this is basically the same thing. If you've written in R function and written documentation, you can write a tool. It's basically the same process, just with an LLM as the intended audience instead of another person.
Okay. So, we can use tools to do things like bring real time or up-to-date information to the model or let the model interact with the world. So, we're going to see how to implement tools in R with ellmer.
I'm going to go over this at a high level, and then we'll take a closer look at the specifics of how to do this. So, the first step is just to write or find an R function that carries out your desired functionality. So, let's say we want to make a tool so that the LLM can access information about the current weather. We can write a function get weather. We would have some code in there that returns the weather for latitude and longitude. And then the second step is to document that function for the LLM. In ellmer, you do this with the tool function, and we pass it the name of the function. And again, like documentation, this is you're annotating the function for the model. We're giving it a description, and we'll give it the arguments. I'm going to show you the exact code in a bit. This is just at a high level what's happening. You write a function, you document it for the LLM. And then the third step is to register the tool. This tells your chat object about the tool so the LLM knows it exists and can request to use it when it thinks it is required.
Okay. So, let's take a look in a little bit more detail. So, again, the first step is to create a function that does our desired functionality. This function is a little silly because we're just wrapping an existing function, but I wanted to show you how this would work. So, we're going to use the weather package to get a forecast for a lat and long. Then we annotate it with the ellmer function tool. So, we pass it the function, a description, just what it does, and the arguments. You might recognize these type functions from when we talked about structured output. These are the same functions. We're giving a type for each argument so the LLM knows exactly what to do when it requests that the tool be run. Okay. And then, finally, we register it. And, again, this is telling the model that the tool exists and it's available for use.
This is just that simplified a little bit. Like I said, that code was a little bit weird because we wrapped an existing function. If you want to use a function that already exists, you don't have to do that. You can just do what I did here and do an inline anonymous function, but you don't need to worry about this if that sounds complicated. But let's try it. So, I've registered the tool. The chat object knows about it. Now when we ask what the weather is like right now, it is going to actually give us a useful response. So, let's go through this. Notice that it has this tool call at the start. So, we know that it did a tool call. It called get weather with a lat and long. The weather API returned weather information to the LLM. And then the model was able to incorporate that information into its response. So, we just gave the model a new ability.
And again, we're reusing these type functions that we saw earlier to specify the type for each argument. And these functions specify object types in a way that it's easy for the LLM to understand, which is why we keep using these and they're in ellmer. And so, you just choose the type for your argument. And there are type functions for all of the types. And you can see the full list on the ellmer website.
How tool calling works under the hood
Okay. So, we saw how this works in R. But let's talk a little bit about how it actually works. So, again, as we keep seeing, you have a conversation. You send a message as the user to the LLM. And let's say we're, again, asking about the weather. And let's say that the LLM has access to our weather tool already. It knows that it does not have access to realtime weather data. And it knows it has access to the tool. So, it is going to choose to request that it be called. So, it decides to use the weather tool. And it specifies the code to run.
But one of the, like, main things to know about tool calling is that the LLM itself is not running the code. When we register a tool with ellmer and chat and the LLM calls it, that's running in your own R session. The tool, like, it's essentially like you ran it, you know, in your console or something. But the LLM has requested that it be run. The code doesn't run, you know, in the cloud or on Anthropic servers or something. Okay. So, the LLM specifies which code to run. So, it's saying it gives a particular latitude and longitude that it knows from its knowledge base.
ellmer takes that tool call request, actually executes it in your R session, querying the weather API. The weather API sends back some data. That goes to the LLM. And then it's able to incorporate that in its response. Again, ellmer is taking care of all of this communication for you. So, you don't really even see that this happens because it's handling it all under the hood.
ellmer takes that tool call request, actually executes it in your R session, querying the weather API. The weather API sends back some data. That goes to the LLM. And then it's able to incorporate that in its response. Again, ellmer is taking care of all of this communication for you. So, you don't really even see that this happens because it's handling it all under the hood.
Okay. So, again, the LLM cannot run code by itself. It just requests that tools be run. If when for these exercises, the code is being the tool code is being run in your session in the instruct environment, it's not being run in the LLM itself because they can't run code.
And instead, the LLM has control over two things. When the tool is called. So, it has the ability to understand, you know, the user is asking for the weather. I'm going to use the weather tool and pick between tools if it has the option. So, it controls when the tool is called as well as how the tool is called. And this mainly means which arguments it's passing in.
And so, this is really sort of like the power behind tool calling is that it can do those two things pretty well. So, again, the LLM is choosing these arguments. I didn't tell it the latitude and longitude for San Francisco. It has that knowledge already and it's able to pass it in. If our function had more arguments, like a time, it would also be able to use its knowledge and knowledge of what the user is requesting to pick the right arguments.
Okay. If you already have a function and it is documented, so this might be, you know, a function from a package or built in or one that you've created and documented yourself, you can use the ellmer helper function create tool def which will spit out this tool definition for you so you don't have to type all of that. And even if it's just a starting point, this can be really helpful.
Exercise six: tool calling with health data
So, now you're going to try tool calling yourself. So, there's some health expenditure data in your folder. So, your job is to write a get country spending function that takes a country name and a year and returns health spending by purpose. There's some code started already for you in there. And then you're going to wrap it as a tool and register it like we saw and then try it out by asking the model about spending for a specific country.
If anyone's logging back into instruct and they get a request for email verification, if you can take a screenshot of that and put it into the chat, I could take that. That'd be useful for me. That's a new behavior. To be honest, it sounds like instruct is dealing with some sort of attack. I feel like we're stress testing instruct or something.
I can run all the code locally, but it'll take me a minute to get this set up. It didn't work when I entered the code and also the workbench instances. Or it's working, but I would have to reinstall the packages.
So, what we'll do is, for those of you who were able to run the code, do you have, does anyone have any questions or get stuck? I realize that this is mostly, you know, you trying to get instruct to work. But we can, I'm going to keep going here, and then if we get an environment that is set up and working for me, at least, I can go back and talk about some of the exercises and show the remaining demo.
Okay. So, these are questions to ask yourself if you were able to get this code to work. So, we can still talk about these sort of abstractly. So, the point of this exercise was to write a tool where the model can specify a year and a country. It gets back a bit of data, and then it's able to incorporate that data into its response. And so, the first question is, does the model have access to the underlying data? And no, it does see the result of the tool call, but it doesn't actually have access to that underlying data frame. Instead, what it's doing is just passing in a country name and a year and then getting a result back. And again, the model is just controlling when to use the tool and what arguments to pass to the function.
And then, I think there is actually a lot that we could do to make this setup better. This is sort of a minimal tool setup. One thing you might do is give the model access to the list of country and years available so it doesn't have to guess and think through how this function could fail and do some just sort of normal function writing to throw errors if that happens. And error messages, just like they're helpful for people, can also be helpful for the algorithm. It is going to see that response. If it requests a tool be run and it gets an error, it's going to see the error message. So, again, a lot of this with tool writing and prompt writing, there is a lot of overlap for doing these things for people and documenting things well, writing code that is easy to use, error messages that make sense, all of that. Those are transferable skills when working with LLMs.
Okay. If you want to give your chat the ability to search the web, ellmer does have built-in web search tools so you don't need to write these from scratch. This is just sort of for your awareness. You can use these built-in web search tools. This is the Cloud one but there's ones for the other providers as well.
What's coming next
Okay. So, we have three sections left. So, up to this point, we've been mostly talking about how to use ellmer to access and program with LLM APIs from R. We're going to shift gears a little bit and first talk about query chat, which is a way to build shiny apps for your data where you can use natural language to query your data and update your app. Then we'll talk about coding agents and then finally we'll talk a little bit about privacy and security with LLMs.
So, what is query chat? So, query chat is another Posit package. It lets you explore tabular data in a shiny app using natural language, meaning you can just chat to ask questions about your
data or update the app. So, instead of writing your own SQL or D player code, you're just asking questions about the data in plain English. I just want to say for this part, you really don't need to know shiny at all. If you're going to make your own query chat app and customize things, you probably need to know a bit about shiny. But for this section, you really don't. We want to show you query chat because we think it is really useful and also a good example of how to make something that uses an LLM that is constrained, takes advantage of what LLMs are, and takes advantage of what LLMs are good at. So, you really just need to know that shiny is packaged for making web apps in R.
Again, query chat, we're going to explore the data with natural language built on top of LLM and shiny and it works with data frames or a database connection if you have it. This is kind of abstract. It's going to be easier to take a look. So, I have, I think someone mentioned this works for them when they ran it. This should work for you to run it yourself if you have instruct working. But this is an example query chat dashboard. So, I'm going to point out a couple things. So, we have a chat in the sidebar here. And this kind of looks like a normal shiny app. We have some value boxes, plots, a map. And then here it's showing us some SQL code. So, if you don't know SQL, this is basically saying take all the columns, everything from the table Airbnb data.
Query chat demo
What query chat is nice for is that you can ask questions about the data in the chat or request that the dashboard be updated to only show a subset of the data. So let's do that second one first.
And first, you pay attention to that the app itself updated. So based on what I said here, it's now only showing superhost listings with more than 100 reviews.
The nice thing is that it shows you the exact SQL that it wrote here and up here. And if we want to see what underlying data was created, we can click table.
So we can do things like that where it's going to filter the data for us and then update everything in the app.
But we can also ask questions generally about our data. So I think if we ask it this, it is not going to update the app, but run a query, get a result, and then give us the answer right in the chat here. elegant and edgy loft has the highest occupancy rate.
Great. So this is really cool. We'll talk a little bit about how it works. So the, again, you can ask a question in natural language, and then the LLM is writing a SQL query. We just have been talking about how tool calling works. And so this is a tool it has access to. And again, it's going to specify what SQL to write, but it's not actually running the code itself. It's in a tool, it requests that tool be run, the tool is run, it gives it back the results. And so because the setup, the LLM is never touching your raw data directly.
Yeah, so again, the LLM isn't executing the query, the database is executing the query, but the LLM is saying which SQL to write based on your question. And then it's giving you back the real filtered data.
And this sort of constrained approach has a variety of benefits. Um, the first is that the database is running the query, and not the LLM or like the LLM running it somewhere else, which means that the numbers are not hallucinated, it's just SQL that's being run, and then the result is being brought back into the chat or into the underlying data.
It's safe, this is query chat is limited to read only query, so it is not going to delete the tables in your database. It's reproducible, you saw that the SQL, you can see the SQL, this can be exported, it can be rerun. And I think these, like if you can make something with an LLM that has these three benefits, that's like you made a great thing with an LLM basically, because all of these three things can often be difficult to get. LLMs are non-deterministic, they can do unsafe things if unlimited, and often the things that they do are non-reproducible, again, because they're, you know, non-deterministic, or they aren't running code to get the answers or something like that.
And I think these, like if you can make something with an LLM that has these three benefits, that's like you made a great thing with an LLM basically, because all of these three things can often be difficult to get.
Okay. So I'm going to show you how to make a really simple query chat app. This is basically the simplest version that you can make. It's just one function from the query chat package, which is query chat app, and then you pass it your data frame. So again, query chat is built on Shiny, but you don't really need to know Shiny to run this code and get a sense of what query chat can do. So you'll run this in just a second.
Okay. And before you take a look at it yourself, let's just take a closer look at how it works under the hood. So again, the LLM, I guess even before this diagram starts, you ask the LLM a question, it takes in that question, and based on what you're saying, devises a SQL query to either answer your question or change the data in a way that will help you answer it, sends that SQL query to the database, database executes the query, and then that updates the underlying data in the app, which is why the tables and the plots and those value boxes all change. If you are familiar with Shiny, what it's doing is updating reactives, and so when it filters it, the data is updated, all of the UI in the app is updated.
Okay. It turns out this is really powerful, and you can do all sorts of things with this format.
Exercise: building a query chat app
Okay. So now hopefully it's your turn. You're going to open the seventh exercise and just fill in that query chat app call. There's not much code to write. Again, this is a really simple function call. It's going to make a really basic query chat app, and instead your job is to just run it and explore the data with natural language and just get a feel for how query chat works, and here's some example questions.
I'm going to make sure this is going to work for you all, too. The documentation says it defaults to open AI, so if you don't have a chat object in there, so, but maybe it sees the key. Okay. I do have a local setup working, so I'll just share that quickly in case you weren't able to do this yourself.
Okay. So this, I think all you need to do is fill in the health expectancy data here, and if you, let's take a look at the documentation. What I was trying to figure out earlier is if you don't specify a client, which is like the chat itself, what it's going to default to, because if it was going to default to open AI, it wasn't going to work for you, because you'll notice here we didn't specify chat anywhere, and I think what is happening is you can pass in a chat object, but it is, or it's going to look for an environment variable that specifies what model to use or defaults to open AI. I think when I have it running locally, it's defaulting to open AI, but it looks either you, either in that environment there's a query chat client set, or it goes down the list and then tries Anthropic. Either way, I'm happy that it works.
So, this is what you should have seen. This is just like the basic query chat app. It's just showing us the data and the SQL query, and again, we can ask questions about the data or have it filter and show us particular rows. You can do a lot more with query chat, and this is just sort of the basics. Earlier, I showed you that Airbnb query chat dashboard where it had plots, so if you want to keep going, you'd need to sort of pull the app out of, like, instead of using this function, actually write the code for the app and then add different elements to your UI, which we'll spend a little bit of time sort of doing in a bit.
Further resources and shiny chat
Okay. If you want to learn more, the query chat website is very helpful. In particular, there's a vignette called build an app, which I think is a good starting point if you have just your query chat app and you want to start writing a custom app, and this is linked at the bottom here. If you use Python, there's also a query chat for Python. Okay. And again, this is built on top of shiny chat. If you want to make just a, you know, shiny app that uses an LLM or has an LLM chat bot in it, you can use shiny chat for that. We didn't talk about this today, just because I didn't want to bring in, like, require shiny knowledge, but same thing with query chat. You can make a really basic chat bot in shiny with shiny chat with pretty little code, but then if you want to make something more complicated, you can extend it further. So, here's the shiny chat website.
Coding agents for data tasks
Okay. So, now we're going to spend a little bit of time talking about using coding agents for data tasks. And the first question we really need to answer is what is an agent?
And at a high level, an agent is an LLM that can execute tools in a loop. So, you now know what a tool is, and so you can kind of conceptualize this. It can, like, execute the tool or it can observe the world, choose a tool, execute a tool, see the result, and act again continuously. At an even more general level, I think an agent is just something that can gather information from its environment, such as what files are in a directory, and it can alter its environment. It has the power to alter the environment, like writing a data set to a file.
And you might have heard about various coding agents. I think they're, like, everywhere now. There are a variety of them. You might have used Cloud Code or Codex, which is OpenAI's general coding agent. You might have something, like, bespoke that your organization made for you or something that lives in the environment where you write your code. There's a variety of agents. Posit has a general purpose coding agent and data analysis agent called Posit Assistant, which is what we're going to try out briefly today. But a lot of the lessons can extend to other ones. So, if you don't have access to a particular agent, a lot of the lessons can be extended to whatever agent you have access to.
Posit Assistant demo
But we're going to use Posit Assistant today, because that's what we have access to in the environment. And so, Posit Assistant is a coding assistant. It's built right into RStudio and Positron. And you can use it to help you write code, like R, Python, or Bash code, generally. But you can also use it for data analysis, specifically. I'm going to show you what that looks like in a bit. And it works with R and Python. You can also technically write Bash code.
The nice thing about Posit Assistant is that it has access to your R or Python session. And so, this means it can see the objects in your environment. So, it actually can, like, if you have, you know, a data frame loaded, it can actually access that. And this makes it much more reliable, generally, for working with data and also just a more pleasant experience.
And if you at one point heard about DataBot, which is available in Positron, Posit Assistant is essentially DataBot's successor. And if you heard about Positron Assistant, Posit Assistant is a separate thing, despite their very similar names. The other thing I just want to add is that Posit Assistant is relatively new, and we're still making a lot of changes every day.
Okay. I'm just going to show you a demo fast, and then you will should be able to use it. I'll show you locally, just so that it's easy, but it should look very similar for you.
Okay. Great. So, this is my local RStudio, but it should look similar for you.
So, Posit Assistant lives in the sidebar in RStudio, which is sort of a new feature of the IDE, and that's why it's over here on the left-hand side. And we can use Posit Assistant to help with general coding tasks, like I said, or data analysis. So, first thing I'm going to do is just read in some of our data, and you can use the at if you want to reference a particular file. So, I'm going to read this in, ask it if I will allow it, and give me a little bit of a summary. So, one of the things you can do is do data analysis directly in the chat if you have, like, quick questions about the data or in the exploration process. You might eventually want to, you know, move this over into a script or a report or something.
But for now, we can ask it some questions. It's going to write some code for us. It has to install a package. While it does that, I'll point out this thinking text. So, this is, it's using reasoning to, like, think, the model itself is using reasoning to reason through what it wants to say before actually giving you the response. And so, you can expand that there if you want to see its reasoning text. You can also turn that off here.
Interesting. I've never seen it cross something out before. So, yeah, it ran a bit of code. It made some plots. We can now inspect those, ask for changes, or start to get a sense of the data.
So, it plotted total health expenditure by region. So, I think what's driving North America up is mostly the U.S. And so, we could keep going here. You can also ask it to do sort of more general coding questions. So, and it will behave a little bit differently. So, for example, if we asked, like, we haven't done that much with the data, but if we said, you know, can you make a shiny app to display the data? It's going to treat this more like just a coding task, and it's not going to show us a lot of output. It's just going to sort of do it and then create an artifact.
At least that is what it is instructed to do. So, it's building the app and writing it to a file.
And so, I just want to say, like, there's sort of a lot that goes into Posit Assistant, but at the core of it, a lot of the things that you learn today are also used to make something like this. So, it has a bunch of prompting, and it has a bunch of tools. There's other stuff, too. But those sort of basic building blocks can build up to larger things that you might make with LLMs.
And so, it's writing an app file. It's also helpful. Sorry, it opened it in another window, but I can show you later. And you can also ask it to debug, help with any of that kind of stuff.
Okay. So, oh, one other thing I wanted to point out. You'll see this little skill thing here. So, skills are like additional pieces of information for the model. Another way to give it additional context to help it do a good job at what you're trying to use it for. And I'm going to go back to the slides to talk about skills a bit more because you can also write your own skills.
Skills and memory in Posit Assistant
Great. This is the app it made, if you want to see. It's gray because I stopped it from running. We're going to talk about skills first. So skills are like specialized knowledge modules, and they automatically load when they're relevant. So you might have noticed, like I said, I mentioned shiny, and so it loads the shiny skill. You don't have to manually activate them or anything. So Posit Assistant has various built-in skills, including the shiny BSLib one. BSLib is a package for like the Shiny UI, writing Quarto, and there's other ones. But you can also make your own skills, and this is not just for Posit Assistant. If you have like Cloud Code or Codex or anything like that, you can write skills for those agents as well, and this is sort of a general format that you can use across agents. The prompting might be slightly different, but it's a general concept. But for Posit Assistant specifically, you can either make project-level skills like for an entire project or like entire tree of directories, if you do .posit.ai.gils or user-level skills.
Okay. So, we talked about several ways to add context to LLMs or to agents, talked about prompting, tools, now skills. And then the fourth way to like get agents or LLMs to do what you want is with memory. And there's sort of a general memory format that many of these agents use, which is an agents.md file. And this is where you can put stuff that you want to persist across sessions with the agent. So, you might think of sort of like a system prompt, but for the agent. And this is a markdown file, just like the prompts. This is going to store persistent context. So, earlier we said that LLMs don't have memory, and you sort of give them a piece of memory with an agents.md file. And this is going to be loaded at the start of every conversation.
Some things you might want to include are like the structure of your project. If you have sort of a confusing file structure, you want it to know where certain pieces of information are. Coding conventions, like if you have particular conventions that you or your organization uses and you always want to use those. Preferred libraries, et cetera. Extra information about your data, any of that.
Q&A: data access, privacy, and model setup
Okay, so one of the questions about how much access this model has to your data, was that about query chat or maybe that was about Posit Assistant? Posit Assistant. Yeah. I'll just, like, for example, query chat does never seize your underlying data, like the underlying table. It could see the result of a query, if you're asking a question like, what's the, which country spent the most on preventative error or something, it's going to see the results of the query, it's not going to see the underlying data.
Posit Assistant, yeah, we're going to talk about coding agents and privacy and, like, the information flow in a little bit, so I'll just save that, but that's, yeah, Garrett's answer is good as well.
Yeah, and it is not, the agents.md is not, there's no rag involved, yeah, it's like appended to the system prompt of the agent itself, and it's going to be there each time you start a conversation.
Yeah, I believe, it's a question about, can you run query chat on the open or local models? Yes, you can use query chat with anything that you could use with ellmer, yeah, so any ellmer chat that you can set up, which you can for any of those models.
Setting up Posit Assistant
Okay, so we're going to try to set this up. I'm realizing that I can't show you the setup because it's not working for me. Is it working? Do you have instruct working, Garrett? Let me check that it's still running. I can also try again. I do have it, but you'll have to guide me through the steps. Oh, yeah, yeah. Do you mind sharing and I can tell you what to do?
All right, so here I am inside of instruct. What should I do next? Oh, sorry. Okay, so you're going to click on Posit Assistant, yeah, right there. And then install trust, yeah, and then I realized we weren't actually in the folder, but this is all our content. And I think because we're not in a project, it would look at the entire thing anyway, and then sign in. Open browser to authorize. You might already be logged in, but click continue anyway.
Okay, so you are already logged in, I'm going to send the login information for everyone else in the chat.
It says my name, but this isn't my account. This is just how we set this up. So when it prompts you to log in, you should be able to use that. And again, like with the keys, this will be shut off after the workshop, but you can use it for 25 more minutes or so.
So once you have that set up, and yeah, feel free to message if it's not working. You're going to use Posit Assistant to extend your query chat app. Again, it's okay if you don't really know Shiny. You're going to try to use Posit Assistant to get what you want from the app.
So there is a longer version of our query chat app in 08positiveassistantapp.r. Yeah, run it first to see if it works. And then after that, you can chat with Posit Assistant to try and just try to add a plot to the query chat app, or whatever you want, but I would recommend adding a plot.
Well, yes, there's a question about specifying a local model for use with Posit Assistant. So at the moment, if you use Posit Assistant in RStudio, you have to go through the Posit AI service, and we currently only have the Cloud models. Like everything in the LLM world, this may change. That is just how it is at the moment.
If you use it in Positron, you can use it with any model you have access to at this time that is either an Anthropic model, Bedrock model, or has an OpenAI API compatible endpoint. So you might be able to use your local model depending on the specifics there, but you can't currently do that in RStudio.
Privacy and security with LLMs
So I have 20 minutes left. I don't think this is going to take all the 20 minutes, so you might have some time for additional questions if you have them. We're going to talk a little bit about privacy and security with LLMs.
Yeah, and people always have a lot of questions about this. I think it's especially important if you're working with protected data, like I imagine a lot of you are. And so, first, we talked about this a little bit, but there's another sort of distinction between model providers and LLMs that I want to draw out. So, again, the provider is the company that hosts the model. The LLM is the actual model that generates responses to your queries.
So, like we keep saying, LLMs are stateless. They have no memory of your prior requests. And this means that the LLM itself, the actual model, is not remembering anything. If you send it your data, it does not remember your data. It doesn't remember your requests. It doesn't have, like, a memory portion of the model that is storing this. At least the core LLM technology does not have this.
The tricky part is that the model provider itself might store your requests or might log them and then store them. And so, the takeaway is that the model, even if the model doesn't remember you, the model provider's servers might. And so, this is where, yeah, data privacy, issues with protected data, all of that can come in.
And so, the takeaway is that the model, even if the model doesn't remember you, the model provider's servers might.
So, I'm going to walk through a flow of where the data goes. You have a conversation. So, again, we see this is sort of what you would see if you're just a user. You send a question. You ask how LMRChat works to the model provider. Like, you're sending it to Anthropic. You don't know what happens there. You send it to Anthropic. Anthropic sends you a response back.
But on Anthropic's side or the model provider's side, it's taking that. It took your request. It sent it to its model. It's routing it to the actual LLM. And, again, it's stateless. No data is stored there. LLM gives a model provider response. The model provider sends it back to you. The nuance is that, again, the model provider might store your data. So, it could store your data and use it for future model training. It could maybe share it with third parties. And it might just store it to have it. And this can vary by provider and by your agreement with your provider.
And so, this, again, changes a little bit when you are using something like a coding agent because there's more inputs that can go into it. Like I said, like Posit Assistant can see your R and Python session. It can also see your console. It can see your files. So, all this is going into Posit Assistant. And so, then the question is, like, what happens? Does that mean, like, you know, Anthropic knows all my files or something like that? Or does Posit know all my files?
So, the flow of information is the same. Again, the LLM doesn't store your data. The model provider might. With Posit Assistant, specifically, if you're using the Posit AI service in an Anthropic model, we have a ZDR, a zero data retention agreement with them, which means they're never going to store. They don't store your data. And the only reason that Posit would store your data is if you're using Posit AI, like you bought Posit AI service and you opted in. If those things aren't true, your data would not be stored.
And we're talking, I'm talking specifically about Posit Assistant here, but there might be something similar with whatever coding agent you have and whatever model provider you might have. But I think the main takeaway is that the LLM doesn't store your data, but the model provider might, and you should know what your model provider is doing with your data.
And so, because of that, you, or more likely your organization, needs to trust your model provider, and that trust might be formed by a formal agreement that you have with the model provider. Because you need to know, or your organization at least, needs to know what your model provider does with your data.
And just to clarify, like ellmer, QueryChat, ShinyChat, any of those packages, they will never store your data anywhere. They just pass the request onto the model provider. And, again, Posit Assistant would only store your data if Posit's your model provider and you've opted in.
Okay, so I feel like this sounds bad, or like, you know, how can you develop this trust relationship? The good news is that this is actually relatively easy for organizations to do. ZDRs or HIPAA-compliant agreements or other arrangements, depending on the level of protection you need for your data, are pretty common with model providers now. And this would be something that your organization, like your compliance team or something, would probably work out with the model provider, like not you as an individual. And then they would tell you what agreement you have in place, what data you can use with the models, all of that.
Wrapping up
So now we're going to wrap up. I can answer more questions about that if you have it. But here's a series of Posit packages for working with LLMs. We mostly talked about ellmer today. That's sort of the core LLM API package in R that many of these build on, but there are others for different use cases. We mentioned Vitals, which is for evaluations. Ragnars for doing RAG from R. Chatless is basically ellmer and Python, and there are many others.
Yeah, so thank you. That was all the material I had. I'm happy to answer questions for the last 10 minutes. Thank you especially for bearing with us through some of the technical difficulties. I appreciate your patience, and I'm glad we got something working. Thank you, Garrett, for getting everything working.
Garrett, there's a question about when your workshop is. I believe it will be the afternoon of June 11th. We will be advertising that later this week at the conference some more, but it will be on June 11th, and the time will be 12 p.m. to 3 p.m. Eastern time, Eastern U.S. time, so whatever your time zone is. But we will be advertising that throughout the conference so that you'll be able to write it down.
And I think that will be a great follow-up to what everyone learned today, so I hope folks can make it. This one was more about assembling your own AI tools by programming with ellmer. That one will be about using the AI as it is to do data science work.
There's a question about if Posit Assistant has access to objects between sessions or is the session memory cleared every time? Yeah, it only has access to the active session. So if you restart your session, it's not going to have a memory of an object that existed before or be able to access that object. Sort of similar to how, like, you're running code in the console. If you restart your R session, those objects from before are gone.
Okay. Does it have an easy way to store the code that it has created? Yes. I meant to show this. I'll put this in the chat. But Posit Assistant also has slash commands. So one of these is report. And this will make a Quarto report or a Jupyter notebook from your analysis. So if you want to move what you've done in the chat into a report, you can use that. You can also just ask it, like, if you wanted to put in a script, you could ask it to write something to a script. Yeah, in general, like, the chat is very ephemeral. Like, you can see your past conversations. But if you want, you know, code to share, reproduce, you probably want to move it into some kind of artifact, definitely.
Oh, I see. Is Posit Assistant optimized to write good R code? Yes. There is a lot of prompting about writing good R code or, like, R code according to our preferences, I guess, or what we think is useful for data tasks. And then also it has various skills that it can load if they're relevant to the task that helps it write even better R or Python code.
Oh, the optimized for R code programming? Yes. I think they have prompting for R. Yeah. I don't — I work on Posit Assistant. Positron Assistant is a different team. But I think they have custom prompting for writing R, definitely.
I'm just trying to understand the difference between these two in terms of what the abilities are. Yeah. It's confusing, especially if you've been using Positron. Posit Assistant is a successor to Data Bot, which was like a data exploratory data analysis agent in Positron. Whereas Positron Assistant was, like, just for coding. And I think, like, as an organization, we sort of moved behind the Data Bot approach instead of the Positron Assistant approach. Positron Assistant is essentially built on top of Copilot. And so it sort of had to use the structure and philosophy of that.
And so a lot of the differences are, like, in how it is built and how it behaves. Posit Assistant is more agentic or, like, it does more things on its own. With your input than Positron Assistant, generally. And then there's some, like, under-the-hood design things. And the UI is different.
Sorry, I keep asking these questions. Which skills MD files? So you mentioned that the tools that you just got done showing, there's skills files for them. I teach. And so I'm curious to see what you've worked into the skills, to see how that compares to the skills files I'm building for cloud code for my students. Yeah. So Posit Assistant itself isn't open source. So I can't directly share the skills with you. But we do have a collection of open source skills here that you can, like, add to any of your coding agent. Or you can just look at them if you want. But you can also add them to any coding agent you want. And there's instructions on how to do that in the readme.
I don't believe it would, but neither sir and I are really like an IT sysadmin sort of person. No worries. It was just sometimes like some of the researchers here at our school, they tend to have a lot of fun with containers and I say fun in a sarcastic way. But I was just curious if I if anyone has any experience or has seen anything in that way. So no worries. Thank you so much. Jared, I do know some of our customers also like to like to have fun with containers and they still use these tools. So I anticipate a good experience.
Great. I think that was all the questions. Yeah, I don't see anything else in there. So unless there's something else, I think we can wrap up. Okay. Thanks. You probably have to go let your cortisol levels drop from all the technical issues you dealt with very gracefully today. So thank you for persisting through all of the issues that come with these live demos plus AI plus third party vendors that are out of your control. This was really great.
Yeah. Yeah. Thanks. Thank you very much. Thanks for setting up the presenters worst nightmare. It was okay. That was a one workshop years ago and there was no Wi-Fi. That's worse. Yes. Well, okay. I'm glad we're not your worst then. And yeah, I mean, personally, I had a great user experience. I learned a lot and was able to end up executing everything.
Yeah. Yeah. Thank you all for making it work. Yeah. I put my email somewhere. Feel free to reach out with any more questions. I'm happy to talk more. Great. Great. Thank you. And to everyone else. We'll see you back at 11 Eastern tomorrow morning for the start of first day of regular talks. Thanks. Yeah. Thanks. Bye.
