<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>Forem: Ken Collins</title>
    <description>The latest articles on Forem by Ken Collins (@metaskills).</description>
    <link>https://forem.com/metaskills</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F410373%2F64169ce5-6358-45f4-ae5e-2ee7e317601d.jpg</url>
      <title>Forem: Ken Collins</title>
      <link>https://forem.com/metaskills</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/metaskills"/>
    <language>en</language>
    <item>
      <title>Multi AI Agent Systems using OpenAI's new GPT-4o Model</title>
      <dc:creator>Ken Collins</dc:creator>
      <pubDate>Sat, 18 May 2024 02:52:12 +0000</pubDate>
      <link>https://forem.com/metaskills/multi-ai-agent-systems-using-openais-new-gpt-4o-model-15gi</link>
      <guid>https://forem.com/metaskills/multi-ai-agent-systems-using-openais-new-gpt-4o-model-15gi</guid>
      <description>&lt;p&gt;A few weeks ago &lt;a href="https://www.unremarkable.ai/consistent-on-brand-artwork-using-ideogram-with-openai-assistants/"&gt;we explored&lt;/a&gt; using OpenAI's new Assistant's API to build a personal creative assistant capable of creating consistent on-brand artwork using Ideogram. Back then I promised we would explore expert-based architectures in a future post... and today is that day. 🥳 &lt;/p&gt;

&lt;p&gt;Two major updates have happened since then. First, the Assistants API now supports &lt;a href="https://x.com/OpenAIDevs/status/1788693943544135864"&gt;vision&lt;/a&gt; 👀 allowing messages in a thread to become truly multi-modal. Second, and the most important, OpenAI finally released a new model, &lt;a href="https://openai.com/index/hello-gpt-4o/"&gt;GPT-4o&lt;/a&gt;. The oh stands for omniscient and the model delivers.&lt;/p&gt;

&lt;h2&gt;
  
  
  Introducing Experts.js
&lt;/h2&gt;

&lt;p&gt;The new Assistants API (still in beta) from OpenAI sets a new industry standard, significantly advancing beyond the widely adopted Chat Completions API. It represents a major leap in the usability of AI agents and the way engineers interact with LLMs. Paired with the cutting-edge GPT-4o model, Assistants can now reference attached files &amp;amp; images as knowledge sources within a managed context window called a &lt;a href="https://github.com/metaskills/experts"&gt;Thread&lt;/a&gt;. Unlike &lt;a href="https://openai.com/index/introducing-gpts/"&gt;Custom GPTs&lt;/a&gt;, Assistants support instructions up to 256,000 characters, integrate with 128 tools, and utilize the innovative &lt;a href="https://platform.openai.com/docs/assistants/tools/file-search/vector-stores"&gt;Vector Store&lt;/a&gt; API for efficient file search on up to 10,000 files per assistant!&lt;/p&gt;

&lt;p&gt;Experts.js aims to simplify the usage of this new API by removing the complexity of managing Run objects and allowing Assistants to be linked together as Tools.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;thread&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;Thread&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;assistant&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;MyAssistant&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;output&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;assistant&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ask&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Say hello.&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;thread&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;output&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;// Hello&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://github.com/metaskills/experts"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhyp6c2hjmw486zh6p3os.png" alt="Experts.js" width="800" height="208"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Experts.js
&lt;/h2&gt;

&lt;p&gt;Please read over the projects documentation on GitHub for a full breakdown on the Expert.js capabilities and options. I think you will find the library small and easy to understand and immediately see the value in using it. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/metaskills/experts"&gt;https://github.com/metaskills/experts&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;However, for our group, I wanted to explore a very real use case for Experts.js. Where a company assistant acts a main router for an entire panel of experts. This sales and router expert has one tool, a merchandising expert. This merchandising tool in turn has its own tool, one capable of searching an OpenSearch vector database. The idea here is that each Assistant owns its domain and context. Why would a company sales assistant need to know (and waste tokens) on how to perform amazing OpenSearch queries. Likewise, being an amazing accounts or order assistant requires context and tools that would likely confuse another. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgd24t3es0kyfzkp01fcz.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgd24t3es0kyfzkp01fcz.png" alt="Multi AI Agent System Example with Company Product Catalog BEFORE" width="800" height="332"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Yet, given this architecture there are some critical flaws that need to be addressed. &lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Data loss moving from left to right. The grapevine effect. See how messages get truncated or reinterpreted? Some of that behavior is good, you want experts to contextualize. However, this is clearly a problem.&lt;/li&gt;
&lt;li&gt;Assistants-only outputs. The typical mental model for most Multi-Agent Systems (MAS) takes the output of one LLM as the input or results to another. See how the Products Tool got all the great aggregate category information? But the main assistant only knows what it was told. If asked a followup question, it would not have the true data to respond. Worse, it may summarize a summary to the user. Also, that Product Tools output is just wasted tokens. &lt;/li&gt;
&lt;li&gt;Some Assistants can leverage many tools and some of those tools should be outputs for their parents context. In this case there was an image created by code interpreter which has no way to make it to the parent company assistant.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fkxcccsfu1cwg9jliejze.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fkxcccsfu1cwg9jliejze.png" alt="Multi AI Agent System Example with Company Product Catalog AFTER" width="800" height="286"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The fix is pretty simple. The Experts.js framework allows for Tools to control their output so we can redirect or pipe all knowledge where it needs to go. The grape vine data loss is an easy fix. Models such as gpt-4o are great at following instructions. A little prompt engineering ensures messages or tool calls have all the context they need.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fze2bqsikcgvd6yovgi7n.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fze2bqsikcgvd6yovgi7n.png" alt="Multi AI Agent System Example with Company Product Catalog Thread Management" width="800" height="134"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Lastly, thread management. By default, each &lt;a href="https://github.com/metaskills/experts#tools"&gt;Tool&lt;/a&gt; in Experts.js has its own thread &amp;amp; context. This avoids a potential &lt;a href="https://platform.openai.com/docs/assistants/how-it-works/thread-locks"&gt;thread locking&lt;/a&gt; issue which happens if a Tool were to share an &lt;a href="https://github.com/metaskills/experts#assistants"&gt;Assistant's&lt;/a&gt; thread still waiting for tool outputs to be submitted. The following diagram illustrates how Experts.js manages threads on your behalf to avoid this problem.&lt;/p&gt;

&lt;p&gt;All questions to your experts require a thread ID. For chat applications, the ID would be stored on the client. Such as a URL path parameter. With Expert.js, no other client-side IDs are needed. As each &lt;a href="https://github.com/metaskills/experts#assistants"&gt;Assistant&lt;/a&gt; calls an LLM backed &lt;a href="https://github.com/metaskills/experts#tools"&gt;Tool&lt;/a&gt;, it will find or create a thread for that tool as needed. Experts.js stores this parent -&amp;gt; child thread relationship for you using OpenAI's &lt;a href="https://platform.openai.com/docs/api-reference/threads/modifyThread"&gt;thread metadata&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Other Multi-Agent Systems (MAS)
&lt;/h2&gt;

&lt;p&gt;A lot of research has been doing in this are and we can expect a lot more in 2024 in this space. I promise to share some clarity around where I think this industry is headed. In personal talks I have warned that multi-agent systems are complex and hard to get right. I've seen little evidence of real-world use cases too. So if you are considering exploring MAS, put your &lt;a href="https://a16z.com/the-future-of-prosumer-the-rise-of-ai-native-workflows/"&gt;prosumer hat on&lt;/a&gt;, roll up your sleeves, and prepare to get hands dirty with Python ☹️ &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.crewai.com"&gt;https://www.crewai.com&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/microsoft/autogen"&gt;https://github.com/microsoft/autogen&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/geekan/MetaGPT"&gt;https://github.com/geekan/MetaGPT&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In my opinion, exploration of multi-agent systems is going to require a broader audience of engineers. For AI to become a true commodity, it needs to move out of the Python origins and into more popular languages like JavaScript 🟨, a major fact on why I wrote Experts.js.&lt;/p&gt;

&lt;p&gt;I very much hope folks enjoy this framework and helps the community at large figure out where and how Multi Agent AI Systems can be effective. 💕&lt;/p&gt;

</description>
      <category>openai</category>
      <category>ai</category>
      <category>javascript</category>
    </item>
    <item>
      <title>Consistent On-Brand Artwork using Ideogram + OpenAI Assistants</title>
      <dc:creator>Ken Collins</dc:creator>
      <pubDate>Fri, 26 Apr 2024 12:07:41 +0000</pubDate>
      <link>https://forem.com/metaskills/consistent-on-brand-artwork-using-ideogram-openai-assistants-55n</link>
      <guid>https://forem.com/metaskills/consistent-on-brand-artwork-using-ideogram-openai-assistants-55n</guid>
      <description>&lt;h2&gt;
  
  
  Better AI Images
&lt;/h2&gt;

&lt;p&gt;Chances are, if you're browsing an article online today, you're looking at an AI-generated image somewhere in that post. These images are typically clichéd and readily recognizable. They often feature a blue hue and depict scenes using robots or futuristic landscapes with brains and glowing cities, reminiscent of science fiction movies or modern cyberpunk themes.Casual analysis of AI related content posts on LinkedIn with a featured image. Of which 70% used an AI-Generated image of which more than half are still using older AI tropes.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fpi39tyhon221vq6cdltu.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fpi39tyhon221vq6cdltu.png" alt="Casual analysis of AI related content posts on LinkedIn with a featured image. Of which 70% used an AI-Generated image of which more than half are still using older AI tropes." width="800" height="520"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwydkmbm6obefq1a5xzi5.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwydkmbm6obefq1a5xzi5.png" alt="A series of 3 cliche AI photos from LinkedIn" width="714" height="140"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Having your brand or content stand out with AI-generated artwork could be a key differentiator. Larger media companies learned this last year when a collaborative group built a platform called &lt;a href="https://betterimagesofai.org/?ref=unremarkable.ai"&gt;Better Images of AI&lt;/a&gt; to promote more engaging representations of AI. Today, our text to image models are way more sophisticated yet some folks may have not put in the work ✨ to get the outputs they need or still stick to older tropes.&lt;/p&gt;

&lt;p&gt;So for today, I'd like to share my latest experiment utilizing a tool called &lt;a href="https://ideogram.ai/?ref=unremarkable.ai"&gt;Ideogram&lt;/a&gt;. They promote themselves as 'Helping People Become More Creative' and indeed, they do deliver on this promise. Especially with images requiring properly spelled and stylized text. This service will become our illustrator agent. Our creative concept artist assistant will be built using OpenAI's latest &lt;a href="https://platform.openai.com/docs/assistants/how-it-works?ref=unremarkable.ai"&gt;Assistants API&lt;/a&gt;. Our goal is to develop an interactive copilot capable of leveraging human feedback and past experiences to seamlessly ideate and execute our creative requirements.&lt;/p&gt;

&lt;h2&gt;
  
  
  Architecture &amp;amp; Process
&lt;/h2&gt;

&lt;p&gt;This post will focus on the agentic architecture of our workflow vs. a technical deep dive into the code or the Assistants API behind it. This API (still in beta) is a foundational shift from their completions APIs which required you to manage all messages &amp;amp; tool calls within a LLM's context window. AKA memory. However, feel free to explore the code on GitHub. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9bt9ydcmj35dujjaqjfw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9bt9ydcmj35dujjaqjfw.png" alt="OpenAI Assistants API with Ideogram Agentic Architecture" width="800" height="329"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Explore the code on GitHub. &lt;a href="https://github.com/metaskills/unremarkable-ideogram-assistant"&gt;https://github.com/metaskills/unremarkable-ideogram-assistant&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Take a moment and zoom into the image, this is not a formal sequence diagram. Each white box (except for the browser tool) represents an LLM-backed Assistant with its own thread. Similar to &lt;a href="https://openai.com/blog/introducing-gpts?ref=unremarkable.ai"&gt;Custom GPTs&lt;/a&gt;, each Assistant can leverage tools such as File Search (retrieval), Code Interpreter, and custom tools (functions). Unlike Custom GPTs, Assistants can leverage Instructions (system prompt) up to 256,000 characters! Simply massive new capabilities y'all.&lt;/p&gt;

