FluxFeed 0.8.0
See the version list below for details.
dotnet add package FluxFeed --version 0.8.0
NuGet\Install-Package FluxFeed -Version 0.8.0
<PackageReference Include="FluxFeed" Version="0.8.0" />
<PackageVersion Include="FluxFeed" Version="0.8.0" />
<PackageReference Include="FluxFeed" />
paket add FluxFeed --version 0.8.0
#r "nuget: FluxFeed, 0.8.0"
#:package FluxFeed@0.8.0
#addin nuget:?package=FluxFeed&version=0.8.0
#tool nuget:?package=FluxFeed&version=0.8.0
FluxFeed
문서 파이프라인 표면(④b) — 수집·파싱·정제를 묶어 FluxIndex(④a)에 적재(feed)한다. FluxIndex에 비대칭 의존(④b는 ④a 필요, ④a는 ④b 불필요).
Quick Start
// 파일-소스 vault: FileFlux 추출/청킹 + FluxIndex 적재
services.AddFileVaultFactoryWithFluxIndex(o => o.VaultBasePath = "./data");
File selection patterns
FileVaultOptions.DefaultIncludePatterns / DefaultExcludePatterns는 discovery 경로에만 실효한다:
| 경로 | 패턴 적용 |
|---|---|
ScanFolderAsync / SyncAsync |
✅ 패턴 밖 파일은 감지·큐잉 전에 skip |
| 폴더 워처 이벤트 | ✅ (폴더별 패턴이 기본값보다 우선) |
명시적 MemorizeAsync / RefreshAsync |
❌ 의도적 미적용 — 명시 호출은 명시 의도이며, 조용히 skip하면 호출자 오류가 숨는다 |
exclude가 include보다 우선하며, include가 빈 리스트면 "전부 포함"이다.
Extraction diagnostics
추출기가 보고한 구조화 진단은 VaultEntry에 그대로 실려 meta.json에 영속된다. 스캔 PDF처럼 정당한 0청크가 "조용한 성공"으로 보이지 않게 하는 것이 목적이다.
var entry = await vault.MemorizeAsync(path, waitForCompletion: true); // Stage=Memorized, ChunkCount=0
if (entry.ExtractionHints?.TryGetValue("extraction_failure_reason", out var reason) == true)
{
// reason: "no_text_layer" (이미지-only/스캔 문서) | "blank_page" (빈 문서)
// entry.ExtractionWarnings: 사람이 읽는 설명 (예: "... requires OCR")
}
- 불투명 패스스루 — 키/값은 추출기(FileFlux
RawContent.Hints/Warnings) 어휘 그대로다. FluxFeed는 해석하지 않는다. - 스칼라만 영속 — 값이 문자열·불리언·수치·날짜류인 힌트만 저장한다. 리더 내부 구조값(예:
PageRanges)은 타입명으로 문자열화되어meta.json을 오염시키므로 제외한다. 키가 아니라 값 타입 기준이라 FileFlux가 힌트를 추가해도 드리프트가 없다. - 항상 최신 추출분 — 재추출 시 교체되고, 진단 없이 추출되면 이전 값은 지워진다. 예외 경로 전용인
LastError와는 별개 채널이다. - FileFlux 0.14.0+ 필요 (
no_text_layer/blank_page세분 라벨의 출처).
Failure diagnostics
실패 사유는 두 필드로 나뉜다. LastError는 마지막 실패, FirstError는 그 실패 에피소드를 시작한 실패다.
if (entry.FirstError is not null)
{
// FirstError: 최초 원인 (추출기 분류가 실려 있는 쪽)
// LastError: 가장 최근 실패 — 재시도가 다른 이유로 실패했다면 다르다
}
- 재시도가 자기 이유로 실패하면
LastError는 덮이지만FirstError는 남는다. 최초 실패가 추출기의 진단을 싣고 있으므로, 그것이 지워지면 원본 파일 없이 진단할 방법이 사라진다. FirstError는LastError와 같은 생애를 갖는다 — 처리 단계가 진행되거나(Extracted/Refined/Memorized)ResetToSource()하면 둘 다 지워진다. 반대로 sync 상태 전이는 어느 쪽도 지우지 않는다(MarkInSync포함). 따라서FirstError != null을 "지금 고장난 엔트리"로 읽지 말 것 — 그 판정은Stage/SyncStatus로 한다.- 이전 버전이 쓴
meta.json은LastError를FirstError로 승계한다(한 번만 실패한 엔트리에서는 같은 값). ChangeDetectionResult에도 같은 두 필드가 실린다.
엔트리 레이아웃
엔트리 디렉터리에는 작업 산출물(레코드·추출 텍스트·이미지)이 들어가고, git이 추적하는 저장소는
그 아래 vault/ 하나다. 작업 산출물은 저장소 바깥이라 무시 규칙의 대상이 아니며, 따라서 엔트리
수준에 ignore 파일을 두지 않는다 — 저장소 바깥의 ignore 파일은 git이 읽지 않는다.
0.8.0 breaking — 위 이유로 효과가 없던
VaultEntry.GitignorePath와IVaultStorageService.CreateGitignoreAsync가 제거됐다. 대체 API는 없다(생성하던 파일 자체가 무의미했다). 호출부가 있으면 지우면 된다.
Damaged records
엔트리 레코드(meta.json)는 임시 파일에 쓴 뒤 제자리 교체된다. 동시 writer가 있어도 어느 레코드가
이길지만 정해지고 둘이 섞이지 않으며, 중단된 쓰기가 반쪽 레코드를 남기지 않는다.
읽을 수 없는 레코드는 없는 레코드와 구분된다.
// 없음 → null. 존재하지만 읽을 수 없음 → VaultRecordUnreadableException
var entry = VaultEntry.LoadByHash(hash, vaultBasePath);
// 목록에서 빠진 레코드를 복구 대상으로 노출한다
IReadOnlyList<string> damaged = await vault.ListUnreadableAsync();
ListAsync()는 읽을 수 없는 레코드를 건너뛰되 경고 로그를 남긴다. 그 엔트리를 화면에 표시하거나 복구를 제안하려면ListUnreadableAsync()가 돌려주는 엔트리 디렉터리 경로를 쓴다.- 두 목록은 같은 신호를 기준으로 나뉜다 — 엔트리는 정확히 한쪽에만 나타난다. 따라서
ListAsync().Count + ListUnreadableAsync().Count가 전체 엔트리 수다. 그 밖의 IO 오류는 삼켜지지 않고 전파된다(목록이 조용히 짧아지는 것이 바로 이 보고 기능이 없애려는 실패다). - 제자리 교체는 나가는 레코드를 스크래치 이름으로 옆에 둔 채 바꾼다. 그 스크래치 파일을 플랫폼이 치우지 못하면(읽는 쪽이 레코드를 붙들고 있으면 충분히 발생한다) 엔트리 디렉터리에 남으므로, 다음 쓰기가 치운다 — 단 진행 중인 교체가 되돌아갈 대상을 지우지 않도록 충분히 오래된 것만. 따라서 방금 끝난 동시 쓰기 직후에는 잠깐 보일 수 있고, 무한히 쌓이지는 않는다.
- memorize/refresh처럼 레코드를 어차피 다시 쓰는 경로는 읽을 수 없는 레코드를 보고한 뒤 새로 만든다. 실패시키면 그 엔트리가 영구히 묶이기 때문이다. 단, 재생성된 레코드는 이력이 비어 있다.
Refresh 전제
refresh는 refined 콘텐츠를 재인덱싱하며 재추출하지 않는다. 따라서 전제는 refined 콘텐츠의 존재이고,
ProcessingStage는 그것을 함의하지 않는다 — 인덱싱할 내용이 없던 memorize는 refine 단계를 건너뛰므로
Memorized인데 refined가 없는 엔트리가 정상적으로 생기고, Error는 어떤 산출물이 남았는지 말해주지 않는다.
RefreshAsync는 refined 콘텐츠가 없으면 거부한다(메시지가memorize를 지시한다). 이 전제는 가드와 파이프라인이 같은 값을 쓴다.DetectChangesAsync는 refresh가 성공할 수 없는 엔트리에Refresh를 추천하지 않고Memorize로 낮춘다. memorize는 재추출하므로 실패했거나 빈 엔트리가 스스로 회복할 수 있다.
Image enrichment
문서에서 추출된 이미지는 파이프라인이 vault에 저장한다. 소비앱이 설명 생성기만 등록하면 그 설명이 인덱싱까지 이어진다 — 호출 시점·멱등·재시도·본문 반영·출처 노출은 파이프라인이 소유한다.
public sealed class VisionEnricher : IVaultImageEnricher
{
public async Task<string?> DescribeAsync(VaultImageDescriptionRequest request, CancellationToken ct)
=> await _vision.CaptionAsync(request.Image.FilePath, request.DocumentText, ct);
// null 반환 = 이번엔 실패 → 파이프라인이 다음 실행에 재시도
}
services.AddSingleton<IVaultImageEnricher, VisionEnricher>();
- 미등록 시 종전과 동일 — 이미지는 저장되지만 설명되지 않는다 (하위 호환).
- 멱등 — 설명은 이미지 단위로 영속된다. 재-memorize 시 이미 설명된 이미지는 생성기를 재호출하지 않는다(이미지가 바이트 동일한 한). 실패한 이미지만 다음 실행에서 재시도되며, 한 이미지의 실패가 다른 이미지나 memorize 자체를 중단시키지 않는다.
- 출처는 메타데이터로 — 설명은 전용 청크로 인덱싱되고
chunk_kind="image_description"·image_id·image_file메타데이터를 갖는다. 본문에 마커를 심지 않으므로 사용자에게 보여줄 때 걷어낼 것도 없다. - 이미지-only 문서 — 텍스트 레이어가 없는 스캔·도표 문서는 종전에 0청크로 끝났으나, 설명이 있으면 그 설명이 곧 내용으로 인덱싱된다. (텍스트도 없고 설명도 없으면 종전대로 0청크.)
request.DocumentText는 원문서 추출 텍스트이며, 텍스트 레이어가 없으면 null이다.
Keyword index (hybrid search)
파이프라인은 벡터 스토어·GraphRAG와 같은 지점에서 청크를 인덱싱한다. DI 컨테이너에 IKeywordSearchService가
등록되어 있으면(FluxIndex SDK가 기본으로 등록하는 in-memory BM25 폴백이든, PostgreSQL/SQLite 같은 영속
백엔드든) 같은 청크가 키워드 인덱스에도 적재되어 하이브리드 검색의 세 번째 다리가 채워진다 — FluxIndex의
자체 Indexer 경로가 아니라 이 ingestion 파이프라인으로 적재하는 구성에서는, 이 배선 없이는 키워드
인덱스가 항상 비어 있다(벡터 단독 검색과 사실상 동일).
- 미등록 시 종전과 동일 — 벡터·GraphRAG 인덱싱만 수행된다 (하위 호환).
- GraphRAG과 달리 옵션 게이트가 없다 — 등록 자체가 신호다. 서비스가 있으면 항상 인덱싱하고, 없으면 항상 스킵한다(벡터 스토어 적재와 같은 규약).
- 제거도 대칭 —
RemoveAsync는 등록된 모든 백엔드(벡터 스토어·키워드 인덱스)에서 문서를 지운다. VaultPipeline.SupportsKeywordIndex로 배선 여부를 확인할 수 있다.
상세 표면·경계는 CHARTER.md 참조.
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net10.0 is compatible. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
-
net10.0
- FileFlux (>= 0.16.0)
- FluxIndex.Core (>= 0.17.0)
- Microsoft.Data.Sqlite (>= 10.0.8)
- Microsoft.Extensions.Hosting.Abstractions (>= 10.0.8)
- Microsoft.Extensions.Options (>= 10.0.8)
- SQLitePCLRaw.bundle_e_sqlite3 (>= 2.1.12)
NuGet packages (1)
Showing the top 1 NuGet packages that depend on FluxFeed:
| Package | Downloads |
|---|---|
|
IronHive.Flux.Rag
RAG tools for IronHive using FluxIndex capabilities |
GitHub repositories
This package is not used by any popular GitHub repositories.
| Version | Downloads | Last Updated |
|---|---|---|
| 0.13.0 | 44 | 8/11/2026 |
| 0.12.0 | 88 | 8/6/2026 |
| 0.11.0 | 86 | 8/6/2026 |
| 0.10.0 | 91 | 8/6/2026 |
| 0.8.0 | 236 | 8/1/2026 |
| 0.6.1 | 116 | 7/31/2026 |
| 0.6.0 | 103 | 7/30/2026 |
| 0.5.0 | 98 | 7/30/2026 |
| 0.4.0 | 144 | 7/24/2026 |
| 0.3.0 | 97 | 7/24/2026 |
| 0.2.2 | 103 | 7/19/2026 |
| 0.2.1 | 130 | 7/7/2026 |
| 0.2.0 | 117 | 7/3/2026 |
| 0.1.0 | 137 | 7/2/2026 |