<?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: Robbie Heywood</title>
    <description>The latest articles on DEV Community by Robbie Heywood (@robbie_portia).</description>
    <link>https://dev.to/robbie_portia</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%2F3034383%2F0d0d6c4c-9803-48c1-9df4-022ccc3940e3.jpg</url>
      <title>DEV Community: Robbie Heywood</title>
      <link>https://dev.to/robbie_portia</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/robbie_portia"/>
    <language>en</language>
    <item>
      <title>Building agents with Controlled Autonomy using our new PlanBuilder interface</title>
      <dc:creator>Robbie Heywood</dc:creator>
      <pubDate>Wed, 10 Sep 2025 14:23:42 +0000</pubDate>
      <link>https://dev.to/portia-ai/building-agents-with-controlled-autonomy-using-our-new-planbuilder-interface-1oc1</link>
      <guid>https://dev.to/portia-ai/building-agents-with-controlled-autonomy-using-our-new-planbuilder-interface-1oc1</guid>
      <description>&lt;p&gt;Balancing autonomy and reliability is a key challenge faced by teams building agents (and getting it right is &lt;a href="https://fortune.com/2025/08/18/mit-report-95-percent-generative-ai-pilots-at-companies-failing-cfo/" rel="noopener noreferrer"&gt;notoriously difficult!&lt;/a&gt;). At Portia, we’ve built many production-ready agents with our design partners and today we’re excited to share our solution: &lt;strong&gt;Controlled Autonomy&lt;/strong&gt;. Controlled autonomy is the ability to control the level of autonomy of an agent at each step of an agentic plan. We implement this using our newly reshaped PlanBuilder interface to build agentic systems, and today we’re excited to be releasing it into our open-source SDK. We believe it’s a simple, elegant interface (without the boilerplate of many agentic frameworks) that is the best way to create powerful and reliable agentic systems - we can’t wait to see what you build with it!&lt;/p&gt;

&lt;p&gt;If you’re building agents, we’d love to hear from you! Check out our &lt;a href="https://github.com/portiaAI/portia-sdk-python" rel="noopener noreferrer"&gt;open-source SDK&lt;/a&gt; and let us know what you’re building on &lt;a href="https://discord.com/invite/DvAJz9ffaR" rel="noopener noreferrer"&gt;Discord&lt;/a&gt;. We also love to see people getting involved with contributions in the repo - if you’d like to get started with this, check out our &lt;a href="https://github.com/portiaAI/portia-sdk-python/issues" rel="noopener noreferrer"&gt;open issues&lt;/a&gt; and let us know if you’d like to take one on.&lt;/p&gt;

&lt;h2&gt;
  
  
  Straight into an example
&lt;/h2&gt;

&lt;p&gt;Our PlanBuilder interface is designed to feel intuitive and we find agents built with it are easy to follow, so let’s dive straight into an example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;portia&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;PlanBuilderV2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;StepOutput&lt;/span&gt;

&lt;span class="n"&gt;plan&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nc"&gt;PlanBuilderV2&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Run this plan to process a refund request.&lt;/span&gt;&lt;span class="sh"&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;input&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;refund_info&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;description&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Info of the customer refund request&lt;/span&gt;&lt;span class="sh"&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;invoke_tool_step&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;step_name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;read_refund_policy&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;tool&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;file_reader_tool&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;filename&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;./refund_policy.txt&lt;/span&gt;&lt;span class="sh"&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;single_tool_agent_step&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;step_name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;read_refund_request&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;task&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Find the refund request email from &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nc"&gt;Input&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;customer_email_address&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;tool&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;portia:google:gmail:search_email&lt;/span&gt;&lt;span class="sh"&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;llm_step&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;step_name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;llm_refund_review&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;task&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Review the refund request against the refund policy. &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
             &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Decide if the refund should be approved or rejected. &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
             &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Return the decision in the format: &lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;APPROVED&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt; or &lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;REJECTED&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;inputs&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nc"&gt;StepOutput&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;read_refund_policy&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="nc"&gt;StepOutput&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;read_refund_request&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)],&lt;/span&gt;
        &lt;span class="n"&gt;output_schema&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;RefundDecision&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;function_step&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;function&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;record_refund_decision&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;refund_decision&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;StepOutput&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;llm_refund_review&lt;/span&gt;&lt;span class="sh"&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;react_agent_step&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;task&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Find the payment that the customer would like refunded.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;tools&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;portia:mcp:mcp.stripe.com:list_customers&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;portia:mcp:mcp.stripe.com:list_payment_intents&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
        &lt;span class="n"&gt;inputs&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nc"&gt;StepOutput&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;read_refund_request&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)],&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="c1"&gt;# Full example includes more steps to actually process the refund etc.