&lt;p&gt;Why break this out into multiple assistants? Mainly because I am exploring various &lt;a href="https://towardsdatascience.com/generative-ai-design-patterns-a-comprehensive-guide-41425a40d7d0?ref=unremarkable.ai#fc13"&gt;Panel of Experts&lt;/a&gt; architectures. However, there is a more practical answer here, attention via separation of responsibilities. Consider that both the &lt;strong&gt;Creative&lt;/strong&gt; &amp;amp; &lt;strong&gt;Magic Prompts&lt;/strong&gt; assistants need to embody a role with varying levels of knowledge about the customer. Yet only one needs to know about their brand, color schemes, and elements. All of which are required context to translate brand requirements into 3rd party prompts. That context could easily skew the &lt;strong&gt;Creative&lt;/strong&gt; assistant's capabilities to be abstract or "think outside the box" when creating concepts &amp;amp; illustration instructions.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;We will explore the Assistants API and expert-based architectures in future posts.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Everything else is straightforward, the user interface here is a simple Node.js console session supporting an interactive chat. What might not be obvious is why use a local browser executor? Ideogram, as amazing as they are, still lacks an API. So our agent will display your artwork using a macOS script to open the browser. Since the chat is ongoing, you can provide feedback on any or all Ideogram images. Repeating this cycle for as long as it takes to be happy with your creative. &lt;/p&gt;

&lt;h2&gt;
  
  
  Brand Identity
&lt;/h2&gt;

&lt;p&gt;If you do not already have brand guidelines for your illustration needs, here are a few helpful ways to wrangle them together. The brand guidelines are part of our &lt;strong&gt;Magic Prompts&lt;/strong&gt; assistant's instructions. This is where the assistant turns  concepts &amp;amp; illustration details into on-brand magic prompts. Use descriptive color names that reflect your brand vs. their technical HEX or RGB values. &lt;/p&gt;

&lt;p&gt;Here is a ChatGPT prompt that can help you talk about your brand identity and identify useful guidelines.&lt;/p&gt;

&lt;p&gt;⬆️ PROMPT: Please come up with a plan to help me identify my brand guidelines by asking a series of questions. Using but not limited to, the target audience, brand personality, key messages, and visual style preferences such as color.&lt;/p&gt;

&lt;p&gt;Most wont be needed. Try to stay high level. In the next section we will focus more on the artistic and illustration styles needs.&lt;/p&gt;

&lt;h3&gt;
  
  
  Example
&lt;/h3&gt;

&lt;p&gt;The unRemarkable.ai brand embodies simplicity, catering specifically to AI practitioners rather than focusing on the broader origins of the industry in machine learning or data science. With a basic color palette and a visual style that leverages visual metaphors. Here is a list of things you may need:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Red Sharpie #DF413F&lt;/li&gt;
&lt;li&gt;Yellow Sharpie: #FFC43C&lt;/li&gt;
&lt;li&gt;Hand-drawn with a heavy marker is preferred. &lt;/li&gt;
&lt;li&gt;Avoid paintbrush texture effects.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Brand Illustration Style
&lt;/h2&gt;

&lt;p&gt;We will need a list of detailed illustration styles for your brand to include in our Magic Prompts assistant's instructions. If you are starting from scratch, here is a way you can turn your current artwork or any creative inspiration into descriptive guidelines. I'm going to use &lt;a href="https://www.anthropic.com/?ref=unremarkable.ai"&gt;Anthropic's&lt;/a&gt; artwork as an example.&lt;/p&gt;

&lt;h3&gt;
  
  
  Describe with Ideogram
&lt;/h3&gt;

&lt;p&gt;Earlier this month, Ideogram hit several new milestones. Included was the ability to describe your images. Turning them into details prompts which presumable can be used to generate the same image with Ideogram. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://about.ideogram.ai/1.0-upgrade"&gt;https://about.ideogram.ai/1.0-upgrade&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Let's get a peak into a few of Anthropic's illustrations from their &lt;a href="https://www.anthropic.com/news?ref=unremarkable.ai"&gt;news&lt;/a&gt; posts. I'll feed these into Ideogram, capture their description, then render an image using that description as the prompt.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
  &lt;colgroup&gt;
    &lt;col&gt;
    &lt;col&gt;
    &lt;col&gt;
  &lt;/colgroup&gt;
  &lt;thead&gt;
    &lt;tr&gt;
      &lt;th&gt;Anthropic&lt;/th&gt;
      &lt;th&gt;Ideogram Describe&lt;/th&gt;
      &lt;th&gt;Ideogram&lt;/th&gt;
    &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
    &lt;tr&gt;
      &lt;td&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--uJHPYQt_--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://raw.githubusercontent.com/metaskills/unremarkable-ideogram-assistant/main/public/anthropic-1-rockpile.webp" width="384" height="384"&gt;&lt;/td&gt;
      &lt;td&gt;A &lt;strong&gt;minimalist illustration&lt;/strong&gt; of a hand holding a pink-colored circle. The hand is positioned on the left side of the image, and the circle is being gently held between the thumb and index finger. The background is a soft beige color, and the overall design is simplistic and elegant.&lt;/td&gt;
      &lt;td&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Hcr7EETu--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://raw.githubusercontent.com/metaskills/unremarkable-ideogram-assistant/main/public/anthropic-1-rockpile-ideogram.webp" width="800" height="800"&gt;&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--NaPnbPwQ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://raw.githubusercontent.com/metaskills/unremarkable-ideogram-assistant/main/public/anthropic-2-todolist.webp" width="384" height="384"&gt;&lt;/td&gt;
      &lt;td&gt;A hand holding a clipboard with a checklist. The clipboard is set against a vibrant red background. The checklist contains three squiggly lines, each marked with a check. The hand appears to be in the process of checking off the first line.&lt;/td&gt;
      &lt;td&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--JUCgtSKC--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://raw.githubusercontent.com/metaskills/unremarkable-ideogram-assistant/main/public/anthropic-2-todolist-ideogram.webp" width="800" height="800"&gt;&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--2Fvg43PH--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://raw.githubusercontent.com/metaskills/unremarkable-ideogram-assistant/main/public/anthropic-3-newtonscradle.webp" width="384" height="384"&gt;&lt;/td&gt;
      &lt;td&gt;A &lt;strong&gt;simple, hand-drawn&lt;/strong&gt; depiction of a rectangular frame. Within this frame, there are three white spheres hanging vertically. One of the spheres is distinctly colored in a shade of orange, making it stand out from the others. The frame is set against a plain, light gray background.&lt;/td&gt;
      &lt;td&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s---cxrLhaN--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://raw.githubusercontent.com/metaskills/unremarkable-ideogram-assistant/main/public/anthropic-3-newtonscradle-ideogram.webp" width="800" height="800"&gt;&lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Like most vision-capable LLMs, Ideogram is not capturing the conceptual details  of each object needed to entirely recreate the source image. However, this is really good. Notice how it captured the colors and key descriptions? Also, in two cases it correctly inferred enough of the creative style (highlighted in bold) to just almost capture Anthropic's visual brand. Take notes when you see patterns like these.&lt;/p&gt;

&lt;h3&gt;
  
  
  Describe with GPT-4V
&lt;/h3&gt;

&lt;p&gt;Just like Ideogram, ChatGPT users who have access to GPT-4V, OpenAI's vision model, can upload several images and ask the following.&lt;/p&gt;

&lt;p&gt;⬆️ PROMPT: Classify the artwork style in these images using bullet points.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Minimalist&lt;/strong&gt;: The images employ a very minimal amount of shapes and colors.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Modernist&lt;/strong&gt;: The straightforward depiction with little to no embellishment.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Geometric&lt;/strong&gt;: Use of geometric forms to abstract real-life objects.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Flat&lt;/strong&gt;: The absence of shading or depth and the use of solid colors.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Line Art&lt;/strong&gt;: The artwork relies on the clever use of lines to outline &amp;amp; define.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Instruction's Examples
&lt;/h2&gt;

&lt;p&gt;Both the &lt;strong&gt;Creative&lt;/strong&gt; and &lt;strong&gt;Magic Prompts&lt;/strong&gt; agents are going to need feedback loops, examples of what makes a great concept &amp;amp; illustration or Ideogram prompt. Commonly called few-shot prompting or in-context learning, these help "fine tune"  your agent's behavior over time. Start with the Creative assistant whose job it is to come up with a concept, the creative thinking behind it, and a detailed illustration description.&lt;/p&gt;

&lt;h3&gt;
  
  
  Starting from Scratch
&lt;/h3&gt;

&lt;p&gt;When starting out, it could be helpful to come up with a few examples manually based on styles you like. You can use Ideogram's or GPT-4V's describe capabilities to help you. Focus first on the Creative assistant's concept needs by writing very clear concept names, thinking and illustration descriptions. For example, using Anthropic's first image above.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;*&lt;em&gt;Concept&lt;/em&gt;: A hand removing a stone from the middle of a structured pile.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Thinking&lt;/strong&gt;: Like the puzzle game of Jenga, the hand is grabbing a stone which would cause the ones above it to fall if removed. This illustrates a basic concept of 'Safety' as the stones above could hurt your hand. Or it could illustrate the 'How' of safety and if done wrong could cause negative impacts in other areas.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Illustration Description&lt;/strong&gt;: A haphazardly stacked small pile of circular stones in the shape of a triangular pile. The stones get smaller as they are stacked up 3 or 4 high. The pile consists roughly of 7 to 9 stones of varying sizes. The stone being pulled out has a few others resting on top. An arm extends from the left side with a hand holding onto a stone in the middle of the triangular pile indicating some might fall when it is pulled from the pile.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Capturing good Ideograms
&lt;/h3&gt;

&lt;p&gt;While chatting with the assistant, occasionally an amazing concept and illustration will surface. I'll use this Ideogram illustration I really liked when exploring the subject of a post tag called "Emergent Behavior".&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgh6vtsxs8m0y8qm9aeo2.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgh6vtsxs8m0y8qm9aeo2.png" alt="My unRemarkable.ai Emergent Behavior Ideogram Example" width="800" height="444"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;When I saw the assistant come up with this idea, I captured the relevant bits and added them to the examples in the &lt;strong&gt;Creative&lt;/strong&gt; assistant's instructions. Note how the concept and illustration description are abstract and lack brand context. That's the goal.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Concept&lt;/strong&gt;: Digital Vineyard&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Thinking&lt;/strong&gt;: Depicts data as vine plants spreading across a digital landscape, symbolizing how information grows and intertwines, creating new pathways and connections, much like vines in a vineyard, representing the organic proliferation of digital networks.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Illustration Description&lt;/strong&gt;: This image features two rows of utility poles connected by multiple horizontal wires, with green vines and leaves intertwining with the wires. Glowing orbs representing data are interspersed among the leaves, giving the impression of lights along the wires.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Here is the magic prompt that was created for the creative concept. I added this one along with the concept above to the Magic Prompt assistant's instructions.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Magic Prompt&lt;/strong&gt;: A minimalist and abstract illustration, hand-drawn with bold, heavy strokes in black marker on a yellow background. Wires and poles stretch across the canvas, with vines in dark green carrying glowing data nodes, intertwining and expanding, depicting the organic spread of digital networks.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Using the Creative Assistant
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://github.com/metaskills/unremarkable-ideogram-assistant?ref=unremarkable.ai"&gt;https://github.com/metaskills/unremarkable-ideogram-assistant?ref=unremarkable.ai&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Simply run the npm command in your terminal after to start your creative copilot. Our demo code is written in such a way that any changes to the assistants or their instructions will recreate the underlying OpenAI Assistants so you can get immediate feedback after adding new instructions such as brand guidelines or examples to learn from.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ npm run assistant
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A demonstration of me chatting with my Ideogram assistant for this blog post. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fq7hfxflcp9hgb66mx8gi.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fq7hfxflcp9hgb66mx8gi.png" alt="A screenshot of my unRemarkable.ai Ideogram assistant at work" width="800" height="463"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Tips &amp;amp; Improvements
&lt;/h2&gt;

&lt;p&gt;Overall this is a very iterative process and I'm still learning to to make this assistant work for me using less feedback. Here are some thing I recommend if you are doing something similar.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Look for artistic hints in the prompts generated that work for you. Adding them to your &lt;strong&gt;Magic Prompt&lt;/strong&gt; assistant's instructions as brand guidelines or examples could help future iterations.&lt;/li&gt;
&lt;li&gt;When starting, your Ideogram prompts might not be magic ✨. Try setting Ideograms "Magic Prompt" to on and see if it helps. &lt;/li&gt;
&lt;li&gt;Leverage Ideograms editor to correct spelling mistakes using their remix feature with an 80-90% image weight. &lt;/li&gt;
&lt;li&gt;In our examples we focus on illustrations, this process should work for any creative image type. For example realistic photography.&lt;/li&gt;
&lt;li&gt;Post process with your favorite image editor. Try not to make Ideogram do everything. For example, all my images are color corrected with Pixelmator's replace color feature.&lt;/li&gt;
&lt;li&gt;If you are not on a Mac, feel free to my usage of AppleScript to something else. ⚠️  Ideogram uses MUI and I found it near impossible to automate their UI with JavaScript.&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;I'm certain there are numerous tools available for accomplishing this task, and I encourage you to share your methods in the comments. 💞&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Other Examples
&lt;/h2&gt;

