<?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>DEV Community: Charly Poly</title>
    <description>The latest articles on DEV Community by Charly Poly (@whereischarly).</description>
    <link>https://dev.to/whereischarly</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%2F1113307%2Fdff17dfe-65ea-475b-879a-5fba5a7ab7bf.jpg</url>
      <title>DEV Community: Charly Poly</title>
      <link>https://dev.to/whereischarly</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/whereischarly"/>
    <language>en</language>
    <item>
      <title>Replacing complex UX patterns with Next.js and OpenAI o1</title>
      <dc:creator>Charly Poly</dc:creator>
      <pubDate>Thu, 17 Oct 2024 16:02:39 +0000</pubDate>
      <link>https://dev.to/inngest/replacing-complex-ux-patterns-with-nextjs-and-openai-o1-7pi</link>
      <guid>https://dev.to/inngest/replacing-complex-ux-patterns-with-nextjs-and-openai-o1-7pi</guid>
      <description>&lt;p&gt;Anyone who has already built a data-import user experience knows it requires some complex column-matching UI and many branches on the backend to safely parse and save the user-provided data:  &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%2F9mrnee1ly9rsvb9t7i4z.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%2F9mrnee1ly9rsvb9t7i4z.png" alt="Image description" width="800" height="516"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Such UI is a slow and tedious experience for the end-user and a challenge to maintain for developers.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;In this article, we will review a demo CRM Next.js putting a contacts import feature on autopilot, remarkably demonstrating the power of agentic workflows.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is an AI Agentic workflow?
&lt;/h2&gt;

&lt;p&gt;An Agentic workflow is a new pattern consisting of relying on model reasoning to achieve a goal instead of providing a series of static prompts.&lt;br&gt;
In short, the model is given a high-level goal to achieve and figures out the necessary steps to reach that goal.&lt;/p&gt;

&lt;p&gt;Many &lt;a href="https://arxiv.org/abs/2210.03629" rel="noopener noreferrer"&gt;papers&lt;/a&gt; and &lt;a href="https://www.techzine.eu/blogs/applications/118176/the-ai-shift-from-prompt-engineering-to-flow-engineering/" rel="noopener noreferrer"&gt;articles&lt;/a&gt; have been published earlier this year, showcasing the &lt;a href="https://www.deeplearning.ai/the-batch/how-agents-can-improve-llm-performance/" rel="noopener noreferrer"&gt;outstanding performance of agentic workflows&lt;/a&gt; compared to standard prompting techniques.&lt;br&gt;&lt;br&gt;
It turns out that agentic workflows, by combining reflection (reasoning), planning, and tools, lead to more precise answers, &lt;a href="https://www.bbc.com/travel/article/20240222-air-canada-chatbot-misinformation-what-travellers-should-know" rel="noopener noreferrer"&gt;solving important integration issues&lt;/a&gt; of AI in user-facing use cases.&lt;/p&gt;

&lt;p&gt;We are now witnessing the rise of new tools that help with agentic workflow developments with LangGraph and, recently, &lt;a href="https://github.com/openai/swarm" rel="noopener noreferrer"&gt;OpenAI's swarm&lt;/a&gt;, along with their new reasoning model: &lt;a href="https://openai.com/o1/" rel="noopener noreferrer"&gt;&lt;code&gt;o1&lt;/code&gt;&lt;/a&gt;.&lt;br&gt;
Adding Agentic workflows to an application comes with many challenges:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Duration volatility&lt;/strong&gt;: Models are responsible for reflecting and planning all the steps to reach a given goal, resulting in significant variance in the workflow duration.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Reliability&lt;/strong&gt;: Agentic workflows rely on more tools than regular prompt-designed workflows. Adding more tools calling external APIs based on LLM-generated parameters raises the risk of failure. Recovering from failure enables the model to self-correct during the workflow execution.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Unpredictability&lt;/strong&gt;: Pushing an agentic workflow to production requires setting up some safeguards on cost, duration, and output validation.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Let's now look at our Next.js CRM demo, featuring an autopilot contacts import feature.&lt;br&gt;&lt;br&gt;
We'll see that agentic workflows mostly reuse existing patterns found in Next.js  and can already be used today to bring brand-new capabilities to Next.js applications.&lt;/p&gt;
&lt;h2&gt;
  
  
  Designing an agentic workflow with OpenAI o1