&lt;/span&gt;    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;build&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 above is a modified extract from our Stripe refund agent (full example &lt;a href="https://github.com/portiaAI/portia-agent-examples/blob/main/refund-agent-mcp/refund_agent_with_builder.py" rel="noopener noreferrer"&gt;here&lt;/a&gt;), setting up an agent that acts as follows:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Read in our company’s refund policy:&lt;/strong&gt; this uses a simple &lt;code&gt;invoke_tool_step&lt;/code&gt;, which means that the tool is directly invoked with the args specified with no LLM involvement. These steps are great when you need to use a tool (often to retrieve data) but don’t need the flexibility of an LLM to call the tool because the args you want to use are fixed (this generally makes them very fast too!).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Read in the refund request from an email:&lt;/strong&gt; for this step, we want to flexibly find the email in the inbox based on the refund info that is passed into the agent. To do this, we use a &lt;code&gt;single_tool_agent&lt;/code&gt;, which is an LLM that calls a single tool once in order to achieve its task. In this case, the agent creates the inbox search query based on the refund info passed in to find the refund email.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Judge the refund request against the refund policy:&lt;/strong&gt; the &lt;code&gt;llm_step&lt;/code&gt; is relatively self-explanatory here - it uses your configured LLM to judge whether we should provide the refund based on the request and the policy. We use the &lt;code&gt;StepOutput&lt;/code&gt; object to feed in the results from the previous steps, and the &lt;code&gt;output_schema&lt;/code&gt; field allows us to return the decision as a &lt;a href="https://docs.pydantic.dev/latest/" rel="noopener noreferrer"&gt;pydantic&lt;/a&gt; object rather than as text.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Record the refund decision:&lt;/strong&gt; we have a python function we use to record the decisions made - we can call this easily with a &lt;code&gt;function_step&lt;/code&gt; which allows directly calling python functions as part of the plan run.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Find the payment in Stripe:&lt;/strong&gt; finding a payment in Stripe requires using several tools from Stripe’s remote MCP server (which is &lt;a href="https://docs.portialabs.ai/portia-tools/remote-mcp/stripe" rel="noopener noreferrer"&gt;easily enabled in your Portia account&lt;/a&gt;). Therefore, we set up a &lt;a href="https://www.promptingguide.ai/techniques/react" rel="noopener noreferrer"&gt;ReAct&lt;/a&gt; agent with the required tools and it can intelligently chain the required Stripe tools together in order to find the payment. As a bonus, Portia uses MCP Auth by default so these tool calls will be fully authenticated.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Controlled Autonomy
&lt;/h2&gt;

&lt;p&gt;As demonstrated in the above example, the power of &lt;code&gt;PlanBuilderV2&lt;/code&gt; comes from the fact you can easily connect and combine different step types, depending on your situation and requirements. This allows you to control the amount of autonomy your system has at each point in its execution, with some steps (e.g. &lt;code&gt;react_agent_step&lt;/code&gt;) making use of language models with high autonomy while others are carefully controlled and constrained (e.g. &lt;code&gt;invoke_tool_step&lt;/code&gt;).&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%2F0kla772rncam4irxkmdu.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%2F0kla772rncam4irxkmdu.png" alt="Autonomy of PlanBuilder steps" width="716" height="223"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;From our experience, it is this ‘&lt;strong&gt;controlled autonomy&lt;/strong&gt;’ that is the key to getting agents to execute reliably, which allows us to move from exciting prototypes into real, production agents. Often, prototypes are built with ‘full autonomy’, giving something like a ReAct agent access to all tools and letting it loose on a task. This approach is possible with our plan builder and can work well in some situations, but in other situations (particularly for more complex tasks) it can lead to agents that are unreliable. We’ve found that tasks often need to be broken down and structured into manageable sub-tasks, with the autonomy for each sub-task controlled, for them to be done reliably. For example, we often see research and retrieval steps in a system being done with high autonomy ReAct agent steps because they generally use read-only tools that don’t affect other systems. Then, when it comes to the agent taking actions, these steps are done with zero or low autonomy so they can be done in a more controlled manner.&lt;/p&gt;