&lt;p&gt;Here are a few Ideograms created by my assistant while working on this post.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdqwrraxsuew8hdz99r8a.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdqwrraxsuew8hdz99r8a.png" alt="Image description" width="713" height="408"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Thanks everyone. Please let me know if you found this useful and I would love to hear from folks that are solving this type of problem with other tools. Remember, to get updates on future posts, you &lt;a href="https://www.unremarkable.ai/#/portal"&gt;can signup for my newsletter&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>openai</category>
      <category>ai</category>
      <category>javascript</category>
    </item>
    <item>
      <title>RAGs To Riches - Part #2 Building On Lambda</title>
      <dc:creator>Ken Collins</dc:creator>
      <pubDate>Tue, 05 Sep 2023 01:10:25 +0000</pubDate>
      <link>https://forem.com/aws-heroes/rags-to-riches-part-2-building-on-lambda-2c9g</link>
      <guid>https://forem.com/aws-heroes/rags-to-riches-part-2-building-on-lambda-2c9g</guid>
      <description>&lt;p&gt;Welcome to the second part of this two-part series on using AWS Lambda to build a retrieval-augmented generation (RAG) application with OpenAI. In this part, we will cover creating a ChatGPT proxy application that you can run locally and explore integration patterns with OpenAI. Please read the first part of this series &lt;a href="https://dev.to/aws-heroes/rags-to-riches-part-1-generative-ai-retrieval-4pd7"&gt;Generative AI &amp;amp; Retrieval&lt;/a&gt; which covers the basics of generative AI and retrieval and the purpose of this demo application.&lt;/p&gt;

&lt;h2&gt;
  
  
  Demo Application
&lt;/h2&gt;

