지난 15년 사이 어느 시점에, 웹은 조용히 모든 중요한 사이트가 모바일 앱도 필요하다고 결정했습니다. HTML이 작동을 멈춰서가 아니라 — 앱이 *통제된 표면(controlled surface)*이기 때문입니다: 큐레이션된 동작 집합, 당신이 고르지 않은 크롬(chrome) 없음, 하나의 상호작용 방식을 위해 구축된 인터페이스.
우리는 다른 사용자 집합과 다른 인터페이스 집합을 위해 동일한 움직임이 이루어지길 기다리고 있다고 생각합니다. 모두가 자신의 사이트를 안드로이드 앱으로 바꾼다면, 우리는 사이트를 음성 앱으로 바꿀 수 있습니다 — 그리고 명령줄 앱으로, 그리고 스크린 리더 네이티브 흐름으로도. 같은 아이디어, 반대 방향: 사이트를 당신이 그것과 상호작용하고 싶은 방식을 위해 구축된 표면으로 감싸되, 그 표면이 터치스크린 대신 당신의 목소리와 터미널인 것입니다.
웹은 귀로 거의 사용할 수 없다
마우스를 가진, 시력이 있는 사용자에게는 현대적인 사이트가 괜찮습니다. 음성으로, 또는 스크린 리더를 통해, 또는 터미널에서 탐색하는 사람에게 웹의 대부분은 적대적인 환경입니다: 무한 스크롤 벽, 쿠키 배너, 팝업, 포인터가 필요한 메뉴, 세 겹의 상호작용 잡동사니 아래에 묻힌 콘텐츠. 정보는 그 안에 있습니다. 손을 쓰지 않고 그것을 꺼내는 것은 비참합니다.
일반적인 답은 “사이트가 더 접근성이 좋아야 한다”이고, 그래야 합니다. 하지만 우리는 정중히 부탁한다고 해서 웹 전체를 고치지는 못할 것입니다. 우리가 할 수 있는 것은 중요한 사이트를 골라 각각에 깨끗하고 말로 하는 인터페이스를 구축하는 것입니다 — 앱 스토어가 터치를 위해 했던 방식으로, 다만 음성과 CLI를 위해, 그리고 개방적으로.
두 계층: 깨끗한 API, 그다음 음성 스킬
이 음성 앱들 각각은 두 조각이 쌓인 것이며, 우리는 이미 둘 다 구축합니다.
계층 1 — 사이트를 API로 바꾸는 타입이 정의된 클라이언트. 이것이 바로 우리의 스크래핑 및 API 역공학 작업입니다: 사용 가능한 공개 인터페이스가 없는 사이트에 손을 뻗어 취약한 HTML 대신 구조화되고 타입이 정의된 객체를 돌려주는 것 — 스크래핑이 아니라 동사(verb):
from py_bandcamp import BandCamp
for release in BandCamp.search_albums("king gizzard"):
artist = release.work.credits[0].entity.name if release.work.credits else ""
print(release.work.title, artist, release.uri)
그 아래의 정찰과
안티봇 전송
도구는 사이트가 변경됨에 따라 그 접근을 계속 작동하게 유지합니다. 그 클라이언트는
그 자체로 이미 유용합니다: 터미널 사용자에게 API 가 곧 웹사이트의 접근 가능한
버전입니다 — 우리의 SoundCloud 클라이언트는 심지어 브라우저 없이 음악을 검색하고
재생하는 명령줄 앱인 nds도 함께 제공합니다. 일단 사이트가 API가 되면, 그것은
시각적 산물이기를 그치고 기계 — 또는 음성 파이프라인 — 이 구동할 수 있는 무언가가
됩니다.
계층 2 — 그 API를 말하는 OVOS 플러그인. 클라이언트 위에는 말로 된 의도를 API 호출로 매핑하고 우리의 오프라인 TTS 음성으로 결과를 서술하는 OpenVoiceOS 플러그인이 자리 잡습니다. 그것은 의도적으로 사이트마다의 맞춤형 스킬이 아닙니다 — 그 길은 아무도 유지할 수 없는 수십 개의 일회성 스킬로 이어집니다. 미디어 형태의 무엇이든 그것은 OCP 제공자 플러그인입니다: 사이트의 검색-및-재생 표면을 전체 Open Common Play 프레임워크에 노출하는 하나의 작은 어댑터로, “검색”, “재생”, “다음”, “재개”가 다른 모든 소스에서 작동하는 것과 동일한 방식으로 이미 작동하게 합니다. 사이트는 자체적인 것을 발명하는 대신 균일한 음성 인터페이스에 끼워집니다.
그 결과: “SomaFM Groove Salad 채널을 재생해.” “Bandcamp에서 크리에이티브 커먼즈 앰비언트를 검색해.” 웹사이트가, 보지 않고도 사용할 수 있는 무언가로 바뀝니다 — 그리고 사이트마다 배워야 할 새로운 문법 없이.
LLM의 시대에, 타입이 정의된 API는 곧 실현될 자연어 UI다
이 형태가 5년 전보다 지금 더 중요한 두 번째 이유가 있습니다. 깨끗하고 타입이 정의된 클라이언트는 대규모 언어 모델이 웹사이트에 대한 자연어 프론트엔드가 되기 위해 필요한 바로 그것입니다.
LLM에게 문서화된 함수 집합을 주면 — search_albums, get_recommendations,
stream_url — 그것은 기꺼이 “Naxatras 같지만 더 무거운 것을 찾아줘”를 올바른
호출로 번역하고, 그것들을 연결하며, 결과를 다시 말해 줍니다. 구조화된 API가 어려운
부분입니다. 그 위의 대화형 인터페이스는, 넘겨받은 도구가 타입이 잘 정의되어 있고
반환하는 것에 대해 정직하기만 하다면, 점점 더 모델이 그저 제공하는 무언가가
됩니다. 지저분한 HTML은 LLM에게 붙잡을 것을 아무것도 주지 않습니다. 타입이 정의된
클라이언트는 그것에게 통제 표면을 줍니다.
그래서 우리의 웹사이트 클라이언트는 SKILL.md — API가 무엇을 하는지, 그
동사들, 그 반환 타입들, 그리고 예시 호출을, 에이전트가 읽도록 작성한 평이한 언어의
설명 — 을 함께 제공합니다. LLM 구동 어시스턴트를 그것에 겨누면 클라이언트는 모델이
즉시 사용할 수 있는 도구가 됩니다: 글루 코드 없이, 맞춤형 통합 없이, 그저 “이
사이트가 할 수 있는 것이 여기, 말로 있습니다.” 문서 하나가 스크래퍼를 언어 모델이
당신을 대신해 조작할 수 있는 무언가로 바꿉니다.
동일한 구조화된 데이터가 한 번에 세 개의 프론트엔드를 제공합니다: 터미널 사용자를 위한 CLI, 손을 쓰지 않는 사용을 위한 OCP/음성 플러그인, 그리고 자연어 제어를 위한 LLM 도구. API를 한 번 구축하고, 세 가지 방식으로 착용하세요.
이것이 화면을 볼 수 없는 사람들에게 가장 중요한 이유
시각장애인과 저시력 사용자에게 이것은 편의 기능이 아닙니다 — 접근과 배제 사이의 차이입니다. 스크린 리더는 페이지가 깨끗하게 노출하는 것만 읽을 수 있고, 대부분의 페이지는 그러지 않습니다. 전용 음성 앱은 페이지를 완전히 건너뜁니다: 구조화된 데이터로 가서 그것을 말하며, 코드의 첫 줄부터 듣기 위해 설계된 흐름으로.
이것은 우리의 오디오 우선 게임 뒤에 있는 것과 동일한 원칙입니다 — 눈이 아니라 귀를 위해 구축되었고, 시각장애 플레이어를 사후적 고려가 아니라 주요 대상으로 삼았습니다. 웹사이트를 위한 음성 앱은 그 원칙을 게임에서 나머지 웹으로 확장합니다.
한 번에 한 사이트씩 — 하지만 방향은 음성 브라우저다
정직한 부분은 이것입니다: 보편적인 지름길은 없습니다. “웹”을 한 번에 음성 지원할 수는 없습니다. 모든 사이트가 각자의 엉킴이기 때문입니다. 그것은 사이트별로 이루어져야 합니다 — 한 번에 하나의 클라이언트, 하나의 스킬, 세심하게 매핑된 하나의 의도 집합. 그것은 한계처럼 들리고, 단기적으로는 그렇습니다.
하지만 축적이 어디를 가리키는지 보세요. 우리가 감싸는 각 사이트는 이제 음성과 CLI로 도달할 수 있는 웹의 한 구석이 하나 더 늘어난 것입니다. 그것들을 충분히 많이 엮으면 — 공통 메타데이터 어휘, 공유된 음성 계층, “검색 / 열기 / 읽기 / 재생 / 다음”의 일관된 의도 집합 — 더 이상 분리된 스킬 더미를 보고 있는 것이 아닙니다. 당신은 음성 브라우저의 시작을 보고 있는 것입니다: 말하면서 웹을 누비는 방법, 개별 사이트는 이미 응답하는 법을 아는 목적지일 뿐인 곳.
모바일 시대의 베팅은 사용할 가치가 있는 사이트는 앱을 가질 가치가 있다는 것이었습니다. 우리의 베팅은 사용할 가치가 있는 사이트는 음성을 가질 가치가 있다는 것입니다. 우리는 개방적으로, 한 번에 하나씩 그것들을 구축하고 있으며, 그 각각은 시각적 웹이 뒤에 남겨둔 사람들을 위해 웹을 조금 더 탐색 가능하게 만듭니다.
특정 사이트를 음성 또는 CLI 앱으로 바꾸고 싶으신가요 — 접근성을 위해, 당신의 제품을 위해, 아니면 그저 존재해야 하기 때문에? 이야기해 봅시다.