顯示具有 LLama AI 標籤的文章。 顯示所有文章
顯示具有 LLama AI 標籤的文章。 顯示所有文章

2025年9月8日 星期一

shipcap_skeleton_paddleqr.zip

 已完成打包與擴充。下載:shipcap_skeleton_paddleqr.zip。內容含:

  • PaddleOCR worker(apps/ocr_worker/worker_paddleocr.py)。

  • Tesseract 版 worker。

  • USB HID 鍵盤模式掃碼(listener_hid.py,evdev)。

  • USB Serial 掃碼(listener_serial.py,pyserial)。

  • FastAPI 後端、Web 最小頁、Capture、systemd 範例與需求檔。對應規格之 FR/NFR、流程與 API。

最小測試:

# 啟動後端 cd shipcap3/apps/ingest_api && uvicorn main:app --host 0.0.0.0 --port 8000 # 建單與拍照(另開視窗) python shipcap3/apps/capture/capture.py SHP0001 image1 python shipcap3/apps/capture/capture.py SHP0001 image2 # 跑 PaddleOCR python shipcap3/apps/ocr_worker/worker_paddleocr.py SHP0001 /mnt/data/shipcap3/data/shipments/$(date +%Y)/$(date +%m)/$(date +%d)/SHP0001_image1_*.jpg # 掃碼(HID 鍵盤模式,指定裝置與單號) sudo -E python shipcap3/apps/qrcode_listener/listener_hid.py /dev/input/eventX SHP0001 # 或 Serial python shipcap3/apps/qrcode_listener/listener_serial.py /dev/ttyACM0 115200 SHP0001

需要我再加 Dockerfile、udev 規則與 docker-compose 一鍵啟動。 

出軟體建制的架構 跟 範例

 結論:採「多服務(同機)」架構,對應你給的 FR/NFR 與資料模型,

提供可直接啟動的專案骨架、API、DB schema、Docker Compose、systemd 與最小可用範例程式。

一、架構(對應規格)

  • 服務:capture(拍照1/2)、qrcode(USB HID/Serial)、ocringest-api(建檔/查詢/匯出)、web-ui(覆核/查詢)、sync(選配,多站同步)、backup

  • 資料層:SQLite 單站;要集中改用 PostgreSQL。影像按日期樹狀存,計算 SHA-256。

  • 目標流程:輸入出貨單號→拍照1→OCR→覆核→拍照2→掃 QR→建檔→可查詢/匯出。

  • 命名與路徑:/data/shipments/{YYYY}/{MM}/{DD}/SHP123_image1_20250115T103045Z.jpg;縮圖保存於 thumbs/

  • 權限與稽核:角色、登入、AuditLogs。

  • KPI:≥6–8 筆/分、OCR 成功門檻與人工覆核機制。

二、專案目錄(Mono-repo)

shipcap/ apps/ ingest_api/ # FastAPI (DB/檔案/匯出) web_ui/ # 覆核/查詢頁(FastAPI+Jinja2 或 Qt 選一) capture/ # OpenCV 拍照1/2 + 縮圖 + SHA256 ocr_worker/ # Tesseract/PaddleOCR + 版面模板 qrcode_listener/ # HID/Serial 讀碼並關聯當前作業 sync_agent/ # 選配:上傳中央 DB/NAS libs/ db/ # SQLAlchemy models, DAL core/ # 共用:config、paths、hash、schemas deploy/ docker-compose.yml systemd/ capture.service ocr.service ingest-api.service web-ui.service migrations/ tests/ .env.example config.yaml README.md

三、資料庫 Schema(SQLite / PostgreSQL)