&lt;p&gt;Want to jump right to the end and play around with your new LambdaRAG chat application? Head on over to the GitHub repo (&lt;a href="https://github.com/metaskills/lambda-rag" rel="noopener noreferrer"&gt;https://github.com/metaskills/lambda-rag&lt;/a&gt;), clone or fork it, and follow the instructions in the README. Keep reading if you want to dig into more details of how this application works to retrieve external knowledge and generate responses. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/metaskills/lambda-rag" rel="noopener noreferrer"&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fraw.githubusercontent.com%2Fmetaskills%2Flambda-rag%2Fmain%2Fpublic%2Flambda-rag-start-light.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fraw.githubusercontent.com%2Fmetaskills%2Flambda-rag%2Fmain%2Fpublic%2Flambda-rag-start-light.png" alt="Screenshot of the LambdaRAG Demo application."&gt;&lt;/a&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Technologies Used
&lt;/h2&gt;

&lt;p&gt;This demo application uses a split-stack architecture. Meaning there is a distinct front-end and back-end. The front-end is a &lt;a href="https://vuejs.org/" rel="noopener noreferrer"&gt;💚 Vue.js&lt;/a&gt; application with &lt;a href="https://pinia.vuejs.org" rel="noopener noreferrer"&gt;🍍 Pinia&lt;/a&gt; for state and &lt;a href="https://vitejs.dev/" rel="noopener noreferrer"&gt;⚡️ Vite&lt;/a&gt; for development. The front-end also uses &lt;a href="https://tailwindcss.com/" rel="noopener noreferrer"&gt;🌊 Tailwind CSS&lt;/a&gt; along with &lt;a href="https://daisyui.com" rel="noopener noreferrer"&gt;🌼 daisyUI&lt;/a&gt; for styling. The back-end is a &lt;a href="https://nodejs.org/" rel="noopener noreferrer"&gt;🟨 Node.js&lt;/a&gt; application that uses &lt;a href="https://expressjs.com/" rel="noopener noreferrer"&gt;❎ Express&lt;/a&gt; for the HTTP framework, and &lt;a href="https://github.com/asg017/sqlite-vss" rel="noopener noreferrer"&gt;🪶 SQLite3 VSS&lt;/a&gt; along with &lt;a href="https://github.com/WiseLibs/better-sqlite3" rel="noopener noreferrer"&gt;🏆 better-sqlite3&lt;/a&gt; for vector storage and search. &lt;/p&gt;

&lt;p&gt;Throughout the post we will explore various technologies in more detail and how they help us build a RAG application while learning the basics of AI driven integrations and prompt engineering. This is such a fun space. I hope you enjoy it as much as I do! &lt;/p&gt;

&lt;p&gt;⚠️ DISCLAIMIER: I used ChatGPT to build most of this application. It has been several years since I did any heavy client-side JavaScript. I used this RAG application as an opportunity to learn Vue.js with AI's help.&lt;/p&gt;

&lt;h2&gt;
  
  
  Working Backwards - Why Lambda?
&lt;/h2&gt;

&lt;p&gt;So let's start with the end in mind. Our &lt;a href="https://github.com/metaskills/lambda-rag" rel="noopener noreferrer"&gt;LambdaRAG Demo&lt;/a&gt; runs locally to make it easy to develop and learn. At some point though you may want to ship it to production or share your work with others. So why deploy to Lambda and what benefits does that deployment option offer? A few thoughts:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Lambda makes it easy to deploy &lt;a href="https://docs.aws.amazon.com/lambda/latest/dg/images-create.html" rel="noopener noreferrer"&gt;containerized applications&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Lambda's &lt;a href="https://docs.aws.amazon.com/lambda/latest/dg/lambda-urls.html" rel="noopener noreferrer"&gt;Function URLs&lt;/a&gt; are managed API Gateway reverse proxies.&lt;/li&gt;
&lt;li&gt;The &lt;a href="https://github.com/awslabs/aws-lambda-web-adapter" rel="noopener noreferrer"&gt;Lambda Web Adapter&lt;/a&gt; makes streaming API responses simple.&lt;/li&gt;
&lt;li&gt;Container tools like &lt;a href="https://github.com/rails-lambda/crypteia" rel="noopener noreferrer"&gt;Crypteia&lt;/a&gt; make secure SSM-backed secrets easy.&lt;/li&gt;
&lt;li&gt;Lambda containers allow images up to 10GB in size. Great for an embedded SQLite DB.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Of all of these, I think &lt;a href="https://aws.amazon.com/blogs/compute/introducing-aws-lambda-response-streaming/" rel="noopener noreferrer"&gt;Response Streaming&lt;/a&gt; is the most powerful. A relatively new feature for Lambda, this enables our RAG to stream text back to the web client just like ChatGPT. It also allows Lambda to break the 6MB response payload and 30s timeout limit. These few lines in the project's &lt;code&gt;template.yaml&lt;/code&gt; along with the Lambda Web Adapter make it all possible.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;FunctionUrlConfig&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;AuthType&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;NONE&lt;/span&gt;
  &lt;span class="na"&gt;InvokeMode&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;RESPONSE_STREAM&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Before you run &lt;code&gt;./bin/deploy&lt;/code&gt; for the first time. Make sure you to log into the AWS Console and navigate to &lt;a href="https://docs.aws.amazon.com/systems-manager/latest/userguide/systems-manager-parameter-store.html" rel="noopener noreferrer"&gt;SSM Parameter Store&lt;/a&gt; first. From there create a secret string parameter with the path &lt;code&gt;/lambda-rag/OPENAI_API_KEY&lt;/code&gt; and paste in your OpenAI API key. &lt;/p&gt;

&lt;h2&gt;
  
  
  OpenAI API Basics
&lt;/h2&gt;

&lt;p&gt;Our backend has a very basic &lt;a href="https://github.com/metaskills/lambda-rag/blob/main/src/utils/openai.js" rel="noopener noreferrer"&gt;&lt;code&gt;src/utils/openai.js&lt;/code&gt;&lt;/a&gt; module. This exports an OpenAI client as well as a helper function to create embeddings. We cover &lt;a href="https://platform.openai.com/docs/guides/embeddings" rel="noopener noreferrer"&gt;Embeddings&lt;/a&gt; briefly in the &lt;a href="https://dev.to/aws-heroes/rags-to-riches-part-1-generative-ai-retrieval-4pd7"&gt;Basic Architect&lt;/a&gt; section of the first part of this series. This function simply turns a user's query into a vector embedding which is later queried against our SQLite database. There are numerous ways to create and query embeddings. For now we are going to keep it simple and use OpenAI's &lt;code&gt;text-embedding-ada-002&lt;/code&gt; model which outputs 1536 dimensional embeddings.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;OpenAI&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;openai&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;openai&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;OpenAI&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;apiKey&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;OPENAI_API_KEY&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;createEmbedding&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;query&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;openai&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;embeddings&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;model&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;text-embedding-ada-002&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;input&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;query&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nx"&gt;embedding&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;So how does OpenAI's API work to create a chat interface and how does the &lt;a href="https://dev.to/aws-heroes/rags-to-riches-part-1-generative-ai-retrieval-4pd7"&gt;Context Window&lt;/a&gt; discussed in part one come into play? Consider the following screenshot where I tell LambdaRAG my name and then ask if it remembers.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fraw.githubusercontent.com%2Fmetaskills%2Flambda-rag%2Fmain%2Fpublic%2Flambda-rag-name-light.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fraw.githubusercontent.com%2Fmetaskills%2Flambda-rag%2Fmain%2Fpublic%2Flambda-rag-name-light.png" alt="Screenshot of the LambdaRAG Demo application."&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;ChatGPT is stateless, like most web applications. It has no session for the LLM model. Every time you send a message you have to send all the previous messages (context) to the &lt;a href="https://platform.openai.com/docs/api-reference/completions" rel="noopener noreferrer"&gt;Completions&lt;/a&gt; endpoint. This is why we use &lt;a href="https://pinia.vuejs.org" rel="noopener noreferrer"&gt;🍍 Pinia&lt;/a&gt; for client-side state management. So from an API perspective, it would look something like this below.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;openai&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;chat&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;completions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
 &lt;span class="na"&gt;model&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;gpt-3.5-turbo-16k&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
 &lt;span class="na"&gt;messages&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;role&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;user&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;content&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Hello my name is Ken Collins.&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;role&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;assistant&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;content&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Hello Ken Collins! How can I...&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;role&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;user&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;content&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Do you remember my name?&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
 &lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Did you notice how the assistant responded not only with my name but also knew it was here to help us with Luxury Apparel? This is a technique called &lt;a href="https://learnprompting.org/docs/basics/roles" rel="noopener noreferrer"&gt;Role Prompting&lt;/a&gt;. We do this in the LambdaRAG Demo by prepending this role to the user's first message in the &lt;a href="https://github.com/metaskills/lambda-rag/blob/main/src-frontend/utils/roleprompt.js" rel="noopener noreferrer"&gt;&lt;code&gt;src-frontend/utils/roleprompt.js&lt;/code&gt;&lt;/a&gt; file.&lt;/p&gt;

&lt;p&gt;You may have noticed that the LambdaRAG Demo is written entirely in 💛 JavaScript vs. Python. As you learn more about building AI applications you may eventually have to learn Python as well as more advanced frameworks like &lt;a href="https://js.langchain.com/docs/get_started/introduction/" rel="noopener noreferrer"&gt;🦜️🔗 LangChain&lt;/a&gt; or Hugging Face's &lt;a href="https://huggingface.co/docs/transformers.js/index" rel="noopener noreferrer"&gt;🤗 Transformers.js&lt;/a&gt;. All of which have JavaScript versions. I hope this trend of providing JavaScript clients will continue. It feels like a more accessible language.&lt;/p&gt;

&lt;p&gt;In the next section, we will cover how to create embeddings with your data and query for documents using SQLite's new VSS extension.&lt;/p&gt;

&lt;h2&gt;
  
  
  Proprietary Data &amp;amp; Embeddings
&lt;/h2&gt;

&lt;p&gt;💁‍♂️ The LambdaRAG Demo application contains a ready-to-use SQLite database with ~5,000 products from the &lt;a href="https://www.kaggle.com/datasets/chitwanmanchanda/luxury-apparel-data" rel="noopener noreferrer"&gt;Luxury Apparel Dataset&lt;/a&gt; on Kaggle. It also has vector embeddings pre-seeded and ready to use!&lt;/p&gt;

&lt;p&gt;Before we dig into &lt;a href="https://github.com/asg017/sqlite-vss" rel="noopener noreferrer"&gt;sqlite-vss&lt;/a&gt;, I'd like to explain why I think this extension is so amazing. To date, I have found sqlite-vss the easiest and quickest way to explore vector embeddings. Many GenAI projects use &lt;a href="https://supabase.com" rel="noopener noreferrer"&gt;Supabase&lt;/a&gt; which seems great but is difficult to run locally. The goal here is to learn!&lt;/p&gt;

&lt;p&gt;As your application grows, I highly recommend looking at &lt;a href="https://aws.amazon.com/blogs/big-data/introducing-the-vector-engine-for-amazon-opensearch-serverless-now-in-preview/" rel="noopener noreferrer"&gt;Amazon OpenSearch Serverless&lt;/a&gt;. It is a fully managed, highly scalable, and cost-effective service that supports vector similarity search. It even supports &lt;a href="https://opensearch.org/docs/latest/search-plugins/knn/filter-search-knn/" rel="noopener noreferrer"&gt;pre-filtering with FAISS&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Let's look at &lt;a href="https://github.com/asg017/sqlite-vss" rel="noopener noreferrer"&gt;sqlite-vss&lt;/a&gt; a bit closer. This article &lt;a href="https://observablehq.com/@asg017/introducing-sqlite-vss" rel="noopener noreferrer"&gt;A SQLite Extension for Vector Search&lt;/a&gt; does an amazing job covering the creation of standard tables as well as virtual tables for embeddings and how to query them both. The LambdaRAG Demo follows all these patterns closely in our &lt;a href="https://github.com/metaskills/lambda-rag/blob/main/db/create.js" rel="noopener noreferrer"&gt;&lt;code&gt;db/create.js&lt;/code&gt;&lt;/a&gt; file. Our resulting schema is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;CREATE&lt;/span&gt; &lt;span class="k"&gt;TABLE&lt;/span&gt; &lt;span class="n"&gt;products&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;id&lt;/span&gt; &lt;span class="nb"&gt;INTEGER&lt;/span&gt; &lt;span class="k"&gt;PRIMARY&lt;/span&gt; &lt;span class="k"&gt;KEY&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="nb"&gt;TEXT&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;category&lt;/span&gt; &lt;span class="nb"&gt;TEXT&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;subCategory&lt;/span&gt; &lt;span class="nb"&gt;TEXT&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;description&lt;/span&gt; &lt;span class="nb"&gt;TEXT&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;embedding&lt;/span&gt; &lt;span class="nb"&gt;BLOB&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="k"&gt;CREATE&lt;/span&gt; &lt;span class="k"&gt;TABLE&lt;/span&gt; &lt;span class="n"&gt;IF&lt;/span&gt; &lt;span class="k"&gt;NOT&lt;/span&gt; &lt;span class="k"&gt;EXISTS&lt;/span&gt; &lt;span class="nv"&gt;"vss_products_index"&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;rowid&lt;/span&gt; &lt;span class="nb"&gt;integer&lt;/span&gt; &lt;span class="k"&gt;primary&lt;/span&gt; &lt;span class="k"&gt;key&lt;/span&gt; &lt;span class="n"&gt;autoincrement&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;idx&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="k"&gt;CREATE&lt;/span&gt; &lt;span class="k"&gt;TABLE&lt;/span&gt; &lt;span class="n"&gt;sqlite_sequence&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;seq&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="k"&gt;CREATE&lt;/span&gt; &lt;span class="k"&gt;TABLE&lt;/span&gt; &lt;span class="n"&gt;IF&lt;/span&gt; &lt;span class="k"&gt;NOT&lt;/span&gt; &lt;span class="k"&gt;EXISTS&lt;/span&gt; &lt;span class="nv"&gt;"vss_products_data"&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;rowid&lt;/span&gt; &lt;span class="nb"&gt;integer&lt;/span&gt; &lt;span class="k"&gt;primary&lt;/span&gt; &lt;span class="k"&gt;key&lt;/span&gt; &lt;span class="n"&gt;autoincrement&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="k"&gt;CREATE&lt;/span&gt; &lt;span class="n"&gt;VIRTUAL&lt;/span&gt; &lt;span class="k"&gt;TABLE&lt;/span&gt; &lt;span class="n"&gt;vss_products&lt;/span&gt; &lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="n"&gt;vss0&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;embedding&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1536&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you want to re-create the SQLite database or build a custom dataset, you can do so by changing the &lt;code&gt;db/create.js&lt;/code&gt; and running &lt;code&gt;npm run db:create&lt;/code&gt;. This will drop the existing database and re-create it with data from any CSV file(s), supporting schema, or process you are willing to code up.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; npm run db:create
&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; lambda-rag@1.0.0 db:create
&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;rm&lt;/span&gt; &lt;span class="nt"&gt;-rf&lt;/span&gt; db/lambdarag.db &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; node db/create.js
Using sqlite-vss version: v0.1.1
Inserting product data...
 ██████████████████████████████████░░░░░░ 84% | ETA: 2s | 4242/5001
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Afterward you would need to run the &lt;code&gt;npm run db:embeddings&lt;/code&gt; script which uses the OpenAI API to create embeddings for each product. This takes a few minutes to complete all the API calls. The task includes a local cache to make it faster to re-run. Lastly, there is a &lt;code&gt;npm run db:clean&lt;/code&gt; script that calls a &lt;code&gt;VACUUM&lt;/code&gt; on the DB to remove wasted space for the virtual tables. Again, all of this is only required if you want to re-create the database or build a custom dataset. There is a &lt;code&gt;./bin/setup-db&lt;/code&gt; wrapper script that does all these steps for you.&lt;/p&gt;

&lt;h2&gt;
  
  
  Retrieval with Function Calling
&lt;/h2&gt;

&lt;p&gt;OK, so we have a database of products and their matching vector embeddings to use for semantic search. How do we code up going from chat to retrieving items from the database? OpenAI has this amazing feature named &lt;a href="https://platform.openai.com/docs/guides/gpt/function-calling" rel="noopener noreferrer"&gt;Function Calling&lt;/a&gt;. In our demo, it allows the LLM to search for products and describe the results to you.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fraw.githubusercontent.com%2Fmetaskills%2Flambda-rag%2Fmain%2Fpublic%2Flambda-rag-hats-light.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fraw.githubusercontent.com%2Fmetaskills%2Flambda-rag%2Fmain%2Fpublic%2Flambda-rag-hats-light.png" alt="Screenshot of the LambdaRAG Demo application."&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;But how does it know? You simply describe an &lt;a href="https://github.com/metaskills/lambda-rag/blob/main/src/utils/functions.json" rel="noopener noreferrer"&gt;array of functions&lt;/a&gt; that your application implments and during a chat completion API call. OpenAI will 1) automatically make a determination a function should be called 2) return the name of the function to call along with the needed parameters. Your request looks something like this.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;openai&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;chat&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;completions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;model&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;gpt-3.5-turbo-16k&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;functions&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;[{"search_products":{"parameters": {"query": "string"}}}]&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;messages&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;role&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;user&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;content&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;I need a cool trucker hat.&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If a function has been selected, the response will include the name of the function and parameters. Your responsibility is to check for this, then call your application's code matching the function and parameters. For LambdaGPT, this will be querying the database and returning any matching rows. We do this in our &lt;a href="https://github.com/metaskills/lambda-rag/blob/main/src/models/products.js" rel="noopener noreferrer"&gt;&lt;code&gt;src/models/products.js&lt;/code&gt;&lt;/a&gt; file.&lt;/p&gt;

&lt;p&gt;For OpenAI to respond with the results, we send it another request that now has two additional messages included. The first is of type "function" and includes the name and parameters of the function you were asked to call. The second is of type "user" which includes the JSON data of the products returned from our retrieval process. OpenAI will now respond as if it has this knowledge all along!&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;openai&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;chat&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;completions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;model&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;gpt-3.5-turbo-16k&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;functions&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;[{"search_products":{"parameters": {"query": "string"}}}]&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;messages&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;role&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;user&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;content&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;I need a cool trucker hat.&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;role&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;function&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;search_products&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;content&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;{"query":"trucker hats"}&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;role&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;user&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;content&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;[{"id":3582,"name":"Mens Patagonia Logo Trucker Hat..."}]&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Since all messages are maintained in client-side state, you can see them using a neat debug technique. Open up the &lt;a href="https://github.com/metaskills/lambda-rag/blob/main/src-frontend/components/Message.vue" rel="noopener noreferrer"&gt;&lt;code&gt;src-frontend/components/Message.vue&lt;/code&gt;&lt;/a&gt; file and make the following change.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight diff"&gt;&lt;code&gt;  'border-b-base-300': true,
  'bg-base-200': data.role === 'user',
&lt;span class="gd"&gt;- 'hidden': data.hidden,
&lt;/span&gt;&lt;span class="gi"&gt;+ 'hidden': false,
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can now see all the messages' state in the UI. This is a great way to debug your application and see what is happening. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fraw.githubusercontent.com%2Fmetaskills%2Flambda-rag%2Fmain%2Fpublic%2Flambda-rag-hats-wfun-light.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fraw.githubusercontent.com%2Fmetaskills%2Flambda-rag%2Fmain%2Fpublic%2Flambda-rag-hats-wfun-light.png" alt="Screenshot of the LambdaRAG Demo application."&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  More To Explore
&lt;/h2&gt;

&lt;p&gt;I hope you found this quick overview of how OpenAI's chat completions can be augmented for knowledge retrieval. There is so much more to explore and do. Here are some ideas to get you started:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;All responses are streamed from the server. The &lt;code&gt;fetchResponse&lt;/code&gt; in the &lt;a href="https://github.com/metaskills/lambda-rag/blob/main/src-frontend/stores/messages.js" rel="noopener noreferrer"&gt;&lt;code&gt;src-frontend/stores/messages.js&lt;/code&gt;&lt;/a&gt; Pinia store does all the work here and manages client side state.&lt;/li&gt;
&lt;li&gt;That same file also converts the streaming responses Markdown code into HTML. This is how the demo can build tables just like ChatGPT does.&lt;/li&gt;
&lt;li&gt;Sometimes the keywords passed to the search products function can be sparse. Consider making an API call to extend the keywords of the query using the original message. You can use functions here too!&lt;/li&gt;
&lt;li&gt;Consider adding more retrieval methods to the &lt;a href="https://github.com/metaskills/lambda-rag/blob/main/src/utils/functions.json" rel="noopener noreferrer"&gt;&lt;code&gt;src/utils/functions.json&lt;/code&gt;&lt;/a&gt; file. For example, a &lt;code&gt;find_style&lt;/code&gt; by ID method that would directly query the database.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;❤️ I hope you enjoyed these posts and find the LambdaRAG Demo application useful in learning how to use AI for knowledge retrieval. Feel free to ask questions and share your thoughts on this post. Thank you!&lt;/p&gt;

</description>
      <category>ai</category>
      <category>serverless</category>
      <category>beginners</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>RAGs To Riches - Part #1 Generative AI &amp; Retrieval</title>
      <dc:creator>Ken Collins</dc:creator>
      <pubDate>Mon, 04 Sep 2023 03:30:00 +0000</pubDate>
      <link>https://forem.com/aws-heroes/rags-to-riches-part-1-generative-ai-retrieval-4pd7</link>
      <guid>https://forem.com/aws-heroes/rags-to-riches-part-1-generative-ai-retrieval-4pd7</guid>
      <description>&lt;p&gt;LambdaRAG Demo: &lt;a href="https://github.com/metaskills/lambda-rag" rel="noopener noreferrer"&gt;https://github.com/metaskills/lambda-rag&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Welcome to my two-part series on using AWS Lambda to build a retrieval-augmented generation (RAG) application with OpenAI. In this first part, we will explore the basics of generative AI and retrieval. In the second part, we will build a RAG application using AWS Lambda, Express, and SQLite VSS.&lt;/p&gt;

&lt;h2&gt;
  
  
  Knowledge Navigator
&lt;/h2&gt;

&lt;p&gt;If you have interacted at all this year with OpenAI's &lt;a href="https://openai.com/chatgpt" rel="noopener noreferrer"&gt;💬 ChatGPT&lt;/a&gt; you may think we are closer than ever to &lt;a href="https://www.youtube.com/watch?v=mE2Z30pyw8c" rel="noopener noreferrer"&gt;🎥 Apple's 1987 Knowledge Navigator&lt;/a&gt;. A way to interact with a computer that most of us have only seen in SciFi movies. At first glance today, these language model's knowledge do feel eerily expansive and unlimited. With very little context they can solve interesting problems in highly probabilistic ways.&lt;/p&gt;

&lt;p&gt;Yet for knowledge workers, these models are still very limited in their ability to help us. We have all seen the "As of my last update..." or "I don't have real-time..." messages when asking about current events or within a highly specific domain. It is frustrating to hit these roadblocks for those looking to use data, often proprietary, with our friendly Large Language Models (LLMs). After all, half of the video above is an AI resembling Mark Zuckerberg in a bow tie responding to new data. But how?&lt;/p&gt;

&lt;h2&gt;
  
  
  Retrieval-Augmented Generation (RAG)
&lt;/h2&gt;

&lt;p&gt;Did you know that "GPT" in ChatGPT stands for &lt;a href="https://en.wikipedia.org/wiki/Generative_pre-trained_transformer" rel="noopener noreferrer"&gt;ℹ️ Generative Pre-Trained Transformers&lt;/a&gt;? The key words here are "generative" and "pre-trained". It is easy from these terms to understand that ChatGPT is pre-trained on massive amounts of knowledge and it generates real language responses based on that knowledge. &lt;/p&gt;

&lt;p&gt;A GPT model can learn new knowledge in one of two ways. The first is via model weights on a training set (fine-tuning). The other is via model inputs or inserting knowledge into a context window (retrieval). While fine-tuning may seem like a straightforward method for teaching GPT, it is typically not recommended for factual recall, but rather for &lt;a href="https://www.youtube.com/watch?v=539DTibvZuA" rel="noopener noreferrer"&gt;💩 specialized tasks&lt;/a&gt;. OpenAI has a great cookbook titled &lt;a href="https://github.com/openai/openai-cookbook/blob/main/examples/Question_answering_using_embeddings.ipynb" rel="noopener noreferrer"&gt;📚 Question answering using embeddings-based search&lt;/a&gt; where they make these points on your choices.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
  &lt;thead&gt;
    &lt;tr&gt;
      &lt;th&gt;Fine-Tuning&lt;/th&gt;
      &lt;th&gt;Retrieval&lt;/th&gt;
    &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
    &lt;tr&gt;
      &lt;td&gt;
        As an analogy, model weights are like long-term memory. When you fine-tune a model, it's like studying for an exam a week away. When the exam arrives, the model may forget details, or misremember facts it never read.
      &lt;/td&gt;
      &lt;td&gt;
        In contrast, message inputs are like short-term memory. When you insert knowledge into a message, it's like taking an exam with open notes. With notes in hand, the model is more likely to arrive at correct answers.
      &lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Open book exam? I'm sold. After all, this is how the internet works today. Information is retrieved over many different protocols, locations, and APIs. If you would like to keep exploring this topic I have included some references below on how on retrieval-augmented generation fits into the current market and the opportunities and tools available today.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://ai.meta.com/blog/retrieval-augmented-generation-streamlining-the-creation-of-intelligent-natural-language-processing-models/" rel="noopener noreferrer"&gt;Meta: Retrieval Augmented Generation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://research.ibm.com/blog/retrieval-augmented-generation-RAG" rel="noopener noreferrer"&gt;IBM: What is retrieval-augmented generation?&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://build.microsoft.com/en-US/sessions/038984b3-7c5d-4cc6-b24e-5d9f62bc2f0e?wt.mc_ID=Build2023_esc_corp_em_oo_mto_Marketo_FPnews_Elastic" rel="noopener noreferrer"&gt;Microsoft: Vector Search Isn’t Enough&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.youtube.com/watch?v=dzChvuZI6D4" rel="noopener noreferrer"&gt;YouTube: Retrieval-Augmented Generation (RAG)&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Basic Architecture
&lt;/h2&gt;

&lt;p&gt;Our RAG's architecture with OpenAI is going to follow this diagram. Our demo application described in the next article of this series will only focus on using OpenAI's &lt;a href="https://platform.openai.com/docs/guides/gpt/function-calling" rel="noopener noreferrer"&gt;Function Calling&lt;/a&gt; feature since we are building a stand-alone chat application. If you were building &lt;a href="https://openai.com/blog/chatgpt-plugins" rel="noopener noreferrer"&gt;ChatGPT Plugin&lt;/a&gt;, that is when you would use the &lt;a href="https://platform.openai.com/docs/plugins/getting-started/openapi-definition" rel="noopener noreferrer"&gt;OpenAPI Definition&lt;/a&gt;. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fraw.githubusercontent.com%2Fmetaskills%2Flambda-rag%2Fmain%2Fpublic%2Fai-knowledge-retrieval-light.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fraw.githubusercontent.com%2Fmetaskills%2Flambda-rag%2Fmain%2Fpublic%2Fai-knowledge-retrieval-light.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Our demo will also showcase using &lt;a href="https://observablehq.com/@asg017/introducing-sqlite-vss" rel="noopener noreferrer"&gt;SQLite for Semantic Search&lt;/a&gt; as a fast and easy to use vector database that can store and query our &lt;a href="https://dev.to/dandv/understanding-vector-embeddings-18p0"&gt;Vector Embeddings&lt;/a&gt;. Vector embeddings are numerical representations of complex data like words or images, simplifying high-dimensional data into a lower-dimensional space for easier processing and analysis.&lt;/p&gt;

&lt;p&gt;Lastly we are going to need some proprietary data to use with our RAG. I chose the &lt;a href="https://www.kaggle.com/datasets/chitwanmanchanda/luxury-apparel-data" rel="noopener noreferrer"&gt;Luxury Apparel Dataset&lt;/a&gt; from Kaggle. It contains ~5,000 products with good descriptions and categories to facet.&lt;/p&gt;

&lt;h2&gt;
  
  
  Context Windows
&lt;/h2&gt;

&lt;p&gt;So how much data can we insert into a message when retrieving data? The answer depends on the size of the model's &lt;a href="https://www.hopsworks.ai/dictionary/context-window-for-llms" rel="noopener noreferrer"&gt;Context Window&lt;/a&gt;. This refers to the maximum number of tokens the model can consider as input for generating outputs. There is a growing trend and demand for LLMs with larger context windows. For instance, some previous generation models could only consider 2,000 token inputs, while some more advanced versions can handle up to 32,000 tokens.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fraw.githubusercontent.com%2Fmetaskills%2Flambda-rag%2Fmain%2Fpublic%2Fcontext-window-siccos-light.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fraw.githubusercontent.com%2Fmetaskills%2Flambda-rag%2Fmain%2Fpublic%2Fcontext-window-siccos-light.png" alt="Word Cloud: data, experience, business, analysis, etc. To the left is the Siccos meme of a man pressed up against a window with a word bubble: Yes... Ha ha ha... YES! On the man's shirt says Generative Pre-Trained Models."&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;So is the context window our Moore's Law for LLMs? Some think so. There is even thinking that we get diminishing returns with larger models. While newer Claude models are pushing 100K tokens, some think &lt;a href="https://www.pinecone.io/blog/why-use-retrieval-instead-of-larger-context/" rel="noopener noreferrer"&gt;Less is More&lt;/a&gt; and solid retrieval patterns are the key to good results. We should all keep an eye out as we rapidly explore this area of AI.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>serverless</category>
      <category>beginners</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>💔 Goodbye Cold Starts ❤️Hello Proactive Initialization</title>
      <dc:creator>Ken Collins</dc:creator>
      <pubDate>Sun, 16 Jul 2023 16:29:38 +0000</pubDate>
      <link>https://forem.com/aws-heroes/goodbye-cold-starts-hello-proactive-initialization-28j7</link>
      <guid>https://forem.com/aws-heroes/goodbye-cold-starts-hello-proactive-initialization-28j7</guid>
      <description>&lt;p&gt;&lt;strong&gt;💁 Full Rails &amp;amp; Lambda Details at:&lt;br&gt; &lt;a href="https://lamby.cloud/docs/cold-starts" rel="noopener noreferrer"&gt;https://lamby.cloud/docs/cold-starts&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;As described in &lt;a href="https://twitter.com/astuyve" rel="noopener noreferrer"&gt;AJ Stuyvenberg's&lt;/a&gt; post on the topic &lt;a href="https://aaronstuyvenberg.com/posts/understanding-proactive-initialization" rel="noopener noreferrer"&gt;Understanding AWS Lambda Proactive Initialization&lt;/a&gt;, AWS Lambda may have solved some of your cold start issues for you since March 2023. Stated in an excerpt &lt;a href="https://aaronstuyvenberg.com/posts/understanding-proactive-initialization" rel="noopener noreferrer"&gt;from AWS' docs&lt;/a&gt;:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;For functions using unreserved (on-demand) concurrency, Lambda occasionally pre-initializes execution environments to reduce the number of cold start invocations. For example, Lambda might initialize a new execution environment to replace an execution environment that is about to be shut down. If a pre-initialized execution environment becomes available while Lambda is initializing a new execution environment to process an invocation, Lambda can use the pre-initialized execution environment.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This means the &lt;a href="https://lamby.cloud/docs/cold-starts#monitoring-with-cloudwatch" rel="noopener noreferrer"&gt;Monitoring with CloudWatch&lt;/a&gt; is just half the picture. But how much is your application potentially benefiting from proactive inits? Since &lt;a href="https://github.com/rails-lambda/lamby/pull/169" rel="noopener noreferrer"&gt;Lamby v5.1.0&lt;/a&gt;, you can now find out easily using CloudWatch Metrics. To turn metrics on, enable the config like so:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;lamby&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;cold_start_metrics&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kp"&gt;true&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Lamby will now publish &lt;a href="https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/CloudWatch_Embedded_Metric_Format.html" rel="noopener noreferrer"&gt;CloudWatch Embedded Metrics&lt;/a&gt; in the &lt;code&gt;Lamby&lt;/code&gt; namespace with a custom dimension for each application's name. Captured metrics include counts for Cold Starts vs. Proactive Initializations. Here is an example running sum of 3 days of data for a large Rails application in the &lt;code&gt;us-east-1&lt;/code&gt; region.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Flamby.cloud%2Fimg%2Fdocs%2Flamby-cloud-watch-metrics-cold-start-v-proactive-init-light.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Flamby.cloud%2Fimg%2Fdocs%2Flamby-cloud-watch-metrics-cold-start-v-proactive-init-light.png" alt="A CloudWatch Metrics graph showing a running sum of cold starts vs proactive inits for a large Rails application on Lambda."&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This data shows the vast majority of your initialized Lambda Contaienrs are proactively initialized. Hence, no cold starts are felt by end users or consumers of your function. If you need to customize the name of your Rails application in the CloudWatch Metrics dimension, you can do so using this config.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;lamby&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;metrics_app_name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'MyServiceName'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



</description>
      <category>tailscale</category>
      <category>lambda</category>
      <category>containers</category>
      <category>rails</category>
    </item>
    <item>
      <title>The Elusive Lambda Console; A Specification Proposal.</title>
      <dc:creator>Ken Collins</dc:creator>
      <pubDate>Sat, 17 Jun 2023 20:15:35 +0000</pubDate>
      <link>https://forem.com/aws-heroes/the-elusive-lambda-console-a-specification-proposal-35po</link>
      <guid>https://forem.com/aws-heroes/the-elusive-lambda-console-a-specification-proposal-35po</guid>
      <description>&lt;p&gt;After years of smashing Cloud &amp;amp; Rails together, I've come up with an idea. Better than an idea, a working specification! One where us &lt;a href="https://lamby.cloud" rel="noopener noreferrer"&gt;Rails &amp;amp; Lambda&lt;/a&gt; enthusiasts can once again "console into" our "servers" and execute CLI tasks like migrations or interact via our beloved IRB friend, the Rails console. Today, I would like to present, the &lt;a href="https://github.com/rails-lambda/lambda-console" rel="noopener noreferrer"&gt;Lambda Console&lt;/a&gt; project. An open specification proposal for any AWS Lambda runtime to adopt.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Flamby.cloud%2Fimg%2Fdocs%2Flambda-console-cli-dark.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Flamby.cloud%2Fimg%2Fdocs%2Flambda-console-cli-dark.png" alt="Lambda Console CLI Screenshot"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Lambda Console
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-g&lt;/span&gt; lambda-console-cli
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The Lambda Console is a CLI written in Node.js that will interactively create an AWS SDK session for you to invoke your Lambda functions with two types of modes. &lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;CLI Runner&lt;/li&gt;
&lt;li&gt;Interactive Commands&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Think of the CLI Runner as a bash prompt. You can run any process command or interact with the filesystem or environment. For Rails users, running rake tasks or DB migrations. These tasks assume the Lambda task root as the present working directory.&lt;/p&gt;

&lt;p&gt;Interactive commands however are evaluated in the context of your running application. For Ruby and Rails applications, this simulates IRB (Interactive Ruby Shell). For &lt;a href="https://lamby.cloud" rel="noopener noreferrer"&gt;Lamby&lt;/a&gt; users, this mode simulates the Rails console. Making it easy for users to query their DB or poke their models and code.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Proposal
&lt;/h2&gt;

&lt;p&gt;There is nothing about the &lt;a href="https://github.com/rails-lambda/lambda-console" rel="noopener noreferrer"&gt;Lambda Console&lt;/a&gt; that is coupled to Ruby or Rails. The idea is simple, as a Lambda community, could we do the following?&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Finalize a Lambda Console request/response specification.&lt;/li&gt;
&lt;li&gt;Create more runtime-specific language implementations.&lt;/li&gt;
&lt;li&gt;Build an amazing CLI client for any runtime.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Here is what we have today. The request specification, a simple &lt;a href="https://github.com/rails-lambda/lambda-console#event-structure" rel="noopener noreferrer"&gt;event structure&lt;/a&gt; that is only a few dozen lines of JSON schema.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"X_LAMBDA_CONSOLE"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"run"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"cat /etc/os-release"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"X_LAMBDA_CONSOLE"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"interact"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"User.find(1)"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Any Lambda runtime code or framework could implement the handling of these event in their own language-specific pakages. You can find the Ruby implementation of these in the Lambda Console's first reference implementations.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Ruby: The &lt;a href="https://github.com/rails-lambda/lambda-console-ruby" rel="noopener noreferrer"&gt;lambda-console-ruby&lt;/a&gt; gem for any Ruby Lambda.&lt;/li&gt;
&lt;li&gt;Rails: Integrated into the &lt;a href="https://github.com/rails-lambda/lamby" rel="noopener noreferrer"&gt;Lamby&lt;/a&gt; v5.0.0 for Rails on Lambda.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  The Possibilities
&lt;/h2&gt;

&lt;p&gt;What I really want is an amazing CLI client. The current Lambda Console CLI was hacked together in a few days using some amazing Node.js tools that make building interactive CLIs so so easy. But I've never done this before. If this type of tooling sounds interesting to you and you like Node.js, let me know! It would be amazing to see implementation packages for these for Node, PHP, Python, and other frameworks using these languages. Here are some ideas on where I could see this going.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Live STDOUT &amp;amp; STDERR:&lt;/strong&gt; We could take advantage of Lambda's new &lt;a href="https://aws.amazon.com/blogs/compute/introducing-aws-lambda-response-streaming/" rel="noopener noreferrer"&gt;Response Streaming&lt;/a&gt; and send output buffers as they happen. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Pseudo TTY:&lt;/strong&gt; Is there a way to better simulate a real TTY session? Could this even include ANSI colors?&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Quality of Life Improvements:&lt;/strong&gt; Everything from, Allowing the CLI tool to switch modes without restarting it; Creating a command buffer to up arrow navigate history; Prettier UI. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Formal Response JSON Schema:&lt;/strong&gt; As the features grow, should the response JSON be standardized? For example, if the client wanted to syntax highlight interactive language commands, how would it know what language was being used? We could have a &lt;code&gt;X_LAMBDA_CONSOLE_LANG&lt;/code&gt; response header.&lt;/p&gt;

&lt;p&gt;What else would you like to see in a Lambda Console client?&lt;/p&gt;

</description>
      <category>lambda</category>
      <category>bash</category>
      <category>cli</category>
      <category>ruby</category>
    </item>
    <item>
      <title>Using Tailscale on Lambda for a Live Development Proxy</title>
      <dc:creator>Ken Collins</dc:creator>
      <pubDate>Sat, 03 Jun 2023 11:55:06 +0000</pubDate>
      <link>https://forem.com/aws-heroes/using-tailscale-on-lambda-for-a-live-development-proxy-3hkc</link>
      <guid>https://forem.com/aws-heroes/using-tailscale-on-lambda-for-a-live-development-proxy-3hkc</guid>
      <description>&lt;p&gt;⚠️ DISCLAIMER: In no way am I advocating for the use of live proxies as a normal way to develop against cloud resources. However in some edge cases, such as developing a new system, live dev proxies or the general use of Tailscale in Lambda could be useful.&lt;/p&gt;

&lt;h2&gt;
  
  
  🐋 Tailscale on Lambda
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://tailscale.com"&gt;Tailscale&lt;/a&gt; makes networking easy. Like really easy. It shines in situations where private networks do not allow inbound connections. Tailscale can connect your devices and development environments for easy access to remote resources, or allow those remote systems to access your home or office network devices.&lt;/p&gt;

&lt;p&gt;A few years ago Corey Quinn wrote a Tailscale &lt;a href="https://www.lastweekinaws.com/blog/corey-writes-open-source-code-for-lambda-and-tailscale/"&gt;Lambda Extension&lt;/a&gt;. It is great and helped a lot of folks. Today, I'd like to share a new project based on Corey's work that makes it even easier to use Tailscale in Lambda Container. Check it out here.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;a href="https://github.com/rails-lambda/tailscale-extension"&gt;🔗 Tailscale Lambda Extension for Containers&lt;/a&gt;&lt;/strong&gt; on GitHub 🐙&lt;/p&gt;

&lt;p&gt;This new version tries to improve upon Corey's work. Initialization is now stable, there are more configuration options, and we even have multi-platform Docker container packages for both &lt;code&gt;x86_64&lt;/code&gt; and &lt;code&gt;arm64&lt;/code&gt;. We even have Amazon Linux 2 and Debian/Ubuntu variants. Installation is really easy, simply add one line to your Dockerfile. For example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight docker"&gt;&lt;code&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="s"&gt; public.ecr.aws/lambda/ruby:3.2&lt;/span&gt;
&lt;span class="k"&gt;RUN &lt;/span&gt;yum &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-y&lt;/span&gt; curl
&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; --from=ghcr.io/rails-lambda/tailscale-extension-amzn:1 /opt /opt&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Once your container starts, taking to any device within your tailnet can be done by using the local &lt;a href="https://en.wikipedia.org/wiki/SOCKS"&gt;SOCKS5&lt;/a&gt; proxy. In the example below, we are using Ruby's &lt;a href="https://github.com/astro/socksify-ruby"&gt;socksify&lt;/a&gt; gem.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="nb"&gt;require&lt;/span&gt; &lt;span class="s1"&gt;'socksify/http'&lt;/span&gt;
&lt;span class="no"&gt;Net&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;HTTP&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;socks_proxy&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'localhost'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1055&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;start&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;...&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;
  &lt;span class="c1"&gt;# your http code here...&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  🔌 ActionCable on Lambda
&lt;/h2&gt;

&lt;p&gt;How did I use Tailscale for the &lt;a href="https://lamby.cloud"&gt;Rails on Lambda&lt;/a&gt; work? A few months ago, I &lt;a href="https://twitter.com/metaskills/status/1647714842550185985"&gt;started work&lt;/a&gt; on the last critical part of the Rails ecosystem which did not work on Lambda... &lt;a href="https://guides.rubyonrails.org/action_cable_overview.html"&gt;ActionCable&lt;/a&gt; &amp;amp; WebSockets. Specifically, I wanted &lt;a href="https://hotwired.dev"&gt;Hotwire&lt;/a&gt; to work.&lt;/p&gt;

&lt;p&gt;So far, everything is &lt;a href="https://twitter.com/metaskills/status/1651067256242151424"&gt;working great&lt;/a&gt; with our new LambdaCable gem. Eventually it will be a drop-in adapter for ActionCable and join the ranks of other popular alternatives like &lt;a href="https://anycable.io"&gt;AnyCable&lt;/a&gt;. To bring the project to completion faster, I needed feedback loops that were much faster than deploying code to the cloud. I needed a development proxy! One where my Rails application would receive events from both Lambda's Function URLs and the WebSocket events from API Gateway. Illustrated below with a demo video.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--7U22VKmy--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://lamby.cloud/img/blog/tailscale/live-development-proxy-overview.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--7U22VKmy--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://lamby.cloud/img/blog/tailscale/live-development-proxy-overview.png" alt="Architecture diagram of the use of a Lambda development proxy for WebSockets with API Gateway." width="800" height="459"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/k02k38o4ih8"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;If you are curious to learn more about how Rails &amp;amp; Lambda work together, check out our &lt;a href="https://lamby.cloud"&gt;Lamby&lt;/a&gt; project. The architecture of Lambda Containers works so well with Rails since our framework distills everything from HTTP, Jobs, Events, &amp;amp; WebSocket connections down to Docker's &lt;code&gt;CMD&lt;/code&gt; interface. The architecture above at the proxy layer was easy to build and connect up to our single delegate function, &lt;code&gt;Lamby.cmd&lt;/code&gt;. Shown below:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--4xkSh-j4--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://lamby.cloud/img/blog/tailscale/live-development-proxy-detail.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--4xkSh-j4--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://lamby.cloud/img/blog/tailscale/live-development-proxy-detail.png" alt="Architecture diagram of the use of a Lambda development proxy for WebSockets with API Gateway." width="800" height="144"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;For our Rails application on Lambda, here are the changes we made to leverage this. All outlined in our &lt;a href="https://github.com/rails-lambda/websocket-demo/pull/4"&gt;WebSockets Demo Pull Request&lt;/a&gt;.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Created a &lt;code&gt;.localdev&lt;/code&gt; folder. Added a copy of our SAM template.yaml for all AWS Resources. &lt;/li&gt;
&lt;li&gt;Made a simple &lt;code&gt;.localdev/Dockerfile&lt;/code&gt; that included the Tailscale Extension along with basic proxy code.&lt;/li&gt;
&lt;li&gt;Leveraged Lamby's &lt;a href="https://github.com/rails-lambda/lamby/pull/164"&gt;Local Development Proxy Sever&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Ensured our Devcontainers exposed port 3000 to all local network devices so Tailscale could detect the service.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I hope you find reasons to learn more about Tailscale and how using a SOCKS5 proxy from Lambda could help your development or production needs. More so, I hope you like the new Lambda Extension project of ours making it easy for containerized applications to use. Drop us a comment if you do.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;a href="https://github.com/rails-lambda/tailscale-extension"&gt;🔗 Tailscale Lambda Extension for Containers&lt;/a&gt;&lt;/strong&gt; on GitHub 🐙&lt;/p&gt;

</description>
      <category>tailscale</category>
      <category>lambda</category>
      <category>container</category>
      <category>rails</category>
    </item>
    <item>
      <title>Trigger CircleCI Workflow. AKA Simple Deploy Button</title>
      <dc:creator>Ken Collins</dc:creator>
      <pubDate>Fri, 03 Mar 2023 16:52:17 +0000</pubDate>
      <link>https://forem.com/aws-heroes/trigger-circleci-workflow-aka-simple-deploy-button-3ocl</link>
      <guid>https://forem.com/aws-heroes/trigger-circleci-workflow-aka-simple-deploy-button-3ocl</guid>
      <description>&lt;p&gt;Very simple, no parameters needed, no enums, no booleans... just a really easy way to trigger a deploy with CircleCI. We can do this making use of the &lt;a href="https://circleci.com/docs/variables/#pipeline-values" rel="noopener noreferrer"&gt;trigger_source&lt;/a&gt; pipeline value. When you click the button in CircleCI to "Trigger Pipeline" the value would be &lt;code&gt;api&lt;/code&gt; vs something like &lt;code&gt;webhook&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;2.1&lt;/span&gt;
&lt;span class="na"&gt;jobs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;deploy&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;machine&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ubuntu-2204:current&lt;/span&gt;
    &lt;span class="na"&gt;steps&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;echo 'Deploying...'&lt;/span&gt;
&lt;span class="na"&gt;workflows&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;deploy&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;when&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;{&lt;/span&gt; &lt;span class="nv"&gt;equal&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt; &lt;span class="nv"&gt;api&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;&amp;lt;&amp;lt; pipeline.trigger_source &amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="pi"&gt;]&lt;/span&gt; &lt;span class="pi"&gt;}&lt;/span&gt;
    &lt;span class="na"&gt;jobs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;deploy&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If your workflow needs a test job, consider doing something a bit more complicated. Here we use two &lt;code&gt;when&lt;/code&gt; conditions to work with a parameter.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;2.1&lt;/span&gt;
