<?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: rick</title>
    <description>The latest articles on DEV Community by rick (@ho4040).</description>
    <link>https://dev.to/ho4040</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%2F3825025%2F53217b9e-12f4-40de-922a-fe3703e767a1.jpeg</url>
      <title>DEV Community: rick</title>
      <link>https://dev.to/ho4040</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/ho4040"/>
    <language>en</language>
    <item>
      <title>psyctl: Steer LLM Personality Without Fine-Tuning</title>
      <dc:creator>rick</dc:creator>
      <pubDate>Sun, 15 Mar 2026 13:03:46 +0000</pubDate>
      <link>https://dev.to/ho4040/psyctl-steer-llm-personality-without-fine-tuning-4i0a</link>
      <guid>https://dev.to/ho4040/psyctl-steer-llm-personality-without-fine-tuning-4i0a</guid>
      <description>&lt;h2&gt;
  
  
  What if you could make an LLM more extroverted — without any training?
&lt;/h2&gt;

&lt;p&gt;That's the idea behind &lt;strong&gt;&lt;a href="https://modulabs-personalab.github.io/psyctl/" rel="noopener noreferrer"&gt;psyctl&lt;/a&gt;&lt;/strong&gt;, a CLI tool I'm building at &lt;a href="https://modulabs.co.kr/" rel="noopener noreferrer"&gt;Modulabs Persona Lab&lt;/a&gt;. It lets you extract personality vectors from a model's internal activations and inject them during inference to shift behavior. No fine-tuning, no LoRA, no RLHF — just vector addition.&lt;/p&gt;

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

&lt;p&gt;The technique is called &lt;strong&gt;Contrastive Activation Addition (CAA)&lt;/strong&gt;. Here's the pipeline:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Generate a contrastive dataset&lt;/strong&gt; — pairs of responses that differ only in personality (e.g., extroverted vs. neutral)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Extract a steering vector&lt;/strong&gt; — compute the mean activation difference between the two response sets&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Inject the vector at inference&lt;/strong&gt; — add the vector to a target layer's activations during forward pass&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Validate with psychological tests&lt;/strong&gt; — run standardized inventories to measure the personality shift&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;What's fascinating is that meaningful behavior changes emerge from simple vector arithmetic on activations — no gradient updates needed.&lt;/p&gt;

&lt;h2&gt;
  
  
  The CLI
&lt;/h2&gt;

&lt;p&gt;psyctl automates the entire pipeline:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Generate contrastive personality dataset&lt;/span&gt;
psyctl dataset.build.steer &lt;span class="nt"&gt;--personality&lt;/span&gt; Extroversion &lt;span class="nt"&gt;--output&lt;/span&gt; ./data

&lt;span class="c"&gt;# Extract steering vector using mean difference method&lt;/span&gt;
psyctl extract.steering &lt;span class="nt"&gt;--dataset&lt;/span&gt; ./data &lt;span class="nt"&gt;--method&lt;/span&gt; mean_diff &lt;span class="nt"&gt;--output&lt;/span&gt; ./vec.safetensors

&lt;span class="c"&gt;# Apply steering and generate text&lt;/span&gt;
psyctl steering &lt;span class="nt"&gt;--steering-vector&lt;/span&gt; ./vec.safetensors &lt;span class="nt"&gt;--input&lt;/span&gt; &lt;span class="s2"&gt;"Tell me about yourself"&lt;/span&gt;

&lt;span class="c"&gt;# Validate with psychological inventory&lt;/span&gt;
psyctl benchmark inventory &lt;span class="nt"&gt;--steering-vector&lt;/span&gt; ./vec.safetensors
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Extraction Methods
&lt;/h2&gt;

&lt;p&gt;Two approaches are supported:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Mean Difference&lt;/strong&gt; — a statistics-based method that computes the mean activation difference between positive and neutral responses. Fast and simple.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;BiPO (Bidirectional Preference Optimization)&lt;/strong&gt; — an optimization-based method using DPO loss to learn a more refined steering direction.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Evaluation
&lt;/h2&gt;

&lt;p&gt;How do you measure if an LLM's personality actually changed? With the same tools psychologists use on humans:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;IPIP-NEO&lt;/strong&gt; — measures the Big Five personality traits (Openness, Conscientiousness, Extraversion, Agreeableness, Neuroticism)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;NPI-40&lt;/strong&gt; — measures narcissistic personality traits&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;MACH-IV&lt;/strong&gt; — measures Machiavellianism&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;psyctl administers these inventories automatically and compares scores before and after steering.&lt;/p&gt;

&lt;h2&gt;
  
  
  Compatibility
&lt;/h2&gt;

&lt;p&gt;Works with HuggingFace Transformers models including:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Llama 3.x&lt;/li&gt;
&lt;li&gt;Gemma 3&lt;/li&gt;
&lt;li&gt;Qwen 2.5&lt;/li&gt;
&lt;li&gt;Mistral&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Any decoder-only transformer with accessible intermediate layers should work.&lt;/p&gt;

&lt;h2&gt;
  
  
  Key Papers
&lt;/h2&gt;