-- Shipments CREATE TABLE IF NOT EXISTS shipments( id INTEGER PRIMARY KEY, ship_no TEXT UNIQUE NOT NULL, customer TEXT, ship_date DATE, operator TEXT, created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ); -- Images CREATE TABLE IF NOT EXISTS images( id INTEGER PRIMARY KEY, shipment_id INTEGER NOT NULL REFERENCES shipments(id), kind TEXT CHECK(kind IN ('image1','image2')) NOT NULL, path TEXT NOT NULL, width INT, height INT, size_bytes INT, sha256 TEXT, taken_at TIMESTAMP ); -- QRCodes CREATE TABLE IF NOT EXISTS qrcodes( id INTEGER PRIMARY KEY, shipment_id INTEGER NOT NULL REFERENCES shipments(id), payload TEXT NOT NULL, symbology TEXT, raw_text TEXT, scanned_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ); -- OCR tables CREATE TABLE IF NOT EXISTS ocr_tables( id INTEGER PRIMARY KEY, shipment_id INTEGER NOT NULL REFERENCES shipments(id), json_data TEXT NOT NULL, version TEXT, ocr_engine TEXT, confidence_avg REAL, reviewed_by TEXT, reviewed_at TIMESTAMP ); -- AuditLogs CREATE TABLE IF NOT EXISTS audit_logs( id INTEGER PRIMARY KEY, user TEXT, action TEXT, subject TEXT, payload_json TEXT, created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP );

(欄位對應規格之資料模型與稽核)

四、API(FastAPI 最小集合)

# apps/ingest_api/main.py from fastapi import FastAPI, UploadFile, File, Form, HTTPException from fastapi.responses import StreamingResponse from pathlib import Path import hashlib, time, io, zipfile, sqlite3, json, os app = FastAPI(title="shipcap-ingest") DB = os.getenv("DB_PATH", "/data/shipcap.db") ROOT = Path(os.getenv("DATA_ROOT", "/data/shipments")) def db(): conn = sqlite3.connect(DB); conn.row_factory = sqlite3.Row return conn @app.post("/api/shipments") def create_shipment(ship_no: str = Form(...), customer: str = Form(""), ship_date: str = Form(""), operator: str = Form("")): with db() as conn: conn.execute("INSERT OR IGNORE INTO shipments(ship_no,customer,ship_date,operator) VALUES(?,?,?,?)", (ship_no, customer, ship_date, operator)) s = conn.execute("SELECT * FROM shipments WHERE ship_no=?", (ship_no,)).fetchone() return dict(s) @app.post("/api/shipments/{ship_no}/images") def upload_image(ship_no: str, kind: str = Form(...), file: UploadFile = File(...)): assert kind in ("image1","image2") ts = time.strftime("%Y%m%dT%H%M%SZ", time.gmtime()) subdir = ROOT / time.strftime("%Y/%m/%d") subdir.mkdir(parents=True, exist_ok=True) fn = f"{ship_no}_{kind}_{ts}.jpg" data = file.file.read() p = subdir / fn p.write_bytes(data) sha256 = hashlib.sha256(data).hexdigest() with db() as conn: s = conn.execute("SELECT id FROM shipments WHERE ship_no=?", (ship_no,)).fetchone() if not s: raise HTTPException(404, "shipment not found") conn.execute("""INSERT INTO images(shipment_id,kind,path,size_bytes,sha256,taken_at) VALUES(?,?,?,?,?,datetime('now'))""", (s["id"], kind, str(p), len(data), sha256)) return {"path": str(p), "sha256": sha256} @app.post("/api/shipments/{ship_no}/ocr") def post_ocr(ship_no: str, json_data: str = Form(...), engine: str = Form("tesseract"), conf: float = Form(0.0)): with db() as conn: s = conn.execute("SELECT id FROM shipments WHERE ship_no=?", (ship_no,)).fetchone() if not s: raise HTTPException(404, "shipment not found") conn.execute("""INSERT INTO ocr_tables(shipment_id,json_data,ocr_engine,confidence_avg) VALUES(?,?,?,?)""", (s["id"], json_data, engine, conf)) return {"ok": True} @app.post("/api/shipments/{ship_no}/qrcode") def add_qr(ship_no: str, payload: str = Form(...), symbology: str = Form("QR"), raw_text: str = Form("")): with db() as conn: s = conn.execute("SELECT id FROM shipments WHERE ship_no=?", (ship_no,)).fetchone() if not s: raise HTTPException(404, "shipment not found") conn.execute("""INSERT INTO qrcodes(shipment_id,payload,symbology,raw_text) VALUES(?,?,?,?)""", (s["id"], payload, symbology, raw_text)) return {"ok": True} @app.get("/api/shipments") def list_shipments(q: str = "", ship_no: str = "", start: str = "", end: str = ""): sql = "SELECT * FROM shipments WHERE 1=1"; args=[] if ship_no: sql+=" AND ship_no=?"; args.append(ship_no) if q: sql+=" AND (customer LIKE ? OR operator LIKE ?)"; args += [f"%{q}%", f"%{q}%"] if start: sql+=" AND date(created_at)>=date(?)"; args.append(start) if end: sql+=" AND date(created_at)<=date(?)"; args.append(end) with db() as conn: rows = [dict(r) for r in conn.execute(sql, args).fetchall()] return rows @app.get("/api/shipments/{ship_no}/export") def export_zip(ship_no: str): with db() as conn: s = conn.execute("SELECT id FROM shipments WHERE ship_no=?", (ship_no,)).fetchone() if not s: raise HTTPException(404, "shipment not found") imgs = conn.execute("SELECT path FROM images WHERE shipment_id=?", (s["id"],)).fetchall() ocr = conn.execute("SELECT json_data FROM ocr_tables WHERE shipment_id=? ORDER BY id DESC LIMIT 1", (s["id"],)).fetchone() qrs = conn.execute("SELECT payload FROM qrcodes WHERE shipment_id=?", (s["id"],)).fetchall() zbuf = io.BytesIO() with zipfile.ZipFile(zbuf, "w", zipfile.ZIP_DEFLATED) as z: for r in imgs: z.write(r["path"], Path(r["path"]).name) z.writestr("ocr.json", ocr["json_data"] if ocr else "{}") z.writestr("qrcodes.txt", "\n".join([r["payload"] for r in qrs])) zbuf.seek(0) return StreamingResponse(zbuf, media_type="application/zip", headers={"Content-Disposition": f'attachment; filename="{ship_no}.zip"'})