&lt;/h2&gt;

&lt;p&gt;We will design our CRM's autopilot contact importer feature by leveraging the new OpenAI &lt;code&gt;o1&lt;/code&gt; reasoning model to plan the best steps to import a given file by:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Ensuring that the fields are properly set, without typos
&lt;/li&gt;
&lt;li&gt;Ranking the provided contact as good software Sales lead dynamically based on the provided columns
&lt;/li&gt;
&lt;li&gt;Matching provided column by our CRM ones: Name, Email, Role, Company&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Open AI &lt;code&gt;o1&lt;/code&gt; will take this high-level goal to generate a set of steps leveraging our existing handwritten actions (&lt;code&gt;convert&lt;/code&gt;, &lt;code&gt;enrich&lt;/code&gt;, &lt;code&gt;save&lt;/code&gt;) and generating custom OpenAI calls (if necessary) while managing cost.&lt;/p&gt;

&lt;p&gt;Here's a visualization of our autopilot import contacts feature in our Next.js application:  &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%2Foz57h2wokxjuinhd62kq.jpg" 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%2Foz57h2wokxjuinhd62kq.jpg" alt="Image description" width="800" height="478"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Creating our contacts importer UI with Vercel v0
&lt;/h2&gt;

&lt;p&gt;Our import contacts UI has been, of course, generated with &lt;a href="https://v0.dev/" rel="noopener noreferrer"&gt;Vercel v0&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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F83sfdpysltr1s7odpwy0.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%2F83sfdpysltr1s7odpwy0.png" alt="Image description" width="800" height="364"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Once a file is selected, we call a &lt;a href="https://nextjs.org/docs/app/building-your-application/data-fetching/server-actions-and-mutations#forms" rel="noopener noreferrer"&gt;Server Action&lt;/a&gt; with the &lt;code&gt;FormData,&lt;/code&gt; which triggers a &lt;code&gt;”contacts.uploaded”&lt;/code&gt; event to Inngest.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;use server&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;inngest&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;@/lib/inngest/client&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="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;uploadFile&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;formData&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;FormData&lt;/span&gt;&lt;span class="p"&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;file&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;formData&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;file&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;File&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;fileText&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;file&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;text&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

  &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;inngest&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;send&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;contacts.uploaded&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;contactFileContent&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;fileText&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="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The front end does not expect the import to be instantaneous, and also, because the call to OpenAI's o1-preview may take multiple minutes, the actual processing and generation of the contact import workflow are performed in the background by an Inngest Function: &lt;code&gt;generateImportWorkflow()&lt;/code&gt;. Let's look at its implementation.&lt;/p&gt;

&lt;h2&gt;
  
  
  Asking OpenAI o1 to generate an import workflow
&lt;/h2&gt;

&lt;p&gt;Our first Inngest Function, &lt;code&gt;generateImportWorkflow(),&lt;/code&gt; leverages Vercel Edge Function's streaming capabilities to call OpenAI's &lt;code&gt;o1-preview&lt;/code&gt; model and generate a tailored import workflow for our contact list without duration limitation.&lt;/p&gt;