&lt;p&gt;The implementation builds on these research papers:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://arxiv.org/abs/2312.06681" rel="noopener noreferrer"&gt;Steering Llama 2 via Contrastive Activation Addition&lt;/a&gt; (CAA)&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://arxiv.org/abs/2406.00045" rel="noopener noreferrer"&gt;Personalized Steering via Bi-directional Preference Optimization&lt;/a&gt; (BiPO)&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://arxiv.org/abs/2206.07550" rel="noopener noreferrer"&gt;Evaluating and Inducing Personality in Pre-trained Language Models&lt;/a&gt; (P2)&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Links
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Documentation &amp;amp; Getting Started&lt;/strong&gt;: &lt;a href="https://modulabs-personalab.github.io/psyctl/" rel="noopener noreferrer"&gt;modulabs-personalab.github.io/psyctl&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;GitHub&lt;/strong&gt;: &lt;a href="https://github.com/modulabs-personalab/psyctl" rel="noopener noreferrer"&gt;modulabs-personalab/psyctl&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Original blog post&lt;/strong&gt;: &lt;a href="https://ho4040.github.io/posts/psyctl-intro/" rel="noopener noreferrer"&gt;ho4040.github.io&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;If you're interested in LLM interpretability or personality research, give psyctl a try. Contributions and feedback are welcome!&lt;/p&gt;

</description>
      <category>ai</category>
      <category>llm</category>
      <category>python</category>
      <category>opensource</category>
    </item>
    <item>
      <title>runpod-log: A CLI Tool for Viewing RunPod GPU Pod Logs</title>
      <dc:creator>rick</dc:creator>
      <pubDate>Sun, 15 Mar 2026 12:57:05 +0000</pubDate>
      <link>https://dev.to/ho4040/runpod-log-a-cli-tool-for-viewing-runpod-gpu-pod-logs-1bfl</link>
      <guid>https://dev.to/ho4040/runpod-log-a-cli-tool-for-viewing-runpod-gpu-pod-logs-1bfl</guid>
      <description>&lt;h2&gt;
  
  
  Why I Built This
&lt;/h2&gt;

&lt;p&gt;RunPod is great for spinning up GPU pods, but there's one frustrating gap: &lt;strong&gt;you can't view pod logs from the CLI&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;The official &lt;code&gt;runpodctl&lt;/code&gt; lets you start, stop, and manage pods — but if you want to check logs, you're forced to open the web console every time. This is especially painful when you're managing multiple pods or trying to build automation scripts.&lt;/p&gt;

&lt;p&gt;So I built &lt;strong&gt;runpod-log&lt;/strong&gt;, a simple CLI tool that fetches RunPod GPU pod logs directly in your terminal.&lt;/p&gt;

&lt;h2&gt;
  
  
  Features
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Fetch logs instantly&lt;/strong&gt; — get both container logs and system logs in one command&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Real-time monitoring&lt;/strong&gt; — stream logs to a file with the &lt;code&gt;tail&lt;/code&gt; command&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Automatic authentication&lt;/strong&gt; — browser-based login via Playwright with automatic JWT token refresh&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Installation
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pip &lt;span class="nb"&gt;install &lt;/span&gt;runpod-log
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Usage
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Login (opens browser for authentication)&lt;/span&gt;
runpod-log login

&lt;span class="c"&gt;# Fetch logs for a specific pod&lt;/span&gt;
runpod-log logs &amp;lt;pod-id&amp;gt;

&lt;span class="c"&gt;# Filter by log type&lt;/span&gt;
runpod-log logs &amp;lt;pod-id&amp;gt; &lt;span class="nt"&gt;--only&lt;/span&gt; container
runpod-log logs &amp;lt;pod-id&amp;gt; &lt;span class="nt"&gt;--only&lt;/span&gt; system

&lt;span class="c"&gt;# Real-time log monitoring&lt;/span&gt;
runpod-log &lt;span class="nb"&gt;tail&lt;/span&gt; &amp;lt;pod-id&amp;gt; ./logs.txt

&lt;span class="c"&gt;# Logout&lt;/span&gt;
runpod-log &lt;span class="nb"&gt;logout&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;h3&gt;
  
  
  Authentication
&lt;/h3&gt;

&lt;p&gt;Since RunPod doesn't offer a public API for logs, runpod-log uses a browser-based authentication flow:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;code&gt;runpod-log login&lt;/code&gt; opens a Playwright browser window&lt;/li&gt;
&lt;li&gt;You log in to RunPod normally&lt;/li&gt;
&lt;li&gt;The tool captures the JWT token from &lt;code&gt;hapi.runpod.net&lt;/code&gt; requests&lt;/li&gt;
&lt;li&gt;Session data is stored locally — no repeated logins needed&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Token Refresh
&lt;/h3&gt;

&lt;p&gt;JWT tokens expire after about 60 seconds. When that happens, runpod-log automatically spins up a headless browser to fetch fresh credentials — no manual intervention required.&lt;/p&gt;

&lt;h3&gt;
  
  
  Log Retrieval
&lt;/h3&gt;

&lt;p&gt;Under the hood, it calls the undocumented &lt;code&gt;https://hapi.runpod.net/v1/pod/{pod_id}/logs&lt;/code&gt; endpoint to fetch both container and system logs.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Not Just Use the Web Console?
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Automation&lt;/strong&gt;: pipe logs into other tools, grep for errors, trigger alerts&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Multi-pod management&lt;/strong&gt;: check logs across pods without switching browser tabs&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;SSH workflows&lt;/strong&gt;: view logs on remote machines without a GUI&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Links
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;GitHub&lt;/strong&gt;: &lt;a href="https://github.com/ho4040/runpod-log" rel="noopener noreferrer"&gt;ho4040/runpod-log&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;PyPI&lt;/strong&gt;: &lt;a href="https://pypi.org/project/runpod-log/" rel="noopener noreferrer"&gt;runpod-log&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Original blog post (Korean)&lt;/strong&gt;: &lt;a href="https://ho4040.github.io/posts/runpod-log-intro/" rel="noopener noreferrer"&gt;ho4040.github.io&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;If you're a RunPod user who's been frustrated by the lack of CLI log access, give it a try and let me know what you think!&lt;/p&gt;

</description>
      <category>python</category>
      <category>cli</category>
      <category>opensource</category>
      <category>runpod</category>
    </item>
  </channel>
</rss>