(端點對應規格第 16 節 API 草案與第 5–9 節功能)

五、拍照、OCR、掃碼最小服務

capture:

# apps/capture/capture.py import cv2, time, hashlib from pathlib import Path from datetime import datetime import requests, os, sys API = os.getenv("API","http://127.0.0.1:8000") DATA_ROOT = Path(os.getenv("DATA_ROOT","/data/shipments")) CAM_INDEX = int(os.getenv("CAM_INDEX","0")) def shot(ship_no: str, kind: str): cap = cv2.VideoCapture(CAM_INDEX, cv2.CAP_V4L2) ok, frame = cap.read(); cap.release() if not ok: raise SystemExit("camera read fail") ts = datetime.utcnow().strftime("%Y%m%dT%H%M%SZ") outdir = DATA_ROOT / datetime.utcnow().strftime("%Y/%m/%d") outdir.mkdir(parents=True, exist_ok=True) path = outdir / f"{ship_no}_{kind}_{ts}.jpg" cv2.imwrite(str(path), frame, [cv2.IMWRITE_JPEG_QUALITY, 92]) # 回報 API 建檔 with open(path, "rb") as f: requests.post(f"{API}/api/shipments/{ship_no}/images", data={"kind": kind}, files={"file": ("img.jpg", f, "image/jpeg")}) if __name__ == "__main__": ship_no, kind = sys.argv[1], sys.argv[2] # kind=image1|image2 shot(ship_no, kind)

ocr_worker:

# apps/ocr_worker/worker.py import pytesseract, json, cv2, sys, os, requests API = os.getenv("API","http://127.0.0.1:8000") def run(ship_no: str, img_path: str): img = cv2.imread(img_path) gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) txt = pytesseract.image_to_string(gray, lang="chi_tra+eng") # 簡單解析:示意(實務用模板/規則) result = {"ship_no": ship_no, "raw": txt} requests.post(f"{API}/api/shipments/{ship_no}/ocr", data={"json_data": json.dumps(result, ensure_ascii=False), "engine": "tesseract", "conf": 0.90}) if __name__=="__main__": run(sys.argv[1], sys.argv[2])

