Iris
ทางการเซิร์ฟเวอร์ประเมินและสังเกตการณ์เอเจนต์แบบ MCP-native พร้อมการบันทึก trace การประเมินคุณภาพผลลัพธ์ การติดตามต้นทุน กฎการประเมินในตัว 12 ข้อ แดชบอร์ดแบบเรียลไทม์ และการตรวจจับ PII
คุณทำอะไรได้บ้างด้วย Iris MCP?
- บันทึกและประเมินผลการทำงานของ agent — ให้ผู้ช่วยของคุณบันทึกงานไปยัง Iris และรับคะแนนคุณภาพ ความปลอดภัย และต้นทุนที่แน่นอนบนผลลัพธ์
- สอบถามประวัติ trace — ดึงข้อมูลการทำงานของ agent ที่เก็บไว้พร้อมการกรอง การแบ่งหน้า และการรองรับช่วงเวลา เพื่อตรวจสอบประสิทธิภาพในอดีต
- เปรียบเทียบการทำงานในช่วงเวลาต่างๆ — วิเคราะห์การทำงานสองครั้งบนคำถามเดียวกันแบบเคียงข้างกัน เพื่อค้นหาการถดถอยหรือการปรับปรุงในพฤติกรรมของ agent
- ให้คะแนนคุณภาพผลลัพธ์ — ประเมินข้อความใดๆ กับกฎในตัว 25 ข้อที่ครอบคลุมความครบถ้วน ความเกี่ยวข้อง ความปลอดภัย และต้นทุน พร้อมการตรวจจับ PII และการฉีดพรอมต์
- รันแดชบอร์ดสาธิต — เปิดฐานข้อมูลสาธิตที่เตรียมข้อมูลไว้พร้อมตัวอย่างข้อผิดพลาดและคำตัดสิน เพื่อสำรวจกลไกการให้คะแนนของ Iris ในเครื่องของคุณ
เอกสาร
Iris — หยุดส่ง agents ไปบนความรู้สึก
Iris ให้คะแนนทุกการรันของ agent ในด้านคุณภาพ ความปลอดภัย และค่าใช้จ่าย — บนเครื่องของคุณ โดยไม่ต้องใช้ SDK และไม่ต้องมีบัญชี โปรเจกต์ agent ส่วนใหญ่ตรวจสอบคุณภาพด้วยการรันพรอมต์ที่จำไว้สองสามอันแล้วดูผลลัพธ์ด้วยตา Iris แทนที่สิ่งนั้นด้วยตัวเลขที่คุณตรวจสอบได้: การรันของ agent ของคุณจะถูกเก็บในฐานข้อมูล SQLite บนดิสก์ของคุณ กฎในตัว 25 ข้อให้คะแนนแบบ deterministic — PII, prompt injection, สัญญาณของ hallucination, เกณฑ์ค่าใช้จ่าย และการเรียกใช้ tool ของ agent เอง — ฟรี ไม่มีการเรียก LLM และมี LLM judge แบบเลือกได้พร้อมเพดานค่าใช้จ่ายต่อการประเมินแบบตายตัวสำหรับคำถามเชิงความหมาย ทุกกฎสามารถตรวจสอบและแก้ไขได้ เพราะ judge ที่คุณตรวจสอบไม่ได้ก็แค่ความรู้สึกที่มีตัวเลขกำกับ ใช้สัญญาอนุญาต MIT ไม่มี telemetry ไม่มีอะไรออกจากเครื่องของคุณเว้นแต่คุณจะเปิดหนึ่งในสิ่งเหล่านี้: ปลายทาง OpenTelemetry (IRIS_OTEL_ENDPOINT) ซึ่งส่ง traces ไปยัง collector ที่คุณระบุ; LLM judge ที่ใช้คีย์ของคุณเอง ซึ่งส่งข้อความที่มันประเมินไปยังผู้ให้บริการนั้น และการตรวจสอบการอ้างอิงของมันจะดึงหน้าที่ผลลัพธ์อ้างถึง; หรือ webhook ซึ่งส่ง id, verdict และชื่อกฎ ไม่เคยส่งข้อความ ไปยังที่อยู่ที่คุณตั้งไว้
ต้องใช้ Node.js 22.13 หรือใหม่กว่า ตรวจสอบด้วย node --version

