
결론부터 말씀드리겠습니다. 2026년 2월, 저희는 OpenClaw에서 xAI의 Grok Search를 켜려다 겪은 문제를 두 편의 글로 나눠 다뤘습니다. 그런데 이번에 통합 개정하면서 다시 검증해보니, 그 글들이 소개한 수동 패치 두 건은 저희가 글을 올리기도 전에 이미 상류(upstream)에서 고쳐져 있었습니다. 심지어 원인으로 지목했던 GitHub 이슈 번호도 저희 여섯 편 전부가 잘못 인용하고 있었습니다. 이 글은 그 정정과 함께, 지금 기준으로 실제 필요한 설정만 다시 정리한 가이드입니다.
🔍 개요 — Grok Search와 이 글의 배경
Grok Search는 xAI의 Grok 모델을 활용해 OpenClaw의 AI 에이전트가 실시간 웹 검색을 수행하도록 해주는 도구입니다. 기존에는 Brave Search API만 지원했는데, Brave 쪽은 검색 품질은 안정적이지만 결과가 순수 검색 스니펫 위주라 최신 이슈나 빠르게 바뀌는 정보를 다룰 때는 다소 아쉬운 부분이 있었습니다. 2026.2.9 버전(PR #12419)에서 Grok이 새 검색 프로바이더로 추가되면서, xAI의 /v1/responses 엔드포인트에 web_search 도구를 붙여 쓰는 방식이 함께 들어왔습니다. Grok 모델 자체가 실시간성이 강점이라, 검색 프로바이더로서도 이 부분이 기대를 모았습니다.
저희는 이 기능을 켜는 과정에서 여러 문제를 만났고, 이를 2월 13일 버그 패치 기록(디버깅 일지 형식)과 2월 23일 설정 가이드(정리된 튜토리얼 형식) 두 편으로 나눠 다뤘습니다. 두 글을 나란히 놓고 이번에 다시 살펴보니, 각 글이 말하는 “문제 개수”부터 서로 어긋나 있었습니다.
당시 상황을 조금 더 설명하면, Grok Search는 릴리즈되자마자 바로 쓸 수 있는 상태가 아니었습니다. PR #12419가 머지된 지 얼마 안 된 신규 기능이었고, 저희가 실제로 손대던 시점(2월 초~중순)에는 관련 버그들이 상류에서도 한창 수정되고 있던 구간이었습니다. 그래서 저희가 겪은 문제 중 상당수는 저희 환경 탓이 아니라, 기능 자체가 아직 안정화되기 전 상태를 그대로 만난 것이었습니다. 이 배경을 알고 나면, 뒤에서 다룰 “이미 고쳐진 버그를 고쳐진 줄 모르고 다시 패치했다”는 이야기도 조금 더 납득이 갑니다.
🐛 원래 발견된 문제 다섯 가지
저희 기존 글들은 하나같이 “문제 4가지”라고 소개했지만, 실제로는 다섯 가지 서로 다른 문제가 있었고, 어느 글도 이 다섯 가지를 하나로 정리하지 못했습니다. 버그 패치 기록은 제목에서 “버그 3개”라고 해놓고 본문에서는 “4가지 문제(코드 버그 2개 + 설정 오류 2개)”라고 말하며 npm 이중 설치 항목을 번호 없는 “보너스”로 따로 뒀습니다. 설정 가이드는 반대로 API 키 문제를 4번째로 번호를 매기고, 이번엔 npm 이중 설치 쪽을 번호 없는 해결 단계로 돌렸습니다. 결과적으로 저희 콘텐츠 전체에 걸쳐 “4가지”라는 숫자만 반복되고, 정작 그 4가지가 매번 다른 조합이었던 셈입니다. 이번 통합 개정에서는 다섯 가지 전부를 정직하게 나열합니다.
| # | 문제 | 분류 |
|---|---|---|
| 1 | 모델명이 grok-2로 설정됨 (web_search 미지원 모델) | 설정 오류 |
| 2 | include 파라미터 400 에러 | 코드 버그 |
| 3 | 검색은 되는데 항상 “No response” | 코드 버그 |
| 4 | npm 이중 설치로 게이트웨이가 옛날 코드 실행 | 운영/배포 문제 |
| 5 | .env의 XAI_API_KEY가 주석 처리됨 | 설정 오류 |
🔬 어떻게 진단했나
당시 버그 패치 기록에 남아 있던 진단 과정을 옮겨둡니다. 처음 만난 에러는 모델명 문제였습니다.
xAI API error (400): {"error": "Model not found: grok-2"}
모델명을 grok-4-1-fast로 고치자 다른 에러가 나타났습니다.
xAI API error (400): {"code":"400","error":"Argument not supported: include"}
이 에러는 코드를 직접 봐야 원인을 알 수 있는 종류였습니다. 에러가 사라진 뒤에도 검색 결과가 항상 비어서 왔고, xAI API를 curl로 직접 호출해 실제 응답 구조를 확인했습니다.
curl -s -X POST https://api.x.ai/v1/responses \
-H "Authorization: Bearer $XAI_API_KEY" \
-d '{"model":"grok-4-1-fast",
"input":[{"role":"user","content":"latest AI news"}],
"tools":[{"type":"web_search"}]}'
당시 OpenClaw 코드가 기대하던 응답 형태와 xAI가 실제로 돌려주는 응답 형태가 완전히 달랐습니다.
| OpenClaw이 기대하던 것 | xAI 실제 응답 구조 |
|---|---|
data.output_text | data.output[0].content[0].text |
이 과정에서 정리했던 교훈은 네 가지였습니다.
- PR 원문이 진실의 소스입니다. 모델명이나 설정 기본값이 헷갈릴 때는 공식 문서보다 GitHub PR의 커밋 메시지가 더 빠르고 정확한 근거인 경우가 많습니다. 문서화는 항상 코드 변경보다 한 박자 늦게 따라옵니다.
- xAI API는 OpenAI와 다릅니다.
/v1/responses엔드포인트의 응답이 중첩 배열 구조라서, OpenAI 호환을 전제로 짠 코드는 파싱 단계에서 어긋나기 쉽습니다. - 직접 curl로 확인하는 게 가장 빠릅니다. 애플리케이션 레이어를 거치지 않고 API를 직접 호출해보면, 문제가 클라이언트 코드에 있는지 API 자체에 있는지 바로 구분됩니다.
- npm 전역 설치는 한 경로로 통일해야 합니다. sudo 설치와 사용자 prefix 설치를 병행하면 systemd 같은 서비스가 어느 쪽을 참조하는지 헷갈리기 쉽습니다.
🔧 당시의 해결 방법
당시 저희가 실제로 적용했던 수동 패치입니다. 아래 코드 패치 두 건(문제 2, 3)은 뒤에 나올 “그래서 지금은?” 절에서 정정합니다 — 이미 상류에서 고쳐진 뒤였습니다. 원래 기록을 그대로 남겨두는 이유는, 같은 시기 다른 버전을 쓰고 계신 분들이 참고할 수도 있고, 저희 판단 과정 자체를 투명하게 남기기 위해서입니다.
npm 이중 설치 정리 — /usr/lib/node_modules/openclaw/와 ~/.npm-global/lib/node_modules/openclaw/ 두 곳에 설치돼 있었고, systemd 서비스가 후자를 참조하고 있었습니다.
sed -i 's|/home/{username}/.npm-global/lib/node_modules/openclaw/dist/index.js|/usr/lib/node_modules/openclaw/dist/index.js|g' \
~/.config/systemd/user/openclaw-gateway.service
systemctl --user daemon-reload
rm -rf ~/.npm-global/lib/node_modules/openclaw
rm ~/.npm-global/bin/openclaw
모델명 수정 — grok-2를 grok-4-1-fast로 바꿨습니다.
python3 -c "
import json
with open('/home/{username}/.openclaw/openclaw.json') as f:
d = json.load(f)
d['tools']['web']['search']['grok']['model'] = 'grok-4-1-fast'
with open('/home/{username}/.openclaw/openclaw.json', 'w') as f:
json.dump(d, f, indent=2)
"
(당시 임시 조치) include 파라미터 패치 — 빌드된 파일을 직접 sed로 수정했습니다.
sudo sed -i 's/if (params.inlineCitations) body.include = \["inline_citations"\];/\/\/ PATCHED/' \
/usr/lib/node_modules/openclaw/dist/reply-DptDUVRg.js
(당시 임시 조치) 응답 파싱 패치 — 폴백 경로를 직접 추가했습니다.
sudo sed -i 's|content: data.output_text ?? "No response"|content: (data.output_text ?? data.output?.find(o => o.type === "message")?.content?.find(c => c.type === "output_text")?.text) ?? "No response"|' \
/usr/lib/node_modules/openclaw/dist/reply-DptDUVRg.js
API 키 활성화 — .env에서 주석을 해제했습니다.
sed -i 's/^#XAI_API_KEY=/XAI_API_KEY=/' ~/.openclaw/.env
include 파라미터 패치와 응답 파싱 패치는 더 이상 적용하지 말아야 합니다. 아래 “그래서 지금은?” 절을 먼저 확인하시기 바랍니다 — 빌드 파일 경로(reply-DptDUVRg.js) 자체가 현재 아키텍처에는 존재하지 않습니다.🔄 그래서 지금은?
이번 통합 개정에서 가장 중요하게 다룰 부분입니다. 다섯 가지 문제를 실제 GitHub PR·이슈·현재 코드와 하나씩 대조해봤습니다.

