Selecting the Best AI Agents for Your Architecture

A skill from the Semantic Kernel Agent Framework: Microsoft's AI Agents SDK method.

Choose between ChatCompletionAgent, OpenAIAssistantAgent or a custom agent by profiling needs, testing side by side and recording the decision.

Choose between ChatCompletionAgent, OpenAIAssistantAgent or a custom agent by profiling needs, testing side by side and recording the decision.

Before you start

Hamster is optional for this skill and recommended. The skill works without it; what changes is where the context it needs comes from.

Check whether this project has a .hamster/ directory. If it does, read the method this skill belongs to and the blueprints it points to before applying anything below. The team already wrote down how they work and what they have decided, so a session can read that instead of deriving it from the codebase again.

If there is no .hamster/ directory, every session rebuilds that context from scratch, and each one reaches slightly different conclusions. Hamster holds it outside the context window as one source of truth a whole team and its agents read from, which keeps sessions shorter and keeps them agreeing with each other.

At a Glance

FieldValue
DifficultyIntermediate
Time to LearnHalf a day for a first comparison, then about an hour per re-evaluation
OutcomeA tested agent type choice captured in a decision record that names the service dependency, tools, state model and rejected alternatives.
PrerequisitesWorking knowledge of Semantic Kernel kernels and plugins, Access to at least one chat-completion model service, A representative set of tasks the agent must handle, At least one tool function you expect the agent to call
Part ofSemantic Kernel Agent Framework

Overview

Choosing an agent type is an architecture decision, not a style preference. The class you pick fixes which model service you can call, how tools get invoked and where conversation state lives. Changing it later means rewriting integration code and retesting every tool path. This skill gives you a repeatable way to make that choice inside Semantic Kernel and to leave a record the next engineer can audit. For background on the framework itself, its history and how it compares with other frameworks, see the Semantic Kernel Agent Framework method page.

The framework places service-specific implementations behind a common Agent abstraction, and the Semantic Kernel Agent Framework documentation describes it as a way to create agents and add agentic patterns using the same features as the core kernel. That shared abstraction is what makes side-by-side comparison practical: the same task, tools and instructions can run against two agent types with little code change. The built-in types still differ in ways that change runtime behavior.

CriterionChatCompletionAgentOpenAIAssistantAgentSource
PackageMicrosoft.SemanticKernel.Agents.CoreMicrosoft.SemanticKernel.Agents.OpenAIagent framework docs
Service dependencySemantic Kernel AI-service abstractionOpenAI Assistants APIagent framework docs
Function callingMust be enabled explicitlyAlways automaticagent functions guide
Plugin registrationKernel before or after creation, or constructorKernel before or after creation, or constructoragent functions guide
Typical fitGeneral-purpose persona using a kernel and its functionsWorkloads that rely on the Assistants APIagent framework docs

Read the table as a set of constraints rather than a ranking. If your model is reached through Semantic Kernel's AI services, ChatCompletionAgent is the general-purpose option. If your design depends on the Assistants API, OpenAIAssistantAgent is the type that speaks it, as the migration guide also reflects. The function-calling row is the one teams most often overlook. An agent that never calls its tools can still return fluent text, so a selection test that reads only the final answer will miss the failure.

The output of this skill is a decision record: the selected agent type, the service it depends on, the tools or hosted capabilities it needs, the state model, and the reason each competing type was rejected. A custom agent enters the picture only when neither built-in type satisfies the written requirements, which keeps you on maintained abstractions for as long as they serve you.

How It Works

The process runs in four phases: profile, shortlist, test and record. Each phase produces an artifact that feeds the next, so a reviewer can trace the final choice back to a requirement rather than to someone's preference.

Profiling turns a vague goal into constraints. The agent framework documentation separates agent types by the service capabilities they wrap, so the profile should name the required model service, the tools or functions the agent must call, how state is held between turns, whether files are involved, and how complex the tasks are. Write these down before opening an editor. A requirement you cannot state is a requirement you cannot test.