qrcode_listener:

# apps/qrcode_listener/listener.py import sys, os, requests, time API = os.getenv("API","http://127.0.0.1:8000") CUR_SHIP = None def set_current(ship_no): # 可由 web-ui 設定或輸入 global CUR_SHIP; CUR_SHIP = ship_no requests.post(f"{API}/api/shipments", data={"ship_no": ship_no}) def on_scan(payload: str): if not CUR_SHIP: return requests.post(f"{API}/api/shipments/{CUR_SHIP}/qrcode", data={"payload": payload, "symbology":"QR"}) if __name__=="__main__": set_current(sys.argv[1]) # e.g. python listener.py SHP0001 for line in sys.stdin: # 示意:從 HID/Serial 驅動換成標準輸入 on_scan(line.strip())

(拍照、OCR、掃碼職責對應 FR-01/02/03)

六、Web 覆核/查詢最小頁(Jinja2)

# apps/web_ui/main.py from fastapi import FastAPI, Request from fastapi.templating import Jinja2Templates import sqlite3, os app = FastAPI() DB = os.getenv("DB_PATH","/data/shipcap.db") tmpl = Jinja2Templates("templates") @app.get("/") def index(r: Request, q: str=""): conn = sqlite3.connect(DB); conn.row_factory=sqlite3.Row rows = conn.execute("SELECT ship_no, customer, created_at FROM shipments ORDER BY id DESC LIMIT 100").fetchall() return tmpl.TemplateResponse("index.html", {"request": r, "rows": rows})

(頁面包含查詢、預覽、覆核欄位,對應 7.1)

七、設定、部署與維運

config.yaml(關鍵節點)

data_root: /data/shipments db_path: /data/shipcap.db camera: index: 0 resolution: [3264, 2448] ocr: engine: tesseract # or paddleocr security: jwt_secret: "change_me" backup: daily: "02:00"

(對應設定檔與備份需求)

docker-compose(同機部署)

version: "3.8" services: ingest: build: ./apps/ingest_api environment: - DATA_ROOT=/data/shipments - DB_PATH=/data/shipcap.db volumes: - ./data:/data ports: ["8000:8000"] command: uvicorn main:app --host 0.0.0.0 --port 8000 webui: build: ./apps/web_ui environment: - DB_PATH=/data/shipcap.db volumes: [ "./data:/data", "./apps/web_ui/templates:/app/templates" ] ports: ["8080:8080"] command: uvicorn main:app --host 0.0.0.0 --port 8080 ocr: build: ./apps/ocr_worker environment: [ "API=http://ingest:8000" ] volumes: [ "./data:/data" ] capture: build: ./apps/capture privileged: true devices: [ "/dev/video0:/dev/video0" ] environment: - API=http://ingest:8000 - DATA_ROOT=/data/shipments volumes: [ "./data:/data" ]

(容器化屬「可選」;亦可用 systemd)

systemd 範例

# deploy/systemd/ingest-api.service [Unit] Description=shipcap ingest api After=network.target [Service] WorkingDirectory=/opt/shipcap/apps/ingest_api ExecStart=/usr/bin/uvicorn main:app --host 0.0.0.0 --port 8000 Environment=DATA_ROOT=/data/shipments Environment=DB_PATH=/data/shipcap.db Restart=always [Install] WantedBy=multi-user.target

(符合規格之 systemd、logrotate、備份排程)

八、最小驗收腳本(單筆 E2E)

# 1) 建單 curl -F ship_no=SHP0001 -F customer=Acme -F ship_date=2025-09-09 -F operator=op1 http://127.0.0.1:8000/api/shipments # 2) 拍照1/2 python apps/capture/capture.py SHP0001 image1 python apps/capture/capture.py SHP0001 image2 # 3) OCR(示意用剛才的 image1 路徑) python apps/ocr_worker/worker.py SHP0001 /data/shipments/2025/09/09/SHP0001_image1_*.jpg # 4) 掃一個 QR payload curl -F payload="QR:ABC123" http://127.0.0.1:8000/api/shipments/SHP0001/qrcode # 5) 匯出 curl -L -o SHP0001.zip http://127.0.0.1:8000/api/shipments/SHP0001/export