가장 중요한 발견: 코드 버그 두 건은 저희가 글을 올리기도 전에 이미 고쳐져 있었습니다. include 파라미터 버그의 진짜 수정은 PR #12945로, 2026년 2월 11일에 머지됐습니다. 응답 파싱 버그의 수정은 PR #13049로, 2026년 2월 10일에 머지됐습니다. 두 수정 모두 2026년 2월 13일에 배포된 v2026.2.12에 포함돼 있었는데, 이날은 저희 버그 패치 기록(KO)이 발행된 바로 그날입니다. 저희는 “다음 릴리즈에 픽스가 포함될 예정”이라고 미래형으로 썼지만, 사실 그 릴리즈는 이미 나와 있었습니다.
include 파라미터 버그의 원인을 GitHub Issue #12860으로 지목했는데, 이번에 재검증한 결과 이 이슈는 실제로는 응답 파싱 버그(문제 3)에 관한 것이었습니다. include 파라미터 버그의 진짜 이슈는 Issue #12910이고, 이걸 고친 PR #12945는 저희 기존 글 어디에도 인용된 적이 없습니다. 저희 쪽 인용 오류였다는 걸 분명히 밝혀둡니다.정리하면 이렇습니다.
당시엔 맞았지만 지금은 아닌 것
- include 파라미터 패치, 응답 파싱 패치 — 둘 다 상류에서 이미 고쳐졌습니다. 게다가 패치 대상이던
reply-DptDUVRg.js같은 빌드 파일 직접 수정 방식 자체가, 지금은 Grok/xAI 로직이extensions/xai/전용 플러그인으로 완전히 분리되면서 더 이상 성립하지 않습니다. 현재 코드(extractXaiWebSearchContent)는output[]배열을 순회하면서type === "message"블록을 찾고, 그 안에서content[]를 다시 훑어 텍스트와 인용(annotation)을 함께 뽑아냅니다. 당시 저희가 추가했던 단순 폴백은 인덱스 기반이라 응답 구조가 조금만 달라져도 깨질 수 있었는데, 현재 방식은web_search_call같은 중간 항목이 섞여 있어도 견고하게 처리합니다. - 모델명
grok-4-1-fast— 아직 유효한 모델 ID이긴 하지만 더 이상 기본값이 아닙니다. 현재 기본 모델은grok-4.3이고, xAI의 최신 플래그십은 2026년 7월 8일 출시된grok-4.5입니다. 더 근본적으로, 모델 선택 자체가web_search설정에서 더 이상 문서화된 옵션이 아닙니다.
지금도 유효한 것
- API 키 문제 —
.env나 설정 파일에 키를 빠뜨리는 실수는 아키텍처가 바뀌어도 똑같이 일어날 수 있습니다. 다만 설정 경로는 아래에서 갱신해 드립니다. - npm 이중 설치 위험 — 완전히 사라지진 않았습니다. 공식 설치 스크립트가 생기면서 위험은 줄었지만, 여전히 문서화된 트러블슈팅 항목입니다.
⚙️ 현재 권장 설정

