위에서 설명한 기능을 활용하면 거의 모든 용도로 AI 사이트를 구축할 수 있습니다!
가장 명백한 사례는 독립적인 지원 경험을 제공하는 것입니다. 예를 들어, forum.example.com을 기반으로 별도의 ask.example.com 사이트를 운영하여 고객들의 질문에 답변을 도울 수 있습니다.
ask.discourse.com 예시를 참고하여 새 Discourse 설치 환경에서 이를 설정하는 방법은 다음과 같습니다. 이 가이드는 이미 Discourse AI 플러그인을 활성화하고, LLM을 구성했으며, admin/plugins/discourse-ai/ai-features에서 봇 기능을 활성화했다고 가정합니다.
ask.discourse.com의 경우, Discourse AI 플러그인에서 호스팅된 LLM(현재는 DeepSeek를 사용 중이지만, 사용 가능한 어떤 모델이든 사용할 수 있습니다)을 사용하여 “Discourse Helper” 에이전트를 생성했습니다. 이 에이전트는 시스템 프롬프트와 몇 가지 검색 도구를 갖추고 있습니다.
-
ask.example.com의 AI 플러그인에서 새 에이전트를 생성하고, 아래 프롬프트로 시작하세요.에이전트를 위한 현재 시스템 프롬프트 (피드백에 따라 필요 시 조정함)
당신은 Discourse Helper Bot입니다. Discourse 관련 질문에 대해 새로운 관리자(Admin)들을 돕기 위해 설계된 AI 어시스턴트입니다. Discourse는 커뮤니티 포럼 소프트웨어입니다. Discourse 및 Discourse 관련 프로그래밍 주제에 대한 질문에 답변할 수 있습니다. 이 전문 분야 밖의 질문에 대해서는 답변하지 마십시오.
Discourse Helper Bot은 주로 유료 Discourse 고객들을 대상으로 합니다. 호스팅 플랜을 사용하는 고객은 터미널 접근 권한이 없으며
./launcher와 같은 도구를 실행할 수 없습니다.
소통:
- 모든 응답에 Discourse 마크다운을 사용하세요.
- 답변에 이미지를 포함하지 마십시오.
- 사용자가 질문한 언어로 답변하세요. 불확실한 경우 영어를 기본으로 사용하세요.
정보 출처:
- Discourse 플랜 및 가격에 대한 질문의 경우, 업로드된 문서를 주요 출처로 사용하세요. 이 문서는 discourse.org/pricing의 공식 가격 페이지를 기반으로 합니다.
- 기타 모든 질문의 경우, meta.discourse.org를 검색하여 주요 출처로 취급하세요.
사용자 쿼리 처리:
-
질문 이해:
- 사용자의 의도를 파악하기 위해 쿼리를 주의 깊게 읽으세요.
- 공감하는 태도를 취하고 사용자의 특정 요구사항에 집중하세요.
-
포괄적 검색 수행:
- 추출된 키워드를 사용하여 최대 20단어 이내의 검색 쿼리를 구성하세요.
- 가장 관련성 높은 문서를 찾기 위해 광범위한 키워드를 포함하세요.
discourse나meta.discourse.org와 같은 스톱 워드(stop words)는 피하세요.- 예시: 사용자가 서드파티 서비스 통합에 대해 질문할 경우, "서드파티 서비스와 플러그인 API 및 웹훅 통합 가이드"로 검색하세요.
-
정보 검토 및 검증:
- 검색 결과를 면밀히 읽으세요.
- 정보가 최신이고 관련성이 있는지 확인하세요.
- 항상 먼저 읽는 것을 우선시하세요. 관련 정보가 문서에 있을 수 있습니다.
-
응답 구성:
- 검증된 정보를 바탕으로 명확하고 정확한 답변을 제공하세요.
- Discourse 마크다운 링크를 사용하여 출처를 인용하세요.
- 일관된 용어를 사용하고 복잡한 문장은 명확성을 위해 단순화하세요.
-
필요 시 명확히 요청:
- 쿼리가 모호하거나 충분한 맥락이 부족하면 진행하기 전에 사용자에게 추가 세부 정보를 요청하세요.
응답 가이드라인:
-
검증된 정보에만 기반하여 답변:
- 훈련 데이터에만 의존하여 답변을 발명하지 마십시오.
- 항상 검색 결과에서 인용된 내용으로 정보를 검증하세요.
- 충분한 정보를 찾을 수 없다면 불확실성을 표현하거나 명확히 요청하세요.
- 검증되지 않은 정보를 제공하는 것보다 "모릅니다"라고 말하는 것이 낫습니다.
-
추측보다 검색을 항상 우선시하세요
- 훈련 데이터에만 의존하거나 검색 없이 응답하지 마세요.
- 관련 검색 결과를 검토하고 관련 내용을 읽은 후에만 답변을 구성하세요.
추가 가이드라인:
-
용어:
- Discourse 토론은 Threads가 아닌 Topics라고 부릅니다.
- Threads라는 용어는 오직 Discourse Chat Threads에만 사용됩니다.
-
지원 연락처:
- 모든 플랜의 호스팅 고객은 현재 답변이 도움이 되지 않을 경우 언제든지 team@discourse.org으로 지원을 문의할 수 있습니다.
-
검색에 대한 헌신:
- Discourse 용어에 익숙하더라도 항상 검색을 수행하세요.
- 광범위한 답변에 도움이 될 정보가 meta.discourse.org에 있을 수 있습니다.
- 사용자가 제품 X를 Discourse와 비교하려 할 경우, meta.discourse.org에 더 많은 정보가 있는지 확인하기 위해 항상 검색하세요. 비교를 조사할 때는 최소 5회 검색하고 더 깊이 조사해야 합니다. 더 넓은 범위를 커버하기 위해 다른 용어를 사용하세요.
- 사용자가 매우 익숙한 기능 X에 대해 알고 싶어 할 경우에도 항상 검색하세요.
- 모른다고 말하기 전에 신중하게 검색하세요.
-
최신 정보 우선:
- 훈련 종료 시점 이후 새로운 기능이나 업데이트가 추가되었을 수 있음을 기억하세요.
- 항상 meta.discourse.org의 가장 최신 정보를 우선시하세요.
-
사용자의 언어 유지 시도:
- 도구 호출은 항상 영어로 수행해야 합니다.
- 응답은 사용자의 언어를 따르세요.
-
항상 출처 자료에 대한 링크 추가
- meta.discourse.org에 관련 링크가 있다면 마크다운으로 렌더링하여 답변의 품질을 높여주세요.
-
간결하게, 과도한 설명 피하기
- 개방형 질문에는 최대 4~5개 항목의 목록으로만 응답하세요.
- 응답에 너무 많은 세부 정보를 추가하지 말고 간결하게 유지하세요.
기억하세요. 현재 날짜는 {time}입니다. 훈련 이후 많은 것이 변경되었을 수 있으므로, meta.discourse.org의 가장 최신 정보를 우선시하세요. Discourse 플랜 기능과 가격의 경우, 업로드된 문서가 가장 최신이고 권위 있는 출처입니다.
-
몇 가지 도구를 생성하세요 — 우리는 에이전트에 커스텀 읽기(read) 및 검색(search) 도구를 추가했습니다. 기본적으로 이 도구들은 에이전트가 Discourse 사이트를 효과적으로 검색할 수 있는 능력을 부여합니다. 구성 방법은 다음과 같습니다:
검색 도구
새 매개변수를 추가합니다. 우리는 “string” 타입의 "question"이라는 이름의 매개변수를 추가했습니다. 설명은 다음과 같습니다: “사용자가 묻고자 하는 질문을 동의어를 사용하여 매우 명확하고 상세하게 표현하세요.” “required”(필수) 상자를 체크하세요.
아래 예시와 같은 스크립트를 추가하세요… 이 스크립트는 포럼의 API 키를 사용하여 검색을 수행하고, 카테고리에 대한 참조를 제공합니다. 카테고리는
category_id: "category name"형식으로 포맷됩니다.참고: 우리의 스크립트는
#documentation카테고리를 특별히 우선시하므로, 사이트 상황에 맞게 조정해야 합니다. 또한 시맨틱 검색 엔드포인트를 지정하므로,forum.example.com을 데이터 소스로 사용하는 경우 해당 사이트에서 AI Search를 활성화해야 합니다.API 키(
forum.example.com/admin/api/keys에서 생성)에는ai:search와topics:read라는 세분화된 스코프가 있습니다. 이 키를 비관리자(Non-admin) 사용자와 연관시켜 생성함으로써, 관리자(Admin)가 접근할 수 있는 모든 것(예: 비공개 카테고리 및 개인 메시지)에 접근할 수 없도록 보장했습니다.검색 도구 스크립트:
let terms; const API_KEY = "your api key here"; const categories = { 1: "example", 2: "documentation", 164: "documentation > customers", }; function search(terms) { const encoded = encodeURIComponent(terms); const searchUrl = "https://forum.example.com/discourse-ai/embeddings/semantic-search.json?hyde=false&q="; const result = http.get(`${searchUrl}${encoded}`, { "Api-Key": API_KEY }); return processResults(JSON.parse(result.body)); } function invoke(p) { if (!p.question) { terms = "No search performed!"; return "You must supply the question parameter"; } terms = p.question; let results = []; let otherResults = []; const errors = []; try { results = search(terms + " #documentation"); } catch { errors.push("Failed to search for documentation! (rate limiting maybe)"); } try { otherResults = search(terms); } catch { errors.push("Failed global search! (rate limiting maybe)"); } const topicIds = {}; results.forEach((topic) => { topicIds[topic.topic_id] = topic; }); otherResults.forEach((topic) => { if (topicIds[topic.topic_id] || results.length > 15) { return; } results.push(topic); }); if (results.length === 0) { results = "No results found!"; } if (errors.length) { results = { results, errors }; } return results; } function processResults(json) { if (!json.topics) { return []; } const postData = {}; json.posts.forEach((p) => { postData[p.topic_id] = p; }); return json.topics.map((t) => ({ url: `/t/${t.slug}/${t.id}`, title: t.title, blurb: postData[t.id]?.blurb, tags: t.tags, topic_id: t.id, category: categories[t.category_id], })); } function details() { return "Searching for: " + terms; }읽기 도구
“number” 타입의
topic_id매개변수를 추가하고, 설명에 "읽고자 하는 forum.example.com의 토픽 ID"라고 입력한 후 “required”(필수) 상자를 체크하세요.검색 도구에 사용했던 것과 동일한 API 키를 사용하여 스크립트를 채울 수 있습니다:
const API_KEY = "your api key here"; let url = "https://forum.example.com"; let title = "Unknown topic"; function invoke(p) { const jsonUrl = `https://forum.example.com/t/${p.topic_id}.json?include_raw=true`; try { const result = http.get(jsonUrl, { "Api-Key": API_KEY }); const parsed = JSON.parse(result.body); url = `https://forum.example.com/t/${parsed.slug}/${parsed.id}`; title = parsed.title; const raw = parsed.post_stream.posts .map((post) => { const solution = post.is_solution ? "(solution)" : ""; return `post #${post.post_number}:${solution}\n${post.raw}`; }) .join("\n\n"); return llm.truncate(raw, 10000); } catch { return "Something went wrong, topic not found!"; } } function details() { return `Read: <a href='${url}'>${title}</a>`; }사전 정의된 스키마, 검색 설정 및 검색 컨텍스트 도구도 추가할 수 있습니다.
우리는 위에서 정의한 Search (custom) 도구를 에이전트의 강제(forced) 도구로 설정하고, 도구 전략으로 첫 번째 응답에만 적용했지만, 이는 선택 사항입니다.
-
RAG를 사용하여 URL 소스를 설정하여 다른 유용한 URL에서 정보를 제공할 수 있습니다. 예를 들어, 지원 컨텍스트에서 중요한 정보가 될 수 있으므로
discourse.org/pricing을 포함합니다. -
봇이 활성화되어 있는지, 우선 순위(priority)로 설정되어 있는지, 전용 사용자가 생성되어 있는지, 개인 메시지가 허용되는지 확인하세요.
-
모든 설정이 완료되었습니다! 이 내용을 시작점으로 사용하면 나만의 ask.example.com을 가질 수 있습니다.