The Power of Aligning With User Mental Models
When designing ConnectOnion's API, we faced a crucial decision:
What should we call the primary method for interacting with an agent?
This seemingly simple choice would impact every user's first experience with our framework.
The Problem With run()
We initially followed industry convention with:
agent.run(prompt)
It seemed logical — agents “run” tasks, right?
But user feedback revealed a critical issue:
The word
"run"
created cognitive friction.
Users had to mentally translate their intent (“I want to ask the agent something”) into technical terminology (“I need to run the agent”).
This tiny friction point happened thousands of times per day across our user base.
The Research Process
We studied how new users approached our API without reading documentation.
First Attempts by New Users:
- 40% tried
agent.input()
- 18% tried
agent.ask()
- 15% tried
agent.chat()
- 12% tried
agent.run()
- 8% tried
agent.process()
- 7% other variations
The data was clear: users thought in terms of what THEY do (provide input), not what the AGENT does (run/process).
Evaluating Alternatives
We evaluated 7 different options:
1. agent.chat(prompt)
- Conversational and friendly
- But implies stateful conversation (misleading for stateless calls)
- Not all agents "chat" (some calculate, analyze, etc.)
2. agent.ask(prompt)
- Natural for Q&A scenarios
- But limiting — not all interactions are questions
- Doesn't work for commands ("ask" the agent to "delete file"?)
3. agent.prompt(prompt)
- Technically accurate
- But noun-verb confusion ("prompt the prompt?")
- Too technical for beginners
4. agent.process(prompt)
- Describes what happens internally
- But technical jargon
- Users don't think "I need to process something"
5. agent.invoke(prompt)
- Professional, enterprise-feeling
- But intimidating for beginners
- Sounds like Java/enterprise complexity
6. agent.input(prompt)
- Matches user mental model
- Works for all interaction types
- Self-documenting
- Slightly less “technical” sounding (actually a pro?)
7. agent.run(prompt)
(original)
- Industry standard
- But requires mental translation
- "Run what exactly?"
- Implies execution of code, not conversation
The "Mom Test"
We applied a simple heuristic: could a non-technical person guess what this does?
# Clear to everyone
agent.input("Translate this to Spanish: Hello")
# Confusing to non-developers
agent.run("Translate this to Spanish: Hello")
agent.invoke("Translate this to Spanish: Hello")
"Input" passed the mom test. "Run" and "invoke" didn’t.
The Deeper Principle: User vs System Perspective
This decision revealed a fundamental principle:
Design APIs from the user's perspective, not the system's perspective.
System Perspective (How It Works)
- Agent receives prompt
- Agent processes prompt
- Agent runs inference
- Agent executes tools
- Agent returns response
User Perspective (How It Feels)
- I give input
- I get output
The user perspective is simpler, clearer, and more intuitive.
Implementation Was Trivial
The change itself was one line:
class Agent:
# Before
def run(self, prompt: str) -> str:
return self._process(prompt)
# After
def input(self, prompt: str) -> str:
return self._process(prompt)
But the impact was profound.
Measuring Success
After the change:
- 60% fewer “how do I use the agent?” questions in our Discord
- First-time success rate increased from 67% to 89%
- Time to first successful agent call dropped by 40%
- Documentation lookups for basic usage dropped 55%
Lessons Learned
1. Challenge Industry Conventions
Just because everyone uses run()
doesn’t mean it’s right. Question everything.
2. Data Beats Opinion
We had strong opinions about run()
. Our users' behavior proved us wrong.
3. Small Words, Big Impact
A three-letter change (run
→ input
) transformed our user experience.
4. Design for Mental Models
Align with how users think, not how systems work.
5. The Best API Needs No Documentation
When users guess correctly, you've found the right name.
The Ripple Effect
This decision influenced our entire API design philosophy:
agent.input("...") # Not agent.run()
agent.history.summary() # Not agent.get_execution_log()
agent.tools = [...] # Not agent.register_capabilities()
Looking Back
Choosing input()
over run()
might seem trivial, but it represents something bigger:
Our commitment to user experience over technical correctness.
When you type:
agent.input("What is 2+2?")
You're not thinking about execution models or processing pipelines.
You're thinking about giving input to an agent.
And that's exactly the point.
The ConnectOnion Way
This decision embodies our philosophy:
- Simple things should feel simple
- APIs should match mental models
- User experience trumps technical accuracy
- Data beats opinion
- Question everything — even conventions
Sometimes the best API design decision is the one that makes developers forget they're using an API at all.
Final Thought
Next time you design an API, ask yourself:
Am I naming this from the system’s perspective or the user’s perspective?
The answer might transform your user experience.
Top comments (0)