&lt;h2&gt;
  
  
  Simple Control structures
&lt;/h2&gt;

&lt;p&gt;Extending the above example, our &lt;code&gt;PlanBuilderV2&lt;/code&gt; also provides familiar control structures that you can use when breaking down tasks for your agentic system. This gives you full control to ensure that the task is approached in a reliable way:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# Conditional steps (if, else if, else)
&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;if_&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;condition&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="k"&gt;lambda&lt;/span&gt; &lt;span class="n"&gt;review&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;review&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;decision&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;REJECTED&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;llm_review_decision&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;StepOutput&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;llm_refund_review&lt;/span&gt;&lt;span class="sh"&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;function_step&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;function&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;handle_rejected_refund&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;proposed_refund&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;StepOutput&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;proposed_refund&lt;/span&gt;&lt;span class="sh"&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;endif&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="c1"&gt;# Loops - here we use .loop(over=...), but there are also alternatives for
#         .loop(while=...) and .loop(do_while=...)
&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;loop&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;over&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nc"&gt;StepOutput&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Items&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;step_name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Loop&lt;/span&gt;&lt;span class="sh"&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;function_step&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;function&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="k"&gt;lambda&lt;/span&gt; &lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;item&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;StepOutput&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Loop&lt;/span&gt;&lt;span class="sh"&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;end_loop&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Fun fact: We went with &lt;code&gt;.if_()&lt;/code&gt; rather than &lt;code&gt;.if()&lt;/code&gt; (note the underscore) because &lt;code&gt;if&lt;/code&gt; is a restricted keyword in python&lt;/p&gt;

&lt;h2&gt;
  
  
  Human - Agent interface
&lt;/h2&gt;

&lt;p&gt;Another aspect that is vital towards getting an agent into production is the ability to seamlessly pass control between agents and humans. While we build trust in agentic systems, there are often key steps that require verification or input from humans. Our PlanBuilder interface allows both to be handled easily, using Portia’s &lt;a href="https://docs.portialabs.ai/understand-clarifications" rel="noopener noreferrer"&gt;clarification system&lt;/a&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# Ensure a human approves any refunds our agent gives out
&lt;/span&gt;&lt;span class="n"&gt;builder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;user_verify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Are you happy to proceed with the following proposed refund: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nc"&gt;StepOutput&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;proposed_refund&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;?&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;# Allow your end user to provide input into how the agent runs
&lt;/span&gt;&lt;span class="n"&gt;builder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;user_input&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;How would you like your refund?&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;options&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Return to purchase card&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;gift card&lt;/span&gt;&lt;span class="sh"&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;h2&gt;
  
  
  Controlling your agent with code
&lt;/h2&gt;

&lt;p&gt;The &lt;code&gt;function_step&lt;/code&gt; demonstrated earlier is a key addition to &lt;code&gt;PlanBuilderV2&lt;/code&gt;. In many agentic systems, all tool and function calls go through a language model, which can be slow and also can reduce reliability. With &lt;code&gt;function_step&lt;/code&gt;, the function is called with the provided &lt;code&gt;args&lt;/code&gt; at that point in the chain with full reliability. We’ve seen several use-case for this:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Guardrails:&lt;/strong&gt; where deterministic, reliable code checks are used to verify agent behaviour (see example below)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Data manipulation:&lt;/strong&gt; when you want to do a simple data transformation in order to link tools together, but you don’t want to pay the latency penalty of an extra LLM call to do the transformation, you can instead do the transformation in code.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Plug in existing functions:&lt;/strong&gt; when you’ve already got the functionality you need in code, you can use a function_step to easily plug that into your agent.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# Add a guardrail to prevent our agent giving our large refunds
&lt;/span&gt;&lt;span class="n"&gt;builder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;function_step&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;step_name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;reject_payments_above_limit&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;function&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;reject_payments_above_limit&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;proposed_refund&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;StepOutput&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;proposed_refund&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;limit&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Input&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;payment_limit&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  What’s next?
&lt;/h2&gt;