&lt;span class="na"&gt;parameters&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;workflow&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;enum&lt;/span&gt;
    &lt;span class="na"&gt;default&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;test&lt;/span&gt;
    &lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;The workflow to trigger.&lt;/span&gt;
    &lt;span class="na"&gt;enum&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;test&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;deploy&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
&lt;span class="na"&gt;jobs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;test-job&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;machine&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ubuntu-2204:current&lt;/span&gt;
    &lt;span class="na"&gt;steps&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;echo 'Testing...'&lt;/span&gt;  
  &lt;span class="na"&gt;deploy-job&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;machine&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ubuntu-2204:current&lt;/span&gt;
    &lt;span class="na"&gt;steps&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;echo 'Deploying...'&lt;/span&gt;
&lt;span class="na"&gt;workflows&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;test&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;when&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;{&lt;/span&gt; &lt;span class="nv"&gt;equal&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt; &lt;span class="nv"&gt;test&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;&amp;lt;&amp;lt; pipeline.parameters.workflow &amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="pi"&gt;]&lt;/span&gt; &lt;span class="pi"&gt;}&lt;/span&gt;
    &lt;span class="na"&gt;jobs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;test-job&lt;/span&gt;
  &lt;span class="na"&gt;deploy&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;when&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;{&lt;/span&gt; &lt;span class="nv"&gt;equal&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt; &lt;span class="nv"&gt;deploy&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;&amp;lt;&amp;lt; pipeline.parameters.workflow &amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="pi"&gt;]&lt;/span&gt; &lt;span class="pi"&gt;}&lt;/span&gt;
    &lt;span class="na"&gt;jobs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;deploy-job&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now your CircleCI config will run tests by default and you can easily trigger a deploy via any branch using the "Trigger Pipeline" button.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fr5b23gl0yk10sqpv3hur.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fr5b23gl0yk10sqpv3hur.png" alt="Screen capture of the CircleCI application. This shows the trigger pipeline UI which has the Add Parameter disclosure open. The options Parameter type, Name, and Value have been set to string, workflow, deploy." width="661" height="355"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>frontend</category>
      <category>career</category>
      <category>productivity</category>
      <category>discuss</category>
    </item>
    <item>
      <title>Ruby on Rails on Lambda on Arm64/Graviton2!</title>
      <dc:creator>Ken Collins</dc:creator>
      <pubDate>Sat, 18 Feb 2023 15:40:37 +0000</pubDate>
      <link>https://forem.com/aws-heroes/ruby-on-rails-on-lambda-on-arm64graviton2-154e</link>
      <guid>https://forem.com/aws-heroes/ruby-on-rails-on-lambda-on-arm64graviton2-154e</guid>
      <description>&lt;p&gt;Today I am happy to announce that &lt;a href="https://lamby.custominktech.com" rel="noopener noreferrer"&gt;Lamby&lt;/a&gt; (Simple Rails &amp;amp; AWS Lambda Integration using Rack) now demonstrates just how easy it is to use multi-platform &lt;code&gt;arm64&lt;/code&gt; images on AWS Lambda. If this sounds interesting to you, jump right into our &lt;a href="https://lamby.custominktech.com/docs/quick-start" rel="noopener noreferrer"&gt;Quick Start&lt;/a&gt; guide and deploy a new Rails 7 on Ruby 3.2 Ubuntu image to see it for yourself.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5k83x9ltwfxw3kbm7757.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5k83x9ltwfxw3kbm7757.jpeg" alt="Yay! You're on Rails! welcome page which has been extended by Lamby to show the Rails version, Ruby version, and machine architecture. There is some markup drawing on this page which uses an mechanical arm emoji and a big arrow pointing to the text at the bottom that says aarch64-linux. Cool!"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  How It Works?
