Placement of add_action() for ajax callback?

When you send an AJAX request, wp-admin/admin-ajax.php is called, not your template file. This separate request has no knowledge of all existing code in all existing templates, because they aren’t even included.

What is included: the theme’s functions.php and plugin files. This is why your callback works in a plugin.

As a rule of thumb: templates should never contain business code. No function or class declarations, no registration of callbacks. They are templates, they should just add markup to data, nothing else.