&lt;p&gt;We’ve really enjoyed building agents with &lt;code&gt;PlanBuilderV2&lt;/code&gt; and are excited to share it more widely. We find that it complements our planning agent nicely: our planning agent can be used to dynamically create plans from natural language when that is needed for your use-case, while the plan builder can be used if you want to more carefully control the steps your agentic system takes with code. &lt;/p&gt;

&lt;p&gt;We’ve also got more features coming up over the next few weeks that will continue to make the plan builder interface even more powerful:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Parallelism:&lt;/strong&gt; run steps in parallel with &lt;code&gt;.parallel()&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Automatic caching:&lt;/strong&gt; add &lt;code&gt;cache=True&lt;/code&gt; to steps to automatically cache results - this is a game-changer when you want to iterate on later steps in a plan without having to fully re-run the plan.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Step error handler:&lt;/strong&gt; specify &lt;code&gt;.on_error()&lt;/code&gt; after a step to attach an error handler to it, &lt;code&gt;.retry()&lt;/code&gt; to allow retries of steps or use &lt;code&gt;exit_step()&lt;/code&gt; to gracefully exit a plan.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Linked plans:&lt;/strong&gt; link plans together by referring to outputs from previous plan runs.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;plan&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nc"&gt;PlanBuilderV2&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Run this plan to process a refund request.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="c1"&gt;# 1. Run subsequent steps in parallel
&lt;/span&gt;    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;parallel&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;invoke_tool_step&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;tool&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;file_reader_tool&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;filename&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;./refund_policy.txt&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="c1"&gt;# 2. Add automatic caching to a step
&lt;/span&gt;        &lt;span class="n"&gt;cache&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="c1"&gt;# 3. Add error handling to a step
&lt;/span&gt;    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;on_error&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;react_agent_step&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="c1"&gt;# 4. Link plans together by referring to outputs from a previous run
&lt;/span&gt;        &lt;span class="c1"&gt;# Here, we could have a previous agent that determines which       customer refunds to process
&lt;/span&gt;        &lt;span class="n"&gt;task&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Read the refund request from my inbox from &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nc"&gt;PlanRunOutput&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;previous_run&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;tools&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;portia:google:gmail:search_email&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="c1"&gt;# Resume series execution
&lt;/span&gt;    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;series&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;Shout out to &lt;a href="https://github.com/gaurava05" rel="noopener noreferrer"&gt;gaurava05&lt;/a&gt; for adding &lt;code&gt;ExitStep&lt;/code&gt; as an open-source contribution in &lt;a href="https://github.com/portiaAI/portia-sdk-python/pull/742" rel="noopener noreferrer"&gt;this PR&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;So give our new PlanBuilder a try and let us know how you get on - we can’t wait to see what you build! 🚀&lt;/p&gt;

&lt;p&gt;For more details on &lt;code&gt;PlanBuilderV2&lt;/code&gt;, check out our &lt;a href="https://docs.portialabs.ai/build-plan" rel="noopener noreferrer"&gt;docs&lt;/a&gt;, our &lt;a href="https://github.com/portiaAI/portia-sdk-python/blob/main/example_builder.py" rel="noopener noreferrer"&gt;example plan&lt;/a&gt; or the &lt;a href="https://github.com/portiaAI/portia-agent-examples/blob/main/refund-agent-mcp/refund_agent_with_builder.py" rel="noopener noreferrer"&gt;full stripe refund example&lt;/a&gt;. You can also join our &lt;a href="https://discord.com/invite/DvAJz9ffaR" rel="noopener noreferrer"&gt;Discord&lt;/a&gt; to hear future updates. &lt;/p&gt;

</description>
    </item>
    <item>
      <title>Portia AI: Initial Thoughts on GPT-5</title>
      <dc:creator>Robbie Heywood</dc:creator>
      <pubDate>Mon, 11 Aug 2025 14:57:35 +0000</pubDate>
      <link>https://dev.to/portia-ai/portia-ai-initial-thoughts-on-gpt-5-4ik</link>
      <guid>https://dev.to/portia-ai/portia-ai-initial-thoughts-on-gpt-5-4ik</guid>
      <description>&lt;p&gt;At Portia AI, we’ve been playing around with GPT-5 since it was released a few days ago and we’re excited to announce it will be available to SDK users in tomorrow’s SDK release 🎉&lt;/p&gt;