&lt;/h2&gt;

&lt;p&gt;First, AWS has made this &lt;a href="https://aws.amazon.com/blogs/aws/aws-lambda-functions-powered-by-aws-graviton2-processor-run-your-functions-on-arm-and-get-up-to-34-better-price-performance/" rel="noopener noreferrer"&gt;incredibly easy&lt;/a&gt; since their release in September '21 where AWS SAM can simply switch the deployment architecture in your serverless project's &lt;code&gt;template.yml&lt;/code&gt; file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight diff"&gt;&lt;code&gt; Properties:
   Architectures:
&lt;span class="gd"&gt;-    - arm64
&lt;/span&gt;&lt;span class="gi"&gt;+    - x86_64
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Second, make sure your base Docker image supports the &lt;code&gt;arm64&lt;/code&gt; architecture. Most popular images use &lt;a href="https://www.docker.com/blog/faster-multi-platform-builds-dockerfile-cross-compilation-guide/" rel="noopener noreferrer"&gt;multi-platform builds&lt;/a&gt; already. For example, here is the official Ruby image we use in Lamby's demo project.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;docker manifest inspect ruby:3.2 | &lt;span class="nb"&gt;grep arch&lt;/span&gt;
            &lt;span class="s2"&gt;"architecture"&lt;/span&gt;: &lt;span class="s2"&gt;"amd64"&lt;/span&gt;,
            &lt;span class="s2"&gt;"architecture"&lt;/span&gt;: &lt;span class="s2"&gt;"arm64"&lt;/span&gt;,
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Lastly, make sure your deployment machine matches the production target architecture. This is needed to ensure native dependencies (like the MySQL client) are built to match the Docker image architecture eventually being run in production. If you are on a M1/M2 Mac, you can deploy from your own machine. &lt;/p&gt;