ฐานข้อมูลตัวอย่าง บันทึกโดย scripts/demo-media.mts; แหล่งที่มาคือ demo.mp4 ภาพนิ่ง: dashboard-overview.png
เห็นความล้มเหลวบนหน้าจอใน 60 วินาที
ไม่ต้องต่อ agent ไม่ต้องตั้งค่า — คำสั่งเดียว:
npx @iris-eval/mcp-server --demo
คำสั่งนี้สร้างฐานข้อมูลตัวอย่าง — agent ขนาดเล็กห้าตัว การรันสองสัปดาห์ ทุก verdict มาจากเอนจินของมันเอง — และให้บริการ dashboard กับฐานข้อมูลนั้นที่ http://localhost:6920 (เบราว์เซอร์ของคุณจะเปิดโดยอัตโนมัติในการรันครั้งแรก) dashboard เปิดที่หน้า Failures: อะไรล้มเหลว เรียงจากแย่ที่สุดและใหม่ที่สุดก่อน แต่ละการ์ดระบุกฎและหลักฐานของมัน คุ้มค่าที่จะคลิกเข้าไปดู — การรั่วไหลของ PII ที่กฎความปลอดภัยจับได้, คำสั่งซ่อนเร้นในโพสต์ฟอรัมที่ตัวสรุปปฏิบัติตาม, ตัวเลขที่เอกสารต้นทางไม่เคยพูดถึง, การรันสองครั้งบนคำถามสิบสองข้อเดียวกันที่เปรียบเทียบกับช่วงเวลา (Runs), กฎที่กำหนดเองที่ใช้งานและกฎที่หยุดชั่วคราวพร้อมแถวการตรวจสอบของมัน และคะแนน LLM-judge ที่ล้มเหลวพร้อมเหตุผลของมัน
ข้อมูลตัวอย่างอยู่ในฐานข้อมูลของตัวเอง (demo.db ในไดเรกทอรีบ้านของ Iris — ~/.iris บน macOS/Linux, %USERPROFILE%\.iris บน Windows) และไม่ปะปนกับ traces จริงของคุณ ลบทั้งหมดด้วยคำสั่งเดียว:
npx @iris-eval/mcp-server --demo-clear
เชื่อมต่อ agent ของคุณเอง
ก่อนอื่น พิสูจน์ว่าการติดตั้งทำงานบนเครื่องนี้ — มันทำงานแบบออฟไลน์และไม่เปิดอะไรของคุณ:
npx @iris-eval/mcp-server --self-test # exit 0 = healthy
จากนั้นเพิ่ม Iris ไปยัง MCP client ของคุณ คำสั่งเดียวเขียนไฟล์คอนฟิกของ client เอง เก็บเซิร์ฟเวอร์อื่นทั้งหมดไว้ และปักหมุดเวอร์ชันที่คุณรัน:
npx -y @iris-eval/mcp-server install claude-code
Clients: claude-code, claude-desktop, cursor, windsurf, continue, vscode, cline, zed, codex, gemini install --list แสดงรายการที่พบบนเครื่องนี้ Iris ที่แต่ละตัวรันและไฟล์ที่มันอ่าน; install <client> --uninstall เอา Iris ออกอีกครั้ง ทุก client ใช้ฐานข้อมูลร่วมกัน ดังนั้นหลังอัปเกรดให้ย้ายทั้งหมดพร้อมกันด้วย install --upgrade (การอัปเดต) รีสตาร์ท client เพื่อโหลด
Claude Desktop: คลิกเดียว ทุกรีลีสตั้งแต่ 0.20.0 เป็นต้นไปแนบ iris-eval.mcpb ซึ่งเป็น MCP Bundle: ดาวน์โหลด เวอร์ชันล่าสุด เปิดมัน แล้ว Claude Desktop จะแสดงไดอะล็อกการติดตั้ง ไม่มีอะไรในนั้นที่จำเป็น — คีย์ Anthropic หรือ OpenAI สำหรับ LLM judge เป็นตัวเลือก และ dashboard เป็นสวิตช์ที่ปิดอยู่ตอนเริ่มต้น Bundle เก็บแพ็กเกจ npm และ dependencies ของมัน ดังนั้นไม่ต้องติดตั้งอะไรเพิ่มเติม: Claude Desktop รันมันภายใต้ Node ที่มันมาพร้อมกับเมื่อ Node นั้นเป็น 22.13 หรือใหม่กว่า (Claude Desktop 1.1.6679 มาพร้อม 24.13) และ Iris เก็บ traces ด้วย SQLite ในตัวของ Node ใน ~/.iris เดียวกับการติดตั้งอื่นทั้งหมด บันทึกประจำรุ่นแสดงวิธีตรวจสอบลายเซ็นและการรับรองการ build
มันรันใน MCP client ใดก็ได้ และทุก client ที่มันระบุชื่อมีแถวพร้อมสิ่งที่ตรวจสอบจริง ตรวจสอบแล้วในการรัน CI ทุกครั้ง: Claude Code, Gemini CLI — client จริงเริ่ม Iris จากคอนฟิกที่ตัวติดตั้งเขียนและรายงานว่าเชื่อมต่อแล้ว (claude mcp list, gemini mcp list) บน Linux, macOS และ Windows; ฮุคของ capture plugin ของ Claude Code ก็ขับเคลื่อนผ่านสคริปต์จริงเช่นกัน อ้างจากเอกสาร MCP ของแต่ละ client เอง — ตัวติดตั้งเขียนรูปแบบคอนฟิกที่ client เอกสารไว้ และตัวเขียนนั้นถูกทดสอบกับรูปแบบนั้น; ไม่มีใครฝั่ง Iris เห็นมันเชื่อมต่อ: Claude Desktop, Cursor, Devin Desktop (Windsurf), Continue, VS Code, Cline, Zed, OpenAI Codex CLI ทุกแถวพร้อมแหล่งที่มาและวันที่ที่อ่าน: https://iris-eval.com/clients. ด้วยมือแทน บล็อกเดียว รวม dashboard:
{
"mcpServers": {
"iris-eval": {
"command": "npx",
"args": ["-y", "@iris-eval/mcp-server", "--dashboard"]
}
}
}
Client ของคุณจะแสดงเครื่องมือสิบสองรายการของ Iris เมื่อเชื่อมต่อ และ dashboard ให้บริการที่ http://localhost:6920. ตอนนี้วางสิ่งนี้ให้ agent ของคุณ:
บันทึกงานสุดท้ายนั้นไปยัง Iris และประเมินผลลัพธ์
Trace จะลงบน dashboard พร้อมคะแนนของมัน ชอบ MCP server แบบ headless ไหม? เอา --dashboard ออกจาก args — คุณสามารถเปิด dashboard เดียวกันได้ทุกเวลาด้วย npx @iris-eval/mcp-server --dashboard
สิ่งหนึ่งที่ควรรู้ล่วงหน้า: เครื่องมือ MCP ถูกเรียกเมื่อโมเดลตัดสินใจเรียกมัน Iris ไม่ดักจับ agent ของคุณ ดังนั้น traces จะถูกบันทึกเมื่อ agent ของคุณขอให้บันทึก — ไม่ว่าคุณจะบอกมัน หรือโค้ดของคุณเรียกเครื่องมือโดยตรง ขอให้ agent ของคุณ "บันทึกสิ่งนี้ไปยัง Iris และประเมินมัน" แล้วมันจะทำ หากคุณต้องการ capture ที่ไม่ขึ้นอยู่กับการเลือกของโมเดล POST /api/v1/traces ทำสิ่งนั้นได้พอดี — โค้ดของคุณส่ง trace ผ่าน HTTP ธรรมดา ไม่มีโมเดลอยู่ในวงจร (ดู docs/http-ingest.md) CLI และฮุคของโฮสต์บน roadmap จะเป็นไคลเอนต์แบบบางบนปลายทางเดียวกัน
Capture ผ่าน HTTP (ไม่มีโมเดลในวงจร)
ปลายทาง ingest อยู่บน พอร์ต dashboard — 6920 โดยค่าเริ่มต้น ไม่ใช่พอร์ต transport ของ MCP — และมันมีอยู่เฉพาะเมื่อ dashboard กำลังรัน ส่ง --dashboard (หรือตั้ง IRIS_DASHBOARD=true); --transport http เพียงอย่างเดียว ไม่ เริ่มมัน และคำขอไปยังพอร์ต transport จะคืนค่า 404 เมื่อ dashboard เปิดอยู่ อะไรก็ตามที่ส่งคำขอ HTTP ได้สามารถบันทึก trace — และเลือกที่จะรันการประเมินแบบ deterministic ในคำขอเดียวกัน GET /api/v1/capabilities บนพอร์ตเดียวกันบอกว่าซerver นี้สามารถประเมินอะไรได้ แต่ละกฎต้องการอะไร สถานะของ judge พร้อมขั้นตอนที่เปิดใช้งานมัน และขีดจำกัด — วัตถุเดียวกับที่ MCP resource iris://capabilities ให้บริการ — ดังนั้นผู้เรียก HTTP จึงมีกรอบที่ MCP client ได้ที่การเริ่มต้น:
curl -s -X POST "http://127.0.0.1:6920/api/v1/traces" \
-H "Content-Type: application/json" \
-d '{
"agent_name": "support-bot",
"input": "What is the refund policy?",
"output": "Refunds are available within 30 days of purchase.",
"evaluate": true,
"eval_type": "safety"
}'
คืนค่า 201 พร้อม trace_id ที่เก็บไว้และผลการประเมิน (ในโหมด --demo ปลายทางปฏิเสธการเขียนด้วย 403 ดังนั้นข้อมูลตัวอย่างจะไม่ปะปนกับของคุณ) ปลายทางยอมรับ body เดียวกับเครื่องมือ log_trace และอยู่หลัง middleware stack เดียวกับส่วนที่เหลือของ dashboard: การผูก loopback และการป้องกัน DNS-rebinding โดยค่าเริ่มต้น บวก Bearer auth เมื่อคุณตั้งค่า ข้อเท็จจริงธรรมดาสองข้อเกี่ยวกับมัน: มันยอมรับการเขียนที่ไม่มีการรับรองความถูกต้องเว้นแต่ Iris จะเริ่มด้วย --api-key (หรือ IRIS_API_KEY) — การผูก loopback คือสิ่งที่เก็บมันไว้กับเครื่องของคุณโดยค่าเริ่มต้น ดังนั้นตั้งคีย์ก่อนผูกเกิน loopback; และสิ่งที่มันเก็บคือตามที่ส่งมาแบบคำต่อคำ — input และ output ลงใน iris.db ตามที่ส่งพอดี รวมถึงข้อความใดก็ตามที่ no_pii ไปชี้เพิ่มเติม สัญญาเต็ม การอ้างอิงฟิลด์ และความหมายของข้อผิดพลาด: docs/http-ingest.md
Capture ทุกเทิร์นของ Claude Code (ไม่บังคับ)
/plugin marketplace add iris-eval/mcp-server
/plugin install iris-eval-capture@iris-eval
ปลั๊กอินที่ติดตั้งแยกต่างหากตัวที่สอง: ฮุคสามตัวบันทึกพรอมต์ การเรียก tool และคำตอบสุดท้ายของแต่ละเทิร์น และส่งให้ iris-eval ingest แบบแยกออกไป โดยมีช่วงสำคัญที่ถูกปกปิดในข้อความการประเมินที่เก็บไว้ — capture ที่ไม่ขึ้นอยู่กับโมเดลตัดสินใจเรียก tool มันไม่บันทึกเทิร์นที่โมเดลบันทึกแล้ว ไม่พิมพ์ ไม่บล็อก ไม่ส่งอะไรไปที่ไหน การติดตั้ง iris-eval เพียงอย่างเดียวไม่เปลี่ยนอะไรเกี่ยวกับวงจรเทิร์นของคุณ ขีดจำกัดและการลบ: claude-plugin-capture/README.md
Python
pip install iris-eval
from iris_eval import IrisClient
iris = IrisClient() # IRIS_URL, or the running dashboard's runtime.json
iris.evaluate_output("…", input="…", agent_name="support-bot")["verdict"] # {"state": "pass", "basis": "clean", "by": []}
ไคลเอนต์แบบบางเหนือ HTTP API ของเซิร์ฟเวอร์ 0.16.0 ขึ้นไป มีเวอร์ชันของตัวเอง — iris_eval.__version__ และหน้า PyPI มีหมายเลขของมัน ซึ่งไม่ใช่ของเซิร์ฟเวอร์: log_trace(), evaluate_output(), get_traces(), get_trace(), health(), capabilities(), แบบ sync และ async, คำตอบแบบ typed, ประโยคของเซิร์ฟเวอร์เองเมื่อปฏิเสธ — และปลั๊กอิน pytest: ฟิกซ์เจอร์ iris และ assert_iris(output, expect="pass") ที่ยืนยันสถานะของ verdict packages/python/README.md
บันทึกทุกการเรียก OpenAI และ Anthropic
from iris_eval import wrap_openai
client = wrap_openai(OpenAI(), agent_name="support-bot") # every call: a GenAI span to POST /v1/traces, scored
import { wrapOpenAI } from '@iris-eval/sdk';
const openai = wrapOpenAI(new OpenAI(), { agentName: 'support-bot' });
ครอบ client ของผู้ให้บริการครั้งเดียว แล้วการเรียกโมเดลแต่ละครั้งจะกลายเป็น OpenTelemetry GenAI span หนึ่งรายการที่ส่งไปยังประตู OTLP เก็บด้วย input, output, การใช้ token และการเรียก tool ของมัน และให้คะแนน: capture ที่ไม่ขึ้นอยู่กับโมเดลเรียก tool wrap_openai / wrap_anthropic ในไคลเอนต์ Python; wrapOpenAI, wrapAnthropic และ irisMiddleware สำหรับ Vercel AI SDK ใน @iris-eval/sdk ทั้งสองยังไม่ได้เผยแพร่ (รีลีส iris-eval ถัดไปบน PyPI; @iris-eval/sdk สร้างจากซอร์สจนกว่าจะมีการเผยแพร่ npm ครั้งแรก) สตรีม ตัวช่วยสตรีมของ SDK และการเรียก tool ครอบคลุมแล้ว ไคลเอนต์เดิมไม่ถูกเปลี่ยนแปลง และ Iris ล่มไม่เคยทำลายการเรียก — packages/sdk/README.md, packages/python/README.md
ให้คะแนนทุกการรันของ LangChain และ LangGraph
from iris_eval.langchain import IrisCallbackHandler
graph.invoke(inputs, config={"callbacks": [IrisCallbackHandler(agent_name="support-bot")]})
การรันระดับบนสุดแต่ละครั้งกลายเป็น trace หนึ่งรายการ (การรัน การเรียกโมเดล การเรียก tool และโหนดกราฟของมันเป็น GenAI spans) พร้อม input, output, การเรียก tool, การใช้ token และ verdict Python ในไคลเอนต์ (รีลีสถัดไป ยังไม่ได้เผยแพร่ไปยัง PyPI), JavaScript เป็น @iris-eval/langchain (ยังไม่ได้เผยแพร่ไปยัง npm) ทั้งสองพิสูจน์แล้วใน CI กับแอป LangGraph จริงที่มีโมเดลแบบสคริปต์; การส่งออก OpenTelemetry ของ LangSmith เองก็พิสูจน์ด้วยวิธีเดียวกัน — docs/otel-recipes.md
ประตู CI ไม่ต้องใช้เซิร์ฟเวอร์
npx -y @iris-eval/mcp-server ingest --file traces.ndjson --evaluate --fail-on detector_veto
หรือ GitHub Action (0.16.0) ซึ่งทำให้งานล้มเหลวบน verdicts ที่คุณระบุ เขียนใบเสร็จไปยังสรุปงาน และโพสต์เป็นความคิดเห็น pull request หนึ่งรายการที่อัปเดตในที่: uses: iris-eval/mcp-server/.github/actions/gate@v0.19.0 กับ traces: traces.ndjson — docs/ci-gate.md
ประตูที่สี่ (0.15.0): POST /v1/traces บนพอร์ตแดชบอร์ดรับ OTLP/HTTP JSON หรือ protobuf ที่เครื่องมือวัด OpenTelemetry ของคุณส่งออกอยู่แล้ว (ตัวส่งออกของ Python SDK พูด protobuf อย่างเดียว ดังนั้นนี่จึงเป็นประตูสำหรับ Python ด้วย) และแต่ละ OTLP trace จะกลายเป็น Iris trace พร้อมสแปนของมัน — docs/otel-integration.md; หนึ่งสูตรต่อเฟรมเวิร์ก (Pydantic AI, Google ADK, LangGraph ผ่าน LangSmith, CrewAI, OpenAI Agents SDK ใน Python และ JavaScript, LlamaIndex, AutoGen, Microsoft Agent Framework, Semantic Kernel, Vercel AI SDK และ Mastra) แต่ละสูตรพิสูจน์ด้วย fixture ใน docs/otel-recipes.md ingest อ่าน JSON trace หนึ่งรายการ (หรือ NDJSON หนึ่งรายการต่อบรรทัด) จาก stdin หรือไฟล์ จัดเก็บมัน ประเมินมันภายใต้กฎเดียวกับที่ evaluate_output ใช้ พิมพ์ JSON หนึ่งบรรทัดต่อ trace พร้อมคำตัดสินและพื้นฐานของมัน และออกด้วยรหัส 1 เมื่อคำตัดสินตรงกับ --fail-on --dataset <id|label> จำกัดเกตนั้นให้เหลือเฉพาะคีย์กรณีในชุดข้อมูล (POST /api/v1/datasets เลื่อนคีย์กรณีของการรันหนึ่งครั้งเข้าไปในชุดข้อมูล) ดังนั้นงานจะล้มเหลวเฉพาะกรณีที่คุณเลือกเท่านั้น สูตรเต็ม รหัสออก และแปดพื้นฐานอยู่ใน docs/ci-gate.md
เขียนกฎเป็นโค้ด
eval.plugins ใน config.json โหลดกฎที่คุณเขียน — โมดูล ES ที่ค่า export เริ่มต้นคือ { name, kind, mechanism, version, needs, evaluate(ctx) } — ยึดด้วย sha256 ของไฟล์ ดังนั้นไฟล์ที่เปลี่ยนไปตั้งแต่คุณยึดมันจะปฏิเสธการเริ่มต้นแทนที่จะรัน ปลั๊กอินที่โหลดแล้วทำงานเหมือน built-in และแสดงบน list_rules ภายใต้ plugins สัญญา สูตรแฮช และสิ่งที่ปลั๊กอินสามารถส่งคืนได้: docs/plugins.md
ใช้เอนจินในกระบวนการของคุณเอง
เอนจินการประเมินสามารถนำเข้าได้ — ไม่ต้องมีเซิร์ฟเวอร์ ไม่ต้องมีฐานข้อมูล ไม่ต้องมีโมเดล:
import { EvalEngine, defaultConfig } from '@iris-eval/mcp-server/engine';
const engine = new EvalEngine(defaultConfig.eval.defaultThreshold, defaultConfig.eval.ruleThresholds, defaultConfig.eval);
const result = await engine.evaluateAll({ output: answer, input: prompt, toolCalls, costUsd });
result.verdict.state; // 'pass' | 'fail' | 'unknown', with result.verdict.basis and result.interpretations
เอนจินเดียวกัน กฎเดียวกัน และ composer เดียวกับที่เซิร์ฟเวอร์ใช้; builtInRules(), createCustomRule(), compose() และตัวอ่านความแม่นยำที่เผยแพร่ถูก export อยู่ข้างๆ มัน
ไคลเอนต์แบบมีชนิดสำหรับเส้นทาง HTTP
import { createClient } from '@iris-eval/mcp-server/client';
const iris = createClient({ baseUrl: 'http://127.0.0.1:6920', apiKey: process.env.IRIS_API_KEY });
const { trace_id, evaluation } = await iris.logTrace({ agent_name: 'support-bot', input, output, tool_calls, evaluate: true });
evaluation?.verdict?.state; // the same object evaluate_output returns
หนึ่ง body บนทุกประตู: มันคือสิ่งที่ log_trace และ iris-eval ingest ยอมรับ การปฏิเสธจะโยน IrisClientError พร้อมประโยคและสถานะของเซิร์ฟเวอร์เอง ทั้งสอง subpath ถูกตรวจสอบจาก tarball ที่แพ็กแล้วในทุก build
ตรวจสอบการติดตั้งของคุณ
npx @iris-eval/mcp-server --self-test # offline diagnostic; exit 0 = healthy, 1 = a check failed
npx @iris-eval/mcp-server --version # prints the bare version, e.g. 1.2.3
--self-test สร้าง Iris home ของคุณก่อนถ้ามันหายไป และตรวจสอบว่ามันเขียนได้ (ออกด้วยรหัส 1 ระบุเส้นทาง ถ้ามันเขียนไม่ได้) รายงานว่าดัชนีค้นหาของฐานข้อมูลของคุณอยู่ที่ไหน (ทั้งหมด, มีกี่ trace ที่ build พื้นหลังจัดทำดัชนีไว้แล้ว, หรือไม่มี FTS5 บน SQLite นี้) อ่าน schema ของฐานข้อมูลของคุณ (ออกด้วยรหัส 1 พร้อมวิธีแก้ไข เมื่อเวอร์ชันนี้หรือ MCP client ที่ยึดกับรุ่นเก่ากว่าไม่สามารถเปิดมันได้) จากนั้นรันการตรวจสอบของมัน — การเก็บแบบ round-trip, SSN ที่ปลูกไว้ และการฉีดที่ปลูกไว้ซึ่งถูกจับโดยกฎความปลอดภัย, การบูตแดชบอร์ด, การป้องกัน DNS-rebinding — ภายใน temp home ที่แยกออกมา ฐานข้อมูลจริงของคุณถูกอ่านเท่านั้น ไม่เคยถูกเปลี่ยนแปลง ทุกอย่างที่ Iris เขียนอยู่ภายใต้ไดเรกทอรีเดียว นั่นคือ Iris home ของคุณ: ~/.iris โดยค่าเริ่มต้น (%USERPROFILE%\.iris บน Windows) หรือที่ใดก็ตามที่ IRIS_HOME ชี้ นั่นคือที่ที่ iris.db, config.json, custom-rules.json, audit.log, preferences.json และไฟล์สาธิตอยู่; ชี้ IRIS_HOME ไปที่ไดเรกทอรีขูดเพื่อลอง Iris โดยไม่แตะข้อมูลจริงของคุณ
การตั้งค่าตามเครื่องมือ
| ไคลเอนต์ | สถานะ | ความหมาย | อ่าน |
|---|---|---|---|
| Claude Code | ตรวจสอบแล้ว | การทดสอบขับไคลเอนต์จริงในทุกการรัน CI | 2026-09-25 |
| Claude Desktop | อ้างสิทธิ์ | ตัวติดตั้งเขียนรูปแบบที่ไคลเอนต์เอกสาร และตัวเขียนนั้นถูกทดสอบกับรูปแบบ; ไม่มีใครฝั่ง Iris ได้เห็นมันเชื่อมต่อ | 2026-09-25 |
| Cursor | อ้างสิทธิ์ | ตัวติดตั้งเขียนรูปแบบที่ไคลเอนต์เอกสาร และตัวเขียนนั้นถูกทดสอบกับรูปแบบ; ไม่มีใครฝั่ง Iris ได้เห็นมันเชื่อมต่อ | 2026-09-25 |
| Devin Desktop (Windsurf) | อ้างสิทธิ์ | ตัวติดตั้งเขียนรูปแบบที่ไคลเอนต์เอกสาร และตัวเขียนนั้นถูกทดสอบกับรูปแบบ; ไม่มีใครฝั่ง Iris ได้เห็นมันเชื่อมต่อ | 2026-09-25 |
| Continue | อ้างสิทธิ์ | ตัวติดตั้งเขียนรูปแบบที่ไคลเอนต์เอกสาร และตัวเขียนนั้นถูกทดสอบกับรูปแบบ; ไม่มีใครฝั่ง Iris ได้เห็นมันเชื่อมต่อ | 2026-09-25 |
| VS Code | อ้างสิทธิ์ | ตัวติดตั้งเขียนรูปแบบที่ไคลเอนต์เอกสาร และตัวเขียนนั้นถูกทดสอบกับรูปแบบ; ไม่มีใครฝั่ง Iris ได้เห็นมันเชื่อมต่อ | 2026-09-25 |
| Cline | อ้างสิทธิ์ | ตัวติดตั้งเขียนรูปแบบที่ไคลเอนต์เอกสาร และตัวเขียนนั้นถูกทดสอบกับรูปแบบ; ไม่มีใครฝั่ง Iris ได้เห็นมันเชื่อมต่อ | 2026-09-25 |
| Zed | อ้างสิทธิ์ | ตัวติดตั้งเขียนรูปแบบที่ไคลเอนต์เอกสาร และตัวเขียนนั้นถูกทดสอบกับรูปแบบ; ไม่มีใครฝั่ง Iris ได้เห็นมันเชื่อมต่อ | 2026-09-25 |
| OpenAI Codex CLI | อ้างสิทธิ์ | ตัวติดตั้งเขียนรูปแบบที่ไคลเอนต์เอกสาร และตัวเขียนนั้นถูกทดสอบกับรูปแบบ; ไม่มีใครฝั่ง Iris ได้เห็นมันเชื่อมต่อ | 2026-09-25 |
| Gemini CLI | ตรวจสอบแล้ว | การทดสอบขับไคลเอนต์จริงในทุกการรัน CI | 2026-09-25 |
ทุกแถวพร้อมสิ่งที่ถูกตรวจสอบ: iris-eval.com/clients ไม่มีไคลเอนต์ใดถูกเรียกว่ารองรับโดยไม่มีแถว
npx -y @iris-eval/mcp-server install <client> เขียนแต่ละรายการเหล่านี้ให้คุณ ด้วยมือ ต่อไคลเอนต์:
Claude Desktop
แก้ไขไฟล์ config MCP ของคุณ:
- macOS:
~/Library/Application Support/Claude/claude_desktop_config.json - Windows:
%APPDATA%\Claude\claude_desktop_config.json
เพิ่ม JSON config ด้านบน จากนั้นรีสตาร์ท Claude Desktop
Claude Code
claude mcp add --transport stdio iris-eval -- npx -y @iris-eval/mcp-server
จากนั้นรีสตาร์ทเซสชัน (/clear หรือเปิดใหม่) เพื่อให้เครื่องมือโหลด
หมายเหตุสำหรับ Windows: อย่า ใช้ wrapper
cmd /c— มันทำให้เกิดปัญหาการแยกเส้นทาง คำสั่งnpxทำงานโดยตรง
Cursor
เพิ่ม JSON config ด้านบนไปที่ ~/.cursor/mcp.json (ทุกโปรเจกต์) หรือ .cursor/mcp.json ในเวิร์กสเปซ พร้อม "type": "stdio" ในรายการ iris-eval — เอกสารของ Cursor ทำเครื่องหมายว่าจำเป็น
Devin Desktop (Windsurf)
เพิ่ม JSON config ด้านบนไปที่ mcp_config.json: ~/.config/devin/mcp_config.json บน macOS และ Linux, %APPDATA%\devin\mcp_config.json บน Windows
Continue
บันทึก JSON config ด้านบนเป็นไฟล์ของตัวเองในโฟลเดอร์ mcpServers ของ Continue: ~/.continue/mcpServers/iris-eval.json (ทุกเวิร์กสเปซ) หรือ .continue/mcpServers/iris-eval.json ในหนึ่งเวิร์กสเปซ
VS Code (MCP ดั้งเดิม)
เพิ่มไปที่ .vscode/mcp.json ในเวิร์กสเปซของคุณ (หมายเหตุ: VS Code ใช้ servers, ไม่ใช่ mcpServers):
{
"servers": {
"iris-eval": {
"command": "npx",
"args": ["-y", "@iris-eval/mcp-server"]
}
}
}
Cline
เปิดแผง MCP Servers ของ Cline → Configure MCP Servers และเพิ่ม JSON config mcpServers ด้านบนไปที่ cline_mcp_settings.json (~/.cline/data/settings/cline_mcp_settings.json, แชร์โดย Cline ใน VS Code, JetBrains และ CLI)
Zed
เพิ่มไปที่ Zed settings.json:
{
"context_servers": {
"iris-eval": {
"command": "npx",
"args": ["-y", "@iris-eval/mcp-server"],
"env": {}
}
}
}
OpenAI Codex CLI
เพิ่มไปที่ ~/.codex/config.toml:
[mcp_servers.iris-eval]
command = "npx"
args = ["-y", "@iris-eval/mcp-server"]
Gemini CLI
เพิ่ม JSON config mcpServers ด้านบนไปที่ ~/.gemini/settings.json Gemini CLI เชื่อมต่อกับเซิร์ฟเวอร์ MCP เฉพาะในโฟลเดอร์ที่มันไว้วางใจ: ถ้า gemini mcp list แสดง iris-eval เป็น Disabled ให้รัน /permissions ในโฟลเดอร์นั้น
อื่นๆ ที่พูด MCP
Iris เป็นเซิร์ฟเวอร์ MCP แบบ stdio มาตรฐาน — หนึ่งคำสั่ง npx @iris-eval/mcp-server, ไม่มี SDK, ไม่มีการเปลี่ยนแปลงโค้ด ถ้าไคลเอนต์ของคุณรองรับ MCP มันรองรับ Iris รูปแบบ config ของไคลเอนต์เปลี่ยนไป; เมื่อไม่แน่ใจ ตรวจสอบเอกสาร MCP ของไคลเอนต์ของคุณและชี้มันไปที่คำสั่งนั้น
วิธีการติดตั้งอื่นๆ
# Global install (recommended for persistent data and faster startup)
npm install -g @iris-eval/mcp-server
iris-eval --dashboard
# Docker — two servers, two ports: 3000 = MCP HTTP transport,
# 6920 = dashboard (which also serves the POST /api/v1/traces ingest endpoint).
# The image binds 0.0.0.0 inside the container, so a key is required (see Production).
# The volume is the Iris home: the database, deployed rules and audit log persist in it.
docker run -p 3000:3000 -p 6920:6920 -v iris-data:/data \
-e IRIS_API_KEY="$(openssl rand -hex 32)" ghcr.io/iris-eval/mcp-server
เคล็ดลับ: การติดตั้งแบบ global (
npm install -g) เก็บ traces อย่างถาวรที่~/.iris/iris.dbด้วยnpx, traces ยังคงอยู่ในตำแหน่งเดียวกัน แต่การเริ่มต้นช้าลงเนื่องจากการแก้ไขแพ็กเกจ
สิ่งที่คุณได้รับ
| การบันทึก Trace | ต้นไม้สแปนแบบลำดับชั้นพร้อมความหน่วงต่อการเรียกเครื่องมือ การใช้โทเค็น และต้นทุนเป็น USD เก็บใน SQLite ค้นหาได้ทันที |
| การประเมินผลลัพธ์ | 25 กฎในตัวใน 4 หมวดหมู่: ความครบถ้วน ความเกี่ยวข้อง ความปลอดภัย ต้นทุน การตรวจจับ PII (21 รูปแบบ: SSN, บัตรเครดิต, โทรศัพท์, อีเมล, IBAN, วันเกิด, MRN, IP, คีย์ API, พาสปอร์ต, บวกโทเค็น AWS/Slack/SendGrid/GitHub/Google/npm/DigitalOcean, ข้อมูลรับรองใน URL, การกำหนดชื่อลับ, บล็อกคีย์ส่วนตัว PEM และวลี seed; วันเกิด หมายเลขเวชระเบียน พาสปอร์ต และวลี seed ทำงานเฉพาะเมื่ออยู่ข้างป้ายกำกับของมัน โดยการออกแบบ), การตรวจจับการฉีดพร้อมท์ (38 รูปแบบ, วลี + โครงสร้าง), การตรวจจับเอาต์พุต stub, การตรวจจับภาพหลอน (25 สัญญาณการสร้าง/ความขัดแย้งที่อิงบริบท — ส่ง input เพื่อยึดมันกับแหล่งข้อมูลของเอเจนต์), และหกกฎวิถีที่อ่านสิ่งที่เอเจนต์ทำ: การเรียกเครื่องมือที่ล้มเหลวโดยไม่รับทราบ, การเรียกซ้ำ (โดยการเรียก, โดยลำดับซ้ำ, หรือโดยเป้าหมายเมื่อคุณส่ง tools), การเรียกที่อาร์กิวเมนต์ถูกปฏิเสธโดย JSON Schema ของเครื่องมือเองและเอเจนต์ไม่เคยลองใหม่, ไฟล์ ไดเรกทอรี หรือ URL ที่คำตอบอ้างถึงซึ่งไม่ปรากฏในสิ่งที่เอเจนต์อ่าน, คำสั่งที่มาถึงภายใน TOOL RESULT และถูกปฏิบัติตามโดยการเรียกถัดไป, และงานที่ใช้การเรียกเครื่องมือมากกว่างบประมาณขั้นตอนของคุณ วิถีสามารถมาถึงเป็น tool_calls หรือเป็นสแปน TOOL ของ OpenTelemetry เพิ่มกฎที่กำหนดเองด้วย schema Zod |
| LLM-as-Judge | การให้คะแนนเชิงความหมายแบบไม่บังคับผ่าน Anthropic หรือ OpenAI — นำคีย์ API ของคุณเอง เจ็ดเทมเพลต ด้วยการตั้งค่า IRIS_RELEVANCE_JUDGE_MODEL, answers_the_ask ถามผู้ตัดสิน relevance และล้มเหลวคำตอบนอกหัวข้อ; โดยไม่มีการตั้งค่านั้น กฎอ่านคำขอเชิงศัพท์และแนะนำ วงเงินต้นทุนต่อการประเมินแบบแข็ง (IRIS_LLM_JUDGE_MAX_COST_USD_PER_EVAL, ค่าเริ่มต้น $0.25), ราคาต่อการประเมินเปิดเผยในผลลัพธ์ |
| การมองเห็นต้นทุน | ต้นทุนรวมของเอเจนต์ทั้งหมดในช่วงเวลาใดก็ได้ ตั้งเกณฑ์งบประมาณ รับการแจ้งเตือนเมื่อเอเจนต์ใช้เกิน trace ที่ส่งจำนวนโทเค็นและโมเดลแต่ไม่มีต้นทุน (ส่วนใหญ่เป็น trace ของ OpenTelemetry และเฟรมเวิร์ก) ถูกตั้งราคาที่ราคารายการของโมเดลและทำเครื่องหมายเป็นประมาณทุกที่ที่แสดง; pricing.models ใน config.json ตั้งราคาโมเดลที่ตารางในตัวไม่มี — docs/cost.md |
| แดชบอร์ดเว็บ | UI โหมดมืดแบบเรียลไทม์ที่ลงจอดบนความล้มเหลว แย่ที่สุดและใหม่ที่สุดก่อน — การแสดงภาพ trace พร้อมการค้นหาข้อความเต็มในทุกข้อความของ trace ผลการประเมิน การแยกต้นทุน และจานคำสั่ง (⌘K) ที่ค้นหากฎ traces และ evals ของคุณเอง |
| Local-first | ทุกอย่างอยู่ใน SQLite บนดิสก์ของคุณ ไม่มีบัญชี ไม่มีการลงทะเบียน ไม่มี telemetry HTTP ขาออกเกิดขึ้นเฉพาะที่คุณเลือก: คีย์ LLM-judge ของคุณเอง การดึงการอ้างอิง ตัวส่งออก OTel ที่คุณกำหนดค่า หรือ webhook ที่คุณตั้ง |
ที่ที่สิ่งนี้จะไปต่อ: แผนที่ความสามารถ — ทุกคำถามที่ Iris สามารถถูกถามเกี่ยวกับทุกหัวข้อ พร้อมสิ่งที่มันมีและสิ่งที่มันขาด — และ สามแทร็ก
วัดผล ไม่ใช่กล่าวอ้าง
ทุกกฎในตัวมีค่า precision, recall และ F1 ที่เผยแพร่พร้อมช่วงความเชื่อมั่น 95% ซึ่งวัดจากคลังข้อความที่ติดป้ายกำกับซึ่งอยู่ใน repository นี้ (proof/corpus/) และสร้างใหม่ได้ด้วยคำสั่งเดียว — npm run proof — แบบออฟไลน์ โดยไม่ต้องใช้คีย์หรือโมเดลในกระบวนการ ตัวเลขเหล่านั้นมีสองประเภทที่แตกต่างกัน และหน้าเว็บไม่เคยนำมารวมกัน: กฎบางข้อวัดเทียบกับป้ายกำกับที่โมเดลให้โดยการอ่านความล้มเหลวนั้นเอง ซึ่งวัดการตรวจจับ ส่วนที่เหลือตรวจสอบเทียบกับคำนิยามที่บันทึกไว้ของตัวเอง ซึ่งนำไปใช้อย่างอิสระ ซึ่งแสดงว่าโค้ดนำสูตรไปใช้ได้จริง และไม่ได้บอกว่าสูตรจับความล้มเหลวได้หรือไม่ proof/RESULTS.md และหน้าหลักฐานทำเครื่องหมายแต่ละกฎ CI จะรันการวัดซ้ำในทุก pull request และจะล้มเหลวหากตัวเลขที่คอมมิตแตกต่างจากที่โค้ดสร้างขึ้น ดังนั้นกฎจะไม่เปลี่ยนแปลงโดยที่ตัวเลขไม่เปลี่ยนตามไปด้วย ตัวเลขอยู่ที่ iris-eval.com/proof และใน proof/RESULTS.md; วิธีสร้างคลังข้อความ สิ่งที่ไม่ใช่ และวิธีอ่านช่วงความเชื่อมั่นอยู่ใน docs/proof.md คลังข้อความเป็นข้อมูลสังเคราะห์และติดป้ายโดยโมเดล — ป้ายกำกับจากมนุษย์แบบ blinded ยังอยู่ระหว่างดำเนินการ และหน้าเว็บระบุไว้เช่นนั้น; node proof/blind-sample.mjs สุ่มตัวอย่างที่ทำซ้ำได้ซึ่งจะยุติเรื่องนี้
เครื่องมือ MCP
Iris ลงทะเบียนเครื่องมือสิบสองรายการที่เอเจนต์ที่เข้ากันได้กับ MCP ทุกรายการสามารถเรียกใช้ได้ — วงจรชีวิตของ trace และกฎ การเปรียบเทียบข้ามการรัน LLM-as-judge และการตรวจสอบการอ้างอิงเชิงความหมาย:
log_trace— บันทึกการทำงานของเอเจนต์ด้วย spans, การเรียกเครื่องมือ, การใช้ token และต้นทุน; ส่งevaluate: trueเพื่อให้คะแนนในการเรียกเดียวกันevaluate_output— ให้คะแนนคุณภาพเอาต์พุตเทียบกับกฎความครบถ้วน ความเกี่ยวข้อง ความปลอดภัย และต้นทุน (แบบฮิวริสติก กำหนดตายตัว ไม่มีค่าใช้จ่าย)get_traces— ค้นหา trace ที่เก็บไว้ด้วยการกรอง การแบ่งหน้า และการรองรับช่วงเวลา และค้นหารันที่เอเจนต์พูดบางอย่างด้วยq: การค้นหาข้อความเต็มเหนืออินพุต เอาต์พุต ค่าการเรียกเครื่องมือ และ metadata แบบจัดอันดับ โดยทำเครื่องหมายคำที่ตรงกันlist_rules— แสดงรายการกฎ eval แบบกำหนดเองที่ใช้งานอยู่ (อ่านอย่างเดียว)deploy_rule— ลงทะเบียนกฎ eval แบบกำหนดเองใหม่เพื่อให้ทำงานในทุกevaluate_outputของหมวดหมู่นั้นdelete_rule— ลบกฎแบบกำหนดเองที่ใช้งานอยู่ (ทำลายล้าง, idempotent)delete_trace— ลบ trace ที่เก็บไว้รายการเดียวด้วย ID (ทำลายล้าง, จำกัดเฉพาะ tenant)evaluate_with_llm_judge— การประเมินเชิงความหมายผ่าน LLM (Anthropic หรือ OpenAI) เทมเพลตเจ็ดแบบ: accuracy, helpfulness, safety, correctness, faithfulness, task_completed, relevance จำกัดต้นทุน เปิดเผยราคาต่อการประเมิน นำคีย์ API ของคุณเองมา (IRIS_ANTHROPIC_API_KEYหรือIRIS_OPENAI_API_KEY) — Iris ไม่เป็นพร็อกซีหรือส่งต่อการเรียก LLMverify_citations— ดึงการอ้างอิงจากเอาต์พุต (แบบตัวเลข, ผู้แต่ง-ปี, URL, DOI), ดึงแหล่งที่มาผ่านตัวแก้ที่ป้องกัน SSRF + อนุญาตเฉพาะโดเมน และใช้ผู้ตัดสิน LLM เพื่อตรวจสอบว่าแต่ละแหล่งสนับสนุนข้อกล่าวอ้างที่อ้างจริงหรือไม่ การส่ง HTTP ขาออกแบบเลือกใช้ ข้อกำหนด BYOK เดียวกับevaluate_with_llm_judgecompare_runs— การเปลี่ยนแปลงทำให้เอเจนต์แย่ลงหรือไม่? เปรียบเทียบสองรันของการประเมินที่เก็บไว้: การทดสอบแบบ paired exact เมื่อรันใช้คีย์เคสเดียวกัน ช่วงความแตกต่างในกรณีอื่น "บอกไม่ได้" อย่างตรงไปตรงมาพร้อมจำนวนเคสที่ต้องใช้ หรือ "เทียบเท่าภายในระยะเผื่อ" ทุกกฎมีการทดสอบแบบด้านเดียวของตัวเอง ซึ่งแก้ไขร่วมกัน (Benjamini–Hochberg) เพื่อให้กฎยี่สิบข้อไม่สามารถสร้างการถดถอยปลอมได้compare_traces— เอเจนต์ตอบคำถามเดียวกันได้น่าเชื่อถือแค่ไหน? อัตราผ่านรายเคสพร้อมช่วง ความไม่เสถียรก่อน และอัตราโดยรวมที่เคารพการทำซ้ำevaluate_runs— ให้คะแนนทุก trace ในรันใหม่ภายใต้กฎปัจจุบันเป็นรันใหม่ เพื่อให้การเปลี่ยนแปลงกฎไม่ถูกอ่านว่าเป็นการเปลี่ยนแปลงเอเจนต์
เปิดใช้ผู้ตัดสิน LLM (ไม่บังคับ; กฎกำหนดตายตัวไม่เคยต้องใช้)
- รับคีย์ API จาก Anthropic หรือ OpenAI
- ใส่ใน environment ของกระบวนการที่รัน Iris ไม่ใช่แค่ shell ของคุณ Claude Code, Claude Desktop, Cursor และไคลเอ็นต์ MCP ส่วนใหญ่: บล็อก "env" ของรายการ iris-eval ใน config MCP ของคุณ — "iris-eval": { "command": "npx", "args": ["-y", "@iris-eval/mcp-server"], "env": { "IRIS_ANTHROPIC_API_KEY": "sk-ant-..." } } (IRIS_OPENAI_API_KEY สำหรับคีย์ OpenAI) Docker: -e IRIS_ANTHROPIC_API_KEY=... ในคำสั่งรัน HTTP หรือ CI: export ก่อนเริ่ม iris-eval
- รีสตาร์ทเซสชัน MCP กระบวนการที่รันอยู่จะไม่เห็นตัวแปรที่ตั้งหลังจากเริ่มต้น
- ยืนยันจากภายในไคลเอ็นต์ของคุณ: อ่าน iris://capabilities — judge.enabled ต้องเป็น true ที่นั่น คีย์ที่ export ใน shell ของคุณจะไม่ถูกส่งไปยังกระบวนการที่ไคลเอ็นต์ของคุณสร้างขึ้น เว้นแต่ config จะระบุไว้ บนเครื่อง
npx @iris-eval/mcp-server --self-testพิมพ์บรรทัดผู้ตัดสินสำหรับ shell นั้น และ GET /api/v1/health รายงาน judge.enabled บนแดชบอร์ดที่รันอยู่ - การ์ดค่าใช้จ่าย: แต่ละการเรียกถูกจำกัดโดย IRIS_LLM_JUDGE_MAX_COST_USD_PER_EVAL (ค่าเริ่มต้น 0.25 USD) และถูกปฏิเสธก่อนการใช้จ่ายใดๆ หากกรณีเลวร้ายที่สุดจะเกินนั้น Iris เรียกผู้ให้บริการโดยตรงด้วยคีย์ของคุณและไม่เคยเป็นพร็อกซี
- ไม่บังคับ: ตั้ง IRIS_RELEVANCE_JUDGE_MODEL เป็นรหัสโมเดลที่มีราคา (เช่น claude-haiku-4-5) เพื่อให้ answers_the_ask ถามผู้ตัดสินว่าคำตอบแต่ละข้อตอบคำถามของมันหรือไม่ และล้มเหลวหากนอกประเด็น นั่นคือการเรียกผู้ตัดสินหนึ่งครั้งต่อการประเมินที่มีอินพุต ด้วยคีย์ของคุณและภายใต้การจำกัดข้างต้น; คีย์เพียงอย่างเดียวไม่เคยเปิดใช้งาน แต่ละการเรียกส่งอินพุตและเอาต์พุตนั้นไปยังผู้ให้บริการของโมเดล โดยแทนที่แฟล็ก no_pii สำหรับข้อมูลส่วนบุคคลและข้อมูลรับรองก่อน (IRIS_RELEVANCE_JUDGE_REDACT=off ส่งตามที่เป็น) ใช้จ่ายสูงสุด IRIS_RELEVANCE_JUDGE_DAILY_BUDGET_USD ต่อวัน UTC (ค่าเริ่มต้น 1 USD) และเรียกสูงสุด IRIS_RELEVANCE_JUDGE_MAX_CALLS_PER_REQUEST ครั้งต่อคำขอ (ค่าเริ่มต้น 20); เกินอย่างใดอย่างหนึ่ง answers_the_ask อ่านคำถามแบบศัพท์และบอกว่าทำไม
เมื่อกำหนดค่า IRIS_OTEL_ENDPOINT แล้ว การเรียก log_trace ยังส่งออก JSON ผ่าน OTLP/HTTP แบบ best-effort ไปยังตัวเก็บ OpenTelemetry ใดๆ (Jaeger, Grafana Tempo, Datadog OTLP, Honeycomb ฯลฯ) ดู docs/otel-integration.md
วิธีตัดสิน passed
evaluate_output คืนทั้งแฟล็ก score และ passed — พวกมันตอบคำถามต่างกัน:
score(0..1) คือค่าเฉลี่ยถ่วงน้ำหนักข้ามกฎที่รัน — การไล่ระดับคุณภาพpassedคือคำตัดสิน ship/no-ship และไม่เคยใช้คะแนนสำหรับมัน ตัวประกอบอ่านแต่ละกฎตามประเภทของข้อกล่าวอ้าง: นโยบายที่คุณกำหนดค่าเป็น gate; ตัวตรวจจับวิกฤตเป็น veto; การตรวจสอบวิกฤตที่ถูกขอและตอบไม่ได้ทำให้คำตัดสินเป็น unknown (passed: false) แทนที่จะ clean; ตัวตรวจจับที่เหลือรวมกันเป็นความน่าจะเป็นเดียวว่าเอาต์พุตไม่ดี ชั่งกับอัตราส่วนการสูญเสียที่คุณระบุในeval.falsePassCost(ค่าเริ่มต้น 1 ดังนั้นจุดตัดคือ 0.5)verdict.basisระบุเลเยอร์ที่ตัดสินและverdict.byระบุกฎ และverdict.alsoระบุทุกเลเยอร์ที่ตามมาที่จะตัดสินมันด้วย;interpretations[]บอกว่าทำไมกฎที่ล้มเหลวจึงไม่ตัดสินและการตั้งค่าใดจะเปลี่ยนสิ่งนั้น และระบุคำถามใดที่ไม่ถูกตัดสินและอินพุตที่จะทำให้ตัดสินได้
การละเมิดความปลอดภัยจริง hard-fail โดยค่าเริ่มต้น no_pii, no_injection_patterns และ no_blocklist_words เป็น กฎวิกฤต: หากหนึ่งล้มเหลว eval รายงาน passed: false ไม่ว่ากฎอื่นจะได้คะแนนดีแค่ไหน และการตอบสนองระบุผู้กระทำผิดใน critical_failures SSN ที่รั่วไม่สามารถเฉลี่ยให้หายไปได้ กฎในตัวใดเป็นวิกฤตคือการตั้งค่าการปรับใช้ (eval.criticalRules / eval.nonCriticalRules); ผลกฎทุกข้อมีแฟล็ก critical ที่มีผลและ criticalSource และ list_rules รายงานรายชื่อที่เซิร์ฟเวอร์นี้ใช้ กฎแบบกำหนดเองที่ปรับใช้ด้วย severity: "high" หรือ "critical" hard-fail ในลักษณะเดียวกัน; ระดับความรุนแรง low/medium มีผลกับคะแนนเท่านั้น ขอบเขตหนึ่งที่ควรรู้ ระบุแบบเดียวกันบนทุกพื้นผิว: กฎวิกฤตที่ ข้าม (บริบทหายไป คำนิยามเสีย หรือ regex ถูกฆ่าที่งบประมาณ sandbox) ไม่ได้ตัดสินเอาต์พุตและไม่ veto — ทุกกฎดังกล่าวถูกระบุชื่อใน critical_skipped gate ที่ต้องปิดเมื่อล้มเหลวถือว่า critical_skipped ที่ไม่ว่างเป็น unknown ไม่ใช่ clean และอาจถือว่าการข้าม budgetExceeded ใดๆ ใน rule_results ในลักษณะเดียวกัน
สำหรับ CI gates: หากคุณละเว้น eval_type ทุก bundle รัน — completeness, relevance, safety, cost และกฎแบบกำหนดเองใดๆ — และการตอบสนองพูด eval_type: "all" พร้อม note ว่าค่าเริ่มต้นรัน บวกแผนที่ categories ต่อ bundle bundle ที่ไม่มีอะไรให้ตัดสิน (cost โดยไม่มี cost_usd, relevance โดยไม่มี input) รายงาน passed: null ที่นั่น — ไม่ถูกประเมิน ไม่ล้มเหลว — และไม่นับรวมในคำตัดสิน การตอบสนองสะท้อน eval_type ที่รันเสมอ เพื่อให้ gate ของคุณตรวจสอบความครอบคลุมได้; ใช้ passed สำหรับคำตัดสินและระบุ bundle เฉพาะเมื่อคุณต้องการรันที่แคบลง
การสร้างกฎแบบกำหนดเอง
สองวิธีในการเพิ่มกฎ Inline กฎมากับการเรียก evaluate_output หนึ่งครั้ง (custom_rules, สูงสุด 10 ต่อการเรียก); พวกมันทำงานพร้อมกับ bundle eval_type ที่คุณเลือก หรือเพียงลำพังด้วย eval_type: "custom" Deployed กฎลงทะเบียนครั้งเดียวด้วย deploy_rule, คงอยู่ใน custom-rules.json ภายใต้ Iris home ของคุณ และทำงานในทุก evaluate_output ในอนาคตของ evalType คำนิยามมีรูปร่างเดียวกันทั้งสองวิธี:
| ฟิลด์ | จำเป็น | คืออะไร |
|---|---|---|
name | ใช่ | 1–80 อักขระ; ปรากฏเป็น ruleName ในผลลัพธ์ |
type | ใช่ | หนึ่งใน regex_match · regex_no_match · min_length · max_length · contains_keywords · excludes_keywords · json_schema · cost_threshold |
config | ใช่ | คีย์สำหรับประเภทนั้น: pattern (+ flags ไม่บังคับ) สำหรับสองประเภท regex · min_length / max_length (จำนวนอักขระ) · keywords (+ threshold ไม่บังคับ, 0–1, ค่าเริ่มต้น 1 = ทั้งหมดต้องปรากฏ) สำหรับสองประเภทคีย์เวิร์ด · {} สำหรับ json_schema · max_cost ใน USD สำหรับ cost_threshold |
weight | ไม่ | น้ำหนักในคะแนน; ค่าเริ่มต้น 1 |
deploy_rule ห่อคำนิยามด้วย name, description ไม่บังคับ, evalType (completeness · relevance · safety · cost · custom) และ severity ระดับความรุนแรงบอกว่า ความล้มเหลว หมายถึงอะไร: low/medium ลดคะแนนเท่านั้น; high/critical hard-fail การประเมิน — passed: false, กฎที่ระบุชื่อใน critical_failures — ไม่ว่าคะแนนถ่วงน้ำหนักจะพูดอะไร กฎที่ข้าม (กฎ cost_threshold โดยไม่มี cost_usd, หรือ regex ที่ถูกฆ่าที่งบประมาณ sandbox 100 ms) ไม่ได้ตัดสินเอาต์พุตและถูกระบุใน critical_skipped แทน ปรับใช้กฎวิกฤตที่ห้ามชื่อโฮสต์ภายในในสิ่งที่เอเจนต์พูด:
{
"name": "no_internal_hostnames",
"description": "Output must not mention internal hostnames.",
"evalType": "safety",
"severity": "critical",
"definition": {
"name": "no_internal_hostnames",
"type": "regex_no_match",
"config": { "pattern": "\\b[a-z0-9-]+\\.internal\\.example\\b", "flags": "i" }
}
}
การตอบสนองคือกฎที่คงอยู่ — เก็บ id สำหรับ delete_rule:
{ "rule": { "id": "rule-588823d0", "name": "no_internal_hostnames", "evalType": "safety", "severity": "critical", "enabled": true, "version": 1, "definition": { "…": "…" } } }
จาก evaluate_output ถัดไปด้วย eval_type: "safety", เอาต์พุตที่กล่าวถึง db-primary.internal.example กลับมาเป็น passed: false พร้อม critical_failures: ["no_internal_hostnames"] — แม้ว่ากฎความปลอดภัยในตัวทั้งห้าผ่านและคะแนนถ่วงน้ำหนักคือ 0.895 รูปแบบ regex ต้องผ่านการตรวจสอบ ReDoS ที่เวลาปรับใช้และรันในเวิร์กเกอร์ sandbox ภายใต้กำหนดเวลา 100 ms เสมอ list_rules แสดงสิ่งที่ปรับใช้; ตัวประกอบกฎของแดชบอร์ดสร้างรูปร่างเดียวกันจากความล้มเหลวที่คุณคลิก ข้อมูลอ้างอิงเต็ม การให้คะแนนต่อประเภท และตัวอย่างที่ใช้งานได้: docs/custom-rules.md
สคีมาเครื่องมือเต็มและการกำหนดค่า: iris-eval.com
ฟีเจอร์โฮสต์
Iris รันบนเครื่องของคุณทั้งหมดในวันนี้ และทุกสิ่งที่ทำฟรีและได้รับอนุญาต MIT โดยไม่มีขีดจำกัดและไม่มีบัญชี โฮสต์สตอเรจ ประวัติทีมที่แชร์ร่วมกัน และการแจ้งเตือน อยู่ระหว่างการพิจารณา ไม่ได้อยู่ระหว่างการพัฒนา ยังไม่มีราคา และไม่มีอะไรให้ซื้อ หากประวัติที่แชร์ร่วมกันมีประโยชน์สำหรับคุณ รายชื่อรอ คือวิธีที่เราจะค้นหาว่ามันคุ้มค่าที่จะสร้างหรือไม่ — มันไม่ได้ผูกมัดคุณแต่อย่างใด
มีข้อผูกมัดสองข้อที่คงไว้ไม่ว่าในกรณีใด: สิ่งที่ฟรีในวันนี้จะไม่ถูกย้ายไปอยู่หลังเพย์วอลล์ และ จะไม่มีการอ้างสิทธิ์การรับรองความสอดคล้องก่อนที่จะได้รับการรับรองจริง
ตัวอย่าง
- การตั้งค่า Claude Desktop — การกำหนดค่า MCP สำหรับโหมด stdio และ HTTP
- TypeScript — MCP SDK client — เชื่อมต่อและเรียกใช้เครื่องมือ
- HTTP transport (TS + Python) — โค้ดไคลเอนต์แบบเต็มสำหรับการผสานรวมแบบ REST
- เอเจนต์ LangGraph ให้คะแนนทีละรัน (Python) —
IrisCallbackHandlerใน callbacks ของกราฟ; CI รันกราฟเดียวกันกับโมเดลที่เขียนสคริปต์ไว้ - ทีม CrewAI บน OpenTelemetry (Python) — ตัว instrumentor ของ OpenInference ส่งตรงไปยังประตู OTLP ของ Iris, สูตร CrewAI เป็นสคริปต์
- เอเจนต์ OpenAI Agents SDK บน OpenTelemetry (Python) และ (JavaScript), และ เอเจนต์ LlamaIndex — แต่ละสูตรเป็นสคริปต์ที่ CI รันกับเซิร์ฟเวอร์ Iris จริง
ชุมชน
- GitHub Issues — รายงานบั๊กและคำขอฟีเจอร์
- GitHub Discussions — คำถามและไอเดีย
- คู่มือการมีส่วนร่วม — วิธีมีส่วนร่วม
- HTTP Ingest — การจับ trace แบบกำหนดได้ผ่าน
POST /api/v1/traces - แผนที่ความสามารถ — ทุกคำถามที่ถาม Iris ได้ และสิ่งที่ขาดหายไป
- นโยบายเวอร์ชัน — แต่ละหมายเลขเวอร์ชันสัญญาอะไร และอะไรที่ต้องเป็นจริงก่อนเวอร์ชัน 1.0
การกำหนดค่าและความปลอดภัย
อาร์กิวเมนต์ CLI
| แฟล็ก | ค่าเริ่มต้น | คำอธิบาย |
|---|---|---|
--transport | stdio | ประเภท transport: stdio หรือ http |
--port | 3000 | พอร์ต HTTP transport |
--db-path | ~/.iris/iris.db | เส้นทางฐานข้อมูล SQLite |
--config | ~/.iris/config.json | เส้นทางไฟล์การกำหนดค่า |
--api-key | — | คีย์ API สำหรับการตรวจสอบสิทธิ์ HTTP (transport และแดชบอร์ด รวมถึง POST /api/v1/traces) |
--dashboard | false | เปิดใช้งานแดชบอร์ดเว็บ นอกจากนี้ยังเป็นวิธีเดียวที่ POST /api/v1/traces ingest endpoint จะเริ่มทำงาน — มันไม่เริ่มทำงานโดยปริยายกับ --transport http |
--dashboard-port | 6920 | พอร์ตแดชบอร์ด |
--dashboard-host | 127.0.0.1 | ที่อยู่ bind ของแดชบอร์ด ค่าเริ่มต้นเป็น loopback — แดชบอร์ดไม่มีการตรวจสอบสิทธิ์เว้นแต่ตั้งค่า --api-key ดังนั้นการ bind เกิน loopback จะเปิดเผยประวัติ trace ทั้งหมดของคุณ |
--demo | false | ใส่ข้อมูลตัวอย่างฐานข้อมูล (แยกจาก trace จริงของคุณ) และให้บริการแดชบอร์ดกับข้อมูลนั้น |
--demo-clear | false | ลบฐานข้อมูลตัวอย่างและออก |
--self-test | false | รันการวินิจฉัยการติดตั้งแบบออฟไลน์ในโฮมชั่วคราวที่แยกออก จากนั้นออก (0 = ปกติ, 1 = มีรายการตรวจสอบล้มเหลว) มันยังอ่านฐานข้อมูลที่กำหนดค่าไว้ แบบอ่านอย่างเดียว และล้มเหลวเมื่อเวอร์ชันนี้หรือไคลเอนต์ MCP ที่ปักหมุดไว้ไม่สามารถเปิดได้ |
--purge | false | ลบ ทุก trace, span และ evaluation ที่เก็บไว้จากฐานข้อมูลที่กำหนดค่า บีบอัดไฟล์และตัดทอน write-ahead log เพื่อให้ข้อความที่ลบไม่หลงเหลือบนดิสก์ จากนั้นออก กฎที่ปรับใช้ บันทึกการตรวจสอบ และการตั้งค่าถูกเก็บไว้ ไม่สามารถย้อนกลับได้ หยุดเซิร์ฟเวอร์ Iris ที่รันอยู่ก่อน — ไฟล์ถูกบีบอัดในที่ ปฏิเสธการรวมกับ --demo, --demo-clear หรือ --self-test |
--version | — | พิมพ์เวอร์ชันเปล่า (เช่น 1.2.3) ไปยัง stdout และออก 0 ไม่อ่านอะไรภายใต้ Iris home ของคุณ |
สามคำสั่งรับอาร์กิวเมนต์ของตัวเองและออก: iris-eval ingest โหลด trace จากไฟล์หรือ stdin (ประตู CI ไม่ต้องใช้เซิร์ฟเวอร์), iris-eval export traces|evaluations --format csv|jsonl เขียนสิ่งที่เก็บไว้ กรองเหมือนรายการของแดชบอร์ด ไปยัง stdout หรือ --out (docs/api-reference.md), และ iris-eval install <client> เขียน Iris ลงในการกำหนดค่าของไคลเอนต์ MCP — --uninstall นำออก, --list แสดงไคลเอนต์ที่พบบนเครื่องนี้และ Iris ที่แต่ละตัวรัน, --upgrade ย้ายทุกไคลเอนต์ที่รัน Iris ไปยังเวอร์ชันนี้ (เชื่อมต่อเอเจนต์ของคุณเอง, การอัปเดต) ไม่มีคำสั่งใดเริ่มเซิร์ฟเวอร์
config.json ถูกตรวจสอบเมื่อ Iris เริ่มทำงาน คีย์ที่ Iris ไม่อ่าน — พิมพ์ผิดเช่น eval.critcalRules, คีย์จากเครื่องมืออื่น — หรือค่าที่มีประเภทผิด จะปฏิเสธการเริ่มต้นด้วยหนึ่งประโยคที่ระบุคีย์เต็ม คีย์ที่อาจหมายถึง หรือประเภทที่ต้องการ ไม่มีอะไรในไฟล์ที่ถูกเพิกเฉยอย่างเงียบ ๆ
ตัวแปรสภาพแวดล้อม
ทุกตัวแปรที่ --help เอกสาร แฟล็ก CLI มีลำดับความสำคัญเหนือตัวแปรสภาพแวดล้อมเมื่อตั้งค่าทั้งสอง
| ตัวแปร | คำอธิบาย |
|---|---|
IRIS_TRANSPORT | ประเภท transport (stdio หรือ http) |
IRIS_HOST | ที่อยู่ bind ของ HTTP transport (ค่าเริ่มต้น 127.0.0.1) |
IRIS_PORT | พอร์ต HTTP transport (1-65535, ค่าเริ่มต้น 3000) |
IRIS_HOME | ไดเรกทอรีสำหรับไฟล์ต่อผู้ใช้ทั้งหมด: config.json, iris.db, custom-rules.json, audit.log, preferences.json (ค่าเริ่มต้น ~/.iris) |
IRIS_DB_PATH | เส้นทางฐานข้อมูล SQLite (แทนที่ IRIS_HOME สำหรับ DB เท่านั้น) |
IRIS_SQLITE_DRIVER | ไดรเวอร์ SQLite ใดที่ถือฐานข้อมูล: native (better-sqlite3, ค่าเริ่มต้น) หรือ node (Node ในตัว node:sqlite, Node 22.13+) ไม่ได้ตั้งค่า: native และเมื่อโมดูล native ไม่สามารถโหลดได้ (หรือเป็นบิลด์ที่จะหยุดทำงานบน Node นี้) Iris เตือนครั้งเดียวและถอยกลับไปใช้ในตัว |
IRIS_SEARCH_BUDGET_MS | การค้นหา trace หนึ่งครั้ง (q) อาจอ่านนานเท่าใดก่อนที่จะตอบด้วยรายการที่ตรงที่พบจนถึงตอนนี้และ search.complete: false, เป็นมิลลิวินาที (50 ถึง 60000, ค่าเริ่มต้น 1000) การค้นหาถือคำขออื่นไว้ขณะอ่าน ดังนั้นนี่คือเวลานานที่สุดที่มันทำให้พวกเขารอได้ นอกจากนี้ storage.searchBudgetMs ใน config.json |
IRIS_SEARCH_INDEX | on (ค่าเริ่มต้น) หรือ off off ไม่เก็บดัชนี full-text ของ trace: การเขียนเก็บ trace และไม่มีอะไรเพิ่มเติม และการค้นหา trace (q) อ่าน trace เองภายใน IRIS_SEARCH_BUDGET_MS, ใหม่ที่สุดก่อน ดังนั้นในสโตร์ขนาดใหญ่มันสามารถตอบด้วยส่วนหนึ่งของรายการที่ตรง (search.complete: false) การปิดมันลบดัชนีที่ฐานข้อมูลเก็บไว้; การเปิดอีกครั้งสร้างใหม่ในเบื้องหลัง นอกจากนี้ storage.searchIndex ใน config.json |
IRIS_LOG_LEVEL | ระดับบันทึก: debug, info, warn, error |
IRIS_DASHBOARD | true/1/yes/on เปิดใช้งานแดชบอร์ดเว็บ; false/0/no/off ปิดใช้งาน (ยังแทนที่ dashboard.enabled ใน config.json) |
IRIS_DASHBOARD_PORT | พอร์ตแดชบอร์ด (1-65535, ค่าเริ่มต้น 6920) |
IRIS_WEBHOOK_URL | ผู้รับของ webhook ที่ยิงเมื่อมีช่วงเวลา — รวมเข้ากับ notify.webhook ใน config.json (docs/webhooks.md) |
IRIS_WEBHOOK_SECRET | คีย์เซ็นชื่อของ webhook (สตริงใด ๆ หรือ whsec_ + base64); รูปแบบ iris ปฏิเสธการรันโดยไม่มีคีย์ |
IRIS_DASHBOARD_HOST | ที่อยู่ bind ของแดชบอร์ด (ค่าเริ่มต้น 127.0.0.1) |
IRIS_API_KEY | คีย์ API สำหรับการตรวจสอบสิทธิ์ HTTP จำเป็นต้อง bind HTTP transport หรือแดชบอร์ดเกิน loopback (0.0.0.0, ที่อยู่ LAN, คอนเทนเนอร์): หากไม่มีเซิร์ฟเวอร์ปฏิเสธการเริ่ม |
IRIS_API_KEY_FILE | เส้นทางไปยังไฟล์ที่เนื้อหาที่ตัดช่องว่างคือคีย์ API — รูปแบบไฟล์ลับที่ Docker และ Kubernetes เมานต์ เพื่อให้คีย์ไม่เคยอยู่ในบล็อกสภาพแวดล้อม ตั้งค่านี้หรือ IRIS_API_KEY, ไม่ใช่ทั้งสอง |
IRIS_ALLOW_UNAUTHENTICATED | ตั้งเป็น 1 เพื่อรัน bind ที่ไม่ใช่ loopback โดยไม่มีคีย์โดยตั้งใจ (ยกเลิกการปฏิเสธ; เครือข่ายเป็นขอบเขตของคุณแล้ว) |
IRIS_ALLOWED_ORIGINS | รายการอนุญาตต้นทางที่คั่นด้วยเครื่องหมายจุลภาค แดชบอร์ด: ส่วนหัว CORS (รองรับ globs เช่น http://localhost:*) HTTP transport: รายการอนุญาต Origin แบบตรงทั้งหมดสำหรับการป้องกัน DNS-rebinding (ไม่สนใจ globs; ต้นทาง loopback ของเซิร์ฟเวอร์เองได้รับอนุญาตเสมอ) |
IRIS_NO_AUTO_LAUNCH | ตั้งเป็น 1 เพื่อปิดการเปิดแดชบอร์ดอัตโนมัติครั้งแรก |
IRIS_ANTHROPIC_API_KEY | จำเป็นโดย evaluate_with_llm_judge + verify_citations กับ provider=anthropic |
IRIS_OPENAI_API_KEY | จำเป็นโดย evaluate_with_llm_judge + verify_citations กับ provider=openai |
IRIS_LLM_JUDGE_MAX_COST_USD_PER_EVAL | ขีดจำกัดต้นทุนสูงสุดต่อการเรียกผู้ตัดสิน LLM (ค่าเริ่มต้น 0.25) |
IRIS_RELEVANCE_JUDGE_MODEL | รหัสโมเดลผู้ตัดสินแบบมีราคา (เช่น claude-haiku-4-5) เมื่อตั้งค่า พร้อมคีย์ของผู้ให้บริการนั้น answers_the_ask ถามผู้ตัดสิน LLM นี้ในทุก evaluation ที่มี input และตรวจสอบคำตัดสินความเกี่ยวข้อง — หนึ่งการเรียกผู้ตัดสินต่อ evaluation ภายใต้ขีดจำกัดต้นทุนด้านบนและสองขีดจำกัดด้านล่าง input และ output ของแต่ละ evaluation ดังกล่าวถูกส่งไปยังผู้ให้บริการของโมเดลนั้น (Anthropic หรือ OpenAI) ด้วยคีย์ของคุณ โดยข้อมูลส่วนบุคคลและข้อมูลรับรองที่ no_pii แฟล็กถูกแทนที่ก่อน ไม่ได้ตั้งค่า (ค่าเริ่มต้น) answers_the_ask อ่านคำขอแบบ lexical และแนะนำ และไม่มีการส่งอะไร (docs/llm-as-judge.md) |
IRIS_RELEVANCE_JUDGE_DAILY_BUDGET_USD | ผู้ตัดสินความเกี่ยวข้องอาจใช้จ่ายต่อวัน UTC ต่อเทนแนนต์เท่าใด (ค่าเริ่มต้น 1) เก็บในฐานข้อมูล ดังนั้นการรีสตาร์ทไม่รีเซ็ต การเรียกเกิดขึ้นก็ต่อเมื่อกรณีแย่ที่สุดพอดีกับที่เหลือ; เกินนั้น answers_the_ask อ่านคำขอแบบ lexical และ judge.withheld คือ daily_budget 0 หยุดทุกการเรียก |
IRIS_RELEVANCE_JUDGE_MAX_CALLS_PER_REQUEST | การเรียกผู้ตัดสินความเกี่ยวข้องที่คำขอหนึ่งอาจทำได้ (ค่าเริ่มต้น 20): ชุด OTLP หรือ evaluate_runs re-score ตัดสิน 20 trace แรกและอ่านส่วนที่เหลือแบบ lexical พร้อม judge.withheld: "request_cap" |
IRIS_RELEVANCE_JUDGE_REDACT | on (ค่าเริ่มต้น): ทุก span ที่ no_pii แฟล็ก (ข้อมูลส่วนบุคคลและข้อมูลรับรอง) ใน input และ output ถูกแทนที่ด้วยเครื่องหมาย [REDACTED:<kind>#<n>] ก่อนส่งไปยังผู้ตัดสินความเกี่ยวข้อง off ส่งตามที่เป็น |
IRIS_CITATION_ALLOW_FETCH | ตั้งเป็น 1 เพื่ออนุญาต HTTP ขาออกใน verify_citations (ปิดโดยค่าเริ่มต้น) |
IRIS_CITATION_DOMAINS | รายการอนุญาตชื่อโฮสต์ที่คั่นด้วยเครื่องหมายจุลภาคสำหรับ verify_citations (การจับคู่ส่วนต่อท้าย) |
IRIS_OTEL_ENDPOINT | เปิดใช้งานการส่งออก trace JSON แบบ OTLP/HTTP แบบ best-effort ไปยัง URL ตัวรวบรวมนี้ |
IRIS_OTEL_SERVICE_NAME | แอตทริบิวต์ทรัพยากร service.name สำหรับการส่งออก OTel (ค่าเริ่มต้น iris-eval) |
IRIS_OTEL_HEADERS | ส่วนหัว k=v ที่คั่นด้วยเครื่องหมายจุลภาคสำหรับการส่งออก OTel (เช่น authorization=Bearer abc) |
IRIS_OTEL_TIMEOUT_MS | หมดเวลาต่อการส่งออก (ค่าเริ่มต้น 15000) |
RATE_LIMIT_SALT | เฉพาะ API รายชื่อรอเว็บไซต์ — จำเป็นเมื่อไซต์ iris-eval.com ถูกปรับใช้; เซิร์ฟเวอร์ไม่เคยอ่านมัน |
ความปลอดภัย
เมื่อใช้ HTTP transport, Iris รวมถึง:
- การตรวจสอบสิทธิ์คีย์ API ด้วยการเปรียบเทียบที่ปลอดภัยด้านเวลา (Bearer สำหรับไคลเอนต์ API; การเข้าสู่ระบบเบราว์เซอร์ไปยังแดชบอร์ดผ่าน
?key=) - CORS จำกัดเฉพาะ localhost โดยค่าเริ่มต้น
- การจำกัดอัตราต่อที่อยู่ไคลเอนต์และนาที: 600 คำขอไปยัง API แดชบอร์ด (
security.rateLimit.api) และ 20 ไปยัง MCP endpoint (security.rateLimit.mcp), ทั้งสองตั้งในconfig.json; คำขอ MCP ที่เกินขีดจำกัดได้รับข้อผิดพลาด JSON-RPC ที่ระบุคีย์ - ส่วนหัวความปลอดภัย Helmet
- การตรวจสอบ input Zod บนทุกเส้นทาง
- regex ที่ปลอดภัย ReDoS สำหรับกฎ eval ที่กำหนดเอง
- ขีดจำกัดขนาดคำขอ 1MB หนึ่งรายการบนทุก transport (
security.requestSizeLimit): HTTP ตอบ413, stdio ตอบข้อผิดพลาด JSON-RPC และรักษาเซสชันเปิดไว้
# Production deployment
iris-eval --transport http --port 3000 --api-key "$(openssl rand -hex 32)" --dashboard
เมื่อตั้งค่าคีย์แล้ว ไคลเอนต์ API — ไคลเอนต์ MCP, capture SDK, POST /api/v1/traces — จะส่ง Authorization: Bearer <key> ในการเปิดแดชบอร์ดในเบราว์เซอร์ ให้ต่อท้ายคีย์หนึ่งครั้งกับ URL แดชบอร์ดใดก็ได้ http://localhost:6920/?key=<api key>: Iris จะแลกเปลี่ยนเป็นคุกกี้เซสชันแบบ HttpOnly, SameSite=Lax และเปลี่ยนเส้นทางไปยังหน้าเดียวกันโดยนำคีย์ออกจากแถบที่อยู่ หน้าที่เปิดโดยไม่มีเซสชันจะแสดงแบบฟอร์มลงชื่อเข้าที่ทำการแลกเปลี่ยนแบบเดียวกัน คีย์จะไม่ถูกเก็บในเบราว์เซอร์ และเซสชันจะอยู่ในกระบวนการเซิร์ฟเวอร์เท่านั้น (มีเซสชันที่ใช้งานพร้อมกันได้สูงสุด 256 เซสชัน; การลงชื่อเข้าที่พบว่าเซสชันทั้งหมดถูกใช้งานจะถูกปฏิเสธแทนที่จะไล่เซสชันใดออก)
การใช้งานจริง
หลายคีย์ และการหมุนเวียนโดยไม่มีช่องว่าง security.apiKeys ใน config.json เก็บคีย์เพิ่มเติมได้ไม่จำกัดจำนวน แต่ละคีย์มี id และหนึ่งใน keyFile (ไฟล์ที่เนื้อหาที่ตัดช่องว่างแล้วคือคีย์) หรือ keyHash (ค่า sha256 แบบ hex ของคีย์ เพื่อให้ไฟล์คอนฟิกไม่เก็บความลับ — printf %s "$KEY" | openssl dgst -sha256) และมี expiresAt ที่ไม่บังคับ (ISO 8601) หลังจากนั้นคีย์จะหยุดจับคู่ทันที ในการหมุนเวียน: เพิ่มคีย์ใหม่ ย้ายไคลเอนต์ของคุณ ลบคีย์เก่า คีย์ใน config.json และในไฟล์คีย์มีผลทันทีโดยไม่ต้องรีสตาร์ท (0.20.0): ในการร้องขอแต่ละครั้ง เซิร์ฟเวอร์จะตรวจสอบว่า config.json หรือไฟล์คีย์ที่ระบุมีการเปลี่ยนแปลงหรือไม่ และถ้ามีการเปลี่ยนแปลง จะอ่านคีย์ใหม่ก่อนตอบกลับ การลบคีย์ออกจาก security.apiKeys หรือลบไฟล์คีย์ของคีย์นั้น จะเพิกถอนคีย์ในการร้องขอถัดไป: การร้องขอนั้นจะถูกปฏิเสธ และทุกเซสชันเบราว์เซอร์ที่เปิดด้วยคีย์นั้นจะถูกออกจากระบบ config.json ที่ไม่สามารถอ่านได้ (เช่น เขียนไม่ครบ) จะล้มเหลวแบบปิด และจนกว่าจะแก้ไข จะยอมรับเฉพาะคีย์จาก IRIS_API_KEY หรือ --api-key เท่านั้น คีย์ใน IRIS_API_KEY หรือ --api-key เอง และการเปิด/ปิดการตรวจสอบสิทธิ์โดยรวม ยังคงเปลี่ยนแปลงได้เฉพาะเมื่อรีสตาร์ทเท่านั้น ทุกคีย์ใช้ตรวจสอบสิทธิ์ได้จนกว่าจะถูกลบหรือหมดอายุ ทั้งบนเส้นทาง Bearer และการลงชื่อเข้าเบราว์เซอร์เหมือนกัน; บันทึกการเริ่มระบบจะระบุ id security.rateLimit.mcpKeyBy: "apiKey" นับงบประมาณต่อนาทีของปลายทาง MCP ต่อคีย์แทนที่จะเป็นต่อที่อยู่ไคลเอนต์ ดังนั้นเอเจนต์หลายตัวที่อยู่เบื้องหลังที่อยู่เดียวจะได้นาทีของตัวเองแต่ละตัว
Iris ปฏิเสธที่จะเริ่ม เมื่อการขนส่ง HTTP หรือแดชบอร์ดถูกผูกไว้เกินกว่า loopback — 0.0.0.0, ที่อยู่ LAN, คอนเทนเนอร์ — โดยไม่มีคีย์ API และแจ้งเป็นประโยคเดียวที่ระบุ IRIS_API_KEY ซึ่งรวมถึง docker run เปล่าของอิมเมจ ซึ่งผูก 0.0.0.0 ภายในคอนเทนเนอร์เพราะ loopback ไม่สามารถเข้าถึงได้ผ่านพอร์ตที่เผยแพร่ Loopback ที่ไม่มีคีย์ยังคงทำงานได้ (พร้อมคำเตือนบนการขนส่ง HTTP): ขอบเขตของเครื่องคือการควบคุมการเปิดเผยที่นั่น
# The image: pass a key
docker run -p 3000:3000 -p 6920:6920 -v iris-data:/data \
-e IRIS_API_KEY="$(openssl rand -hex 32)" ghcr.io/iris-eval/mcp-server
# Compose: the file requires the variable and refuses before the container starts
IRIS_API_KEY="$(openssl rand -hex 32)" docker compose up
# A network you have already fenced some other way: run open, on purpose
IRIS_ALLOW_UNAUTHENTICATED=1 iris-eval --transport http --dashboard
เปิดโดยการออกแบบ บนเซิร์ฟเวอร์ที่มีคีย์: GET /health บนการขนส่งและ GET /api/v1/health บนแดชบอร์ดตอบกลับโดยไม่ต้องใช้คีย์และนอกขีดจำกัดอัตราทั้งหมด ในรูปแบบเดียว: สถานะ เวอร์ชัน อัปไทม์ ไดรเวอร์ SQLite checks สำหรับพื้นที่จัดเก็บ ไฟล์กฎที่ปรับใช้แล้วและการย้ายฐานข้อมูล (ที่ใช้กับที่รู้จัก) สถานะของดัชนีค้นหา (search: พร้อม หรือการสร้างไปถึงไหนเป็นสัดส่วนของเทรซ) และมีคีย์ผู้ตัดสินอยู่หรือไม่ — ไม่มีคีย์ ไม่มีเทรซ ไม่มีจำนวนของสิ่งเหล่านั้น status เป็น ok เฉพาะเมื่อทุกการตรวจสอบผ่าน; มิฉะนั้นจะเป็น degraded พร้อม HTTP 503 ซึ่ง HEALTHCHECK ของอิมเมจ Docker อ่านเอง อย่างอื่นทั้งหมดต้องใช้ Authorization: Bearer <key> หรือเซสชันเบราว์เซอร์ การเก็บรักษาข้อมูลทำงานบนทุกเซิร์ฟเวอร์: เทรซและการประเมินที่เก่ากว่า retention.days (ค่าเริ่มต้น 30) จะถูกลบเมื่อเริ่มระบบ หลังจากเซิร์ฟเวอร์ตอบสนองแล้ว และทุกๆ retention.sweepIntervalHours ในขั้นตอนสั้นๆ ที่ไม่ทำให้การร้องขอต้องรอนาน; --self-test พิมพ์นโยบายของการติดตั้งนี้ และ iris://capabilities / GET /api/v1/capabilities นำนโยบายนั้นเป็น retention
เว็บฮุคจะทำงานเมื่อเกิดเหตุการณ์ (0.16.0): notify.webhook ใน config.json (หรือ IRIS_WEBHOOK_URL และ IRIS_WEBHOOK_SECRET) ระบุผู้รับ และ Iris จะโพสต์ข้อความที่ลงนามหนึ่งข้อความเมื่อคำตัดสินล้มเหลว การตรวจจับวิกฤตคัดค้าน ต้นทุนเป็นค่าผิดปกติ อัตราความล้มเหลวของกฎเปลี่ยนแปลง หรือกรณีถูกตอบทั้งสองทางเป็นครั้งแรก — id คำตัดสิน กฎและตัวเลข ไม่เคยเป็นข้อความของเอเจนต์ ลงนามทั้งแบบ Standard Webhooks และแบบ GitHub พร้อมกัน ส่งซ้ำพร้อม backoff ระบายความร้อนต่อเอเจนต์และกฎ ไม่เคยขัดขวางการประเมิน; รูปแบบ Slack และ Discord สร้างไว้ในตัว docs/webhooks.md
ข้อมูลของคุณบนดิสก์
ทุกสิ่งที่ Iris เก็บอยู่ภายใต้ Iris home ของคุณ (~/.iris หรือ IRIS_HOME) iris.db เก็บ input และ output ของทุกเทรซ ตามตัวอักษร — รวมถึงข้อความใดๆ ที่ no_pii จะไปแฟล็ก; การตรวจจับไม่แก้ไขข้อมูลเว้นแต่คุณขอ: storage.redact: "critical_spans" ใน config.json เก็บเอาต์พุตของการประเมินแต่ละรายการ โดยสแปนที่ตัวตรวจจับวิกฤตแฟล็กถูกแทนที่ด้วย [REDACTED:<pattern>] (ปิดโดยค่าเริ่มต้น; ออฟเซ็ตหลักฐานยังคงจัดทำดัชนีข้อความที่ผู้เรียกเห็น) storage.synchronous กำหนดเมื่อการเขียนถึงดิสก์: normal (ค่าเริ่มต้น) ซิงค์บันทึก write-ahead ในแต่ละ checkpoint ดังนั้นการขัดข้องของ Iris จะไม่สูญเสียอะไรและไฟล์ไม่สามารถเสียหายได้ แต่ไฟดับหรือระบบปฏิบัติการขัดข้องสามารถยกเลิกการเขียนตั้งแต่การซิงค์ครั้งล่าสุด; full ซิงค์ทุก commit และเก็บรักษาผ่านทั้งสองเหตุการณ์ โดยใช้เวลาประมาณ 1.5 มิลลิวินาทีต่อการเขียนมากขึ้น เมื่อเริ่มระบบ และทุกๆ retention.sweepIntervalHours (ค่าเริ่มต้น 24, 0 ปิดตัวจับเวลา) หลังจากนั้น เทรซและการประเมินที่เก่ากว่า retention.days (ค่าเริ่มต้น 30, 0 ปิด ตั้งค่าใน config.json) จะถูกลบและบันทึก write-ahead ถูก checkpoint การลบเทรซ — โดย delete_trace หรือโดยการกวาด — จะลบข้อความของการประเมินทุกครั้งที่เชื่อมโยงกับมัน (เอาต์พุต ข้อความที่คาดหวัง และข้อความกฎ) และประทับ erased_at; คำตัดสิน คะแนนและออฟเซ็ตหลักฐานยังคงอยู่ การลบแต่ละครั้งจะ checkpoint บันทึก write-ahead ก่อนที่จะส่งคืน ดังนั้นข้อความที่ลบจะไม่ถูกอ่านได้ใน iris.db หรือ iris.db-wal (หากการค้นหากำลังอ่านไฟล์ในขณะนั้น หรือกระบวนการอื่นกำลังอ่านหรือเขียนไฟล์ การลบจะส่งคืนโดยไม่รอและข้อความจะออกจากไฟล์ทันทีที่เสร็จ) ในการลบทุกอย่างทันที ให้หยุดเซิร์ฟเวอร์และรัน --purge: มันลบเทรซ สแปนและการประเมินที่เก็บไว้ทั้งหมด บีบอัดฐานข้อมูลและตัดบันทึก write-ahead เพื่อให้ข้อความหายไปจากดิสก์ และเก็บกฎที่ปรับใช้ บันทึกการตรวจสอบและการตั้งค่าของคุณไว้ ก่อนที่รีลีสจะใช้การย้ายฐานข้อมูลกับ iris.db ที่มีอยู่ มันจะคัดลอกไฟล์ไว้ข้างๆ (iris.db.<from>-to-<to>.<time>.bak, เฉพาะเจ้าของ เก็บสามอันล่าสุด; Downgrading): สำเนานั้นเก็บเทรซตามที่เป็นอยู่ ดังนั้นการกวาดเก็บรักษาจะลบอันที่เก่ากว่า retention.days และ --purge ลบทั้งหมด เซิร์ฟเวอร์ทำการคัดลอกและการย้ายฐานข้อมูลหลังจากตอบไคลเอนต์แล้ว บนเธรดของตัวเอง: การเรียกเครื่องมือ การอ่านทรัพยากรและการร้องขอ HTTP ที่มาถึงระหว่างนั้นจะรอพวกมัน สูงสุด 30 วินาทีต่อครั้ง แล้วจะถูกปฏิเสธด้วยประโยคที่บอกว่าเซิร์ฟเวอร์กำลังทำอะไร (IRIS_STORAGE_ERROR, ลองใหม่ได้; HTTP 503 พร้อม Retry-After) การตอบสนองด้านสุขภาพตอบตลอดและบอกว่าการอัปเกรดกำลังทำอะไร จาก 0.19.0 ที่ 100,000 เทรซซึ่งแต่ละอันเป็นลูปเอเจนต์ การคัดลอกและการย้ายฐานข้อมูลใช้เวลาประมาณ 6 วินาที iris-eval ingest, --purge และ --self-test ยังคงอัปเกรดก่อนที่จะทำอย่างอื่น
Iris ไม่เข้ารหัสข้อมูลที่เก็บไว้ iris.db และไฟล์บันทึก write-ahead ถูกสร้างแบบเจ้าของเท่านั้น (โหมด 600) และไดเรกทอรี Iris home ถูกสร้างแบบโหมด 700 (บน Windows, ACL ของไฟล์ควบคุมแทน) ฐานข้อมูลไม่เก็บคีย์ผู้ให้บริการ LLM: IRIS_ANTHROPIC_API_KEY และ IRIS_OPENAI_API_KEY อ่านจากสภาพแวดล้อมและไม่เคยเขียนลงดิสก์ มันเก็บอินพุตและเอาต์พุตเทรซตามตัวอักษร ดังนั้นให้วาง Iris home บนดิสก์หรือวอลุ่มที่เข้ารหัส (FileVault, BitLocker, LUKS หรือวอลุ่มคลาวด์ที่เข้ารหัสสำหรับการเมานต์ /data ของอิมเมจ Docker)
การส่งออก — ปุ่ม Export บนหน้า Traces และ Evaluations ของแดชบอร์ด GET /api/v1/traces/export และ /api/v1/evaluations/export หรือ iris-eval export — นำข้อความที่เก็บไว้นี้ตามที่เป็น เช่นเดียวกับที่แดชบอร์ดแสดง: อินพุตและเอาต์พุตเทรซตามตัวอักษร เอาต์พุตการประเมินพร้อม storage.redact ที่ใช้ ปฏิบัติต่อไฟล์ที่ส่งออกเหมือนฐานข้อมูลที่มันมาจาก
การแก้ไขปัญหา
ขั้นแรก: รันการทดสอบตัวเอง
npx @iris-eval/mcp-server --self-test
มันตรวจสอบพื้นที่จัดเก็บ การประเมินเชิงกำหนด และแดชบอร์ดในโฮมชั่วคราวที่แยกออก และพิมพ์คำตัดสินต่อขั้นตอน — เอาต์พุตความล้มเหลวระบุขั้นตอนที่เสียหาย รหัสออก 0 หมายถึงการติดตั้งแข็งแรง
Iris ไม่เริ่มทำงาน / ERR_MODULE_NOT_FOUND
คุณอาจมีเวอร์ชันเก่าที่ถูกแคช ล้างแคช npx แล้วลองใหม่:
npx --yes @iris-eval/mcp-server@latest
หรือติดตั้งแบบโกลบอลเพื่อหลีกเลี่ยงปัญหาแคชโดยสิ้นเชิง:
npm install -g @iris-eval/mcp-server@latest
npm install --ignore-scripts ทำลายการผูก SQLite
Iris เก็บเทรซด้วย better-sqlite3 โมดูลเนทีฟที่ดึงหรือคอมไพล์การผูกในสคริปต์ติดตั้ง หากสคริปต์นั้นถูกข้าม — --ignore-scripts บนบรรทัดคำสั่ง ignore-scripts=true ใน .npmrc (พบได้ทั่วไปบนเครื่ององค์กร) หรือมิเรอร์รีจิสทรีที่ตัด postinstall — การเริ่มระบบจะล้มเหลวพร้อมข้อความ "Could not locate the bindings file" ยาวที่แสดงรายการหลายสิบเส้นทางที่ลอง สร้างโมดูลนั้นใหม่:
npm rebuild better-sqlite3
# for a global install:
npm rebuild -g better-sqlite3
เครื่องมือไม่แสดงใน Claude Code
เครื่องมือ MCP โหลดเฉพาะเมื่อเริ่มเซสชัน หลังจากเพิ่ม iris-eval ให้รีสตาร์ทเซสชันด้วย /clear หรือเปิดเทอร์มินัลใหม่
การตรวจสอบเวอร์ชัน
npx @iris-eval/mcp-server --version
บรรทัดบันทึกการเริ่มระบบแรกยังมีเวอร์ชัน (Starting Iris MCP server vX.Y.Z) และ --self-test พิมพ์ในสรุป สำหรับการติดตั้งแบบโกลบอล npm ls -g @iris-eval/mcp-server แสดงเวอร์ชันที่ติดตั้ง
การอัปเดต
ไคลเอนต์ MCP ทุกตัวบนเครื่องใช้ฐานข้อมูลเดียว ~/.iris/iris.db และ install ปักหมุดไคลเอนต์แต่ละตัวกับรีลีสที่เขียนคอนฟิกของมัน เมื่อรีลีสเปลี่ยนสคีมาของฐานข้อมูล กระบวนการแรกของรีลีสนั้นที่เปิดไฟล์จะอัปเกรดมัน และจากนั้นไคลเอนต์ที่ยังปักหมุดกับรีลีสเก่าจะปฏิเสธที่จะเริ่ม ดังนั้นให้ย้ายไคลเอนต์ทุกตัวในขั้นตอนเดียว ก่อนหรือทันทีหลังจากที่คุณอัปเกรด:
npx -y @iris-eval/mcp-server@latest install --upgrade
มันค้นหาคอนฟิกไคลเอนต์ทุกตัวบนเครื่องนี้ที่รัน Iris ย้ายแต่ละปักหมุดไปยังรีลีสนั้น (เก็บสิ่งที่คุณเพิ่มในรายการ เช่น --dashboard หรือบล็อก env) ปล่อยปักหมุดไปยังรีลีสใหม่กว่าและรายการที่รันสิ่งอื่นที่ไม่ใช่แพ็กเกจ npm และแสดงรายการสิ่งที่ทำ รีสตาร์ทไคลเอนต์ที่มันระบุ install --list แสดงว่าไคลเอนต์แต่ละตัวรัน Iris เวอร์ชันใด
การติดตั้งสองรายการอยู่นอกไฟล์เหล่านั้น: ส่วนขยาย Claude Desktop (iris-eval.mcpb) ย้ายเมื่อคุณเปิดบันเดิลใหม่ และปลั๊กอิน Claude Code ด้วย claude plugin marketplace update iris-eval แล้ว claude plugin update iris-eval@iris-eval (และ claude plugin update iris-eval-capture@iris-eval สำหรับปลั๊กอิน capture)
การอัปเกรดจาก 0.19.x เป็น 0.20.0 0.20.0 เพิ่มดัชนีค้นหาและการเพิ่มอื่นๆ ในฐานข้อมูล (การย้ายฐานข้อมูล 015 และหลังจากนั้น) เมื่อกระบวนการ 0.20.0 ใดเปิด ~/.iris/iris.db (ส่วนขยาย Claude Desktop, npx iris-eval หรือ npx @iris-eval/mcp-server ที่ไม่มีเวอร์ชัน) ไคลเอนต์ที่ปักหมุดกับ 0.19.x จะหยุดด้วย This database was migrated by a newer Iris (…) — migration(s) 015-trace-search, … are unknown to v0.19.0. Upgrade Iris, … ข้อความนั้นมาจาก 0.19.x และไม่สามารถเปลี่ยนแปลงได้; วิธีแก้คือคำสั่งด้านบน ก่อนการอัปเกรด 0.20.0 คัดลอกไฟล์ไว้ข้างๆ ดังนั้นการกลับไปก็เป็นไปได้ (ด้านล่าง)
การเริ่มที่อัปเกรดฐานข้อมูลจะพิมพ์สิ่งที่ทำบน stderr: สำเนาที่ถ่าย รีลีสเก่าที่ไม่สามารถเปิดไฟล์ได้อีกต่อไป และไคลเอนต์ใดบนเครื่องนี้ที่ปักหมุดกับหนึ่งในนั้น พร้อมคำสั่ง --self-test อ่านฐานข้อมูลโดยไม่เปลี่ยนแปลงและพูดเหมือนกันก่อนที่คุณจะเริ่มอะไร
สำหรับการติดตั้งแบบโกลบอล npm update -g @iris-eval/mcp-server แล้ว iris-eval install --upgrade
การดาวน์เกรด
A release that upgraded the database copies it first, next to it: iris.db.<from>-to-<to>.<time>.bak in your Iris home (<from> is the release that last changed the file's schema, <to> the one that upgraded it; the startup line printed the exact path). To go back:
- Stop every MCP client and any other Iris process that uses the database.
- Keep the upgraded file, in case you come back: rename
iris.dbtoiris.db.upgraded, and deleteiris.db-walandiris.db-shmif they are there. - Copy the backup to
iris.db:cp ~/.iris/iris.db.0.19.0-to-0.20.0.<time>.bak ~/.iris/iris.db. - Pin every client back to the older release:
npx -y @iris-eval/mcp-server@0.19.0 install <client>for each one (install --upgradenever moves a client back).
Traces stored after the upgrade are in iris.db.upgraded, not in the backup. If no copy was taken (the startup line says why, for example a full disk), the older release cannot open the upgraded file, and the way forward is install --upgrade.
The storage driver
On a platform with no prebuilt better-sqlite3, the install still succeeds. better-sqlite3 is an optional dependency: when npm can neither download a prebuilt binary for your Node and platform nor compile one (compiling needs Python and a C++ toolchain — Visual Studio's C++ build tools on Windows), npm prints the build error, skips the module, and finishes the install. Iris then runs on Node's built-in SQLite, and says so: startup prints one line on stderr naming why, and --self-test shows driver node: better-sqlite3 is not installed …. To get the native driver back, install it where a prebuild or a toolchain exists (npm install better-sqlite3 in the project; for a global install, install Iris again with npm install -g @iris-eval/mcp-server once a toolchain is available). CI installs the packed server with the native build forced to fail on every change, and requires the install to finish and the self-test to store and read a trace on the built-in.
Iris keeps everything in one SQLite file, opened by better-sqlite3 — a native addon that is downloaded or compiled for your Node and platform. When that module cannot load, Iris falls back to Node's built-in SQLite (node:sqlite, Node 22.13 or later) with one warning on stderr, so a missing prebuild is a slower start rather than a dead one. It does the same, before loading it, for a better-sqlite3 compiled on your machine against Node 24.19 or later headers: on every 24.x release so far such a binary aborts the whole process the first time it frees a statement (Assertion failed: (env) != nullptr, nodejs/node#65446), and npm rebuild better-sqlite3 replaces it with the prebuilt binary, which is safe. IRIS_SQLITE_DRIVER=node chooses the built-in on purpose, native forbids the fallback. The built-in is opened with extension loading off and trusted_schema off; Node prints its own ExperimentalWarning: SQLite is an experimental feature line on stderr when it loads, and Iris does not silence it. --self-test and GET /health name the driver in use; every number on the proof page was measured on the native driver, and the test suite runs on both in CI.
Node.js version
Iris requires Node.js 22.13 or later. Node 20 reached end of life on 2026-04-30 and is not supported; Node 18 went in April 2025.
The floor is 22.13 rather than 22.0 because 22.13.0 is the first release that ships node:sqlite. That makes it the first version on which every supported Iris install has a second storage driver: when the native better-sqlite3 addon will not load, Iris falls back to Node's built-in SQLite instead of failing to start. Below 22.13 — and on Node 20, for its whole life — there was only ever one driver, and a missing prebuild was a dead start.
node --version # Must be v22.13.0 or newer
Windows: cmd /c not needed
Claude Code's /doctor may suggest wrapping npx with cmd /c. This is not needed and causes path parsing issues. Use npx directly:
# Correct
claude mcp add --transport stdio iris-eval -- npx -y @iris-eval/mcp-server
# Wrong (causes /c to be parsed as a path)
claude mcp add --transport stdio iris-eval -- cmd /c "npx -y @iris-eval/mcp-server"
If Iris is useful to you, consider starring the repo — it helps others find it.
MIT Licensed.