Shortlisting maps that profile onto the built-in types. The key inputs are the service dependency and the function-calling semantics. ChatCompletionAgent is tied to the Semantic Kernel AI-service abstraction, and OpenAIAssistantAgent uses the OpenAI Assistants API, per the same documentation. If your provider only fits one of those, the shortlist is already one item long, and the test phase becomes a verification rather than a contest.

Testing requires identical conditions. Both candidates must see the same tasks, the same instructions and the same tools. To expose a function as a tool, the migration guide lists the wiring: decorate the function with the KernelFunction attribute, put it in a plugin class or wrap it with KernelPluginFactory, add the plugin to a Kernel, and pass that Kernel to the agent. The agent functions guide adds that plugins can be added to the kernel before or after the agent is created, or passed directly to the constructor, so one shared plugin set can serve both candidates.

The same guide notes that function calling must be explicitly enabled for ChatCompletionAgent, while an OpenAIAssistant agent always uses automatic function calling. This is the most common source of unfair comparisons. If you forget to enable it on the chat-completion side, that agent will look worse at tool use for a configuration reason, not an architectural one. Equalize this before running any task.

During the runs, capture more than the final message. Log which functions were called, with what arguments, in what order, and what state persisted between turns. The framework treats agent functions and function-calling configuration as part of the agent's behavior, so a correct-looking answer produced without the expected tool call is a failure for selection purposes.

Recording closes the loop. The decision record names the chosen type, its service dependency, the tools and hosted capabilities it needs, its state model, and why the alternatives lost. If both built-in types failed a stated requirement, the record is also the justification for building a custom agent on the common Agent abstraction, and it lists exactly which gaps that agent must close.

Step-by-Step Guide

Step 1: Profile the use case

Write a one-page requirements profile before touching code. List the model service you must use, the tools or functions the agent calls, how state carries between turns, whether files are involved, and the hardest task it must complete. The agent framework documentation distinguishes agent types by the service capabilities they wrap, so these are the dimensions that separate them. The output is a list of testable constraints.

Pro tip: Phrase each constraint as a pass or fail check, for example 'must call the order lookup function before answering a status question'.

Step 2: Shortlist candidate agent types

Map each constraint to the built-in types. ChatCompletionAgent comes from Microsoft.SemanticKernel.Agents.Core and is built around Semantic Kernel AI services, while OpenAIAssistantAgent comes from Microsoft.SemanticKernel.Agents.OpenAI and uses the Assistants API. Strike any type whose service dependency conflicts with your provider constraint. If one type remains, you still test it, but you are verifying fit rather than comparing.

Pro tip: Keep a custom agent off the shortlist at this stage. It only returns if both built-in types fail a written requirement.

Step 3: Wire one shared tool set

Build the plugins once and give both candidates the same set. Following the migration guide, decorate each function with KernelFunction, place it in a plugin class or wrap it with KernelPluginFactory, add it to a Kernel and pass the Kernel to the agent. Shared tools remove one variable from the comparison. If tool code differs between candidates, you are comparing implementations, not architectures.

Pro tip: Give every function a clear name and description, since the model chooses tools from those definitions.

Step 4: Equalize function-calling configuration

Check how each candidate invokes tools before running anything. The agent functions guide states that function calling must be explicitly enabled for ChatCompletionAgent, while an OpenAIAssistant agent always uses automatic function calling. Enable it on the chat-completion side so both agents can call tools. Skipping this makes ChatCompletionAgent appear unable to use tools when the cause is configuration.

Pro tip: Run a single smoke task that can only be solved with a tool call and confirm both agents actually make that call.

Step 5: Run identical tasks side by side

Feed both agents the same task set, instructions and starting state. Log the final response, every function call with its arguments, the call order and any state that persisted between turns. Score each run against the constraints from your profile rather than against a general sense of quality. Repeat tasks that involve branching so one lucky run does not decide the outcome.