&lt;p&gt;However, for real production CI/CD, you are better off using something like CircleCI's &lt;a href="https://circleci.com/docs/using-arm/" rel="noopener noreferrer"&gt;Arm Execution Environment&lt;/a&gt;. Currently GitHub Actions lacks native support for Arm64 Runners, but that &lt;a href="https://github.com/actions/runner-images/issues/5631" rel="noopener noreferrer"&gt;issue is being tracked&lt;/a&gt; and I suspect is soon to come.&lt;/p&gt;

&lt;p&gt;In the meantime, Lamby's demo projects includes a working &lt;a href="https://github.com/customink/lamby-cookiecutter/blob/master/%7B%7Bcookiecutter.project_name%7D%7D/.circleci/config.yml" rel="noopener noreferrer"&gt;CircleCI CI/CD&lt;/a&gt; example for you that leverages the &lt;code&gt;arm.large&lt;/code&gt; machine type.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;default-machine&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="nl"&gt;&amp;amp;default-machine&lt;/span&gt;
  &lt;span class="na"&gt;machine&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ubuntu-2204:current&lt;/span&gt;
    &lt;span class="na"&gt;docker_layer_caching&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
  &lt;span class="na"&gt;resource_class&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;arm.large&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Thanks! Please take the time to learn more about Rails on Lambda using Lamby along with how to use arm64 with Graviton2 with your Lambda applications on our site:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://lamby.custominktech.com/docs/anatomy" rel="noopener noreferrer"&gt;How Lamby Works&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://lamby.custominktech.com/docs/cpu" rel="noopener noreferrer"&gt;Lamby CPU Architecture&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
    </item>
    <item>
      <title>Trigger CircleCI Workflow. AKA Simple Deploy Button</title>
      <dc:creator>Ken Collins</dc:creator>
      <pubDate>Sun, 05 Feb 2023 14:29:28 +0000</pubDate>
      <link>https://forem.com/customink/trigger-circleci-workflow-aka-simple-deploy-button-hf0</link>
      <guid>https://forem.com/customink/trigger-circleci-workflow-aka-simple-deploy-button-hf0</guid>
      <description>&lt;p&gt;Very simple, no parameters needed, no enums, no booleans... just a really easy way to trigger a deploy with CircleCI. We can do this making use of the &lt;a href="https://circleci.com/docs/variables/#pipeline-values" rel="noopener noreferrer"&gt;trigger_source&lt;/a&gt; pipeline value. When you click the button in CircleCI to "Trigger Pipeline" the value would be &lt;code&gt;api&lt;/code&gt; vs something like &lt;code&gt;webhook&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;2.1&lt;/span&gt;
&lt;span class="na"&gt;jobs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;deploy&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;machine&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ubuntu-2204:current&lt;/span&gt;
    &lt;span class="na"&gt;steps&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;echo 'Deploying...'&lt;/span&gt;
&lt;span class="na"&gt;workflows&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;deploy&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;when&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;{&lt;/span&gt; &lt;span class="nv"&gt;equal&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt; &lt;span class="nv"&gt;api&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;&amp;lt;&amp;lt; pipeline.trigger_source &amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="pi"&gt;]&lt;/span&gt; &lt;span class="pi"&gt;}&lt;/span&gt;
    &lt;span class="na"&gt;jobs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;deploy&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If your workflow needs a test job, consider doing something a bit more complicated. Here we use two &lt;code&gt;when&lt;/code&gt; conditions to work with a parameter.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;2.1&lt;/span&gt;
&lt;span class="na"&gt;parameters&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;workflow&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;enum&lt;/span&gt;
    &lt;span class="na"&gt;default&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;test&lt;/span&gt;
    &lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;The workflow to trigger.&lt;/span&gt;
    &lt;span class="na"&gt;enum&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;test&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;deploy&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
&lt;span class="na"&gt;jobs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;test-job&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;machine&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ubuntu-2204:current&lt;/span&gt;
    &lt;span class="na"&gt;steps&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;echo 'Testing...'&lt;/span&gt;  
  &lt;span class="na"&gt;deploy-job&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;machine&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ubuntu-2204:current&lt;/span&gt;
    &lt;span class="na"&gt;steps&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;echo 'Deploying...'&lt;/span&gt;
&lt;span class="na"&gt;workflows&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;test&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;when&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;{&lt;/span&gt; &lt;span class="nv"&gt;equal&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt; &lt;span class="nv"&gt;test&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;&amp;lt;&amp;lt; pipeline.parameters.workflow &amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="pi"&gt;]&lt;/span&gt; &lt;span class="pi"&gt;}&lt;/span&gt;
    &lt;span class="na"&gt;jobs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;test-job&lt;/span&gt;
  &lt;span class="na"&gt;deploy&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;when&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;{&lt;/span&gt; &lt;span class="nv"&gt;equal&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt; &lt;span class="nv"&gt;deploy&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;&amp;lt;&amp;lt; pipeline.parameters.workflow &amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="pi"&gt;]&lt;/span&gt; &lt;span class="pi"&gt;}&lt;/span&gt;
    &lt;span class="na"&gt;jobs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;deploy-job&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now your CircleCI config will run tests by default and you can easily trigger a deploy via any branch using the "Trigger Pipeline" button.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fr5b23gl0yk10sqpv3hur.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fr5b23gl0yk10sqpv3hur.png" alt="Screen capture of the CircleCI application. This shows the trigger pipeline UI which has the Add Parameter disclosure open. The options Parameter type, Name, and Value have been set to string, workflow, deploy." width="661" height="355"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>announcement</category>
      <category>devto</category>
      <category>offers</category>
    </item>
    <item>
      <title>New Amazon Linux Dev Container Features</title>
      <dc:creator>Ken Collins</dc:creator>
      <pubDate>Mon, 31 Oct 2022 01:48:24 +0000</pubDate>
      <link>https://forem.com/customink/new-amazon-linux-dev-container-features-3j0c</link>
      <guid>https://forem.com/customink/new-amazon-linux-dev-container-features-3j0c</guid>
      <description>&lt;p&gt;🆕 &lt;strong&gt;Want to use &lt;a href="https://github.com/features/codespaces"&gt;Codespaces&lt;/a&gt; with Amazon Linux 2?&lt;/strong&gt; Check out &lt;a href="https://github.com/customink/codespaces-features"&gt;customink/codespaces-features&lt;/a&gt; for two custom features. 1) &lt;a href="https://github.com/customink/codespaces-features/tree/main/src/common-amzn"&gt;common-amzn&lt;/a&gt; 2) &lt;a href="https://github.com/customink/codespaces-features/tree/main/src/docker-in-docker-amzn"&gt;docker-in-docker-amzn&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;So, last year I shared how we could &lt;a href="https://dev.to/aws-heroes/getting-started-with-github-codespaces-from-a-serverless-perspective-171k"&gt;integrate Codespaces&lt;/a&gt; into our AWS Lambda &lt;a href="https://dev.to/aws-heroes/lambda-containers-with-rails-a-perfect-match-4lgb"&gt;docker compose patterns&lt;/a&gt;. Since then Microsoft's Development Containers specification has come a LONG way. Everything is wrapped up nice and neatly at the &lt;a href="https://containers.dev"&gt;containers.dev&lt;/a&gt; site. Take a look if you have not already seen it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Dev Containers?
&lt;/h2&gt;

&lt;p&gt;So why are Development Containers &amp;amp; Codespaces such a big deal? I can illustrate some Lambda &amp;amp; Kubernetes use cases below, but first I would like to spell out a few features that may be new to some. Including existing Codespaces users.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;The Dev Container &lt;a href="https://containers.dev"&gt;specification&lt;/a&gt; at the lowest level of Codespaces is open to everyone and lots of tooling exists around it by a growing community.&lt;/li&gt;
&lt;li&gt;The specification has a reference implementation via a node &lt;a href="https://dev.toDev%20Container%20CLI"&gt;Command Line Interface&lt;/a&gt;. Think of this &lt;code&gt;devcontainer&lt;/code&gt; CLI as a higher order docker compose. You can use this to run Codespaces projects locally!&lt;/li&gt;
&lt;li&gt;Atop of the CLI, there is CI tooling for &lt;a href="https://github.com/devcontainers/ci"&gt;GitHub Actions&lt;/a&gt;. This means you can use the same development container as your CI/CD environment.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Containers Usage Areas
&lt;/h2&gt;

