<?xml version="1.0" encoding="utf-8"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/"><channel><title>Agents in practice — Juan Reyero</title><link>https://juanreyero.com/topics/agents-in-practice/</link><description>Context, memory, communication, and what it takes to complete real work.</description><language>en</language><atom:link href="https://juanreyero.com/topics/agents-in-practice/index.xml" rel="self" type="application/rss+xml"/><lastBuildDate>Sat, 16 May 2026 00:00:00 +0000</lastBuildDate><item><title>Spend your compute on correctness</title><link>https://juanreyero.com/article/ai/spend-compute-on-correctness/</link><guid>https://juanreyero.com/article/ai/spend-compute-on-correctness/</guid><pubDate>Sat, 16 May 2026 00:00:00 +0000</pubDate><description>How I think about allocating agent effort to checking the work we produce.</description><content:encoded>&lt;p>For developers who have fully embraced AI agents, productivity is
no longer the bottleneck. Agents produce code faster than humans,
and often better. The bottleneck is correctness: whether the code
solves the problem, whether the architecture can still hold the
feature set you&amp;rsquo;re growing into, whether the implementation
encodes the right premises. The practical shift is that a
significant fraction of your agent compute should now go to
validation (tests, reviewers, scope checks), rather than to
producing more code.&lt;/p>
&lt;h2 id="productivity-is-no-longer-the-bottleneck">Productivity is no longer the bottleneck&lt;/h2>
&lt;p>A year ago, the argument for agentic programming was throughput:
agents let you ship more code in less time.&lt;/p>
&lt;p>That is not controversial anymore. With the current generation of
models inside agentic harnesses (Claude Code, Codex, and the
like), a single developer supervising one agent can run circles
around a small team writing by hand.&lt;/p>
&lt;p>For people fully inside this workflow, the question is no longer
&amp;ldquo;how do I produce more?&amp;rdquo;. It is &amp;ldquo;how do I know what I produced
is right?&amp;rdquo;.&lt;/p>
&lt;h2 id="three-layers-where-right-can-fail">Three layers where &amp;ldquo;right&amp;rdquo; can fail&lt;/h2>
&lt;p>Each layer has its own remedies.&lt;/p>
&lt;h3 id="the-product-layer-does-this-match-what-a-user-wants">The product layer: does this match what a user wants?&lt;/h3>
&lt;p>Part of &amp;ldquo;right&amp;rdquo; is still human judgment. An actual human has to
look at the running product and say whether it does what they
actually need. No amount of agent compute substitutes for that.&lt;/p>
&lt;p>(Incidentally, this will probably change fast, as more and more
products are targeted at agents.)&lt;/p>
&lt;p>The most you can do is make this human&amp;rsquo;s job easy: ship into a
real environment quickly, with real data, so the human can poke
at it and react.&lt;/p>
&lt;h3 id="the-architecture-layer-is-this-the-right-shape-of-code">The architecture layer: is this the right shape of code?&lt;/h3>
&lt;p>This is the hardest layer, and the one where current agents are
weakest.&lt;/p>
&lt;p>A lot of what experienced software engineers do is architectural
judgment:&lt;/p>
&lt;ul>
&lt;li>structuring code so it can accommodate the features that will
land on it, &lt;strong>without knowing in advance what&amp;rsquo;s coming&lt;/strong>;&lt;/li>
&lt;li>knowing what features &lt;strong>not&lt;/strong> to implement;&lt;/li>
&lt;li>recognizing when the feature set has outgrown the original
architecture, and the codebase needs to be reshaped before
more code can land cleanly.&lt;/li>
&lt;/ul>
&lt;p>Agents are not yet good at any of these. They will happily add
the feature you asked for, in the place where it fits least,
with abstractions that make the next three features harder.&lt;/p>
&lt;p>They will implement the configurability you asked for instead
of pushing back on whether you should want it. They will keep
extending a structure that has outlived its assumptions, because
each individual diff still looks reasonable in isolation.&lt;/p>
&lt;p>The remedy at this layer is human-driven architectural review,
backed by an agent whose explicit job is to check each diff
against a source-of-truth document for scope and shape.&lt;/p>
&lt;h3 id="the-implementation-layer-is-the-code-doing-what-it-claims">The implementation layer: is the code doing what it claims?&lt;/h3>
&lt;p>The third failure mode is the easiest to miss: code that looks
right, has passing tests, and is actually wrong. The premises
it encodes are off by a degree. There is a workaround in the
middle that the tests happen not to exercise. A helper that
&amp;ldquo;handles edge cases&amp;rdquo; is actually swallowing errors that should
be propagated.&lt;/p>
&lt;p>This is the failure mode the writer agent cannot see, because
it inherited the premises from its own earlier reasoning. It
needs a separate pair of eyes (a reviewer agent, a fresh-context
subagent, or a different agent kind entirely) to read the diff
without the writer&amp;rsquo;s assumptions.&lt;/p>
&lt;h2 id="validation-is-what-you-spend-compute-on">Validation is what you spend compute on&lt;/h2>
&lt;p>The remedy is simple to state and harder to commit to: spend a
significant fraction of your agent budget on validation.&lt;/p>
&lt;p>&lt;strong>The point of running teams of coding agents is no longer to
produce more code faster. It is to make it more likely that the
code is correct.&lt;/strong>&lt;/p>
&lt;p>Validation, in practice, means several things at once:&lt;/p>
&lt;ul>
&lt;li>&lt;strong>Tests, including the expensive ones.&lt;/strong> Real end-to-end tests
against a real database. Browser tests with Playwright. Runs
against representative data.&lt;/li>
&lt;li>&lt;strong>Constant code review, not just at PR time.&lt;/strong> A reviewer
agent that reads each diff as it lands, with the architectural
document and the task list in its context.&lt;/li>
&lt;li>&lt;strong>Scope rechecks against a source-of-truth document.&lt;/strong> Has the
diff drifted from the original ask? Has the agent quietly
expanded the scope? Has it implemented something the SOT
explicitly said not to do?&lt;/li>
&lt;/ul>
&lt;p>The mistake is to treat validation as a tax on productivity. It
isn&amp;rsquo;t. The output of one coding agent whose work has been
validated is worth meaningfully more than the output of two
coding agents whose work has not.&lt;/p>
&lt;h2 id="three-patterns-to-apply">Three patterns to apply&lt;/h2>
&lt;p>There are several ways to deploy validation compute. They are
not exclusive.&lt;/p>
&lt;ol>
&lt;li>&lt;strong>A code-reviewer subagent inside the same agent.&lt;/strong> Both
Claude Code and Codex ship with strong code-reviewer
subagents. The writer spawns one mid-task, gets local
feedback, applies it. Catches bugs, missing edge cases, style
violations. Cheap and easy first step.&lt;/li>
&lt;li>&lt;strong>A different agent kind reviewing the writer.&lt;/strong> Have Claude
Code spawn Codex (or vice versa) for review. Different
training, different priors, catches a slightly different
class of issue. Works, but is qualitatively close to (1).&lt;/li>
&lt;li>&lt;strong>A persistent, specialized reviewer agent.&lt;/strong> Two agents per
significant task. One programmer, one reviewer; they persist,
share a task list, and talk after each TDD cycle. This is
the pattern I have found most useful. I &lt;a href="https://juanreyero.com/article/ai/two-agents-not-one/">wrote separately
about it&lt;/a>; in this article&amp;rsquo;s
framing, it is the highest-context, most expensive, and most
useful form of validation compute.&lt;/li>
&lt;/ol>
&lt;h2 id="the-shift">The shift&lt;/h2>
&lt;p>The earlier argument for agentic programming was: &lt;strong>you can
produce more code per hour of attention&lt;/strong>. That is still true,
and still useful.&lt;/p>
&lt;p>The argument that matters more for people already inside the
workflow is: &lt;strong>you can produce more correct code per hour of
attention, if you spend the compute on correctness&lt;/strong>.&lt;/p>
&lt;p>The bottleneck has moved. The budget should move with it.&lt;/p>
&lt;hr>
&lt;p>&lt;em>Our team behind &lt;a href="https://github.com/awebai/aweb">aweb&lt;/a> uses this
pattern daily. aweb is an open-source coordination layer for AI
coding agents — identity, task claims, messaging across worktrees
and machines. MIT-licensed. Hosted at &lt;a href="https://aweb.ai">aweb.ai&lt;/a>&lt;/em>&lt;/p></content:encoded></item><item><title>Pair your coding agent with a reviewer</title><link>https://juanreyero.com/article/ai/two-agents-not-one/</link><guid>https://juanreyero.com/article/ai/two-agents-not-one/</guid><pubDate>Fri, 08 May 2026 00:00:00 +0000</pubDate><description>A working arrangement for two agents, and why giving them different responsibilities matters.</description><content:encoded>&lt;p>The simplest improvement you can make to your agentic programming
workflow is to run two agents instead of one. One writes code in
its own worktree; the other, in a parallel worktree, reviews it.
They share a task list and talk after every TDD cycle. The reviewer
is the holder of the lamp: it keeps the end goal fresh in context
across the whole task, catching drift before it accumulates.&lt;/p>
&lt;p>I &lt;a href="https://juanreyero.com/article/ai/we-need-more-programmers/">wrote previously&lt;/a> that
the bottleneck in AI-assisted programming is shifting from
individual productivity to coordination. The two-agent pair is the
simplest possible coordination, and the most useful next step for
anyone who has gotten comfortable running one agent and is ready
for more.&lt;/p>
&lt;h2 id="one-agent-works-but-it-drifts">One agent works, but it drifts&lt;/h2>
&lt;p>A single coding agent gets a lot done. It picks up a task, writes
the test, writes the implementation, runs code-reviewer
subagents, runs the test suite, fixes what&amp;rsquo;s broken,
commits.&lt;/p>
&lt;p>However, when a task is longer than its working context can hold
cleanly, the agent tends to lose sight of the original brief. It
makes locally-correct decisions that drift from the overall goal.&lt;/p>
&lt;h2 id="two-agents-writer-and-reviewer">Two agents: writer and reviewer&lt;/h2>
&lt;p>The pattern is simple: two shells, each with its own worktree of
the same repo, each with an &lt;a href="https://aweb.ai">aweb identity&lt;/a>. Run
a coding agent in each.&lt;/p>
&lt;p>One agent writes code, the other agent reviews. They share tasks,
because they are in the same aweb team. When the coding agent
finishes a task, it sends mail to the reviewing agent
requesting feedback. The reviewing agent does a thorough code
review, and then chats with the coding agent. They discuss the
findings, and either move on to the next task or agree to have
the coding agent go back and fix the implementation.&lt;/p>
&lt;p>The cycle, per task:&lt;/p>
&lt;ol>
&lt;li>The writer picks up the next task.&lt;/li>
&lt;li>Writes the test first (TDD: red, then green).&lt;/li>
&lt;li>Implements until the test passes.&lt;/li>
&lt;li>Asks the reviewer for a review on the diff.&lt;/li>
&lt;li>Waits for the review to come back.&lt;/li>
&lt;li>Discusses anything unclear with the reviewer.&lt;/li>
&lt;li>Applies the changes the review asked for.&lt;/li>
&lt;li>Marks the task done; moves to the next.&lt;/li>
&lt;/ol>
&lt;h2 id="the-reviewer-holds-the-lamp">The reviewer holds the lamp&lt;/h2>
&lt;p>A coding agent that has been writing for an hour has its working
context filled with implementation details: the function it just
refactored, the test it just made green, the import it just
moved. The original goal — the why of the task — has been
crowded out by the how.&lt;/p>
&lt;p>The reviewer agent has a different job. It reads the original
brief, the task list, the architectural constraints. When the
diff arrives, the reviewer asks the question the writer can no
longer ask: does this still solve the original
problem? Does it move us toward the end state we agreed on?&lt;/p>
&lt;p>I think of the reviewer as the holder of the lamp — the one who
keeps the destination visible while the writer is heads-down in
the trench. Without the lamp, the writer eventually walks in a
circle and convinces itself the new spot is the destination.&lt;/p>
&lt;p>The reviewer also catches a class of error that is invisible to
the writer: implementations that are correct but make the next
task harder. &lt;strong>The writer is optimizing the current diff. The
reviewer is optimizing the trajectory.&lt;/strong>&lt;/p>
&lt;h2 id="on-top-of-subagents">On top of subagents&lt;/h2>
&lt;p>Both Claude Code and Codex have strong code-reviewer subagents
built in. The writer agent can spawn a code-reviewer subagent
mid-task to catch local issues — bugs, missing edge cases, style
violations. These work well and you should keep using them.&lt;/p>
&lt;p>A dedicated reviewer agent is a different layer. The
code-reviewer subagent runs once inside the writer&amp;rsquo;s session and
forgets when it returns. It sees the diff but not the
trajectory. The dedicated reviewer is a separate, persistent
session whose context is kept fresh on the end goal across the
whole task list.&lt;/p>
&lt;p>The two complement cleanly. Subagents catch local issues at the
diff level. The dedicated reviewer catches drift at the
trajectory level. Use both; they do not compete for context, and
they catch different classes of mistake.&lt;/p>
&lt;h2 id="scaling-up-a-product--engineering-owner-agent">Scaling up: a product / engineering owner agent&lt;/h2>
&lt;p>Once the writer/reviewer pair works for one task list, the next
step is adding a third agent: a product / engineering owner.
This one is not in the loop on every diff. It scopes work, breaks
larger goals into the task list each pair consumes, and reviews
the result before it ships.&lt;/p>
&lt;p>In our team, this agent is named Athena. She owns engineering
direction for the &lt;a href="https://github.com/awebai/aweb">aweb&lt;/a>
codebase: architecture, invariants, review of every diff that
lands on main. She does not write code on most tasks; she
scopes, dispatches, reviews. When a substantial feature needs
authoring, Athena asks for a writer/reviewer pair as a
worktree-scoped task, then reviews the gate-input commit before
it goes to ship.&lt;/p>
&lt;p>Athena pairs with another agent, Hestia, who handles operations.
Hestia runs the gate chain (full end-to-end tests, release-ready
checks) then tags releases, deploys, and verifies that the new
version is live. Athena hands off the reviewed code to Hestia,
and Hestia ships releases. Neither is the other&amp;rsquo;s manager; they
are peers in different roles.&lt;/p>
&lt;p>This is the working pattern across our codebase today. Two-agent
pairs implement; Athena scopes and reviews; Hestia runs gates and
deploys. Even multi-day shipping efforts, like a customer-blocking
bug we recently worked through across several back-to-back
releases, fit this shape without any extra orchestration layer.&lt;/p>
&lt;p>I believe that the lesson generalizes. Most agentic-programming
bottlenecks are no longer capability problems. They are
coordination problems. &lt;strong>The simplest form of coordination is a
peer that holds context the working agent has lost. Two agents
can do this for each other with no infrastructure beyond the
conventions of how they talk.&lt;/strong>&lt;/p>
&lt;hr>
&lt;p>&lt;em>Our team behind &lt;a href="https://github.com/awebai/aweb">aweb&lt;/a> uses this
pattern daily. aweb is an open-source coordination layer for AI
coding agents — identity, task claims, messaging across worktrees
and machines. MIT-licensed. Hosted at &lt;a href="https://aweb.ai">aweb.ai&lt;/a>&lt;/em>&lt;/p></content:encoded></item><item><title>BeadHub: coordination for AI programming teams</title><link>https://juanreyero.com/article/ai/beadhub/</link><guid>https://juanreyero.com/article/ai/beadhub/</guid><pubDate>Mon, 16 Feb 2026 00:00:00 +0000</pubDate><description>An earlier experiment in coordinating AI programming teams, since superseded by aweb.</description><content:encoded>&lt;p>&lt;strong>Note added on 2026-05-08:&lt;/strong> I am moving away from
beadhub. Having a tool that messed up with my .git was too
painful. I have been focussing all my efforts in &lt;a href="https://aweb.ai">https://aweb.ai&lt;/a>
(OSS at &lt;a href="https://github.com/awebai/aweb">https://github.com/awebai/aweb&lt;/a>) which fully replaces
beads and beahdub.&lt;/p>
&lt;p>I wrote &lt;a href="https://juanreyero.com/article/ai/we-need-more-programmers/">previously&lt;/a> that
the bottleneck in AI-assisted programming is shifting from
individual productivity to coordination. I&amp;rsquo;ve spent the past
several months building a tool to address that.&lt;/p>
&lt;p>&lt;a href="https://beadhub.ai">BeadHub&lt;/a> is an open-source coordination
server that lets AI programming agents claim work, talk to each
other, reserve files, and escalate to humans—across machines and
across programmers. I use it daily to manage around fifteen
agents working on two or three products.&lt;/p>
&lt;h2 id="beads">Beads&lt;/h2>
&lt;p>Around the time I wrote that article, I started using Steve
Yegge&amp;rsquo;s &lt;a href="https://github.com/steveyegge/beads">beads&lt;/a>, a
git-native issue tracker designed for AI agents. Your agent runs
&lt;code>bd create &amp;quot;Fix the login redirect bug&amp;quot;&lt;/code> and it appends a JSON
line to &lt;code>.beads/issues.jsonl&lt;/code>, right in the repository. Issues
travel with the code. When you push a branch, the issues come
along.&lt;/p>
&lt;p>Yegge calls it the &amp;ldquo;50 First Dates&amp;rdquo; problem: agents wake up every
session with no memory of yesterday&amp;rsquo;s work. Beads fixes that. An
agent reads the issue list and knows where things stand. My
agents got much more done.&lt;/p>
&lt;p>Which meant more agents, more worktrees, more parallel work—and
the coordination problem became even more acute. Two agents
modify the same file. One refactors a function while another adds
to it. An agent picks up a task already in progress in a
different worktree. Nobody knows who&amp;rsquo;s working on what.&lt;/p>
&lt;p>But beads is also the right scaffolding for coordination. If
everyone in a team uses beads, all agents share a picture of what
needs doing. Beads gives agents something useful to talk about;
BeadHub gives them a way to talk.&lt;/p>
&lt;h2 id="the-coordination-gap">The coordination gap&lt;/h2>
&lt;p>The major platforms are moving in this direction. Anthropic just
shipped &lt;a href="https://code.claude.com/docs/en/agent-teams">Agent
Teams&lt;/a> in Claude
Code: a lead session that spawns independent teammates who
communicate directly and self-coordinate. OpenAI&amp;rsquo;s &lt;a href="https://openai.com/index/introducing-codex/">Codex
app&lt;/a> runs parallel
agent threads in isolated worktrees.&lt;/p>
&lt;p>Yegge built &lt;a href="https://github.com/steveyegge/gastown">Gas Town&lt;/a> on
top of beads to tackle the single-machine case: a &amp;ldquo;Mayor&amp;rdquo; agent
orchestrates dozens of coding agents, tracks work in convoys, and
persists state so agents can pick up where they left off.&lt;/p>
&lt;p>These are real steps forward, but they&amp;rsquo;re solving a specific
version of the problem: multiple agents for one programmer, on
one machine, within one tool.&lt;/p>
&lt;p>The version I am interested in is Maria in Buenos Aires running a
frontend agent while Juan in San Francisco runs a backend agent,
and they need their agents to not destroy each other&amp;rsquo;s work, and
to figure out how to work together.&lt;/p>
&lt;h2 id="beadhub">BeadHub&lt;/h2>
&lt;p>BeadHub is a server that agents connect to through &lt;code>bdh&lt;/code>, a
wrapper around the beads &lt;code>bd&lt;/code> command. When an agent runs any
&lt;code>bdh&lt;/code> command it registers with the server. The server tracks
which agents are online across the project—what machine they&amp;rsquo;re
on, what branch, what files they&amp;rsquo;re touching.&lt;/p>
&lt;p>&lt;strong>Communication.&lt;/strong> Agents can send each other mail (async,
fire-and-forget) or chat (sync, block-until-reply). With mail an
agent finishes a task and drops a note: &amp;ldquo;Done with bd-42, tests
passing.&amp;rdquo; Chat is for when agents need to think together: &amp;ldquo;I&amp;rsquo;m
adding a &lt;code>role&lt;/code> field to the user model—will that break your
permission checks?&amp;rdquo; / &amp;ldquo;It will, but the fix is small. Go ahead
and I&amp;rsquo;ll update my side.&amp;rdquo;&lt;/p>
&lt;p>&lt;strong>Claims.&lt;/strong> When an agent marks a bead as in-progress, that claim
is immediately visible to every other agent in the project,
regardless of whose machine they&amp;rsquo;re on. If another agent tries to
claim the same bead, it gets rejected with a message telling it
who has it.&lt;/p>
&lt;p>&lt;strong>File reservations.&lt;/strong> When an agent modifies a file, the server
records an advisory lock. Other agents see a warning if they
touch the same file. Advisory, not blocking—hard locks caused
deadlocks immediately in early versions. Agent A locks file X,
agent B locks file Y, both need the other&amp;rsquo;s file. Warnings work
better. Agents are cooperative; they just need information.&lt;/p>
&lt;p>&lt;strong>Escalation.&lt;/strong> An agent runs &lt;code>bdh :escalate&lt;/code> with a description
of what it&amp;rsquo;s stuck on and a human gets notified with full
context. Without this, agents either fail silently or spin
retrying things that need human judgment.&lt;/p>
&lt;p>The multi-machine part is where it comes together. BeadHub
recognizes Maria&amp;rsquo;s and Juan&amp;rsquo;s clones as the same repo. Maria&amp;rsquo;s
agents and Juan&amp;rsquo;s agents see each other&amp;rsquo;s claims, locks, and
messages. If Maria&amp;rsquo;s frontend agent reserves
&lt;code>src/components/Auth.tsx&lt;/code>, Juan&amp;rsquo;s backend agent sees the warning
even though they&amp;rsquo;re in different cities on different machines.&lt;/p>
&lt;p>A project can span multiple repositories. The frontend repo
agents can message the backend repo agents. A bead in the
frontend can be marked as blocked by a bead in the backend.&lt;/p>
&lt;p>You can see what this looks like in practice on &lt;a href="https://app.beadhub.ai/juanre/beadhub">the BeadHub
project&amp;rsquo;s own dashboard&lt;/a>,
where we coordinate BeadHub&amp;rsquo;s development using BeadHub. Make
sure to check &lt;a href="https://app.beadhub.ai/juanre/beadhub/chat">the chat
page&lt;/a>, it is almost
magical to see them figuring things out.&lt;/p>
&lt;h2 id="what-ive-learned">What I&amp;rsquo;ve learned&lt;/h2>
&lt;p>A few things I got wrong before getting them right.&lt;/p>
&lt;p>&lt;strong>The client is the source of truth.&lt;/strong> My instinct was to make
the server authoritative. But agents work locally, in git repos,
and their local state is the ground truth. The server aggregates
and distributes. If the server and the client disagree, the
client wins. If the server goes down, &lt;code>bdh&lt;/code> falls back to local
&lt;code>bd&lt;/code> with a warning. Work continues. Coordination catches up
later.&lt;/p>
&lt;p>&lt;strong>Async by default.&lt;/strong> My first instinct was real-time negotiation
between agents. Doesn&amp;rsquo;t scale. Agents work at different speeds,
on different schedules, and blocking one while waiting for
another is expensive. Mail is the default. Chat is the exception.&lt;/p>
&lt;p>&lt;strong>Advisory over mandatory.&lt;/strong> Advisory file locks that warn
instead of block. Bead claims that can be overridden with
&lt;code>--:jump-in &amp;quot;reason&amp;quot;&lt;/code> (which notifies the other agent). The
system provides information and trusts agents to act on it.&lt;/p>
&lt;p>&lt;strong>The coordinator role.&lt;/strong> I assign one agent per project the
&amp;ldquo;coordinator&amp;rdquo; role. The coordinator doesn&amp;rsquo;t write code. It
watches the dashboard, assigns work, checks on progress, nudges
stuck agents, and keeps the end goal in sight. The implementer
agents are heads-down in their worktrees; the coordinator is the
one who knows what the project needs next. BeadHub serves each
agent a role-specific policy—markdown documents describing how
agents in that role should behave—and the coordinator&amp;rsquo;s policy is
fundamentally different from an implementer&amp;rsquo;s. This turned out to
matter more than any of the technical decisions.&lt;/p>
&lt;h2 id="where-this-goes">Where this goes&lt;/h2>
&lt;p>The single-machine problem is getting solved. Agent Teams,
Codex—within a few weeks, running multiple agents in parallel on
your laptop will be table stakes.&lt;/p>
&lt;p>The multi-programmer problem is next. Five engineers, fifty
agents, three repositories, two time zones. That&amp;rsquo;s where the
coordination problem changes in kind, not just degree. It&amp;rsquo;s not
enough that your agents can talk to each other. They need to talk
to your teammate&amp;rsquo;s agents, on a different machine, in a different
time zone, working on a different repo in the same project.&lt;/p>
&lt;p>BeadHub is &lt;a href="https://github.com/beadhub/beadhub">open source&lt;/a> and
free for open-source projects.&lt;/p></content:encoded></item><item><title>Data cleaning and anonymizing with GPT-3.5</title><link>https://juanreyero.com/article/ai/data-cleaning-with-gpt-3.5/</link><guid>https://juanreyero.com/article/ai/data-cleaning-with-gpt-3.5/</guid><pubDate>Sun, 06 Aug 2023 00:00:00 +0000</pubDate><description>An early experiment in using language models to clean and anonymize data.</description><content:encoded>&lt;blockquote>
&lt;p>&lt;strong>Note added on 2025-07-28&lt;/strong>: It&amp;rsquo;s been two years of programming with and for LLMs. This article sounds so naïve now.&lt;/p>&lt;/blockquote>
&lt;p>Say you made a website in which customers buy &lt;a href="https://mapaestelar.com">personalized gifts&lt;/a>. Each gift comes with a message, written by the customer in whatever language the customer wants. The use of grammar, punctuation and capitalizations in the messages is often creative.&lt;/p>
&lt;p>You would like to be able to offer reasonably normative messages to your customers. You would also like to store a fully anonymized version of the messages; replace all proper names with a &lt;code>[proper_name]&lt;/code> placeholder, place names with &lt;code>[place_name]&lt;/code>, dates with &lt;code>[date]&lt;/code>, times with &lt;code>[time]&lt;/code>, and geographical coordinates with &lt;code>[coordinates]&lt;/code>.&lt;/p>
&lt;p>Is it possible to use OpenAI&amp;rsquo;s &lt;a href="https://platform.openai.com/docs/models/gpt-3-5">gpt-3.5-turbo&lt;/a> to do this?&lt;/p>
&lt;p>Luckily you happen to have some tens of thousands of messages laying around, so you can actually test whatever solution you come up with.&lt;/p>
&lt;h2 id="the-naïve-approach-just-ask-the-model-to-do-it">The naïve approach: just ask the model to do it&lt;/h2>
&lt;p>The first thing I tried was the straight-forward option: just ask the genie to do it for you, with a system prompt and a user prompt like this:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-python" data-lang="python">&lt;span class="line">&lt;span class="cl">&lt;span class="n">system_prompt&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;You are a proof-reader. You will be given &amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;a text that may be poorly written, perhaps &amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;with bad punctuation and wrong capitalization. &amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;Your task is to first correct the grammar, &amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;punctuation, and capitalization of the text. &amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;Once this is done you should anonymize it by &amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;replacing all the person&amp;#39;s proper names in the text &amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;with [proper_name], place names with [place_name], &amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;dates with [date], times with [time], and &amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;geographical coordinates with [coordinates]&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">user_prompt&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="sa">f&lt;/span>&lt;span class="s1">&amp;#39;Correct and anonymize the following text: &lt;/span>&lt;span class="si">{&lt;/span>&lt;span class="n">message&lt;/span>&lt;span class="si">}&lt;/span>&lt;span class="s1">&amp;#39;&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>This doesn&amp;rsquo;t work with GPT-3.5. It sometimes produces the desired result, but it often misses the anonymization elements, and generally makes a mess of things.&lt;/p>
&lt;h2 id="function-calling">Function calling&lt;/h2>
&lt;p>&lt;a href="https://platform.openai.com/docs/guides/gpt/function-calling">Function calling&lt;/a> is a wonderful tool that allows you to get structured data from the model. You describe functions and their inputs in your call to the model; if the model decides that it wants to call one of the functions, it will come back with a request to call the function and, crucially, with a dictionary containing the function&amp;rsquo;s arguments.&lt;/p>
&lt;p>And, most interesting for the problem at hand, you can also force the model to call a function. If you do, you will get the structured data you would need to call the function.&lt;/p>
&lt;p>So what we do is ask the model to call a function that needs, as arguments, the corrected text and the anonymization elements. Once we get back the dictionary with the arguments for the function we can anonymize by simply searching and replacing the anonymization elements in the corrected text.&lt;/p>
&lt;p>This actually works. Interestingly, the GPT-3.5 model is not able to replace the anonymization elements in the text by their placeholder, but it can reliably find them.&lt;/p>
&lt;h2 id="sample-code">Sample code&lt;/h2>
&lt;p>This is the function I have been using to play with the OpenAI api:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-python" data-lang="python">&lt;span class="line">&lt;span class="cl">&lt;span class="kn">import&lt;/span> &lt;span class="nn">json&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kn">from&lt;/span> &lt;span class="nn">typing&lt;/span> &lt;span class="kn">import&lt;/span> &lt;span class="n">List&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">Dict&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kn">import&lt;/span> &lt;span class="nn">openai&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># Ensure that the openai key is loaded, with something like&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">Api_loaded&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="kc">False&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">def&lt;/span> &lt;span class="nf">ensure_api&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">api_key&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">global&lt;/span> &lt;span class="n">Api_loaded&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="ow">not&lt;/span> &lt;span class="n">Api_loaded&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">openai&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">api_key&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">api_key&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">Api_loaded&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="kc">True&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">def&lt;/span> &lt;span class="nf">chat_completion_request&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">messages&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">List&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="n">Dict&lt;/span>&lt;span class="p">],&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">api_key&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">str&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">functions&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">List&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="n">Dict&lt;/span>&lt;span class="p">]&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="kc">None&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">call_function&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">str&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="kc">None&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">temperature&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">float&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="mi">1&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="c1"># 0 to 2&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">model_name&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">str&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s1">&amp;#39;gpt-3.5-turbo-0613&amp;#39;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">attempts&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">int&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="mi">4&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="o">-&amp;gt;&lt;/span> &lt;span class="n">Dict&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">args&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="p">{&lt;/span>&lt;span class="s1">&amp;#39;model&amp;#39;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">model_name&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s1">&amp;#39;messages&amp;#39;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">messages&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s1">&amp;#39;temperature&amp;#39;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">temperature&lt;/span>&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="n">functions&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">args&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="s1">&amp;#39;functions&amp;#39;&lt;/span>&lt;span class="p">]&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">functions&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="n">call_function&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="ow">not&lt;/span> &lt;span class="n">functions&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">raise&lt;/span> &lt;span class="ne">RuntimeError&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="sa">f&lt;/span>&lt;span class="s1">&amp;#39;Cannot call function &lt;/span>&lt;span class="si">{&lt;/span>&lt;span class="n">call_function&lt;/span>&lt;span class="si">}&lt;/span>&lt;span class="s1"> &amp;#39;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s1">&amp;#39;if no functions are defined&amp;#39;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">found_function&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="nb">len&lt;/span>&lt;span class="p">([&lt;/span>&lt;span class="n">fdesk&lt;/span> &lt;span class="k">for&lt;/span> &lt;span class="n">fdesk&lt;/span> &lt;span class="ow">in&lt;/span> &lt;span class="n">functions&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="n">fdesk&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="s1">&amp;#39;name&amp;#39;&lt;/span>&lt;span class="p">]&lt;/span> &lt;span class="o">==&lt;/span> &lt;span class="n">call_function&lt;/span>&lt;span class="p">])&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="ow">not&lt;/span> &lt;span class="n">found_function&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">raise&lt;/span> &lt;span class="ne">RuntimeError&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="sa">f&lt;/span>&lt;span class="s1">&amp;#39;Cannot call undefined function &lt;/span>&lt;span class="si">{&lt;/span>&lt;span class="n">call_function&lt;/span>&lt;span class="si">}&lt;/span>&lt;span class="s1">&amp;#39;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="n">found_function&lt;/span> &lt;span class="o">&amp;gt;&lt;/span> &lt;span class="mi">1&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">raise&lt;/span> &lt;span class="ne">RuntimeError&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="sa">f&lt;/span>&lt;span class="s1">&amp;#39;Found more than one definitions of &lt;/span>&lt;span class="si">{&lt;/span>&lt;span class="n">call_function&lt;/span>&lt;span class="si">}&lt;/span>&lt;span class="s1">&amp;#39;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">args&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="s1">&amp;#39;function_call&amp;#39;&lt;/span>&lt;span class="p">]&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="p">{&lt;/span>&lt;span class="s1">&amp;#39;name&amp;#39;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">call_function&lt;/span>&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">try&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">ensure_api&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">api_key&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">response&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">openai&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">ChatCompletion&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">create&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="o">**&lt;/span>&lt;span class="n">args&lt;/span>&lt;span class="p">)[&lt;/span>&lt;span class="s2">&amp;#34;choices&amp;#34;&lt;/span>&lt;span class="p">][&lt;/span>&lt;span class="mi">0&lt;/span>&lt;span class="p">][&lt;/span>&lt;span class="s2">&amp;#34;message&amp;#34;&lt;/span>&lt;span class="p">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">function_call&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">response&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">get&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s1">&amp;#39;function_call&amp;#39;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="kc">None&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="n">function_call&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">try&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s1">&amp;#39;call_function&amp;#39;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">function_call&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="s1">&amp;#39;name&amp;#39;&lt;/span>&lt;span class="p">],&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s1">&amp;#39;with_arguments&amp;#39;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">json&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">loads&lt;/span>&lt;span class="p">(&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">function_call&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="s1">&amp;#39;arguments&amp;#39;&lt;/span>&lt;span class="p">]),&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s1">&amp;#39;success&amp;#39;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="kc">True&lt;/span>&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">except&lt;/span> &lt;span class="n">json&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">decoder&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">JSONDecodeError&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># The model may have failed to produce correct json&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="n">attempts&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="n">chat_completion_request&lt;/span>&lt;span class="p">(&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">messages&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="n">messages&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">api_key&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="n">api_key&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">functions&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="n">functions&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">call_function&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="n">call_function&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">temperature&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="n">temperature&lt;/span>&lt;span class="o">/&lt;/span>&lt;span class="mi">2&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">model_name&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="n">model_name&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">attempts&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="n">attempts&lt;/span>&lt;span class="o">-&lt;/span>&lt;span class="mi">1&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="p">{&lt;/span>&lt;span class="s1">&amp;#39;success&amp;#39;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="kc">False&lt;/span>&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="p">{&lt;/span>&lt;span class="s1">&amp;#39;reply&amp;#39;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">response&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="s1">&amp;#39;content&amp;#39;&lt;/span>&lt;span class="p">],&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s1">&amp;#39;success&amp;#39;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="kc">True&lt;/span>&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">except&lt;/span> &lt;span class="n">openai&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">InvalidRequestError&lt;/span> &lt;span class="k">as&lt;/span> &lt;span class="n">exc&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">raise&lt;/span> &lt;span class="ne">RuntimeError&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s1">&amp;#39;Invalid request error from OpenAI&amp;#39;&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="kn">from&lt;/span> &lt;span class="nn">exc&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>We define a &lt;code>store_correct_text&lt;/code> function like this:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-python" data-lang="python">&lt;span class="line">&lt;span class="cl">&lt;span class="n">functions&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="p">[{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;name&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="s2">&amp;#34;store_correct_text&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;description&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="s2">&amp;#34;Store a corrected version of the input text&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;parameters&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;type&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="s2">&amp;#34;object&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;properties&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;correct_text&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;type&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="s2">&amp;#34;string&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;description&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="s2">&amp;#34;A corrected version the text&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">},&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;person_proper_names&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;type&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="s2">&amp;#34;string&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;description&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;A list of the proper names of &amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;persons in the text separated &amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;by semicolons&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">},&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;place_names&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;type&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="s2">&amp;#34;string&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;description&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;A list of the names of places in &amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;the text separated by semicolons&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">},&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;dates&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;type&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="s2">&amp;#34;string&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;description&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;A list of the dates in the text &amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;separated by semicolons&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">},&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;geographical_coordinates&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;type&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="s2">&amp;#34;string&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;description&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;A list of the dates in the text &amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;separated by semicolons&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">},&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;times&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;type&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="s2">&amp;#34;string&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;description&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;A list of the times (hours and minutes) &amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;in the text separated by semicolons&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">},&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;required&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="p">[&lt;/span>&lt;span class="s2">&amp;#34;correct_text&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;person_proper_names&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;place_names&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;dates&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;geographical_coordinates&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;times&amp;#34;&lt;/span>&lt;span class="p">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}]&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>The system and user prompts are:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-python" data-lang="python">&lt;span class="line">&lt;span class="cl">&lt;span class="n">system_prompt&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;You are a proof-reader. You will be &amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;given a text that can be poorly written, &amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;maybe with bad punctuation and wrong &amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;capitalization. Your task is to first correct &amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;the grammar, punctuation, and capitalization &amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;of the text, and once this is done to find all &amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;the person&amp;#39;s proper names in the text. &amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;Person&amp;#39;s proper names are those that identify &amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;people, like Mark or Anne Frank. You should also &amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;find all the proper names of places in the text. &amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;You should also find the dates. You should also &amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;find geographical coordinates (latitude and &amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;longitude). You should also find the times &amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;mentioned in the text (hour and minute).&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">user_prompt&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="s1">&amp;#39;Correct the following text, and make it into &amp;#39;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="sa">f&lt;/span>&lt;span class="s1">&amp;#39;a template:&lt;/span>&lt;span class="se">\n\n&lt;/span>&lt;span class="si">{&lt;/span>&lt;span class="n">message&lt;/span>&lt;span class="si">}&lt;/span>&lt;span class="s1">&amp;#39;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>We can now call &lt;code>chat_completion_request&lt;/code>:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-python" data-lang="python">&lt;span class="line">&lt;span class="cl">&lt;span class="n">result&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">chat_completion_request&lt;/span>&lt;span class="p">(&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">messages&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="p">[{&lt;/span>&lt;span class="s1">&amp;#39;role&amp;#39;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="s1">&amp;#39;system&amp;#39;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s1">&amp;#39;content&amp;#39;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">system_prompt&lt;/span>&lt;span class="p">},&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">{&lt;/span>&lt;span class="s1">&amp;#39;role&amp;#39;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="s1">&amp;#39;user&amp;#39;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s1">&amp;#39;content&amp;#39;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">user_prompt&lt;/span>&lt;span class="p">}],&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">api_key&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s1">&amp;#39;your api key possibly loaded from .env&amp;#39;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">functions&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="n">functions&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">call_function&lt;/span>&lt;span class="s1">&amp;#39;store_correct_text&amp;#39;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Finally, if things worked, simply replace the anonymization elements:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-python" data-lang="python">&lt;span class="line">&lt;span class="cl">&lt;span class="k">if&lt;/span> &lt;span class="n">result&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="s1">&amp;#39;success&amp;#39;&lt;/span>&lt;span class="p">]:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">final_text&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">result&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="s1">&amp;#39;with_arguments&amp;#39;&lt;/span>&lt;span class="p">]&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">get&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s1">&amp;#39;correct_text&amp;#39;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s1">&amp;#39;&amp;#39;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">for&lt;/span> &lt;span class="n">argname&lt;/span> &lt;span class="ow">in&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="s1">&amp;#39;person_proper_names&amp;#39;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s1">&amp;#39;place_names&amp;#39;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s1">&amp;#39;dates&amp;#39;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s1">&amp;#39;geographical_coordinates&amp;#39;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s1">&amp;#39;times&amp;#39;&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">names&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">result&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="s1">&amp;#39;with_arguments&amp;#39;&lt;/span>&lt;span class="p">]&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">get&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">argname&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s1">&amp;#39;&amp;#39;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">for&lt;/span> &lt;span class="n">name&lt;/span> &lt;span class="ow">in&lt;/span> &lt;span class="n">names&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">split&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s1">&amp;#39;;&amp;#39;&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="n">name&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">strip&lt;/span>&lt;span class="p">():&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># The placeholder is the argument name&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># minus the final s&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">final_text&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">final_text&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">replace&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">name&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">strip&lt;/span>&lt;span class="p">(),&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="sa">f&lt;/span>&lt;span class="s1">&amp;#39;[&lt;/span>&lt;span class="si">{&lt;/span>&lt;span class="n">argname&lt;/span>&lt;span class="p">[:&lt;/span>&lt;span class="o">-&lt;/span>&lt;span class="mi">1&lt;/span>&lt;span class="p">]&lt;/span>&lt;span class="si">}&lt;/span>&lt;span class="s1">]&amp;#39;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div></content:encoded></item></channel></rss>