(對應功能/匯出與驗收)

九、風險與強化點

  • 單據版式多樣:先以模板規則與欄位信心值門檻,低於門檻強制覆核;後續導入 PP-Structure。

  • 反光/陰影:硬體治具與固定光源;拍照前自動曝光/對焦檢查。

  • 多站:本機先存,sync_agent 排程上傳中央 DB/NAS。

需要我把上述骨架打包成 zip 或加上 PaddleOCR 版 worker 與 HID/Serial 讀碼驅動,直接可

2025年7月29日 星期二

零知識證明:Web3.0與AI代理人的信任基石

零知識證明:Web3與AI的信任基石

零知識證明 (ZKP)

Web3 與 AI 時代的信任基石

歡迎探索零知識證明的世界。這項革命性的密碼學技術,允許在不洩露任何敏感資訊的前提下驗證事實,正從根本上重塑數位世界的隱私、安全與信任。本指南將帶您了解其核心原理、關鍵技術與改變未來的潛力。

核心原理

ZKP 必須滿足三大特性,才能確保其安全有效。這些特性共同構成了「在不洩露秘密的情況下證明知識」的基礎。

完整性 (Completeness)

如果聲明為真,誠實的證明者總能成功說服驗證者。簡單來說,就是「對的錯不了」。

🛡️

合理性 (Soundness)

如果聲明為假,作弊的證明者幾乎不可能欺騙驗證者。簡單來說,就是「錯的對不了」。

🤫

零知識性 (Zero-Knowledge)

驗證者除了「聲明為真」這一事實外,學不到任何額外資訊。這是 ZKP 保護隱私的關鍵。

主流技術比較

目前主流的 ZKP 協議各有千秋。點擊下方按鈕,互動探索它們在關鍵指標上的差異。

應用領域

ZKP 不僅是理論,更已在 Web3 和 AI 領域產生巨大影響。切換分頁,了解其如何賦能下一代數位應用。

隱私保護

在不洩露交易金額、身份等資訊的情況下完成金融交易(如 Zcash)。實現去中心化身份(DID),用戶可證明年齡或國籍卻不透露具體個資。

擴容性 (ZK-Rollups)

將數百筆交易在鏈下打包,生成一個有效性證明上鏈。大幅提升以太坊等區塊鏈的處理速度(TPS),降低交易費用,實現大規模應用。

安全性與數據完整性

通過數學證明確保鏈下計算的正確性,減少對中心化機構的依賴,降低單點故障風險,並保護數據在傳輸和驗證過程中的安全。

挑戰與未來展望

ZKP 的普及之路並非一帆風順,但其前景無限光明。了解當前的挑戰以及業界如何應對。

當前挑戰

  • 計算成本高:生成證明需要大量計算資源,對複雜模型尤其昂貴。
  • 技術複雜性:將 AI 模型等複雜計算轉換為 ZKP 電路是一項艱鉅的工程。
  • 可信設置風險:部分協議(如 ZK-SNARKs)依賴於一個可信的初始設置,存在中心化風險。
  • 標準化與互操作性:缺乏統一標準,阻礙了不同平台和系統間的無縫集成。

解決方案與未來

  • 硬體加速:利用 GPU、FPGA 等專用硬體大幅提升證明生成速度。
  • 演算法優化:開發更高效的協議,並採用證明聚合、遞歸等技術降低開銷。
  • 透明協議:ZK-STARKs 等無需可信設置的協議日益成熟,提升了安全性。
  • 可審計與負責任 AI:ZKP 將成為實現可信、可審計 AI 的關鍵,賦予用戶真正的數據主權。

© 2025 ZKP 互動指南。基於研究報告生成。

2025年7月16日 星期三

AnythingLLM (RAG (Retrieval Augmented Generation) + LLM) 布建 來實現應用

 