&lt;p&gt;So where are containers used in your organization or projects?  Here are some phases that most of us can identify with. Where projects move from the left to the right.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--FWFdqDhk--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/mfaiqd32kl7juqatzkgt.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--FWFdqDhk--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/mfaiqd32kl7juqatzkgt.png" alt="Container Areas" width="880" height="341"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Development:&lt;/strong&gt; Most of us have tried to use docker or compose at some point. For example, the most common use of this area would be running a database like MySQL. Docker makes this easy.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;CI/CD:&lt;/strong&gt; Typically where we run tests and hopefully build and/or deploy our code to production. If you have used CircleCI before, again a database container here might feel familiar. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Runtime:&lt;/strong&gt; Which is often our final container environment. We can think of this as production for most of us but it could be any container orchestration like Kubernetes, Lambda, or Fargate.&lt;/p&gt;

&lt;h2&gt;
  
  
  Old AWS SAM Patterns with Docker Compose
&lt;/h2&gt;

&lt;p&gt;Today our Lambda SAM cookiecutters leverage SAM's build image via docker compose to ensure local development is within the same environment for our CI/CD tooling. We ended up with something like this image&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--cB-vpIR7--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/brm2tkldsfln5adf75oy.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--cB-vpIR7--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/brm2tkldsfln5adf75oy.png" alt="AWS Lambda Before Dev Containers" width="880" height="469"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;At the bottom we can see the host platform typically associated with each of these stages. Because we use Docker, we can be cross-platform and consistent. &lt;strong&gt;The problem?&lt;/strong&gt; ⚠️ Making up your own docker/compose patterns are a huge drag. From SSH patterns to Docker-in-Docker gotchas. &lt;/p&gt;

&lt;h2&gt;
  
  
  New AWS SAM Patterns with Dev Containers
&lt;/h2&gt;

&lt;p&gt;In the coming weeks the &lt;a href="https://github.com/customink/lamby-cookiecutter/tree/master/%7B%7Bcookiecutter.project_name%7D%7D"&gt;Lamby Cookiecutter&lt;/a&gt; will be updated to use Development Containers so folks with (or without) Codespaces can easily work with the project. The result will be something like this.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--eUTmwaFF--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/9jxmjokl4nm48mehgzpm.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--eUTmwaFF--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/9jxmjokl4nm48mehgzpm.png" alt="AWS Lambda After Dev Containers" width="880" height="392"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;With Development Containers, so much docker compose boilerplate can be removed. Thanks in huge part to our newly released &lt;a href="https://github.com/customink/codespaces-features"&gt;common &amp;amp; docker-in-docker Amazon Linux 2 features&lt;/a&gt; work. If you want to see an example of how this helps everyone including running Codespaces locally with VS Code, checkout our &lt;a href="https://github.com/customink/crypteia#development"&gt;Crypteia Project's Development&lt;/a&gt; section. You can even use all this without VS Code &amp;amp; GitHub Codespaces. For example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;devcontainer build &lt;span class="nt"&gt;--workspace-folder&lt;/span&gt; &lt;span class="nb"&gt;.&lt;/span&gt;
devcontainer up &lt;span class="nt"&gt;--workspace-folder&lt;/span&gt; &lt;span class="nb"&gt;.&lt;/span&gt;
devcontainer run-user-commands &lt;span class="nt"&gt;--workspace-folder&lt;/span&gt; &lt;span class="nb"&gt;.&lt;/span&gt;
devcontainer &lt;span class="nb"&gt;exec&lt;/span&gt; &lt;span class="nt"&gt;--workspace-folder&lt;/span&gt; &lt;span class="nb"&gt;.&lt;/span&gt; ./bin/setup
devcontainer &lt;span class="nb"&gt;exec&lt;/span&gt; &lt;span class="nt"&gt;--workspace-folder&lt;/span&gt; &lt;span class="nb"&gt;.&lt;/span&gt; ./bin/test-local
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Unexplored Development Container Space
&lt;/h2&gt;

&lt;p&gt;So can Development Containers be used in your projects without the Lambda patterns above? Yes! Consider the following diagram that has a Platform Engineering team building base images. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--Sx2gpWxy--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/fklx3ef7j0ypbnf3fff7.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Sx2gpWxy--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/fklx3ef7j0ypbnf3fff7.png" alt="Where could Development Container fit into your Kubernetes/K8s Projects" width="880" height="520"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;These teams typically approach containers from the right to the left. Where base OS images are made into language specific images with variants for CI/CD. Just like SAM has build and runtime images. Technically for them "Runtime" is some container registry like Amazon ECR, but you get the idea.&lt;/p&gt;

&lt;p&gt;At &lt;a href="https://www.customink.com"&gt;Custom Ink&lt;/a&gt; we are using our CircleCI images for our Kubernetes projects with Codespaces. The Microsoft team makes this easy since all of their features work with Ubuntu out of the box.&lt;/p&gt;

&lt;p&gt;If your development stages look something like the image above. Please consider adopting Development Containers based on your CI/CD images and explore that big purple space by connecting your container value chain in a beautiful little circle. Thanks for reading!&lt;/p&gt;

</description>
    </item>
    <item>
      <title>New Amazon Linux Dev Container Features</title>
      <dc:creator>Ken Collins</dc:creator>
      <pubDate>Mon, 31 Oct 2022 01:45:43 +0000</pubDate>
      <link>https://forem.com/aws-heroes/new-amazon-linux-dev-container-features-5db9</link>
      <guid>https://forem.com/aws-heroes/new-amazon-linux-dev-container-features-5db9</guid>
      <description>&lt;p&gt;🆕 &lt;strong&gt;Want to use &lt;a href="https://github.com/features/codespaces" rel="noopener noreferrer"&gt;Codespaces&lt;/a&gt; with Amazon Linux 2?&lt;/strong&gt; Check out &lt;a href="https://github.com/customink/codespaces-features" rel="noopener noreferrer"&gt;customink/codespaces-features&lt;/a&gt; for two custom features. 1) &lt;a href="https://github.com/customink/codespaces-features/tree/main/src/common-amzn" rel="noopener noreferrer"&gt;common-amzn&lt;/a&gt; 2) &lt;a href="https://github.com/customink/codespaces-features/tree/main/src/docker-in-docker-amzn" rel="noopener noreferrer"&gt;docker-in-docker-amzn&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;So, last year I shared how we could &lt;a href="https://dev.to/aws-heroes/getting-started-with-github-codespaces-from-a-serverless-perspective-171k"&gt;integrate Codespaces&lt;/a&gt; into our AWS Lambda &lt;a href="https://dev.to/aws-heroes/lambda-containers-with-rails-a-perfect-match-4lgb"&gt;docker compose patterns&lt;/a&gt;. Since then Microsoft's Development Containers specification has come a LONG way. Everything is wrapped up nice and neatly at the &lt;a href="https://containers.dev" rel="noopener noreferrer"&gt;containers.dev&lt;/a&gt; site. Take a look if you have not already seen it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Dev Containers?
&lt;/h2&gt;

&lt;p&gt;So why are Development Containers &amp;amp; Codespaces such a big deal? I can illustrate some Lambda &amp;amp; Kubernetes use cases below, but first I would like to spell out a few features that may be new to some. Including existing Codespaces users.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;The Dev Container &lt;a href="https://containers.dev" rel="noopener noreferrer"&gt;specification&lt;/a&gt; at the lowest level of Codespaces is open to everyone and lots of tooling exists around it by a growing community.&lt;/li&gt;
&lt;li&gt;The specification has a reference implementation via a node &lt;a href="https://dev.toDev%20Container%20CLI"&gt;Command Line Interface&lt;/a&gt;. Think of this &lt;code&gt;devcontainer&lt;/code&gt; CLI as a higher order docker compose. You can use this to run Codespaces projects locally!&lt;/li&gt;
&lt;li&gt;Atop of the CLI, there is CI tooling for &lt;a href="https://github.com/devcontainers/ci" rel="noopener noreferrer"&gt;GitHub Actions&lt;/a&gt;. This means you can use the same development container as your CI/CD environment.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Containers Usage Areas
&lt;/h2&gt;

&lt;p&gt;So where are containers used in your organization or projects?  Here are some phases that most of us can identify with. Where projects move from the left to the right.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmfaiqd32kl7juqatzkgt.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmfaiqd32kl7juqatzkgt.png" alt="Container Areas"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Development:&lt;/strong&gt; Most of us have tried to use docker or compose at some point. For example, the most common use of this area would be running a database like MySQL. Docker makes this easy.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;CI/CD:&lt;/strong&gt; Typically where we run tests and hopefully build and/or deploy our code to production. If you have used CircleCI before, again a database container here might feel familiar. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Runtime:&lt;/strong&gt; Which is often our final container environment. We can think of this as production for most of us but it could be any container orchestration like Kubernetes, Lambda, or Fargate.&lt;/p&gt;

&lt;h2&gt;
  
  
  Old AWS SAM Patterns with Docker Compose
&lt;/h2&gt;

&lt;p&gt;Today our Lambda SAM cookiecutters leverage SAM's build image via docker compose to ensure local development is within the same environment for our CI/CD tooling. We ended up with something like this image&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbrm2tkldsfln5adf75oy.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbrm2tkldsfln5adf75oy.png" alt="AWS Lambda Before Dev Containers"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;At the bottom we can see the host platform typically associated with each of these stages. Because we use Docker, we can be cross-platform and consistent. &lt;strong&gt;The problem?&lt;/strong&gt; ⚠️ Making up your own docker/compose patterns are a huge drag. From SSH patterns to Docker-in-Docker gotchas. &lt;/p&gt;

&lt;h2&gt;
  
  
  New AWS SAM Patterns with Dev Containers
&lt;/h2&gt;

&lt;p&gt;In the coming weeks the &lt;a href="https://github.com/customink/lamby-cookiecutter/tree/master/%7B%7Bcookiecutter.project_name%7D%7D" rel="noopener noreferrer"&gt;Lamby Cookiecutter&lt;/a&gt; will be updated to use Development Containers so folks with (or without) Codespaces can easily work with the project. The result will be something like this.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9jxmjokl4nm48mehgzpm.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9jxmjokl4nm48mehgzpm.png" alt="AWS Lambda After Dev Containers"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;With Development Containers, so much docker compose boilerplate can be removed. Thanks in huge part to our newly released &lt;a href="https://github.com/customink/codespaces-features" rel="noopener noreferrer"&gt;common &amp;amp; docker-in-docker Amazon Linux 2 features&lt;/a&gt; work. If you want to see an example of how this helps everyone including running Codespaces locally with VS Code, checkout our &lt;a href="https://github.com/customink/crypteia#development" rel="noopener noreferrer"&gt;Crypteia Project's Development&lt;/a&gt; section. You can even use all this without VS Code &amp;amp; GitHub Codespaces. For example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;devcontainer build &lt;span class="nt"&gt;--workspace-folder&lt;/span&gt; &lt;span class="nb"&gt;.&lt;/span&gt;
devcontainer up &lt;span class="nt"&gt;--workspace-folder&lt;/span&gt; &lt;span class="nb"&gt;.&lt;/span&gt;
devcontainer run-user-commands &lt;span class="nt"&gt;--workspace-folder&lt;/span&gt; &lt;span class="nb"&gt;.&lt;/span&gt;
devcontainer &lt;span class="nb"&gt;exec&lt;/span&gt; &lt;span class="nt"&gt;--workspace-folder&lt;/span&gt; &lt;span class="nb"&gt;.&lt;/span&gt; ./bin/setup
devcontainer &lt;span class="nb"&gt;exec&lt;/span&gt; &lt;span class="nt"&gt;--workspace-folder&lt;/span&gt; &lt;span class="nb"&gt;.&lt;/span&gt; ./bin/test-local
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Unexplored Development Container Space
&lt;/h2&gt;

&lt;p&gt;So can Development Containers be used in your projects without the Lambda patterns above? Yes! Consider the following diagram that has a Platform Engineering team building base images. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffklx3ef7j0ypbnf3fff7.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffklx3ef7j0ypbnf3fff7.png" alt="Where could Development Container fit into your Kubernetes/K8s Projects"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;These teams typically approach containers from the right to the left. Where base OS images are made into language specific images with variants for CI/CD. Just like SAM has build and runtime images. Technically for them "Runtime" is some container registry like Amazon ECR, but you get the idea.&lt;/p&gt;

&lt;p&gt;At &lt;a href="https://www.customink.com" rel="noopener noreferrer"&gt;Custom Ink&lt;/a&gt; we are using our CircleCI images for our Kubernetes projects with Codespaces. The Microsoft team makes this easy since all of their features work with Ubuntu out of the box.&lt;/p&gt;

&lt;p&gt;If your development stages look something like the image above. Please consider adopting Development Containers based on your CI/CD images and explore that big purple space by connecting your container value chain in a beautiful little circle. Thanks for reading!&lt;/p&gt;

</description>
      <category>docker</category>
      <category>serverless</category>
      <category>lambda</category>
    </item>
  </channel>
</rss>
