[{"data":1,"prerenderedAt":352},["ShallowReactive",2],{"blueprint-\u002Fblueprints\u002Fai\u002Frag-chat-agent":3},{"id":4,"title":5,"author":6,"blueprintId":7,"body":8,"description":341,"extension":342,"image":163,"meta":343,"navigation":18,"path":344,"seo":345,"stem":346,"tags":347,"updated":350,"__hash__":351},"blueprints\u002Fblueprints\u002Fai\u002Frag-chat-agent.md","OpenAI RAG Chat Agent",null,"Ma2NDMm5JE",{"type":9,"value":10,"toc":313},"minimark",[11,19,22,25,47,52,57,74,95,99,102,106,109,117,121,145,149,152,156,166,171,178,181,185,192,195,198,202,210,214,220,228,238,242,245,261,265,268,272,275,285,289,292,301,305],[12,13,14],"p",{},[15,16],"video",{"src":17,"controls":18},"https:\u002F\u002Fwebsite-data.s3.eu-west-1.amazonaws.com\u002FBlueprint+-+Open+AI+RAG.mp4",true,[12,20,21],{},"Train your own LLM Agents by parsing text-based content with Node-RED, and feeding it to an OpenAI Agent in a Retrieval Augmented Generation (RAG) workflow.",[12,23,24],{},"This Blueprint contains two example flows:",[26,27,28,36],"ol",{},[29,30,31,35],"li",{},[32,33,34],"strong",{},"Text-Based Source Material:"," We chunk and store hardcoded text into Node-RED's flow context store, and use it to train an OpenAI Agent, enabling natural language querying on it's content.",[29,37,38,41,42,46],{},[32,39,40],{},"Website Scraping:"," We scrape a website, using it's ",[43,44,45],"code",{},"sitemap.xml"," to find all the pages to scrape, and then use the content to train an OpenAI Agent, enabling natural language querying on it's content.",[48,49,51],"h2",{"id":50},"prerequisites","Prerequisites",[53,54,56],"h3",{"id":55},"openai-api-key","OpenAI API Key",[12,58,59,60,67,68,73],{},"This Blueprint uses ",[61,62,66],"a",{"href":63,"rel":64},"https:\u002F\u002Fplatform.openai.com\u002Fdocs\u002Foverview",[65],"nofollow","OpenAI"," to run and train an LLM. An OpenAI API key is required to use the OpenAI agent. To get an API key, you can sign up to OpenAI and create a new API key ",[61,69,72],{"href":70,"rel":71},"https:\u002F\u002Fplatform.openai.com\u002Fapi-keys",[65],"here",".",[12,75,76,77,80,81,84,85,84,88,91,92,94],{},"Once you have an API key, set an environment variable called ",[43,78,79],{},"OPENAI_API_KEY"," with your API key. To do this in FlowFuse, you can go to ",[43,82,83],{},"Instance"," > ",[43,86,87],{},"Settings",[43,89,90],{},"Environment Variables",", and add a new variable with the name ",[43,93,79],{}," and the value of your API key.",[48,96,98],{"id":97},"how-rag-works","How RAG Works",[12,100,101],{},"Retrieval Augmented Generation (RAG) is a technique that allows you to use external data sources to provide context to your LLM Agents, such that the information provided can be used when responding to user queries.",[53,103,105],{"id":104},"loading-content","Loading Content",[12,107,108],{},"In order for the LLM to be aware of the external data, we need to parse and store our own data. This is done by:",[26,110,111,114],{},[29,112,113],{},"Parsing the text-based content into \"chunks\", i.e. smaller pieces of information that are easier to digest in their own right.",[29,115,116],{},"Saving the chunks to a vector database, which is a database that stores the chunks in a way that allows us to retrieve them later. In Node-RED, we can use the Node-RED flow context store.",[53,118,120],{"id":119},"handling-user-queries","Handling User Queries",[26,122,123,136],{},[29,124,125,126,132,133,73],{},"When receiving a query, we ",[127,128,129],"em",{},[32,130,131],{},"retrieve"," relevant chunks from the vector database, which we call our ",[127,134,135],{},"\"context\"",[29,137,138,139,144],{},"This context is then provided, along with the user's query, to an OpenAI Agent. The agent then ",[127,140,141],{},[32,142,143],{},"generates"," a response, which can then be sent back to the user. Where appropriate, the agent will use the context to help it respond to the user's query.",[48,146,148],{"id":147},"examples","Examples",[12,150,151],{},"The two examples included in this Blueprint are as follows:",[53,153,155],{"id":154},"example-1-text-parsing","Example 1: Text Parsing",[12,157,158,164],{},[159,160],"img",{"alt":161,"dataZoomable":162,"src":163},"Screenshot of the local text example","","\u002Fblueprints\u002Fai\u002Frag-chat-agent\u002Fimages\u002Fscreenshot-local-file.png",[127,165,161],{},[167,168,170],"h4",{"id":169},"ingesting-text","Ingesting Text",[12,172,173,174,177],{},"In this case, we parse a piece of text that is provided in a ",[43,175,176],{},"template"," node. This text could be loaded from a file, or anywhere else, but for this simple example, we have hardcoded it.",[12,179,180],{},"The text is then \"chunked\" into smaller pieces. This is stored into an in-memory vector database, which in this case is the Node-RED flow context store.",[167,182,184],{"id":183},"retrieving-context","Retrieving Context",[12,186,187,188,191],{},"When a user query is received, we retrieve the most relevant chunks from the vector database. This is done by running a ",[43,189,190],{},"similaritySearch"," query on the vector database, which returns the most relevant chunks. These chunks are then provided as \"context\" to the OpenAI Agent, along with the query defined by the user.",[167,193,120],{"id":194},"handling-user-queries-1",[12,196,197],{},"The user's query, along with the generated context is sent to the OpenAI agent. The agent then generates a response, which is then sent back to the user and displayed using the FlowFuse Dashboard chat widget.",[53,199,201],{"id":200},"example-2-website-scraping","Example 2: Website Scraping",[12,203,204,208],{},[159,205],{"alt":206,"dataZoomable":162,"src":207},"Screenshot of the chat interface for the AI agent trained on FlowFuse documentation","\u002Fblueprints\u002Fai\u002Frag-chat-agent\u002Fimages\u002Fscreenshot-flowfuse-docs.png",[127,209,206],{},[167,211,213],{"id":212},"ingesting-website-content","Ingesting Website Content",[12,215,216,217,219],{},"In this example, we scrape a website, using it's ",[43,218,45],{}," to find all the pages to scrape. The content of each page is then parsed and stored into an in-memory vector database, which in this case is the Node-RED flow context store.",[12,221,222,223,225,226,73],{},"You can type or paste in the URL to the relevant ",[43,224,45],{},", and click \"Load Content\". Alternatively, you can click the Inject node at the start of the Node-RED flow to automatically load FlowFuse's ",[43,227,45],{},[12,229,230,231,233,234,237],{},"Please note that if you do load your own ",[43,232,45],{},", you may need to remove the ",[43,235,236],{},"\u002Fdocs"," filter in the flow, as this is specific to FlowFuse's (or any other site) documentation.",[167,239,241],{"id":240},"handling-questions","Handling Questions",[12,243,244],{},"When a user query is received, the flow logic is as follows:",[246,247,248,255,258],"ul",{},[29,249,250,251,73],{},"Conduct a \"Similarity Search\" on the vector database. This returns the most relevant document chunks from the ingested documentation, in this case the content from ",[61,252,253],{"href":253,"rel":254},"https:\u002F\u002Fflowfuse.com\u002Fdocs",[65],[29,256,257],{},"Provide this context, along with the system prompt and the user's query, to the OpenAI Agent.",[29,259,260],{},"The agent then generates a response, which is sent back to the user and displayed using the FlowFuse Dashboard chat widget.",[48,262,264],{"id":263},"improving-the-agents-performance","Improving the Agent's Performance",[12,266,267],{},"Once you have a lot of documents ingested, you may find your agent's performance lacking in some areas. In this case, there may be some actions you can take to improve the agent's performance.",[53,269,271],{"id":270},"improving-vector-store-retrieval","Improving Vector Store Retrieval",[12,273,274],{},"The vector store retrieval process is a key part of the RAG workflow, as it provides the content to the LLM with which to make a generated response. The more relevant the chunks are to the user's query, the better the agent's response will be.",[12,276,277,278,280,281,284],{},"In this case, we are using the ",[43,279,190],{}," function to retrieve the most relevant chunks from the vector database. A simple experiment could be to increase the number of documents retrieved (e.g. ",[43,282,283],{},"similaritySearch(query, 10)"," would return 10 documents; the default is 4), or to use a different similarity search algorithm. This does however have a knock-on effect on the performance of the agent, as it will take longer to send the relevant chunks to the LLM.",[53,286,288],{"id":287},"alternative-chunking-methods","Alternative Chunking Methods",[12,290,291],{},"We could also improve how documents are put into \"chunks\". This would have a knock-on effect on how the algorithm retrieves the most relevant chunks, providing more relevant context to the LLM will immediately improve performance.",[12,293,294,295,300],{},"Under the covers here we are using LangChain.js, which provides a number of different chunking methods. The Python variant of LangChain provides more advanced alternative methods, such as the ",[61,296,299],{"href":297,"rel":298},"https:\u002F\u002Fpython.langchain.com\u002Fdocs\u002Fhow_to\u002Fsplit_html\u002F#using-htmlsemanticpreservingsplitter",[65],"HTML Semantic Preserving Splitter"," which is designed to split HTML content into manageable chunks while preserving the semantic structure of important elements like tables, lists, and other HTML components.",[48,302,304],{"id":303},"build-on-flowfuse","Build on FlowFuse",[12,306,307,308,312],{},"FlowFuse empowers teams to integrate digital systems with their physical ecosystems, to create and automate workflows through a low-code, end-to-end platform. Get started with this Blueprint (just clicking \"Deploy\" on the right-side), or check out the ",[61,309,311],{"href":253,"rel":310},[65],"FlowFuse documentation"," for more information.",{"title":162,"searchDepth":314,"depth":314,"links":315},4,[316,321,325,336,340],{"id":50,"depth":317,"text":51,"children":318},2,[319],{"id":55,"depth":320,"text":56},3,{"id":97,"depth":317,"text":98,"children":322},[323,324],{"id":104,"depth":320,"text":105},{"id":119,"depth":320,"text":120},{"id":147,"depth":317,"text":148,"children":326},[327,332],{"id":154,"depth":320,"text":155,"children":328},[329,330,331],{"id":169,"depth":314,"text":170},{"id":183,"depth":314,"text":184},{"id":194,"depth":314,"text":120},{"id":200,"depth":320,"text":201,"children":333},[334,335],{"id":212,"depth":314,"text":213},{"id":240,"depth":314,"text":241},{"id":263,"depth":317,"text":264,"children":337},[338,339],{"id":270,"depth":320,"text":271},{"id":287,"depth":320,"text":288},{"id":303,"depth":317,"text":304},"Two examples to show how you can parse text-based content in Node-RED and use it to train an OpenAI Agent in a Retrieval Augmented Generation (RAG) workflow.","md",{},"\u002Fblueprints\u002Fai\u002Frag-chat-agent",{"title":5,"description":341},"blueprints\u002Fai\u002Frag-chat-agent",[348,349],"blueprints","ai","2025-07-22 10:24:12 +0100","ZoDX0wvAXwGNk7AKdl3_6WH7SMugAQ6RwUzZDG2eau8",1789750551316]