&lt;p&gt;After playing with it for a bit, it definitely feels an incremental improvement rather than a step-change (despite my LinkedIn feed being full of people pronouncing it ‘game-changing!). To pick out some specific aspects:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Equivalent Accuracy&lt;/strong&gt;: on our benchmarks, GPT5’s performance is equal to the existing top model, so this is an incremental improvement (if any).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Handles complex tools&lt;/strong&gt;: GPT-5 is definitely keener to use tools. We’re still playing around with this, but it does seem like it can handle (and prefers) broader, more complex tools. This is exciting - it should make it easier to build more powerful agents, but also means a re-think of the tools you’re using.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Slow&lt;/strong&gt;: With the default parameters, the model is seriously slow - generally 5-10x slower across each of our benchmarks. This makes tuning the new &lt;code&gt;reasoning_effort&lt;/code&gt; and &lt;code&gt;verbosity&lt;/code&gt; parameters important.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;I actually miss the model picker!&lt;/strong&gt; With the model picker gone, you’re left to rely on the fuzzier world of natural language (and the new &lt;code&gt;reasoning_effort&lt;/code&gt; and &lt;code&gt;verbosity&lt;/code&gt; parameters) to control the model. This is tricky enough that OpenAI have released a new &lt;a href="https://cookbook.openai.com/examples/gpt-5/gpt-5_prompting_guide" rel="noopener noreferrer"&gt;prompt guide&lt;/a&gt; and &lt;a href="https://platform.openai.com/chat/edit?models=gpt-5&amp;amp;optimize=true" rel="noopener noreferrer"&gt;prompt optimiser&lt;/a&gt;. I think there will be real changes when there are models that you don’t feel you need to control in this way - but GPT-5 isn’t there yet.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Solid pricing&lt;/strong&gt;: While it is a little more token-hungry on our benchmarks (10-20% more tokens in our benchmarks), at half the price of GPT-4o / 4.1 / o3, it is a good price for the level of intelligence (a &lt;a href="https://www.latent.space/p/gpt5-router" rel="noopener noreferrer"&gt;great article&lt;/a&gt; on this from Latent Space).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Reasonable context window&lt;/strong&gt;: At 256k tokens, the context window is fine - but we’ve had several use-cases that use GPT-4.1 / Gemini’s 1m token windows, so we’d been hoping for more...&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Coding&lt;/strong&gt;: In Cursor, I’ve found GPT-5 a bit difficult to work with - it’s slow and often over-thinks problems. I’ve moved back to claude-4, though I do use GPT-5 when looking to one-shot something rather than working with the model.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;There are also two aspects that we haven’t dug into yet, but I’m really looking forward to putting them through their paces:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Tool Preambles&lt;/strong&gt;: GPT 5 has been trained to give progress updates in ‘tool preamble’ messages. It’s often really important to keep the user informed as an agent progresses, which can be difficult if the model is being used as a black box. I haven’t seen much talk about this as a feature, but I think it has the potential to be incredibly useful for agent builders.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Replanning&lt;/strong&gt;: In the past, we’ve got ourselves stuck in loops (particularly with OpenAI models) where the model keeps trying the same thing even when it doesn’t work. GPT-5 is supposed to handle these cases that require a replan much better - it’ll be interesting to dive into this more and see if that’s the case.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;As a summary, this is still an incremental improvement (if any). It’s sad to see it &lt;a href="https://kieranhealy.org/blog/archives/2025/08/07/blueberry-hill/" rel="noopener noreferrer"&gt;still can’t count the letters in various fruit&lt;/a&gt; and I’m still mostly using claude-4 in cursor.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>How I Built an AI Agent That Turns Daily AI News Into a Commute-Sized Podcast</title>
      <dc:creator>Robbie Heywood</dc:creator>
      <pubDate>Fri, 01 Aug 2025 14:54:27 +0000</pubDate>
      <link>https://dev.to/portia-ai/how-i-built-an-ai-agent-that-turns-daily-ai-news-into-a-commute-sized-podcast-44pg</link>
      <guid>https://dev.to/portia-ai/how-i-built-an-ai-agent-that-turns-daily-ai-news-into-a-commute-sized-podcast-44pg</guid>
      <description>&lt;p&gt;The AI landscape moves at breakneck speed. New models, research papers, funding announcements, and product launches happen daily. As someone working in AI, staying current isn't just helpful—it's essential. But when you're heads-down building features and shipping products, it's tough to find the time to stay on top of all the latest developments.&lt;/p&gt;