설정 경로 자체가 바뀌었습니다. 예전 글들이 가르쳤던 tools.web.search.grok.* 경로는 지금도 하위 호환을 위해 읽히긴 하지만(resolveXaiToolSearchConfig가 레거시·플러그인 설정을 함께 병합합니다), 현재 온보딩이 실제로 만들어내는 설정은 아닙니다. 지금 기준 권장 경로는 plugins.entries.xai.config.webSearch.*이고, API 키 대신 xAI OAuth 인증이 우선 경로로 안내됩니다.
{
"plugins": {
"entries": {
"xai": {
"config": {
"webSearch": {
"apiKey": "xai-...(your-key, OAuth를 쓰지 않는 경우)",
"baseUrl": "https://api.x.ai/v1"
}
}
}
}
}
}
web_search 설정의 문서화된 옵션이 아닙니다. 기본값(grok-4.3)을 그대로 쓰시는 걸 권합니다. API 키를 직접 관리하고 싶다면 XAI_API_KEY 환경변수 경로도 여전히 동작합니다.OAuth와 API 키, 뭐가 다른가 — API 키 방식은 이 글이 원래 다루던 방식으로, 발급받은 키 문자열을 설정 파일이나 환경변수에 직접 넣습니다. 키가 새거나 유출되면 직접 재발급해야 하고, 만료·회수 관리도 사용자 몫입니다. 반면 OAuth 경로는 xAI 계정으로 인증한 뒤 토큰을 발급받는 방식이라, 키 관리 부담이 줄고 권한 범위도 더 세밀하게 제어할 수 있습니다. 지금 온보딩 과정에서 우선 안내되는 쪽이 OAuth인 이유입니다. 기존에 API 키로 설정해두신 분들도 당장 바꿀 필요는 없습니다 — 두 경로 모두 계속 지원됩니다.
예전 설정 파일이 남아 있다면 — tools.web.search.grok.* 경로로 설정해두신 상태라도, 지금 버전에서 갑자기 동작을 멈추지는 않습니다. resolveXaiToolSearchConfig가 레거시 경로와 새 플러그인 경로를 함께 병합해서 읽기 때문입니다. 다만 신규 문서나 온보딩 흐름은 전부 새 경로 기준으로 작성돼 있으므로, 이번 기회에 옮겨두시는 걸 권합니다.
npm 이중 설치, 지금은 이렇게 예방합니다 — 공식 설치 스크립트(install.sh, install-cli.sh)를 쓰면 훨씬 안전합니다. install-cli.sh는 사용자 소유의 단일 경로(~/.openclaw)에만 설치해 root 권한 설치본이 따로 생기는 상황 자체를 구조적으로 막고, install.sh는 설치·업그레이드 후 이미 떠 있는 게이트웨이 서비스를 감지해 재시작까지 처리합니다. 당시 저희가 겪은 문제 — sudo npm install -g로 올려도 게이트웨이는 옛날 경로를 계속 실행하던 상황 — 은 바로 이 사후 재시작 단계가 없어서 생긴 일이었습니다. 다만 npm 전역 설치를 손으로 여러 경로에 나눠 하는 경우의 PATH 충돌은 지금도 공식 트러블슈팅 문서에 남아 있는 항목이라, 완전히 사라진 위험은 아닙니다.
API 키 문제, 확인 순서
.env에서XAI_API_KEY줄이 주석 처리(#)돼 있지 않은지 확인- 설정 파일의
apiKey필드가 빈 문자열이 아닌지 확인 - OAuth 경로를 쓰는 경우, 별도 API 키 설정 없이도 동작하는지 먼저 확인 (우선순위가 더 높습니다)
지금 설정이 제대로 됐는지 확인하는 방법 — 가장 확실한 방법은 이전과 마찬가지로 curl로 직접 호출해보는 것입니다. 정상 응답이면 output[] 배열 안에 type: "message" 블록이 있고, 그 안의 content[]에 실제 텍스트가 담겨 있어야 합니다. 만약 예전처럼 응답이 비어 있거나 400 에러가 난다면, 이번엔 코드 버그가 아니라 인증(OAuth 토큰 만료, API 키 오타) 쪽을 먼저 의심하시는 게 순서에 맞습니다 — 원래 코드 버그였던 두 문제는 앞서 설명드린 대로 이미 상류에서 해결됐기 때문입니다.
🧭 정리
이번 통합 개정의 요점은 두 가지입니다. 첫째, 원래 다섯 가지 문제 중 코드 버그 두 건은 이미 해결됐고, 그 수정이 저희가 글을 올린 시점보다도 먼저 나와 있었습니다. 저희가 “곧 고쳐질 예정”이라고 쓴 문장은 발행 시점에 이미 틀린 문장이었던 셈입니다. 둘째, 그 과정에서 저희 쪽 인용 오류(Issue #12860 오귀인)가 여섯 편 전부에 반복됐다는 것도 이번에 확인했습니다.
왜 이런 일이 반복됐는지 생각해보면, 원인은 부주의가 아니라 타이밍이었습니다. Grok Search는 릴리즈 직후 며칠 사이에 관련 PR이 연달아 머지되던 기능이었고, 저희는 그 흐름을 따라잡지 못한 채 스냅샷 하나만 보고 글을 썼습니다. 다만 Issue 번호 오귀인은 타이밍 문제가 아니라 순수한 인용 오류였고, 이건 저희가 인정하고 넘어가야 할 부분입니다. 빠르게 변하는 오픈소스 프로젝트를 다룰 때는, 특정 시점의 스냅샷을 “현재 상태”로 단정하기보다 “이 시점 기준”이라는 꼬리표를 붙이는 습관이 필요하다는 걸 다시 느꼈습니다.
지금 Grok Search를 새로 설정하신다면, 위 “현재 권장 설정” 절만 보시면 됩니다. 나머지는 당시 저희가 어떻게, 그리고 왜 틀렸는지에 대한 기록으로 남겨둡니다.
📚 참고 자료
- PR #12419 — Grok Search 프로바이더 추가
- Issue #12910 — include 파라미터 400 에러 (진짜 원인)
- PR #12945 — include 파라미터 버그 수정 (2026-02-11 머지)
- Issue #12860 — 응답 파싱 버그 (저희가 예전에 잘못 인용했던 이슈)
- PR #13049 — 응답 파싱 버그 수정 (2026-02-10 머지)
- 현재 xAI 플러그인 소스 — responses-tool-shared.ts
- 현재 Grok Search 공식 문서
- 공식 설치 스크립트 문서
- xAI 공식 발표 — Grok 4.5 (2026-07-08)