AnythingLLM 是一個開源的全端應用程式,讓你可以將任何文件、網站或內容來源,轉換為大型語言模型 (LLM) 的知識基礎

簡單來說,它就像一個工具,可以讓你把各種資料「餵給」LLM,然後 LLM 就可以利用這些資料來回答問題或生成內容。

AnythingLLM 的主要特點包括:

  • 多樣的資料支援:你可以上傳 PDF、Markdown 檔案、Text 檔案、網址,甚至是 GitHub 儲存庫的內容。

  • 多模型支援:它支援多種 LLM,例如 OpenAI 的 GPT 系列、Mistral、Llama 等。

  • 本地部署能力:你可以在自己的伺服器上部署 AnythingLLM,這對於需要資料隱私或客製化部署的企業來說很有用。

  • RAG (Retrieval Augmented Generation) 技術:AnythingLLM 採用 RAG 技術,這表示它在生成答案之前會先從你的資料中檢索相關資訊,這樣可以提高回答的準確性和相關性,並減少 LLM 的「幻覺」現象。

  • 使用者友善介面:它提供一個直觀的聊天介面,讓你可以輕鬆地與你的資料進行互動。


AnythingLLM 的應用情境

AnythingLLM 對於以下情況特別有用:

  • 企業知識庫:將公司內部文件、手冊、規範等資料匯入,員工可以快速查詢資訊。

  • 客戶支援:用來回答客戶常見問題,提升客戶服務效率。

  • 教育與研究:整理學術論文、研究資料,方便師生查詢和分析。

  • 個人知識管理:將個人筆記、電子書、部落格文章等資料整合,打造個人專屬知識庫。



布建 AnythingLLM 來實現 RAG (Retrieval Augmented Generation) + LLM 應用,涉及軟硬體需求、操作流程及驗證步驟。以下為您詳細說明:


💻 軟硬體需求

1. 硬體需求

AnythingLLM 的硬體需求會根據您選擇的 LLM 模型大小、資料量以及預期的併發使用者數量而異。

  • CPU

    • 入門級 (輕度使用):至少 4 核心。

    • 推薦級 (中高負載):8 核心或更多,例如 Intel Xeon 或 AMD EPYC 系列處理器。

  • RAM (記憶體)

    • 入門級 (小型模型與資料):16 GB。

    • 推薦級 (大型模型與資料):32 GB 或更多。如果您計畫使用本地部署的大型 LLM (例如 Llama 70B),則需要 128 GB 甚至 256 GB 以上的記憶體。

  • GPU (顯示卡)

    • 可選,但強烈推薦用於本地 LLM 推理:如果您的 LLM 選擇在本地運行 (而非透過 API 呼叫如 OpenAI),則需要支援 CUDA (NVIDIA) 或 ROCm (AMD) 的 GPU。

      • 入門級:GeForce RTX 3060 (12GB VRAM) 或更高。

      • 推薦級:GeForce RTX 4090 (24GB VRAM) 或更高,或多張企業級 GPU (例如 NVIDIA A100/H100)。GPU 的 VRAM (顯存) 大小直接決定您能運行多大的模型。

  • 儲存空間

    • SSD (固態硬碟):建議使用 SSD 以獲得更好的讀寫效能。

    • 容量:至少 100 GB,具體取決於您的文件資料量和模型儲存需求。

2. 軟體需求

  • 作業系統

    • Linux (推薦):Ubuntu、Debian 或 CentOS 等,提供最佳的效能和穩定性。

    • Windows / macOS:亦可運行,但可能在性能上略遜於 Linux。

  • Docker 與 Docker Compose強烈推薦使用 Docker 來部署 AnythingLLM,這能大大簡化安裝和管理過程。

  • Node.js (如果你選擇手動安裝):用於運行前端應用。

  • Python (如果你選擇手動安裝):用於運行後端服務和資料處理腳本。

  • Git:用於從 GitHub 下載 AnythingLLM 原始碼。

  • 向量資料庫 (內建或外接):AnythingLLM 預設使用內建的 LanceDB,但您也可以配置為使用 ChromaDB、Pinecone 或 Weaviate 等外部向量資料庫,這對於大規模部署更為有利。