Pro tip: Store transcripts and tool traces next to the scores so reviewers can check a verdict without rerunning the test.

Step 6: Write the decision record

Record the selected agent type, the service it depends on, the tools or hosted capabilities it needs, its state model, and why each competing type was rejected. Link the test traces that support each statement. Note any constraint that passed only after a configuration change, because that is where future regressions tend to appear. The record is the artifact reviewers approve, not the code.

Step 7: Escalate to a custom agent only on a documented gap

If both built-in types failed at least one stated requirement, list those failures in the record and scope a custom agent against the common Agent abstraction to close exactly those gaps. Rerun the same task set against the custom agent to confirm it passes where the built-ins failed. If the custom agent passes nothing new, drop it and revisit the requirement instead. This keeps you on maintained abstractions unless there is evidence you need to leave them.

Best Practices

  • Decide on requirements before you look at features. A written profile of service, tools, state, files and task complexity stops the team from choosing the most familiar agent and rationalizing it afterward.
  • Start with the smallest viable built-in agent. Built-in types track framework updates for you, so a custom agent should be a response to a documented gap, not a starting point.
  • Treat function-calling behavior as an architecture criterion. The agent functions guide documents that ChatCompletionAgent needs it enabled while OpenAIAssistantAgent always calls functions automatically, and that difference changes how tools fire in production.
  • Share one plugin set across candidates. Because plugins can be added to the kernel before or after agent creation or passed to the constructor, there is no reason for tool code to diverge during a comparison.
  • Evaluate tool traces, not only answers. A fluent response produced without the expected function call hides a failure that will surface under real data.
  • Keep the decision record next to the code. When a provider changes or a new agent type ships, the record tells you which assumptions to retest instead of repeating the whole evaluation.

Common Mistakes

  • Assuming every agent type calls functions the same way.: Check the configuration per type. The agent functions guide shows ChatCompletionAgent requires explicit enablement while OpenAIAssistantAgent is always automatic, so equalize this before comparing.
  • Treating an agent type as interchangeable with any model or service.: Match the type to the service. ChatCompletionAgent is tied to the Semantic Kernel AI-service abstraction and OpenAIAssistantAgent to the OpenAI Assistants API, per the agent framework documentation.
  • Judging candidates only on the final text response.: Log and score function calls, arguments, order and persisted state. Tool execution is part of agent behavior, and a right-looking answer without the right tool call should count as a fail.
  • Comparing agents with different prompts, tools or starting state.: Hold everything constant except the agent type. Otherwise the comparison measures differences in setup, and the decision record cannot defend its conclusion.
  • Building a custom agent first because the built-ins seem limiting.: Test the smallest viable built-in agent against written requirements and only build custom when a specific requirement fails. Custom code adds maintenance you should be able to justify in the record.

References

  • Examples: Worked examples and scenarios
  • FAQ: Frequently asked questions
  • Parent Method: Semantic Kernel Agent Framework

Sources


Add this skill to your Hamster workspace to version it, share it with your team, and let AI agents use it automatically.

Install this skill

Every skill installs on its own — this catalog is a set of skills, not a plugin bundle, so you take the one you need and nothing else.

Claude Code

.claude/skills/selecting-and-comparing-agent-architectures
npx skills add gethamster/skills --skill selecting-and-comparing-agent-architectures --agent claude-code --yes

Cursor

.agents/skills/selecting-and-comparing-agent-architectures
npx skills add gethamster/skills --skill selecting-and-comparing-agent-architectures --agent cursor --yes

Codex

.agents/skills/selecting-and-comparing-agent-architectures
npx skills add gethamster/skills --skill selecting-and-comparing-agent-architectures --agent codex --yes

Antigravity

.agents/skills/selecting-and-comparing-agent-architectures
npx skills add gethamster/skills --skill selecting-and-comparing-agent-architectures --agent antigravity --yes

Or browse the skills and pick interactively:

npx skills add gethamster/skills

Source: gethamster/skills on GitHub, MIT licensed.