지식 베이스와 지식 관리
지식 베이스는 관련 자료를 정리하고 청크, 벡터 모델, 검색 인덱스, Wiki와 지식 그래프를 일괄 설정하는 데 사용합니다. 파일, 웹페이지, 직접 작성한 Markdown과 FAQ 등의 콘텐츠를 지식 항목으로 관리하며, 수집 후 설정에 따라 파싱하고 인덱스를 생성합니다.
지식 베이스마다 독립적인 처리 설정을 사용할 수 있습니다. 질문할 때 검색 범위를 제한할 수 있으며, 멤버 접근과 조직 공유도 지식 베이스 단위로 권한을 부여합니다.
파싱 상태 열, 태그 열, 상단 필터와 문서 선택 후 나타나는 일괄 작업 표시줄이 포함된 문서 목록 페이지를 보여주세요.
website-docs/public/screenshots/kb-document-list.png관리 작업 진입점
| 작업 | UI 진입점 |
|---|---|
| 지식 베이스 생성, 청크 크기와 인덱스 스위치 변경 | 지식 베이스 편집 팝업의 「청크」, 「인덱싱 전략」 탭 |
| 파일 업로드, 웹페이지 가져오기 또는 Markdown 작성 | 문서 목록 페이지의 업로드 영역 또는 「새로 만들기」 드롭다운 |
| 폴더로 문서 정리 | 문서 목록 왼쪽의 폴더 트리. 디렉터리 전체 업로드 시 디렉터리 구조 유지(폴더 트리 참조) |
| 문서에 태그 추가(문서당 여러 개 가능) | 개별 문서는 상세 화면에서 변경. 여러 문서는 선택 후 일괄 작업 표시줄의 「태그」 사용(태그(KnowledgeTag) 참조) |
| 파싱 결과 확인, 오타 수정 | 문서 열기 → 청크 목록 → 청크 직접 편집(청크 편집과 버전 기록 참조) |
| 부서, 보안 등급 등 사용자 지정 필드 추가 | 문서 상세의 사용자 지정 메타데이터(모델 핵심 사항 참조) |
| 작업 기록 조회 | 지식 베이스 설정 → 활동(지식 베이스 활동 스트림(KB Activity) 참조) |
| 지식 베이스 복사 또는 베이스 간 문서 이동 | 지식 베이스 목록의 복사 또는 문서 일괄 작업의 이동(지식 베이스 복사와 지식 이동 참조) |
청크 크기/겹침/부모·자식 청크 설정과 벡터, 키워드, Wiki, 그래프의 네 가지 인덱스 스위치를 보여주세요.
website-docs/public/screenshots/kb-settings.png지식 베이스 생성과 자료 가져오기
지식 베이스를 생성할 때 콘텐츠 유형, 모델과 인덱싱 방식을 선택한 뒤 파일 업로드, 웹페이지 가져오기 또는 Markdown 작성을 진행합니다. 일반 자료에는 문서 베이스를, 표준 질의응답에는 FAQ 베이스를 사용합니다. 벡터 스토리지는 생성 후 변경할 수 없으므로 지식 베이스 생성 전에 결정해야 합니다.
업로드 확인 페이지에서 태그와 이번 파일 묶음의 파싱 옵션을 설정할 수 있습니다. 일회성 처리 옵션은 지식 베이스 설정보다 우선하며, 지식 베이스 설정은 공간 기본값보다 우선합니다. 업로드 후 목록에서 파싱 진행 상황을 확인할 수 있습니다. 기존 문서에 변경된 청크 매개변수를 적용하려면 다시 파싱해야 합니다.
폴더와 태그 정리
폴더는 디렉터리별로 문서를 보관하는 데 사용하며, 문서 하나는 폴더 하나에만 속합니다. 디렉터리 전체를 업로드하면 계층 구조를 유지할 수 있습니다. 폴더 트리에서 이름을 바꾸거나 이동하면 하위 디렉터리 경로도 함께 갱신되며, 대상 디렉터리가 이미 있으면 콘텐츠를 병합합니다. 같은 지식 베이스 안에서 문서의 폴더를 이동하면 분류만 바뀌고 다시 파싱하지 않습니다.
태그는 교차 분류에 사용하며 문서 하나에 여러 태그를 연결할 수 있습니다. 업로드 시 태그를 미리 설정하거나 문서를 선택한 뒤 일괄 변경할 수 있습니다. 일괄 대화상자에서는 선택한 문서들의 공통 태그가 미리 선택됩니다. 여러 태그로 필터링할 때는 어느 하나와 일치하는 문서도 반환합니다.
자동 태그를 켜면 파싱 완료 시 기존 후보 태그 중 일치하는 항목을 선택합니다. 기본적으로 문서당 최대 3개를 연결하며, 기존 태그가 있으면 건너뜁니다. 설정은 이후 파싱에만 영향을 주며 과거 문서를 자동으로 보완하지 않습니다. 모델 실패도 문서 완료를 막지 않습니다.
왼쪽 폴더 트리, 현재 디렉터리의 문서 목록과 폴더 이름 변경/이동 진입점을 보여주세요.
website-docs/public/screenshots/kb-folder-tree.png문서를 여러 개 선택한 뒤 연 태그 대화상자를 보여주세요. 선택된 태그 영역, 검색창과 선택 가능한 태그 목록을 포함해주세요.
website-docs/public/screenshots/kb-batch-tag.png청크 편집과 메타데이터 추가
문서 상세에서 텍스트 청크를 편집하여 파싱 오류를 수정하고 인덱스를 재생성할 수 있습니다. 편집하거나 롤백할 때마다 새 버전이 생성됩니다. 다른 사용자가 같은 청크를 이미 업데이트했다면 UI에서 새로고침 후 다시 시도하도록 안내합니다. 인덱스 업데이트에 실패하면 편집한 콘텐츠를 보존하고 실패 상태를 표시하며, 다시 제출하여 재시도할 수 있습니다.
사용자 지정 메타데이터는 부서, 보안 등급이나 버전 번호 등의 정보를 보완하는 데 사용하며 최대 20개 항목을 지원합니다. 메타데이터를 변경하면 요약 갱신을 트리거합니다. 필드 길이와 지원 유형의 자세한 내용은 참고 섹션을 확인하세요.
청크 하나의 편집 상태, 버전 기록 목록(편집자와 시간 포함), 롤백 진입점을 보여주세요.
website-docs/public/screenshots/kb-chunk-edit.png콘텐츠 복사와 이동
지식 베이스를 복사하면 기존 설정과 콘텐츠를 재사용할 수 있습니다. 베이스 간 이동 시 벡터 재사용 또는 재파싱을 선택할 수 있습니다. 재사용하려면 두 베이스가 같은 벡터 스토리지에 연결되어야 하며, 재파싱하면 대상 베이스의 스토리지와 처리 설정을 사용할 수 있습니다. 이동은 비동기 작업이며 진행 상황을 조회할 수 있습니다.
활동과 사용량 확인
지식 베이스 설정의 「활동」에는 설정, 문서, 청크, 공유와 Wiki 변경 사항이 기록됩니다. 이 진입점은 리소스 관리 권한을 충족하는 로그인 사용자용이며 API Key로는 접근할 수 없습니다.
스토리지 할당량은 작업 공간 단위로 계산하며 파일, 텍스트, 벡터와 인덱스를 포함합니다. 지식 베이스 생성과 업로드 전에 할당량을 확인하고, 콘텐츠 삭제 후 해당 사용량을 회수합니다.
활동 목록(작업자, 동작, 대상 문서, 시간)과 펼친 상세 드로어를 보여주세요.
website-docs/public/screenshots/kb-activity.png설정과 인터페이스 참고
지식 베이스 모델과 설정 항목
KB 유형
internal/types/knowledgebase.go:
const (
KnowledgeBaseTypeDocument = "document" // 문서 유형
KnowledgeBaseTypeFAQ = "faq" // FAQ 유형
KnowledgeBaseTypeWiki = "wiki" // Wiki 유형
)KB 업데이트 시 유형에 맞지 않는 설정을 제거합니다(예: FAQ가 아닌 베이스의 FAQConfig). VectorStoreID는 GORM <-:create 태그를 사용하므로 생성 후 변경할 수 없습니다(인덱스와 스토리지의 불일치 방지).
설정 구조 개요
ChunkingConfig(청크 설정)
| 필드 | 유형 | 기본값 | 설명 |
|---|---|---|---|
chunk_size | int | 필수 | 청크 크기(문자 수) |
chunk_overlap | int | - | 인접 청크의 겹침 |
separators | []string | - | 구분자 목록 |
parser_engine_rules | []ParserEngineRule | - | 파일 유형별 파싱 엔진 지정: {file_types, engine, xlsx_first_row_as_header?} |
enable_parent_child | bool | false | 부모·자식 청크 전략 활성화 |
parent_chunk_size | int | 4096 | 부모 청크 크기(컨텍스트 반환용) |
child_chunk_size | int | 384 | 자식 청크 크기(임베딩 검색용) |
strategy | string | 빈 값(= legacy) | 청크 전략: legacy(기존 재귀 분할)/ auto(프로파일러가 계층 자동 선택)/ heading / heuristic / recursive(특정 계층 고정). 청크 메커니즘 참조 |
token_limit | int | 0 | 토큰 상한(0 = 제한 없음) |
languages | []string | 자동 감지 | 언어 힌트 |
table_metadata_instructions | string | - | 표 메타데이터 생성 지침 |
IndexingStrategy(인덱싱 파이프라인 스위치)
| 필드 | 기본값 | 설명 |
|---|---|---|
vector_enabled | true | 의미 기반 벡터 검색 |
keyword_enabled | true | 키워드(BM25) 검색 |
wiki_enabled | false | Wiki 페이지 생성 |
graph_enabled | false | 지식 그래프 추출 |
멀티모달 및 정보 보강 설정
VLMConfig(비전 언어 모델):
| 필드 | 설명 |
|---|---|
enabled / model_id | 새 버전: 활성화 스위치 + 모델 ID |
description_language | 이미지 설명 언어(빈 값 = 문서 언어 따름) |
custom_instructions | KB 수준 이미지 해석 지침 |
model_name / base_url / api_key / interface_type | 이전 버전 호환 필드(ollama / openai) |
활성화 판정: Enabled && ModelID != "" 또는 이전 버전의 ModelName != "" && BaseURL != "".
ASRConfig: enabled / model_id / language(언어 힌트, 선택 사항).
ImageProcessingConfig: model_id.
QuestionGenerationConfig(질문 생성): enabled; question_count는 청크당 생성할 질문 수(기본값 3, 상한 10); custom_instructions는 대상 독자 / 스타일 설명입니다.
ExtractConfig(지식 그래프): enabled, text, tags, nodes []*GraphNode{name, chunks, attributes}, relations []*GraphRelation{node1, node2, type}, custom_instructions(도메인 추출 지침).
FAQConfig(FAQ 베이스 전용): index_mode(question_only / question_answer, 기본값은 후자), question_index_mode(combined / separate, 기본값 combined). 자세한 내용은 FAQ 문서를 참고하세요.
WikiConfig(indexing_strategy.wiki_enabled를 켠 지식 베이스) — type = "wiki" 전용이 아니라는 점에 유의하세요. 일반 문서 베이스에서 Wiki 인덱스를 켜면 UpdateKnowledgeBase가 다음 조정 항목을 담을 빈 WikiConfig를 자동으로 생성합니다.
| 필드 | 기본값 | 설명 |
|---|---|---|
synthesis_model_id | - | Wiki 생성 LLM |
max_pages_per_ingest | 0(제한 없음) | 단일 수집에서 생성/업데이트할 최대 페이지 수 |
extraction_granularity | standard | focused(주요 주제만)/ standard / exhaustive(모든 엔터티와 개념) |
content_instructions / extraction_instructions | - | 생성 및 추출 스타일 지침 |
ingest_batch_size / ingest_map_parallel / ingest_reduce_parallel / ingest_max_inflight | 5 / 10 / 10 / 4 | 수집 동시성 매개변수 |
모든 custom_instructions 계열 필드는 업데이트 시 validateKnowledgeBasePromptInstructions로 길이와 유효성을 검증합니다(internal/handler/knowledgebase.go).
스토리지 설정
- StorageProviderConfig(신규):
provider ∈ {local, minio, cos, tos, s3, oss, ks3, obs}; - StorageBackendID: 특정 스토리지 백엔드 인스턴스 연결;
- StorageConfig(레거시
cos_config열):secret_id / secret_key / region / bucket_name / app_id / path_prefix / provider / endpoint / use_ssl / force_path_style.
KB 계산 필드
목록 / 상세 응답에 포함되는 항목: knowledge_count, chunk_count, is_processing(FAQ 베이스), processing_count(문서 베이스에서 처리 중인 지식 수), share_count(공유한 조직 수), creator_name, is_pinned / pinned_at(현재 사용자의 상단 고정 상태).
저장 필드 is_temporary도 있습니다. 임시(ephemeral) 지식 베이스를 표시하며 일반 지식 베이스 목록에는 나타나지 않습니다. 시스템 내부에서 사용하며, 대표적으로 웹 검색으로 가져온 웹페이지를 검색 가능한 콘텐츠로 캐시할 때 사용합니다. 수동으로 지식 베이스를 생성하면 임시 베이스가 만들어지지 않습니다.
자동 태그
문서 지식 베이스의 태그 관련 설정에서 자동 태그를 켜고, 후보 태그를 먼저 준비한 뒤 채팅 모델을 선택합니다. 파싱 완료 후 시스템은 기존 태그에서 일치하는 항목을 비동기로 선택하며 새 태그를 생성하지 않습니다. auto_tag_config는 document 유형에만 적용됩니다.
| 필드 | 기본값 | 설명 |
|---|---|---|
| enabled | false | 자동 태그 활성화 |
| model_id | 빈 값 | 비어 있으면 지식 베이스의 summary_model_id 사용 |
| max_tags | 3 | 문서당 자동 연결 최대 개수, 상한 10 |
| skip_if_tagged | true | 수동 또는 데이터 소스에서 추가한 태그를 포함하여 기존 태그가 있으면 건너뜀. false이면 추가 방식으로 연결 |
설정은 이후 새로 파싱하거나 다시 파싱하는 문서에만 적용되며 과거 문서에 자동 소급 적용하지 않습니다. 모델 실패는 문서 완료를 막지 않으며 비동기 작업은 큐 정책에 따라 재시도합니다. 후보 태그는 지식 베이스 정렬 순서의 앞 500개를 가져옵니다. 자동 연결은 수동 태그를 삭제하지 않습니다. 데이터 소스가 출처 이름에 따라 태그를 추가하는 것은 별도 메커니즘입니다.
지식(Knowledge) 관리
모델 핵심 사항
internal/types/knowledge.go. 주요 필드: type(manual 수동 Markdown / faq / 파일 유형), source / channel(수집 채널), parse_status, summary_status, enable_status, file_name/type/size/hash/path, storage_size, metadata(JSON, 수동 지식은 ManualKnowledgeMetadata{content, format, status(draft/publish), version} 저장), custom_metadata(JSON, 사용자가 입력한 메타데이터), last_faq_import_result.
custom_metadata는 사용자가 관리하는 부서, 보안 등급, 버전 번호 등의 설명 필드를 저장합니다. metadata는 처리 흐름의 내부 상태와 ID를 저장합니다. 사용자 지정 메타데이터는 최대 20개 항목이며 키는 1–64자입니다. 값은 문자열, 숫자, 불리언 또는 null을 지원하며 길이는 1000자를 넘을 수 없습니다. 변경 후 요약을 자동으로 갱신합니다.
구현에서 Knowledge.CustomMetadataText()는 키 순서대로 정렬하여 키: 값 텍스트를 생성하고 요약 생성과 문서 수준 모델 컨텍스트에 사용합니다. 이 필드는 마이그레이션 000078에서 도입되었습니다.
수집 채널 상수: web, api, browser_extension, wechat, wecom, feishu, dingtalk, slack, im, notion, yuque, rss.
파싱 상태 머신:
요약의 독립 상태: summary_status ∈ {none, pending, processing, completed, failed}.
지식 라우트
| 메서드 | 경로 | 설명 | 접근 제어 |
|---|---|---|---|
| POST | /knowledge-bases/:id/knowledge/file | 파일 업로드 | OwnedKBOrAdmin + KBAccessWrite |
| POST | /knowledge-bases/:id/knowledge/url | URL 가져오기 | 위와 동일 |
| POST | /knowledge-bases/:id/knowledge/manual | 수동 Markdown 지식 | 위와 동일 |
| GET | /knowledge-bases/:id/knowledge | 목록(페이지네이션 + 필터) | Viewer+ + KBAccessRead |
| DELETE | /knowledge-bases/:id/knowledge | KB 콘텐츠 비우기 | Admin + KBAccessWrite |
| GET | /knowledge/:id, /knowledge/batch | 상세 / 일괄 조회 | Viewer+ |
| GET | /knowledge/:id/stages, /knowledge/:id/spans | 처리 단계 / 스팬 | Viewer+ |
| PUT / DELETE | /knowledge/:id, /knowledge/manual/:id | 업데이트(custom_metadata 포함)/ 삭제 | OwnedKnowledgeKBOrAdmin + KBAccessWrite |
| POST | /knowledge/:id/reparse, /knowledge/:id/cancel-parse | 재파싱 / 파싱 취소 | 위와 동일 |
| POST | /knowledge/:id/regenerate-summary | 문서 요약 재생성 | 위와 동일 |
| GET | /knowledge/:id/download | 원본 파일 다운로드 | Contributor+ + KBAccessWrite |
| GET | /knowledge/:id/preview | 파일 미리 보기 | Viewer+ + KBAccessRead |
| PUT | /knowledge/tags | 태그 일괄 업데이트 | Contributor+ / ingest |
| POST | /knowledge/batch-reparse, /knowledge/batch-delete | 일괄 재파싱 / 삭제 | Contributor+ / ingest |
| POST | /knowledge/move | 지식 이동 | Contributor+ / ingest |
| GET | /knowledge/move/progress/:task_id | 이동 진행 상황 | Viewer+ |
목록 필터 매개변수
internal/types/knowledge.go의 KnowledgeListFilter + internal/handler/knowledge.go:
| 매개변수 | 설명 |
|---|---|
page / page_size | 페이지네이션(기본 정렬 updated_at DESC) |
keyword | 파일 이름 / 제목 검색 |
file_type | 파일 유형 필터(pdf / manual / url …) |
parse_status | 파싱 상태 필터 |
source | 수집 채널 필터(api / web / feishu …) |
tag_id | 태그 필터, 여러 개는 쉼표로 구분(OR 의미) |
updated_from / updated_to | 업데이트 시간 범위(RFC3339) |
folder_path | 폴더별 필터. 이 매개변수의 전달 여부가 목록 모드를 결정: 생략하면 전체 베이스의 평면 보기, 빈 문자열이면 지식 베이스 루트 디렉터리(하위 디렉터리 제외) |
folder_recursive | folder_path와 함께 사용하며, true이면 하위 디렉터리의 문서도 반환 |
폴더 트리
폴더는 프로젝트, 출처 또는 디렉터리 계층별로 문서를 정리하는 데 사용합니다. 업로드 시 디렉터리 구조 유지와 수집 후 이름 변경 및 이동을 지원합니다.
폴더 작업:
- 디렉터리 전체 업로드: 디렉터리 구조를 그대로 유지하므로 나중에 폴더를 수동으로 만들 필요가 없습니다;
- 폴더 생성 / 이름 변경 / 이동: 문서 목록 왼쪽의 폴더 트리에서 실행합니다. 이름 변경 시 하위 디렉터리 경로도 함께 바뀝니다. 대상 경로가 이미 있으면 두 폴더를 병합합니다. 폴더를 자신의 하위 디렉터리로 이동할 수는 없습니다;
- 문서 재분류: 문서를 선택한 뒤 지정 폴더로 이동합니다(루트 디렉터리로 돌아갈 수도 있음). 분류만 바뀌며 다시 파싱하지 않고 인덱스에도 영향을 주지 않습니다;
- 디렉터리별 탐색: 목록 API의
folder_path가 보기 모드를 결정합니다. 생략하면 전체 베이스의 평면 목록, 빈 문자열이면 루트 디렉터리(하위 디렉터리 제외),folder_recursive=true를 함께 사용하면 하위 디렉터리도 나열합니다.
폴더와 태그는 서로 다른 문제를 해결하며 함께 사용할 수 있습니다. 폴더는 단일 소속입니다(문서는 한 디렉터리에만 존재하며 프로젝트/출처별 보관에 적합). 태그는 다대다 관계입니다(문서당 여러 태그가 가능하며 주제, 보안 등급, 상태별 교차 필터링에 적합). 검색 시 둘 다 범위 제한 조건으로 사용할 수 있습니다.
디렉터리 경로는 knowledges.folder_path에 저장하고 file_name에는 파일 이름만 저장합니다. 마이그레이션 000079에서 기존 파일 이름으로부터 디렉터리 경로를 소급 채웠습니다.
폴더 API는 GET/PUT /knowledge-bases/:id/knowledge/folders와 POST /knowledge/folder입니다. 자세한 내용은 지식 베이스 API를 참고하세요.
태그(KnowledgeTag)
internal/types/tag.go + internal/handler/tag.go:
type KnowledgeTag struct {
ID string // UUID
SeqID int64 // 자동 증가 정수 ID(API에서 사용)
TenantID uint64
KnowledgeBaseID string
Name string // KB 내 고유
Color string
SortOrder int
}
type KnowledgeTagRelation struct { KnowledgeID, TagID string } // 다대다문서 하나에 여러 태그를 지정할 수 있습니다. 초기에는 단일 태그(knowledges.tag_id 열 하나)였으나 migration 000063에서 연결 테이블 knowledge_tag_relations로 전환했습니다. 테이블 생성 시 기존 단일 태그 데이터를 이전한 뒤 knowledges.tag_id 열을 삭제했습니다. 따라서 현재 동작은 다음과 같습니다.
- 읽기:
Knowledge.Tags는 조회 시knowledge_id기준으로 일괄 JOIN하여 가져옵니다(gorm:"-", knowledges 테이블에는 저장하지 않음); - 쓰기: 전체 교체 방식입니다.
PUT /knowledge/tags에{knowledge_id: [tag_ids]}를 전달하면 먼저 해당 문서의 모든 연결을 삭제하고 새 집합을 기록합니다; - 필터:
tag_ids는 OR 의미입니다(어느 태그든 일치하면 반환). SQL은knowledges.id IN (SELECT knowledge_id FROM knowledge_tag_relations WHERE tag_id IN (...))를 사용합니다; - FAQ 항목은 별도 체계입니다. 항목 자체가 chunk이며 태그는
chunks.tag_id에 저장합니다(단일 태그). 문서의 다중 태그 연결 테이블과는 다른 경로입니다.
태그 자체의 관리 라우트: GET /knowledge-bases/:id/tags(Viewer+), POST(OwnedKBOrAdmin), PUT/DELETE /knowledge-bases/:id/tags/:tag_id(OwnedKBOrAdmin). tag_id 경로 매개변수는 UUID와 정수 seq_id를 모두 허용합니다.
프런트엔드의 두 진입점:
- 일괄 태그 지정: 문서 목록에서 여러 문서를 선택한 뒤 일괄 작업 표시줄의 「태그」 버튼으로
BatchTagDialog.vue를 엽니다. 대화상자는 선택한 문서들의 공통 태그를 미리 선택하며, 검색과 태그 관리로 바로 이동을 지원합니다. 제출 후 목록을 새로고침합니다; - 업로드 시 태그 설정: 업로드 확인 대화상자(
UploadConfirmDialog.vue)에서 파일 수집 전에 태그와 파싱 옵션을 직접 지정할 수 있어 업로드 후 다시 수정할 필요가 없습니다.
청크 편집과 버전 기록
문서 상세에서 청크 본문을 편집하여 OCR, 표 또는 수식의 파싱 오류를 수정할 수 있습니다. 저장 후 인덱스를 재생성하며 조회와 롤백을 위해 이전 버전을 보존합니다.
구현(internal/application/service/chunk.go, migration 000078):
데이터 모델:
| 필드 / 테이블 | 용도 |
|---|---|
chunks.source_content | 파서 원본 출력, 불변. 기존 행은 최초 수동 편집 시 content에서 지연 방식으로 채움 |
chunks.content | 현재 적용되는 콘텐츠(검색과 인용 표시 모두 사용) |
chunks.content_revision | 편집 또는 롤백마다 +1, 낙관적 잠금에 사용 |
chunks.index_status | ready / processing / failed, 현재 콘텐츠가 검색 스토리지에 반영되었는지 표시 |
chunks.last_editor_id | 현재 버전을 만든 작업자 |
chunk_revisions 테이블 | 덮어쓴 이전 버전 스냅샷(콘텐츠, 활성화 상태, 편집자, 출처, 시간) |
동작 핵심 사항:
text유형 청크만 편집할 수 있습니다. 공백 제거 후 콘텐츠가 비어 있으면 안 되며 상한은 200000바이트입니다;- 낙관적 동시성: 요청에
expected_revision을 포함할 수 있습니다. 현재 버전과 다르면 409를 반환하며 프런트엔드는 새로고침 후 재시도를 안내합니다; - 이미지 추가 불가: 원본 콘텐츠에 없던 이미지 URL이 편집 콘텐츠에 있으면 거부합니다. 특정 이미지의 Markdown 참조를 삭제하면 해당 OCR / caption 하위 청크는 영구 삭제하지 않고 비활성화합니다. 따라서 이전 버전으로 롤백하면 다시 활성화할 수 있습니다;
- 부모·자식 청크 일관성: 자식 청크 편집 후 오프셋에 따라 변경 사항을 부모 청크에 반영합니다(부모의
source_content는 불변으로 유지. 교체는 역순으로 적용하여 길이가 바뀌어도 좌표 체계가 어긋나지 않음); - 인덱스 실패 처리: 인덱스 재생성에 실패해도 행은 정상 저장하지만
index_status = failed로 설정하고 UI에서 이를 안내합니다. 같은 콘텐츠를 다시 제출하면 재시도합니다; - 생성된 질문 유지: 콘텐츠를 편집해도 기존 검색 질문은 유지하며 「현재 본문 버전과 일치하지 않음」으로 표시만 합니다. 개별 수정(
PUT /chunks/by-id/:id/questions)또는 전체 재생성(POST /chunks/by-id/:id/questions/regenerate)이 가능합니다; - 요약 연동: 콘텐츠 또는 활성화 상태가 바뀌면 문서 요약 갱신을 큐에 등록하고
summary_status를pending으로 변경합니다.POST /knowledge/:id/regenerate-summary로 수동 트리거할 수도 있습니다.
롤백(POST /chunks/:knowledge_id/:id/revert)자체도 새로운 편집입니다. 대상 이전 버전의 콘텐츠를 현재 콘텐츠로 기록하고 버전 번호는 계속 증가하며, 원래 콘텐츠는 기록 목록에 들어갑니다. 따라서 「롤백의 롤백」도 가능합니다.
API 목록은 API 참고: 청크와 태그를 확인하세요.
요약 수동 편집과 청크 탐색
문서 콘텐츠 미리 보기에서 요약을 편집하고 저장하여 자동 요약을 수정할 수 있습니다. PUT /knowledge/:id에서 description을 생략하면 기존 요약을 유지하고, 명시적인 빈 문자열이면 지웁니다. 요약 업데이트는 원본 문서 콘텐츠 수정과 같지 않습니다. 다시 생성하려면 「요약 다시 생성」을 사용합니다. 콘텐츠/메타데이터 변경으로도 요약 갱신이 트리거될 수 있습니다.
문서 청크는 페이지 단위로 로드하며 문서 전환과 검색 결과 이동 시 페이지 상태를 갱신합니다. 전체 필드는 지식 API와 청크 API를 참고하세요.
다운로드와 미리 보기 보안
GET /knowledge/:id/preview의 보안 메커니즘은 internal/handler/knowledge_preview_security_test.go로 검증하여 보장합니다.
| 제어 | 구현 | 목적 |
|---|---|---|
Content-Type: application/octet-stream 강제 | 응답 헤더 고정 | 브라우저가 HTML/SVG를 페이지로 실행하지 못하게 함(저장형 XSS 방지) |
X-Content-Type-Options: nosniff | 응답 헤더 | MIME 스니핑 우회 방지 |
Content-Disposition: attachment; filename=... | 응답 헤더 | 인라인 렌더링 대신 다운로드 강제 |
| 경로 검증 | ValidateKBScopedStoragePath() | 파일 경로가 해당 KB의 허가된 스토리지 범위 내에 있어야 함(경로 순회 / 무단 읽기 방지) |
| 크기 제한 | GetFile 응답 본문 제한 | 초대형 파일로 인한 미리 보기 장애 방지 |
테스트는 파일 콘텐츠가 <script>alert(1)</script>여도 바이너리 첨부 파일로만 전송됨을 명시적으로 검증합니다. 다운로드 엔드포인트(/knowledge/:id/download)는 더 높은 Contributor+ 권한이 필요하며 KBAccessWrite 접근 제어를 거칩니다.
지식 베이스 복사와 지식 이동
복사(Copy / Duplicate)와 Preflight
internal/application/service/knowledge_clone_move.go. preflight 규칙은 internal/handler/knowledgebase_copy_preflight_test.go로 보장합니다.
POST /knowledge-bases/copy: 전체 베이스 복사(설정 + 콘텐츠). body에source_id를 전달합니다. 비동기 작업이며 진행 상황은GET /knowledge-bases/copy/progress/:task_id로 조회합니다(활동 스트림에kb.clone_started/kb.clone_completed/kb.clone_failed기록).POST /knowledge-bases/:id/duplicate: 설정만 복사합니다(콘텐츠 / 인덱스 / 공유 기록 제외). 활동 스트림에kb.duplicated를 기록합니다.
Preflight(복사 전 검증, 즉시 동기적으로 거부):
- 원본 / 대상 KB의 테넌트 격리(테넌트 간 요청 거부);
- 원본 KB 존재 여부;
- VectorStore 호환성:
reuse_vectors모드는 서로 다른 벡터 저장소에 있는 KB를 지원하지 않습니다(벡터를 직접 옮길 수 없음); - StorageBackend 호환성: 서로 다른 스토리지 백엔드 간 복사는 지원하지 않습니다;
- API Key로 호출할 때는 원본 / 대상 KB가 모두 allow-list에 있어야 합니다.
지식 이동 접근 제어(move gate)
POST /knowledge/move는 두 모드를 지원하며 제약 조건을 handler와 service 두 계층에서 검증합니다(internal/handler/knowledge_move_gate_test.go와 internal/application/service/knowledge_move_gate_test.go에서 이중 확인).
reuse_vectors모드: 기존 벡터를 직접 재사용하며 원본 KB와 대상 KB가 같은 VectorStore에 연결되어야 합니다;reparse모드: 대상 베이스에서 다시 파싱하여 벡터를 생성하므로 벡터 저장소 간 이동을 허용합니다.
같은 저장소인지 판정하는 SharesStoreWith()의 정규화 의미(빈 문자열은 nil로 정규화하며 nil은 환경 기본 store를 의미):
nil & nil → true (둘 다 env-store)
"" & nil → true (빈 문자열을 nil로 정규화)
"store-a" & "store-a" → true
"store-a" & "store-b" → false
"store-a" & nil → false (명시적 연결과 env-store는 같은 저장소로 보지 않음)GET /knowledge-bases/:id/move-targets는 접근 제어 조건을 충족하는 대상 베이스 후보를 반환합니다. 이동은 비동기 작업이며 진행 상황은 GET /knowledge/move/progress/:task_id로 조회합니다.
스토리지 할당량과 사용량
할당량은 테넌트에 속합니다(internal/types/tenant.go).
| 필드 | 기본값 | 설명 |
|---|---|---|
storage_quota | 10737418240(10GB) | 테넌트 전체 할당량 |
storage_used | 0 | 사용량(원본 파일, 텍스트, 벡터와 인덱스 점유량 포함) |
KB 생성과 지식 업로드 전에 모두 할당량을 확인하며(internal/handler/knowledgebase.go 생성 검증 흐름), 초과하면 쓰기를 거부합니다. 각 지식은 자신의 file_size와 storage_size를 기록하고 삭제 시 사용량을 회수합니다.
KB 라우트와 권한
(접근 제어 의미는 「테넌트, 사용자와 인증·인가」 문서를 참고하세요. KBAccessRead/Write는 조직 공유 경로를 해석합니다.)
| 메서드 | 경로 | Handler | 접근 제어 |
|---|---|---|---|
| POST | /knowledge-bases | CreateKnowledgeBase | Contributor+ / API Key manage_kbs |
| GET | /knowledge-bases | ListKnowledgeBases | Viewer+ / retrieve |
| GET | /knowledge-bases/:id | GetKnowledgeBase | Viewer+ + KBAccessRead |
| PUT | /knowledge-bases/:id | UpdateKnowledgeBase | OwnedKBOrAdmin + KBAccessWrite |
| DELETE | /knowledge-bases/:id | DeleteKnowledgeBase | OwnedKBOrAdmin + KBAccessWrite |
| PUT | /knowledge-bases/:id/pin | TogglePinKnowledgeBase | Viewer+ + KBAccessRead |
| POST/GET | /knowledge-bases/:id/hybrid-search | HybridSearch | Viewer+ + KBAccessRead |
| POST | /knowledge-bases/copy | CopyKnowledgeBase | Contributor+ / manage_kbs |
| POST | /knowledge-bases/:id/duplicate | DuplicateKnowledgeBase | Contributor+ / manage_kbs + KBAccessRead |
| GET | /knowledge-bases/copy/progress/:task_id | GetKBCloneProgress | Viewer+ / retrieve 또는 manage_kbs |
| GET | /knowledge-bases/:id/move-targets | ListMoveTargets | Viewer+ + KBAccessRead |
| GET | /knowledge-bases/:id/activity | ListKnowledgeBaseActivity | OwnedKBOrAdmin + KBAccessRead(JWT 전용) |
생성 흐름(internal/handler/knowledgebase.go): Contributor 검증 → 테넌트 스토리지 할당량 확인 → EmbeddingModelID 검증 → VectorStoreID 연결 검증 → 생성 → KB + vector_store_display 반환.
연쇄 삭제: KB 아래의 모든 Knowledge → Chunk → 벡터 인덱스 → 키워드 인덱스 → Wiki 페이지 → 태그 → 저장 파일 삭제 → KB 자체 소프트 삭제. 공유 측 editor는 원본 KB를 삭제할 수 없습니다(삭제에는 owner 테넌트와 Admin 측 권한 필요).
하이브리드 검색(Hybrid Search)
POST /knowledge-bases/:id/hybrid-search(internal/handler/knowledgebase.go + internal/application/service/knowledgebase_search*.go)는 KB의 IndexingStrategy에 따라 후보 검색을 조합합니다. 벡터(vector_enabled)+ 키워드 BM25(keyword_enabled)를 rank fusion으로 융합하고 리랭킹(rerank)하며, 지식 그래프 보강(graph_enabled)을 추가할 수 있습니다. 다중 KB에서는 knowledgebase_search_fanout.go가 동시 분산 실행하고 knowledgebase_search_fusion.go가 융합합니다. 공유 KB 검색 경로는 knowledgebase_search_shared.go를 참고하세요. FAQ 베이스 검색에는 별도의 매칭 전략(부정 예시 필터링 / 반복 후보 검색)이 있습니다. FAQ 문서를 참고하세요.
지식 처리 파이프라인
internal/application/service/knowledge_create.go / knowledge_process.go / knowledge_process_config.go:
업로드 (file/url/manual)
→ Knowledge 생성 (parse_status=pending) → Asynq 큐 등록
→ Worker: DocReader 파싱 → 청크 분할 (ChunkingConfig)
→ 벡터 임베딩 (indexing_strategy.vector_enabled)
→ 키워드 인덱스 (keyword_enabled)
→ 그래프 추출 (graph_enabled + ExtractConfig)
→ Wiki 생성 (wiki_enabled + WikiConfig)
→ 질문 생성 (QuestionGenerationConfig.enabled)
→ parse_status=finalizing, pending_subtasks_count=N
→ 보강 하위 작업마다 완료 후 원자적으로 감소; 0 도달 → parse_status=completed설정 병합 우선순위(EffectiveProcessConfig): Knowledge.ProcessOverrides(단일 업로드 재정의. 지식 metadata의 KnowledgeProcessOverrides에 저장하며 parser 규칙 / 청크 / VLM / ASR / 질문 생성 / 그래프 스위치 등을 재정의 가능)> KB 설정 > 테넌트 기본값.
Chunk 유형(internal/types/chunk.go): text, parent_text, image_ocr, image_caption, summary, entity, relationship, faq, web_search, table_summary, table_column, wiki_page. chunk는 is_enabled 스위치와 flags 비트 플래그(bit0 = 추천 가능)를 지원합니다.
지식 베이스 활동 스트림(KB Activity)
지식 베이스 설정의 「활동」 탭은 설정 변경, 문서 업로드와 삭제, 청크 편집, 공유 변경과 Wiki 업데이트를 기록하며 작업자, 시간과 결과를 포함합니다.
internal/application/service/kb_activity.go는 감사 로그 체계(AuditLog, scope는 knowledge_base)를 재사용하며 recordKBActivity(ctx, audit, tenantID, kbID, action, targetType, targetID, outcome, details)로 기록합니다.
- 활동 동작(
internal/types/audit_log.go):kb.created/kb.updated/kb.deleted/kb.duplicated/kb.clone_started/kb.clone_completed/kb.clone_failed,kb.share_added/kb.share_permission_changed/kb.share_removed와 지식 / chunk 수준의 추가·삭제·수정 동작; - 트리거 출처: context의
kbActivityTaskMetadata{TaskID, Trigger}(user사용자 작업 /system백그라운드 작업)를 details에 자동 병합합니다. outcome에 따라processing_status를 자동 보완합니다(accepted→pending, success→completed, partial→partial, failed/denied→failed, canceled→canceled); - 일괄 작업의 표본 제목:
kbActivityAppendSampleTitles는 일괄 작업에 중복 제거된 제목을 최대 5개 포함합니다(첫 번째는title, 나머지는titles배열). 활동 스트림의 가독성을 유지하고 크기를 제한합니다; - 억제 메커니즘:
withKBActivitySuppressed(ctx)를 사용하면 내부 연쇄 작업에서 중복 활동 기록을 생성하지 않습니다.
조회 엔드포인트: GET /knowledge-bases/:id/activity(OwnedKBOrAdmin, JWT 사용자 전용, API Key 접근 불가).
구현 참고
아래 경로는 모두 저장소 루트 디렉터리 기준입니다.
| 계층 | 파일 |
|---|---|
| KB 모델과 설정 구조 | internal/types/knowledgebase.go, indexing_strategy.go |
| 지식 / Chunk / 태그 모델 | internal/types/knowledge.go, chunk.go, tag.go |
| 처리 설정 재정의 | internal/types/knowledge_process.go |
| KB Handler | internal/handler/knowledgebase.go |
| 지식 Handler | internal/handler/knowledge.go |
| 태그 Handler | internal/handler/tag.go |
| KB 서비스 | internal/application/service/knowledgebase.go |
| 지식 생성 / 처리 파이프라인 | internal/application/service/knowledge_create.go, knowledge_process.go, knowledge_process_config.go |
| 복사와 이동 | internal/application/service/knowledge_clone_move.go |
| 활동 스트림 | internal/application/service/kb_activity.go |
| 라우트와 접근 제어 | internal/router/router.go, internal/router/rbac.go |
| 주요 검증 테스트 | internal/handler/knowledge_preview_security_test.go, knowledge_move_gate_test.go, knowledgebase_copy_preflight_test.go |