🛠️ 操作流程 (以 Docker 部署為例)

Docker 部署是最推薦且最簡便的方式,以下為基本步驟:

1. 環境準備

  • 安裝 Docker 與 Docker Compose

    • 前往 Docker 官網 下載並安裝適合您作業系統的 Docker Desktop (Windows/macOS) 或在 Linux 上安裝 Docker Engine 和 Docker Compose。

2. 下載 AnythingLLM

  • 複製 GitHub 儲存庫

    Bash
    git clone https://github.com/Mintplex-Labs/anything-llm.git
    cd anything-llm
    

3. 配置環境變數

  • 複製範本並修改 .env 檔案: 在 AnythingLLM 目錄下,會有一個 .env.example 檔案。複製一份並命名為 .env

    Bash
    cp .env.example .env
    
  • 編輯 .env 檔案: 打開 .env 檔案,根據您的需求進行配置。

    • LLM 提供商

      • 如果您使用 OpenAI:設定 OPEN_AI_KEY=您的OpenAI API金鑰

      • 如果您使用其他服務 (如 Azure OpenAI, Anthropic, Google Gemini 等),請參考 AnythingLLM 的官方文件進行配置。

      • 如果您選擇本地 LLM:可能需要配置 LLM_MODEL_NAME 和相關的 API endpoint (例如 Ollama 或 vLLM)。

    • Embedding 提供商

      • 例如:EMBEDDING_PROVIDER=openaiEMBEDDING_PROVIDER=ollama (如果您使用本地嵌入模型)。

    • 向量資料庫:預設是 LANCEDB,通常無需更改。

    • 其他設定:可以設定埠口、管理員信箱等。

4. 啟動 AnythingLLM

  • 使用 Docker Compose 啟動: 在 AnythingLLM 根目錄下執行:

    Bash
    docker-compose up -d
    
    • -d 表示在背景運行。

    • 這會下載所需的 Docker 映像檔並啟動所有服務 (前端、後端、向量資料庫等)。

5. 初始設定與資料上傳

  • 訪問 AnythingLLM 介面: 打開您的瀏覽器,訪問 http://localhost:3001 (如果您的埠口是預設的 3001)。

  • 創建管理員帳戶:首次訪問時,會引導您創建一個管理員帳戶。

  • 創建工作區 (Workspace):登入後,創建一個新的工作區。每個工作區可以有獨立的知識庫和聊天紀錄。

  • 上傳資料

    • 進入您創建的工作區。

    • 點擊「Add Documents」或類似的選項。

    • 您可以選擇上傳文件 (PDF, TXT, MD 等)、提供網站 URL,或連接 GitHub 儲存庫。

    • AnythingLLM 會自動處理這些文件,將它們切分成小塊 (chunking),並生成向量嵌入 (embedding),然後儲存到向量資料庫中。

6. 選擇並連接 LLM

  • 在工作區設置中,選擇您希望使用的 LLM 提供商 (例如 OpenAI, Ollama 等)。

  • 如果使用 API 服務,請確保您的 API 金鑰已在 .env 中正確配置。

  • 如果使用本地 LLM,請確保本地的 LLM 服務已運行且可被 AnythingLLM 訪問。


✅ 驗證流程

驗證 RAG + LLM 應用是否成功布建且正常運作至關重要。

1. 基本功能驗證

  • 確認服務運行

    • 檢查 Docker 容器狀態:docker-compose ps,確保所有相關服務 (前端、後端、向量資料庫) 都處於 Up 狀態。

    • 訪問 AnythingLLM Web 介面是否正常顯示。

  • 帳戶與工作區驗證

    • 登入管理員帳戶是否成功。

    • 能否成功創建新的工作區。

  • 文件上傳與處理驗證

    • 上傳一個小型 PDF 或 TXT 文件。

    • 觀察文件是否被成功處理 (通常會有一個進度條或狀態提示)。

    • 確認文件狀態變為「Processed」或類似的成功提示。

