|
1 | 1 | # Building AI-Native Apps |
2 | 2 |
|
3 | | -ObjectQL is designed from the ground up to be the ideal data layer for AI agents and LLM-powered applications. Unlike traditional ORMs that rely on string-based SQL generation (prone to hallucination and injection), ObjectQL uses a **strict JSON Protocol**. |
| 3 | +ObjectQL is engineered to be the ideal data layer for AI Agents and LLMs. By providing a **Structure-First** protocol (JSON AST) instead of raw strings (SQL), it drastically reduces hallucinations and injection risks. |
4 | 4 |
|
5 | | -## Why ObjectQL for AI? |
| 5 | +## 1. Why ObjectQL for AI? |
6 | 6 |
|
7 | | -| Feature | SQL / Traditional ORM | ObjectQL (JSON AST) | |
| 7 | +| Feature | SQL / Traditional ORM | ObjectQL | |
8 | 8 | | :--- | :--- | :--- | |
9 | | -| **Output Format** | Unstructured Strings | **Structured JSON** | |
10 | | -| **Hallucinations** | High (Syntax errors, non-existent tables) | **Low** (constrained by schema) | |
11 | | -| **Safety** | Injection vulnerable (requires sanitization) | **Injection Proof** (by design) | |
12 | | -| **Context Window** | Heavy (DDL dumps) | **Lightweight** (JSON Schema) | |
| 9 | +| **Output** | Unstructured String | **Strict JSON** | |
| 10 | +| **Safety** | Injection Vulnerable | **Injection Safe** | |
| 11 | +| **Context** | Heavy DDL dumps | **Lightweight Scoped Schema** | |
13 | 12 |
|
14 | | -### The "JSON Advantage" |
| 13 | +LLMs excel at generating JSON. ObjectQL lets the LLM speak its native language. |
15 | 14 |
|
16 | | -LLMs are exceptionally good at generating JSON. By asking the LLM to output a JSON object instead of a SQL query, you drastically reduce error rates. |
| 15 | +## 2. Semantic Search (RAG) |
17 | 16 |
|
18 | | -**User Prompt:** "Find high priority tasks for John." |
| 17 | +ObjectQL has first-class support for Vector Search. You don't need a separate vector database (like Pinecone) or generic ORM hacks. |
19 | 18 |
|
20 | | -**LLM Output (ObjectQL Query):** |
21 | | -```json |
22 | | -{ |
23 | | - "entity": "tasks", |
24 | | - "filters": [ |
25 | | - ["priority", "=", "High"], |
26 | | - "and", |
27 | | - ["assignee", "=", "John"] |
28 | | - ] |
29 | | -} |
30 | | -``` |
31 | | - |
32 | | -## Quick Start |
| 19 | +### Configuration |
33 | 20 |
|
34 | | -### 1. Install Dependencies |
| 21 | +Enable search in your `*.object.yml`. |
35 | 22 |
|
36 | | -You'll need the core package. We assume you are using OpenAI or a similar provider. |
| 23 | +```yaml |
| 24 | +# knowledge.object.yml |
| 25 | +name: knowledge |
| 26 | +fields: |
| 27 | + title: { type: text } |
| 28 | + content: { type: textarea } |
37 | 29 |
|
38 | | -```bash |
39 | | -npm install @objectql/core openai |
| 30 | +# Enable AI capabilities |
| 31 | +ai: |
| 32 | + search: |
| 33 | + enabled: true |
| 34 | + fields: [title, content] # Fields to embed |
| 35 | + model: text-embedding-3-small |
40 | 36 | ``` |
41 | 37 |
|
42 | | -### 2. The Pattern: RAG for Schema |
| 38 | +### Usage |
43 | 39 |
|
44 | | -To let the AI generate correct queries, you must first provide it with the relevant *Context* (your Schema), but only the parts it needs. |
| 40 | +When enabled, the driver manages the embeddings automatically. You can then search using natural language. |
45 | 41 |
|
46 | 42 | ```typescript |
47 | | -// 1. Get Schema Context (Simplified) |
48 | | -const schemaContext = { |
49 | | - entities: { |
50 | | - todo: { |
51 | | - description: "Task items", |
52 | | - fields: ["title", "status", "priority"] |
53 | | - } |
54 | | - } |
55 | | -}; |
56 | | - |
57 | | -// 2. Prompt the AI |
58 | | -const prompt = ` |
59 | | -You are a database assistant. |
60 | | -Context: ${JSON.stringify(schemaContext)} |
61 | | -
|
62 | | -User Request: "Show me all high priority tasks." |
63 | | -
|
64 | | -Output: strictly valid ObjectQL JSON. |
65 | | -`; |
66 | | - |
67 | | -// 3. Call LLM (Pseudo-code) |
68 | | -const response = await openai.chat.completions.create({ |
69 | | - messages: [{ role: "user", content: prompt }] |
70 | | -}); |
71 | | -const query = JSON.parse(response.choices[0].message.content); |
72 | | -``` |
73 | | - |
74 | | -## AI Patterns |
| 43 | +// Search for "How to reset password" |
| 44 | +const results = await objectql.search('knowledge', 'How to reset password'); |
75 | 45 |
|
76 | | -### Pattern A: Natural Language Search (NL2Q) |
77 | | -Directly converting user questions into database queries. |
| 46 | +// returns: [{ id: 1, title: 'Reset Config', _score: 0.89 }, ...] |
| 47 | +``` |
78 | 48 |
|
79 | | -* **Best for:** Reporting, Dashboards, Search bars. |
80 | | -* **Tip:** Use the `description` field in your ObjectQL definitions to give the AI hints about what an object represents. |
| 49 | +## 3. Explicit Vector Columns |
81 | 50 |
|
82 | | -### Pattern B: Intelligent Form Generation |
83 | | -Since ObjectQL schemas are just JSON, AI can easily generate new object definitions on the fly. |
| 51 | +For advanced use cases (e.g., Image Search or Multi-modal embeddings), you can define raw vector columns. |
84 | 52 |
|
85 | | -```typescript |
86 | | -// AI Output for "Create a Customer schema" |
87 | | -const newSchema = { |
88 | | - name: "customer", |
89 | | - fields: { |
90 | | - name: { type: "text" }, |
91 | | - email: { type: "email" }, |
92 | | - status: { type: "select", options: ["active", "lead"] } |
93 | | - } |
94 | | -}; |
95 | | - |
96 | | -// Apply it immediately |
97 | | -await app.metadata.registerObject(newSchema); |
| 53 | +```yaml |
| 54 | +fields: |
| 55 | + image_url: |
| 56 | + type: url |
| 57 | + |
| 58 | + clip_embedding: |
| 59 | + type: vector |
| 60 | + dimension: 512 |
| 61 | + index: true # Create IVFFlat/HNSW index |
98 | 62 | ``` |
99 | 63 |
|
100 | | -## Safety Guidelines (Critical) |
101 | | - |
102 | | -Allowing an AI to generate database queries introduces risks. You must follow these principles: |
| 64 | +## 4. LLM to Query (Text-to-SQL alternative) |
103 | 65 |
|
104 | | -### 1. Never Trust AI Output |
105 | | -Always validate the structure and content of the generated JSON *before* execution. |
106 | | - |
107 | | -```typescript |
108 | | -import { z } from 'zod'; |
| 66 | +Instead of asking an LLM to write SQL, ask it to write ObjectQL JSON. |
109 | 67 |
|
110 | | -// Define a safe schema for the query |
111 | | -const QuerySchema = z.object({ |
112 | | - entity: z.string(), |
113 | | - filters: z.array(z.any()).optional() |
114 | | -}); |
| 68 | +**Prompt Pattern:** |
115 | 69 |
|
116 | | -const rawQuery = JSON.parse(aiOutput); |
| 70 | +```text |
| 71 | +You are a data assistant. |
| 72 | +Schema: |
| 73 | +- Object: Task (fields: title, status, priority) |
117 | 74 |
|
118 | | -// 1. Structural Validation |
119 | | -const safeQuery = QuerySchema.parse(rawQuery); |
| 75 | +User: "Find my high priority tasks" |
120 | 76 |
|
121 | | -// 2. Permission Check (Kernel Level) |
122 | | -// Even if the query is valid, ObjectQL's internal security layer |
123 | | -// will still enforce RLS (Row Level Security). |
124 | | -const result = await db.find(safeQuery); |
| 77 | +Output JSON in ObjectQL format: |
| 78 | +{ |
| 79 | + "entity": "task", |
| 80 | + "filters": [["priority", "=", "High"]] |
| 81 | +} |
125 | 82 | ``` |
126 | 83 |
|
127 | | -### 2. Least Privilege |
128 | | -The database user used by the AI agent should have **read-only** permissions where possible, or be scoped strictly to the objects it needs to modify. |
129 | | - |
130 | | -### 3. Complexity Limits |
131 | | -AI models can sometimes generate deeply nested or inefficient queries. Implement a "Complexity Cost" check before executing: |
132 | | -- Limit the number of joins (lookups). |
133 | | -- Limit the result set size. |
| 84 | +This output can be safely executed by the ObjectQL engine without fear of `DROP TABLE` injections. |
0 commit comments