Perplexity의 상담원 스킬은 더 많은 스킬이 필요하기 전에 실행 취소 경로가 필요합니다.

작성자

카테고리:

← 피드로
DEV Community · Odd_Background_328 · 2026-07-20 개발(SW)

Odd_Background_328

Perplexity added “Skills” to its Agent API, letting developers compose built-in and custom skills for more complex agent outputs. More skills mean more actions, and more actions mean more ways to produce an irreversible change. Before you add a fifth skill to your agent, make sure the first four have an undo path.

The undo problem

An agent skill that writes, sends, publishes, or deploys is an irreversible action if there is no rollback. The more skills an agent has, the more irreversible actions it can take in a single session. A chain of skills (research → draft → format → publish) can complete before a human notices the first step was wrong.

The undo contract

Every agent skill should declare:

{
  "skill_name": "publish_to_blog",
  "action_type": "write",
  "reversible": true,
  "undo_method": "set_published_false",
  "undo_timeout_seconds": 3600,
  "undo_side_effects": ["SEO index will retain the URL for up to 24h"]
}

Enter fullscreen mode Exit fullscreen mode

If reversible is false, the skill should require explicit human approval before execution.

A skill registry with undo support

# skill_registry.py
"""
Registers agent skills with undo metadata.
Blocks irreversible skills from running without explicit approval.
"""
from dataclasses import dataclass
from typing import Optional, Callable
import json

@dataclass
class Skill:
    name: str
    action_type: str  # "read", "write", "send", "deploy"
    reversible: bool
    undo_fn: Optional[Callable] = None
    undo_timeout_seconds: int = 3600
    side_effects: str = ""
    requires_approval: bool = False

class SkillRegistry:
    def __init__(self):
        self.skills = {}
        self.execution_log = []

    def register(self, skill: Skill):
        # Irreversible write/send/deploy skills require approval
        if not skill.reversible and skill.action_type in ("write", "send", "deploy"):
            skill.requires_approval = True
        self.skills[skill.name] = skill

    def execute(self, skill_name: str, inputs: dict, approved: bool = False):
        skill = self.skills.get(skill_name)
        if not skill:
            raise ValueError(f"Unknown skill: {skill_name}")

        if skill.requires_approval and not approved:
            return {
                "status": "blocked",
                "reason": "Skill is irreversible and requires explicit approval",
                "skill": skill_name,
                "action_type": skill.action_type
            }

        # Execute the skill (simulated)
        result = {"status": "executed", "skill": skill_name, "inputs": inputs}
        self.execution_log.append({
            "skill": skill_name,
            "inputs": inputs,
            "result": result,
            "undo_available": skill.reversible,
            "executed_at": "2026-07-20T15:00:00Z"
        })
        return result

    def undo(self, execution_index: int):
        entry = self.execution_log[execution_index]
        skill = self.skills[entry["skill"]]

        if not skill.undo_fn:
            return {
                "status": "failed",
                "reason": "No undo function registered",
                "skill": entry["skill"]
            }

        undo_result = skill.undo_fn(entry["inputs"])
        entry["undone"] = True
        entry["undo_result"] = undo_result
        return {"status": "undone", "skill": entry["skill"], "result": undo_result}

# Example usage
if __name__ == "__main__":
    registry = SkillRegistry()

    # Reversible skill
    def undo_publish(inputs):
        return f"Set published=false for {inputs.get('post_id')}"

    registry.register(Skill(
        name="publish_post",
        action_type="write",
        reversible=True,
        undo_fn=undo_publish,
        side_effects="SEO index retains URL for 24h"
    ))

    # Irreversible skill
    registry.register(Skill(
        name="send_email",
        action_type="send",
        reversible=False,
        undo_fn=None,
        side_effects="Email cannot be un-sent"
    ))

    # Test reversible skill
    result1 = registry.execute("publish_post", {"post_id": "123", "title": "Test"})
    print(f"Publish: {result1}")

    # Undo it
    undo1 = registry.undo(0)
    print(f"Undo publish: {undo1}")

    # Test irreversible skill without approval
    result2 = registry.execute("send_email", {"to": "[email protected]"})
    print(f"Send without approval: {result2}")
    assert result2["status"] == "blocked"

    # Test with approval
    result3 = registry.execute("send_email", {"to": "[email protected]"}, approved=True)
    print(f"Send with approval: {result3}")
    assert result3["status"] == "executed"

    # Try to undo (should fail)
    undo2 = registry.undo(1)
    print(f"Undo send: {undo2}")
    assert undo2["status"] == "failed"

    print("\nPASS: undo contract enforced")

Enter fullscreen mode Exit fullscreen mode

What the registry enforces

Skill type Execution Undo Read-only Always allowed Not needed Reversible write Always allowed Available within timeout Irreversible write Blocked without approval Not available

What to check

List every skill your agent currently has. For each one, fill in the undo contract above. If you have a skill where reversible is false and requires_approval is not enforced, you have an irreversible action running without a safety gate.

원문에서 계속 ↗

코멘트

답글 남기기

이메일 주소는 공개되지 않습니다. 필수 필드는 *로 표시됩니다