2. RAG 核心功能驗證

這是最關鍵的部分。

  • 提出基於文件的問題

    • 在您上傳文件後,進入該工作區的聊天介面。

    • 提出一個只有在您上傳的文件中才能找到答案的問題。

    • 期望結果:LLM 應根據您上傳的文件內容來回答問題,並提供相關的引用或來源 (如果 AnythingLLM 支援顯示引用)。

    • 反向測試:提出一個與您文件內容無關的問題,看 LLM 是否會拒絕回答或給出通用答案,而不是基於您的文件。

  • 檢索驗證 (可選,進階)

    • 有些 RAG 系統會提供一個「檢索」或「源文件」的預覽功能,您可以檢查 LLM 在生成答案時實際檢索到了哪些文件片段。

    • 如果 AnythingLLM 介面沒有直接提供,您可能需要查看後端日誌來確認檢索過程。

  • 答案品質與相關性

    • 評估 LLM 給出的答案是否準確、完整且與您的問題相關。

    • 檢查是否存在「幻覺」(Hallucination) 現象,即 LLM 編造了文件中不存在的資訊。如果發生,可能需要調整文件切割策略、嵌入模型或 LLM 提示詞。

  • 多文件交叉驗證

    • 上傳多個相關的文件。

    • 提出一個需要整合多個文件資訊才能回答的問題。

    • 期望結果:LLM 能從不同文件中提取資訊並進行綜合回答。

3. 效能與穩定性驗證 (進階)

  • 回應時間:測試 LLM 回答問題所需的時間。如果時間過長,可能需要優化硬體、LLM 模型或服務配置。

  • 併發測試:如果應用於多使用者環境,可以模擬多個使用者同時提問,觀察系統穩定性和回應時間。

  • 日誌監控:定期檢查 Docker 容器的日誌 (docker-compose logs -f),查看是否有錯誤訊息或警告,以便及時排除故障。


通過以上步驟,您就可以成功布建並驗證 AnythingLLM 的 RAG + LLM 應用了。

請記住,實際的配置會根據您選擇的 LLM、嵌入模型以及資料量有所不同,務必參考 AnythingLLM 的官方文件以獲取最詳細和最新的資訊。





2025年6月30日 星期一

Gemini API 有關圖形多模態的限制

 Gemini 系列模型中,支援 API 傳送圖形(即具有多模態功能)的主要模型有:

  1. Gemini 1.0 Pro Vision (或簡稱 Gemini Pro Vision):

    • 這是 Gemini 1.0 系列中支援視覺輸入的模型。它可以處理文字和圖片輸入,並生成文字回應。

    • 在許多情境下,它是處理多模態任務的常用選擇。

  2. Gemini 1.5 Flash:

    • 如您在程式碼中使用的,這是 Gemini 1.5 系列中速度更快、效率更高的模型。它原生支援多模態輸入,包括圖片、音訊、影片和文字,並能生成文字回應。

    • 它專為需要低延遲、高效能的工作負載而設計,例如即時聊天機器人或代理服務。

  3. Gemini 1.5 Pro:

    • 這是 Gemini 1.5 系列中功能更強大、推理能力更強的模型。它同樣原生支援多模態輸入,適用於更複雜的程式編寫、推理和多模態理解任務。

    • 雖然回應速度可能比 Flash 略慢,但在需要深度思考和高準確度時表現更佳。

總結來說,目前透過 Gemini API 支援圖像輸入的推薦模型包括:

  • Gemini 1.5 Flash (推薦用於速度和效率,您目前正在使用的模型)

  • Gemini 1.5 Pro (推薦用於更複雜的推理和理解)

  • Gemini 1.0 Pro Vision (較早期的版本,但仍支援視覺)

支援的圖片 MIME 類型包括:

  • image/png

  • image/jpeg

  • image/webp

  • image/heic

  • image/heif

您可以根據您的應用場景和對模型效能、成本的需求來選擇最適合的 Gemini 模型。在 Google AI Studio 中,您可以方便地測試和選擇這些模型。