&lt;p&gt;Let's take a closer look at our &lt;code&gt;o1-preview&lt;/code&gt; prompt:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;prompt&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;contactsFileContent&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s2"&gt;`
Considering the following available actions:
&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;actions&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;filter&lt;/span&gt;&lt;span class="p"&gt;(({&lt;/span&gt; &lt;span class="nx"&gt;kind&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;kind&lt;/span&gt; &lt;span class="o"&gt;!==&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;openaiCall&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="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(({&lt;/span&gt; &lt;span class="nx"&gt;kind&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;description&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s2"&gt;`- &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;description&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;, name: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;kind&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;\n`&lt;/span&gt;&lt;span class="p"&gt;)}&lt;/span&gt;&lt;span class="s2"&gt;

and, given the below CSV file (between &lt;/span&gt;&lt;span class="se"&gt;\`\`\`&lt;/span&gt;&lt;span class="s2"&gt;), recommend the best steps by balancing existing actions and using custom openai calls (do not use deprecated models) to successfully:
    - parse the contact information and remove any typos
    - enrich the contacts data
    - label them a decider and rank them as a good Sales target to sale software to based on the provided property
    - rework the CSV file to match the provided column to the following: Name, Position, Company, Email and the ranking and decider columns
    - save the contacts to the database

Return a JSON array made of steps to execute. When a step is a model call, provide the "model" for model name and "prompt" for the prompt with "{data}" as a placeholder for the provided data; When the step is an action, provide the action name.

&lt;/span&gt;&lt;span class="se"&gt;\`\`\`&lt;/span&gt;&lt;span class="s2"&gt;
&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;contactsFileContent&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;
&lt;/span&gt;&lt;span class="se"&gt;\`\`\`&lt;/span&gt;&lt;span class="s2"&gt;
`&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The above prompts demonstrate the power of reasoning models like &lt;code&gt;o1-preview&lt;/code&gt;. From high-level goals, the model takes a few minutes to find the best chain of predefined actions and additional model calls to perform to successfully parse, transform, rank, and save the contacts.&lt;/p&gt;

&lt;p&gt;We are using the stellar &lt;a href="https://sdk.vercel.ai/docs/reference/ai-sdk-core/generate-text" rel="noopener noreferrer"&gt;Vercel AI SDK&lt;/a&gt; to call &lt;code&gt;o1-preview&lt;/code&gt;. Here is an example of the actions generated by the model:&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="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"action"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"convert"&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;span class="nl"&gt;"model"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"gpt-3.5-turbo"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"prompt"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Parse the following contact information from JSON, correct any typos, and ensure all fields are properly formatted."&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;span class="nl"&gt;"action"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"enrich"&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;span class="nl"&gt;"model"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"gpt-3.5-turbo"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"prompt"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Label each contact as a decider and rank them as a good sales target for software based on their company, role, and industry."&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;span class="nl"&gt;"model"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"gpt-3.5-turbo"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"prompt"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Reformat the following JSON data to match the columns: Name, Position, Company, Email."&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;span class="nl"&gt;"action"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"save"&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;The actions generated will vary depending on the provided CSV file.&lt;br&gt;
The code then transforms these actions into a format using &lt;a href="https://www.inngest.com/docs/reference/workflow-kit/workflow-instance" rel="noopener noreferrer"&gt;Inngest's Workflow Kit&lt;/a&gt; which can easily handle o1's multi-step plans and execute them. The transformed plan is then send to the importContacts Inngest Function to execute the plan.  &lt;/p&gt;

&lt;p&gt;&lt;br&gt;
&lt;strong&gt;Note: &lt;code&gt;o1-preview&lt;/code&gt; vs. &lt;code&gt;o1-mini&lt;/code&gt; accuracy&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
&lt;code&gt;o1-mini&lt;/code&gt; is a preferred choice when developing, offering faster iterations and lower costs. While developing this demo, we realized that &lt;code&gt;o1-mini&lt;/code&gt; struggled to output a deterministic and simple JSON structure for model call actions. Switching back to &lt;code&gt;o1-preview&lt;/code&gt; solved this problem.&lt;br&gt;&lt;br&gt;
&lt;/p&gt;

&lt;p&gt;Our &lt;code&gt;o1-preview&lt;/code&gt; call and the processing of its results is wrapped as an Inngest Function, enabling it to run without duration limitation in the background and matching &lt;code&gt;o1-preview&lt;/code&gt;'s &lt;a href="https://x.com/OpenAIDevs/status/1841176573527077235" rel="noopener noreferrer"&gt;API Rate limits&lt;/a&gt; by leveraging &lt;a href="https://www.inngest.com/docs/guides/throttling" rel="noopener noreferrer"&gt;throttling&lt;/a&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// imports ...&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="nx"&gt;inngest&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createFunction&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;generate-import-workflow&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;throttle&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;limit&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;5000&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;period&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;1m&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;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;event&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;contacts.uploaded&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&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;event&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;step&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;generatedStepsResult&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;step&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;run&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;openai-o1-generate-steps&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="k"&gt;async &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="c1"&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;&lt;em&gt;Access the full source code &lt;a href="https://github.com/inngest/vercel-ai-open-o1-crm-agent/blob/main/lib/inngest/functions/generateImportWorkflow.ts" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Executing the dynamic workflow with Inngest's Workflow Kit
&lt;/h2&gt;

&lt;p&gt;Our &lt;code&gt;importContact()&lt;/code&gt; Inngest Function leverages the &lt;a href="https://www.inngest.com/blog/introducing-workflow-kit" rel="noopener noreferrer"&gt;Inngest Workflow Kit&lt;/a&gt; to execute a dynamic list of steps passed in the &lt;code&gt;”contacts.process”&lt;/code&gt; event's body.&lt;/p&gt;

&lt;p&gt;Our Inngest workflow is composed of 4 predefined actions:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;openaiCall&lt;/code&gt;: Make a dynamic call to OpenAI API
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;convert&lt;/code&gt;: convert CSV data to JSON items&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;enrich&lt;/code&gt;: Enrich contact information
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;save&lt;/code&gt;: Save contact information to the database&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Our &lt;code&gt;o1-preview&lt;/code&gt; model leverages the &lt;code&gt;openaiCall&lt;/code&gt; action to dynamically add actions, helping to format and structure the provided contact data. It takes two parameters: &lt;code&gt;prompt&lt;/code&gt;, and &lt;code&gt;model&lt;/code&gt; which the model configures according to the task to achieve.&lt;/p&gt;

&lt;p&gt;Each workflow's action provides a &lt;code&gt;handler()&lt;/code&gt; function that benefits from Inngest's features, such as &lt;a href="https://www.inngest.com/blog/durable-functions-a-visual-typescript-primer" rel="noopener noreferrer"&gt;automatic retries&lt;/a&gt; and throttling. These features improve the reliability of our agentic workflow and help manage its unpredictability.&lt;/p&gt;

&lt;p&gt;An Inngest Workflow is then passed to our &lt;code&gt;importContacts()&lt;/code&gt; Inngest Function for execution:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&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;Engine&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;EngineAction&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;@inngest/workflow-kit&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;inngest&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;../client&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;actions&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;EngineAction&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="c1"&gt;// other actions ...&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;save&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;Save contacts&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;save contact information to the database&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;handler&lt;/span&gt;&lt;span class="p"&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;state&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;step&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="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;step&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;run&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;save-contacts-to-database&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;async &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;contacts&lt;/span&gt; &lt;span class="o"&gt;=&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;parse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;contacts&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
        &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;sql&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;query&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
          &lt;span class="s2"&gt;`INSERT INTO contacts (Name,Position,Company,Email,Decider,Ranking) VALUES &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;contacts&lt;/span&gt;
            &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;contact&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;any&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="k"&gt;return&lt;/span&gt; &lt;span class="s2"&gt;`('&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;contact&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Name&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;', '&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;contact&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Position&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;', '&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;contact&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Company&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;', '&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;contact&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Email&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;', &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;contact&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Decider&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;, &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;contact&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Ranking&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&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;span class="nf"&gt;join&lt;/span&gt;&lt;span class="p"&gt;()}&lt;/span&gt;&lt;span class="s2"&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;span class="p"&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;workflowEngine&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;Engine&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="nx"&gt;actions&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;loader&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&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="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;event&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="nx"&gt;workflowInstance&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="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="nx"&gt;inngest&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createFunction&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;import-contacts&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;event&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;contact.process&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&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;event&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;step&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="c1"&gt;// When `run` is called, the loader function is called with access to the event&lt;/span&gt;
    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;workflowEngine&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;run&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;step&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;&lt;em&gt;Access the full source code &lt;a href="https://github.com/inngest/vercel-ai-open-o1-crm-agent/blob/main/lib/inngest/functions/importContacts.ts" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  How our Agent performs
&lt;/h2&gt;

&lt;p&gt;Our demo CRM application now features a smooth AI-powered contact import onboarding experience powered by a semi-autonomous agentic workflow as a complete part of the Next.js application ✨&lt;br&gt;&lt;br&gt;
Uploading the below CSV file sample generates a custom import workflow and runs smoothly in the background:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;First Name,Last Name,Email,Seniority,Role,Company,Industry
Amanda,Brown,amanda.brown@example.com,VP,Data Scbentist,AutoCorp,Real Estate
Sarah,Johnson,sarah.johnson@example.com,Junior,CEO,BioGen,Education
Michael,Jackson,michael.jackson@example.com,Junior,CqO,AutoCorp,Healthcare
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;em&gt;Notice the typos in position, roles, and columns that do not match our contact properties.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Once completed, the clean, structured, and enriched contact records are saved to the database:  &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%2F8hv4f2ob29i2ah1cvjfi.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%2F8hv4f2ob29i2ah1cvjfi.png" alt="Image description" width="800" height="620"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Vercel Postgres database with the contact information loaded from the agentic workflow. &lt;strong&gt;Our Agent event fixed the typos in contact properties like "Scbentist"&lt;/strong&gt;&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;When deployed on Vercel, the workflow leverages Edge Function's streaming capabilities to reliably call &lt;code&gt;o1-preview&lt;/code&gt; without duration considerations.&lt;/p&gt;

&lt;h3&gt;
  
  
  Making our agent even smarter
&lt;/h3&gt;

&lt;p&gt;This contacts import on autopilot is a first draft that can be used as a boilerplate to iterate and improve &lt;code&gt;o1&lt;/code&gt;'s results.&lt;br&gt;&lt;br&gt;
A non-exhaustive list of interesting additional capabilities could be:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Leveraging the OpenAI Batching API to reduce cost on large CSV files
&lt;/li&gt;
&lt;li&gt;Have the model learn from previous runs to fine-tune its lead ranking mechanism
&lt;/li&gt;
&lt;li&gt;Iterate and improve &lt;code&gt;o1&lt;/code&gt;'s prompt by following &lt;a href="https://platform.openai.com/docs/guides/reasoning/advice-on-prompting" rel="noopener noreferrer"&gt;OpenAI's best practices&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Try the demo now
&lt;/h2&gt;

&lt;p&gt;The combination of Vercel AI SDK and Inngest makes it super easy to add Agentic workflows to provide more accurate (e.g., support chat) or achieve more complex tasks (e.g., data analysis, agent-based features).&lt;br&gt;&lt;br&gt;
&lt;strong&gt;Try this demo now&lt;/strong&gt; by running it locally or deploying it on Vercel: &lt;a href="https://github.com/inngest/vercel-ai-o1-preview-crm-agent" rel="noopener noreferrer"&gt;https://github.com/inngest/vercel-ai-open-o1-crm-agent&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>nextjs</category>
      <category>openai</category>
      <category>javascript</category>
      <category>learning</category>
    </item>
  </channel>
</rss>
