<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Microsoft Research &#8211; About Things | A Hans Scharler Blog</title>
	<atom:link href="https://nothans.com/tag/microsoft-research/feed" rel="self" type="application/rss+xml" />
	<link>https://nothans.com</link>
	<description>Life, Comedy, Games, Tech, Marketing, and Community</description>
	<lastBuildDate>Fri, 19 Jun 2026 01:15:55 +0000</lastBuildDate>
	<language>en-US</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	

<image>
	<url>https://i0.wp.com/nothans.com/wp-content/uploads/2023/02/cropped-settings.png?fit=32%2C32&#038;ssl=1</url>
	<title>Microsoft Research &#8211; About Things | A Hans Scharler Blog</title>
	<link>https://nothans.com</link>
	<width>32</width>
	<height>32</height>
</image> 
<site xmlns="com-wordpress:feed-additions:1">114568856</site>	<item>
		<title>Create the &#8220;Best Agent Skill&#8221; with SkillOpt from Microsoft Research</title>
		<link>https://nothans.com/create-the-best-agent-skill-with-skillopt-from-microsoft-research</link>
					<comments>https://nothans.com/create-the-best-agent-skill-with-skillopt-from-microsoft-research#respond</comments>
		
		<dc:creator><![CDATA[Hans Scharler]]></dc:creator>
		<pubDate>Fri, 19 Jun 2026 01:15:49 +0000</pubDate>
				<category><![CDATA[AI]]></category>
		<category><![CDATA[Agent Skills]]></category>
		<category><![CDATA[Codex]]></category>
		<category><![CDATA[Microsoft Research]]></category>
		<category><![CDATA[OpenAI]]></category>
		<category><![CDATA[SkillOpt]]></category>
		<guid isPermaLink="false">https://nothans.com/?p=5447</guid>

					<description><![CDATA[]]></description>
										<content:encoded><![CDATA[
<p>For two years the move was simple: pick a better model. Then the models got good, and stayed good, and the gaps between them got boring. So the interesting lever is the other thing you hand the agent now. The skill file.</p>



<p>Microsoft Research just shipped a tool called <a href="https://github.com/microsoft/SkillOpt">SkillOpt</a> that takes that idea literally.</p>



<blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow">
<p>SkillOpt is a text-space optimizer that trains reusable natural-language skills for frozen LLM agents through trajectory-driven edits, validation-gated updates, and deployable best_skill.md artifacts.</p>
</blockquote>



<p>It treats the skill markdown you hand an agent (the instructions, the system prompt, the SKILL.md) as trainable state. It runs epochs. It has a batch size. It has a learning rate. It just never touches the model weights. The weights stay frozen behind the API. The thing that gets trained is the text.</p>



<p>The loop is short. Run the agent on a batch of tasks. Score each one. A second model reads the failures and proposes small edits to the skill file. Keep an edit only if it improves a held-out score. Repeat. What you get at the end is a&nbsp;<code>best_skill.md</code>&nbsp;you drop in front of the same unchanged model.</p>


<div class="wp-block-image">
<figure class="aligncenter size-full is-resized"><a href="https://github.com/microsoft/SkillOpt"><img data-recalc-dims="1" fetchpriority="high" decoding="async" width="750" height="750" data-attachment-id="5448" data-permalink="https://nothans.com/create-the-best-agent-skill-with-skillopt-from-microsoft-research/image-108" data-orig-file="https://i0.wp.com/nothans.com/wp-content/uploads/2026/06/image.png?fit=750%2C750&amp;ssl=1" data-orig-size="750,750" data-comments-opened="0" data-image-title="SkillOpt from Microsoft Research" data-image-description="" data-image-caption="" data-large-file="https://i0.wp.com/nothans.com/wp-content/uploads/2026/06/image.png?fit=750%2C750&amp;ssl=1" src="https://i0.wp.com/nothans.com/wp-content/uploads/2026/06/image.png?resize=750%2C750&#038;ssl=1" alt="" class="wp-image-5448" style="width:504px;height:auto" srcset="https://i0.wp.com/nothans.com/wp-content/uploads/2026/06/image.png?w=750&amp;ssl=1 750w, https://i0.wp.com/nothans.com/wp-content/uploads/2026/06/image.png?resize=300%2C300&amp;ssl=1 300w, https://i0.wp.com/nothans.com/wp-content/uploads/2026/06/image.png?resize=150%2C150&amp;ssl=1 150w, https://i0.wp.com/nothans.com/wp-content/uploads/2026/06/image.png?resize=530%2C530&amp;ssl=1 530w, https://i0.wp.com/nothans.com/wp-content/uploads/2026/06/image.png?resize=500%2C500&amp;ssl=1 500w" sizes="(max-width: 750px) 100vw, 750px" /></a><figcaption class="wp-element-caption">Microsoft Research <a href="https://github.com/microsoft/SkillOpt">SkillOpt</a></figcaption></figure>
</div>


<p>I wanted to see it actually work, so I gave it a job&#8230;</p>


<h2 class="wp-block-heading" id="the-setup">The setup</h2>


<p>I had OpenAI Codex do the writing. The task: take a paragraph stuffed with AI slop and clean it up. The skill it started from was short:</p>



<blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow">
<p>Improve the passage so it reads a little better. Keep the meaning and roughly the length.</p>
</blockquote>



<p>No mention of slop. No list of banned words. Nothing to go on.</p>



<p>The verifier was the part that mattered. I wrote a dumb little counter that scans the output for the tells (the canned phrases, the em-dashes) and returns how many are left. Fewer is better. That is the whole eval. Objective, cheap, no judgment calls.</p>



<p>Then I let SkillOpt run.</p>


<h2 class="wp-block-heading" id="what-it-wrote">What it wrote</h2>


<p>The seed turned into a thirty-line deslop skill. SkillOpt wrote it.</p>



<p>It worked out, on its own, that &#8220;remove AI slop&#8221; is a removal constraint and not a tone nudge. It named the exact phrases that kept leaking through (&#8220;let&#8217;s dive in,&#8221; &#8220;have you ever wondered,&#8221; &#8220;it&#8217;s worth noting,&#8221; &#8220;furthermore,&#8221; &#8220;in conclusion,&#8221; &#8220;great question&#8221;). It flagged em-dashes. And it caught the sneaky failure mode I never told it about: the model dodging a banned word by swapping in a synonym. That one became its own rule, the last line of the file:</p>



<blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow">
<p>Before answering, do a quick scan to ensure none of the original flagged words remain, including close synonyms you may have introduced.</p>
</blockquote>



<p>The score went from passing half the held-out passages to passing all of them. The skill it wrote is one I would actually keep.</p>


<h2 class="wp-block-heading" id="the-part-worth-keeping">The part worth keeping</h2>


<p>The optimizer is the easy part.</p>



<p>I went in assuming the clever bit was the model proposing edits. It isn&#8217;t. The clever bit is the verifier. Give SkillOpt a score and nothing else and it does nothing. I tried that first. It saw the failures, shrugged, and changed not a single line, because &#8220;you got a 0.6&#8221; tells it nothing about what to fix. The run that worked was the one where the verifier also said which words leaked. Same model, same loop. The difference was the signal.</p>



<p>So the rule of thumb is less &#8220;use the self-improving optimizer&#8221; and more: can you score this cheaply, and can you tell it why it failed. If yes, the skill mostly writes itself. If no, there is nothing to train and the fancy loop sits there idle.</p>



<p>That is also the catch, and it is the same catch hiding under every self-improving-agent demo. A slop counter is a clean verifier. Most of what you do in a day is not. &#8220;Was this brief any good.&#8221; &#8220;Did this post land.&#8221; No cheap score, no training. The optimizer was never the bottleneck. The verifier is.</p>



<p>So build the verifier first. Get that right and the skill mostly writes itself.</p>


<h2 class="wp-block-heading" id="bonus-a-taste-of-running-it">Bonus: a taste of running it</h2>


<p>The repo is&nbsp;<a href="https://github.com/microsoft/SkillOpt">github.com/microsoft/SkillOpt</a>. MIT licensed, Python.</p>



<p>Get it:</p>



<pre class="wp-block-code"><code>pip install skillopt
# or, to poke at the internals:
git clone https://github.com/microsoft/SkillOpt &amp;&amp; cd SkillOpt &amp;&amp; pip install -e .</code></pre>



<p>The mental model is one small folder per task. A loader that hands over your examples, a rollout that runs your agent and scores it, and a seed skill to start from. SkillOpt&#8217;s whole job is to grow that seed.</p>



<p>The config reads like a training run, on purpose:</p>



<pre class="wp-block-code"><code>train:
  num_epochs: 4
  batch_size: 40
optimizer:
  learning_rate: 4        # max edits to the skill per step
  lr_scheduler: cosine
evaluation:
  use_gate: true          # keep an edit only if it beats the held-out score
model:
  optimizer: gpt-5.4      # the model that proposes the edits</code></pre>



<p>Then it is one command:</p>



<pre class="wp-block-code"><code>python scripts/train.py --config configs/yourtask/default.yaml</code></pre>



<p>The only part that is really on you is the scoring. Your rollout returns, per task, a pass/fail and a number between 0 and 1:</p>



<pre class="wp-block-code"><code>return {"id": task_id, "hard": passed, "soft": fraction_correct}</code></pre>



<p>That is the whole contract. Give it tasks, a way to score them, and a skill to start from. It runs the epochs.</p>



<p>One side note: keep the tasks hard enough that the agent fails some of them. If it aces everything on the seed skill, there is nothing to learn and SkillOpt politely does nothing. Ask me how I know.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://nothans.com/create-the-best-agent-skill-with-skillopt-from-microsoft-research/feed</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">5447</post-id>	</item>
	</channel>
</rss>
