Webhook 가이드: LLM 답변으로 Discussion 봇 만들기
Webhook 가이드: LLM 답변으로 Discussion 봇 만들기
Hugging Face Inference Providers를 통해 선택한 LLM이 생성한 답변으로 Hub의 Discussion 코멘트에 응답하는 봇을 Hugging Face Webhooks로 만드는 짧은 가이드예요.
출처: 문서
본문
사용자 프로필에서 Webhook 만들기
먼저 설정에서 Webhook을 만들어요.
- Webhook이 수신할 대상 저장소 몇 개를 입력해요.
- 지금은 더미 Webhook URL을 넣어도 되지만, Webhook을 정의하면 전송될 이벤트를 볼 수 있어요(디버깅에 유용한 재생(replay)도 가능).
- 보안을 위해 시크릿을 입력해요.
- Discussion 봇을 만드는 중이니 Community(PR & discussions) 이벤트를 구독해요.
Webhook은 이렇게 생겼어요.

새 Bot 사용자 프로필 만들기
이 가이드에서는 Space를 호스팅하고 코멘트를 게시하기 위해 별도의 사용자 계정을 만들어요.

[!TIP] Hub에서 다른 사용자와 상호작용하는 봇을 만들 때는 계정을 "Bot"으로 명확히 표시해 달라고 요청드려요(프로필 스크린샷 참고).
Webhook에 반응하는 Space 만들기
세 번째 단계는 실제로 Webhook 이벤트를 수신하는 거예요.
쉬운 방법은 Space를 사용하는 거예요. 우리는 만든 사용자 계정을 쓰지만, 원하면 메인 사용자 계정에서도 할 수 있어요.
Space 코드는 여기에 있어요.
NodeJS와 Typescript로 구현했지만, 어떤 언어나 프레임워크도 동등하게 잘 동작해요. Docker Spaces에 대해 더 자세히 알아보려면 여기를 읽어보세요.
메인 server.ts 파일은 여기에 있어요
이 파일에서 무슨 일이 일어나는지 살펴볼게요.
app.post("/", async (req, res) => {
if (req.header("X-Webhook-Secret") !== process.env.WEBHOOK_SECRET) {
console.error("incorrect secret");
return res.status(400).json({ error: "incorrect secret" });
}
...
여기서 /로 들어오는 POST 요청을 수신하고, X-Webhook-Secret 헤더가 이전에 정의한 시크릿과 같은지 확인해요(검증하려면 Space 설정에도 WEBHOOK_SECRET 시크릿을 설정해야 해요).
const event = req.body.event;
if (
event.action === "create" &&
event.scope === "discussion.comment" &&
req.body.comment.content.includes(BOT_USERNAME)
) {
...
이벤트의 페이로드는 JSON으로 인코딩돼요. 여기서 Webhook을 다음 조건에서만 실행하도록 지정해요.
- 이벤트가 discussion 코멘트에 관한 것
- 이벤트가 생성(create), 즉 새 코멘트가 게시된 것
- 코멘트 내용에
@discussion-bot이 포함됨, 즉 봇이 코멘트에 언급된 것
이 경우 다음 단계로 진행해요.
const CHAT_API_URL =
"https://router.huggingface.co/v1/chat/completions";
const SYSTEM_PROMPT = `You are a helpful bot that replies to discussions about machine learning. Keep your responses concise and friendly.`;
const response = await fetch(CHAT_API_URL, {
method: "POST",
headers: {
"Authorization": `Bearer ${process.env.HF_TOKEN}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
model: "moonshotai/Kimi-K2.6",
messages: [
{ role: "system", content: SYSTEM_PROMPT },
{ role: "user", content: req.body.comment.content },
],
max_tokens: 500,
}),
});
if (response.ok) {
const output = await response.json();
const continuationText = output.choices[0].message.content;
...
이게 가장 멋진 부분이에요. Hugging Face Inference Providers를 사용해 시스템 프롬프트와 사용자 코멘트로 오픈 가중치 모델(moonshotai/Kimi-K2.6)을 호출해요. 모델이 답변을 생성하고, 우리는 choices[0].message.content에서 추출해요.
가용 모델 목록에서 아무 모델이나 선택할 수 있어요 — model 필드만 바꾸면 돼요.
마지막으로 같은 Discussion 스레드에 답변으로 게시해요.
const commentUrl = req.body.discussion.url.api + "/comment";
const commentApiResponse = await fetch(commentUrl, {
method: "POST",
headers: {
Authorization: *** ${process.env.HF_TOKEN}`,
"Content-Type": "application/json",
},
body: JSON.stringify({ comment: continuationText }),
});
const apiOutput = await commentApiResponse.json();
Webhook이 이벤트를 Space로 보내도록 설정
마지막으로 Webhook이 Space에 POST 요청을 보내도록 설정해야 해요.
먼저 컨텍스트 메뉴에서 Space의 "direct URL"을 가져와요. "Embed this Space"를 클릭하고 "Direct URL"을 복사하세요.

Webhook을 업데이트해 그 URL로 요청을 보내게 하세요.

결과

더 알아보기 (Learn more)
Webhook을 설정하고 X-Webhook-Secret 헤더로 시크릿을 검증한 뒤, Space의 HTTP 서버에서 discussion.comment 생성 이벤트를 받아요. 코멘트에 봇이 언급되면 Inference Providers의 chat completions로 모델을 호출하고, 생성된 답을 같은 Discussion 스레드에 다시 POST하면 Discussion 봇이 완성돼요.