&lt;p&gt;That's exactly the challenge we faced at Portia AI. The solution? An AI agent that helps us make the most of the 5-minute stroll our team makes each afternoon to Kings Cross on their way home.&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%2F52iisrhxbg07vq5bnwk4.jpg" 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%2F52iisrhxbg07vq5bnwk4.jpg" alt="Alt text" width="800" height="451"&gt;&lt;/a&gt;&lt;br&gt;I’m sure Harry would have spent his commute back from Kings cross listening to our AI podcast too...
  &lt;/p&gt;

&lt;h2&gt;
  
  
  Building AI News Into a Routine
&lt;/h2&gt;

&lt;p&gt;Working in AI means being subscribed to information from multiple sources. The traditional approach of manually checking news sites, Reddit, Twitter, and newsletters was tedious and time-consuming, while important developments could take time to circulate through the team.&lt;/p&gt;

&lt;p&gt;During one of our regular work hack sessions, inspired by NotebookLM's podcast feature, I decided to tackle this problem by building an AI agent that creates daily short AI news podcasts. Here's how it works:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Subscribes to multiple AI news sources throughout the day&lt;/li&gt;
&lt;li&gt;Identifies the most significant developments&lt;/li&gt;
&lt;li&gt;Synthesizes the information into a concise narrative&lt;/li&gt;
&lt;li&gt;Generates a 2-3 minute podcast episode using the fantastic &lt;a href="https://github.com/souzatharsis/podcastfy" rel="noopener noreferrer"&gt;Podcastfy&lt;/a&gt; library&lt;/li&gt;
&lt;li&gt;Provides curated links for deeper investigation&lt;/li&gt;
&lt;li&gt;Shares the podcast and links on Slack and Discord&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;We run the agent in the afternoon, so the podcast is available before people's evening commute. This timing allows people to easily integrate the updates into their daily routine. We've also found that the curated links are particularly valuable when there's a topic that's especially relevant to someone, allowing them to dig deeper into the details.&lt;/p&gt;

&lt;h2&gt;
  
  
  Getting Involved
&lt;/h2&gt;

&lt;p&gt;We know that staying abreast of the latest developments is a difficulty lots of teams face, so we've made these news snippets available on our public &lt;a href="https://discord.com/invite/DvAJz9ffaR" rel="noopener noreferrer"&gt;Discord server&lt;/a&gt;. Come and check it out if it sounds like something that could be useful.&lt;/p&gt;

&lt;p&gt;The code is open sourced in our &lt;a href="https://github.com/portiaAI/portia-agent-examples" rel="noopener noreferrer"&gt;agent examples repo&lt;/a&gt; if you're keen to see exactly how it works or build something similar for your own team. I think it’s a nice example of how Portia’s open-source &lt;a href="https://github.com/portiaAI/portia-sdk-python" rel="noopener noreferrer"&gt;agent SDK&lt;/a&gt; makes agents incredibly easy to build. With the agent framework handling much of the complex orchestration between services and APIs, the code ends up being not much more than:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;plan_prompt&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;&amp;lt;Task specification&amp;gt;&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
&lt;span class="n"&gt;tools&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;DefaultToolRegistry&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;config&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="nc"&gt;PodcastTool&lt;/span&gt;&lt;span class="p"&gt;()]&lt;/span&gt;
&lt;span class="n"&gt;portia&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Portia&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tools&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;tools&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;portia&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="n"&gt;plan_prompt&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Hope this helps others stay on top of the fast-moving AI world! Enjoy!&lt;/p&gt;

</description>
      <category>ai</category>
      <category>agents</category>
      <category>llm</category>
      <category>hackathon</category>
    </item>
  </channel>
</rss>
