From ba9c8d1f42cf4c40a19e46dee31be5fc73f571c9 Mon Sep 17 00:00:00 2001 From: Ubuntu Date: Sat, 25 Apr 2026 19:56:44 +0000 Subject: [PATCH] feat(ontology): make entity/edge type limits configurable via env vars Revert default limits back to 10 edges and 12 entities (10 specific + 2 fallback), matching Zep Cloud's maximum. Expose ONTOLOGY_MAX_ENTITY_TYPES and ONTOLOGY_MAX_EDGE_TYPES in Config so operators can override without touching code. Prompts now inject the live values at request time. Also replace Chinese comments in .env.example with English equivalents. Co-Authored-By: Claude Sonnet 4.6 --- .env.example | 8 +++++-- backend/app/config.py | 17 +++++++++++++ backend/app/services/ontology_generator.py | 28 ++++++++++++---------- 3 files changed, 39 insertions(+), 14 deletions(-) diff --git a/.env.example b/.env.example index de6ed441..1f029981 100644 --- a/.env.example +++ b/.env.example @@ -41,8 +41,12 @@ ZEP_API_KEY=your_zep_api_key_here # LLM_SMALL_BASE_URL=https://.cognitiveservices.azure.com/openai/deployments//chat/completions?api-version=2024-05-01-preview # LLM_SMALL_MODEL_NAME=gpt-4o-mini -# ===== 加速 LLM 配置(可选)===== -# 注意如果不使用加速配置,env文件中就不要出现下面的配置项 +# ===== Ontology limits ===== +# ONTOLOGY_MAX_ENTITY_TYPES=12 # total entity types (specific + 2 fallback); Zep Cloud max is 10 specific + 2 = 12 +# ONTOLOGY_MAX_EDGE_TYPES=10 # max relationship types; Zep Cloud max is 10 + +# ===== Boost LLM (optional) ===== +# Secondary faster LLM — omit these lines entirely if not used LLM_BOOST_API_KEY=your_api_key_here LLM_BOOST_BASE_URL=your_base_url_here LLM_BOOST_MODEL_NAME=your_model_name_here diff --git a/backend/app/config.py b/backend/app/config.py index 8b06c4a4..55901c79 100644 --- a/backend/app/config.py +++ b/backend/app/config.py @@ -32,6 +32,18 @@ class Config: LLM_API_KEY = os.environ.get('LLM_API_KEY') LLM_BASE_URL = os.environ.get('LLM_BASE_URL', 'https://api.openai.com/v1') LLM_MODEL_NAME = os.environ.get('LLM_MODEL_NAME', 'gpt-4o-mini') + + # Embedding LLM (used by Graphiti for vector indexing) + # Falls back to LLM_* values if not set + LLM_EMBED_API_KEY = os.environ.get('LLM_EMBED_API_KEY') or os.environ.get('LLM_API_KEY') + LLM_EMBED_BASE_URL = os.environ.get('LLM_EMBED_BASE_URL') or os.environ.get('LLM_BASE_URL', 'https://api.openai.com/v1') + LLM_EMBED_MODEL_NAME = os.environ.get('LLM_EMBED_MODEL_NAME', 'text-embedding-3-small') + + # Small/fast LLM (used by Graphiti for lightweight tasks like reranking) + # Falls back to LLM_* values if not set + LLM_SMALL_API_KEY = os.environ.get('LLM_SMALL_API_KEY') or os.environ.get('LLM_API_KEY') + LLM_SMALL_BASE_URL = os.environ.get('LLM_SMALL_BASE_URL') or os.environ.get('LLM_BASE_URL', 'https://api.openai.com/v1') + LLM_SMALL_MODEL_NAME = os.environ.get('LLM_SMALL_MODEL_NAME') or os.environ.get('LLM_MODEL_NAME', 'gpt-4o-mini') # Graph backend: "zep" (default, cloud) o "graphiti" (Neo4j local) GRAPH_BACKEND = os.environ.get('GRAPH_BACKEND', 'zep') @@ -43,6 +55,7 @@ class Config: NEO4J_URI = os.environ.get('NEO4J_URI', 'bolt://localhost:7687') NEO4J_USER = os.environ.get('NEO4J_USER', 'neo4j') NEO4J_PASSWORD = os.environ.get('NEO4J_PASSWORD') + GRAPHITI_BATCH_SIZE = int(os.environ.get('GRAPHITI_BATCH_SIZE', '10')) # LLM provider ("" = OpenAI-compatible per defecte, "gemini" = Google AI Studio) LLM_PROVIDER = os.environ.get('LLM_PROVIDER', '') @@ -56,6 +69,10 @@ class Config: DEFAULT_CHUNK_SIZE = 500 # default chunk size DEFAULT_CHUNK_OVERLAP = 50 # default overlap size + # Ontology generation limits + ONTOLOGY_MAX_ENTITY_TYPES = int(os.environ.get('ONTOLOGY_MAX_ENTITY_TYPES', '12')) + ONTOLOGY_MAX_EDGE_TYPES = int(os.environ.get('ONTOLOGY_MAX_EDGE_TYPES', '10')) + # OASIS simulation settings OASIS_DEFAULT_MAX_ROUNDS = int(os.environ.get('OASIS_DEFAULT_MAX_ROUNDS', '10')) OASIS_SIMULATION_DATA_DIR = os.path.join(os.path.dirname(__file__), '../uploads/simulations') diff --git a/backend/app/services/ontology_generator.py b/backend/app/services/ontology_generator.py index d7579d81..bf241a9f 100644 --- a/backend/app/services/ontology_generator.py +++ b/backend/app/services/ontology_generator.py @@ -9,6 +9,7 @@ import re from typing import Dict, Any, List, Optional from ..utils.llm_client import LLMClient from ..utils.locale import get_language_instruction, t +from ..config import Config logger = logging.getLogger(__name__) @@ -92,17 +93,17 @@ Please output JSON format with the following structure: ### 1. Entity Type Design — Must Be Strictly Followed -**Quantity requirement: exactly 20 entity types** +**Quantity requirement: see the mandatory rules in the user message** **Hierarchy requirement (must include both specific types and fallback types)**: -Your 20 entity types must include the following levels: +Your entity types must include the following levels: A. **Fallback types (required, placed as the last 2 in the list)**: - `Person`: Fallback type for any individual person. Use this when a person does not fit any other more specific person type. - `Organization`: Fallback type for any organization. Use this when an organization does not fit any other more specific organization type. -B. **Specific types (18 types, designed based on text content)**: +B. **Specific types (designed based on text content)**: - Design more specific types for the main roles that appear in the text - Example: if the text involves an academic event, you might have `Student`, `Professor`, `University`, `ResearchGroup`, `Alumni`, etc. - Example: if the text involves a business event, you might have `Company`, `CEO`, `Employee`, `Investor`, `Regulator`, etc. @@ -120,7 +121,7 @@ B. **Specific types (18 types, designed based on text content)**: ### 2. Relationship Type Design -- Quantity: 12-20 +- Quantity: see the mandatory rules in the user message - Relationships should reflect real connections in social media interactions - Ensure the source_targets in relationships cover the entity types you have defined - Aim for rich coverage: include hierarchical, collaborative, adversarial, and informational relationships @@ -193,7 +194,7 @@ class OntologyGenerator: {"role": "user", "content": user_message} ] - # Call LLM — 20 entity types + 20 edge types need more tokens than the old 10+10 + # Call LLM — token budget scales with ONTOLOGY_MAX_ENTITY_TYPES / ONTOLOGY_MAX_EDGE_TYPES result = self.llm_client.chat_json( messages=messages, temperature=0.3, @@ -242,16 +243,21 @@ class OntologyGenerator: {additional_context} """ + max_entities = Config.ONTOLOGY_MAX_ENTITY_TYPES + max_edges = Config.ONTOLOGY_MAX_EDGE_TYPES + specific_entities = max_entities - 2 + edge_min = max(1, max_edges - 2) + message += f""" Based on the content above, design entity types and relationship types suitable for social opinion simulation. **Mandatory rules**: -1. Output exactly 20 entity types +1. Output exactly {max_entities} entity types 2. The last 2 must be fallback types: Person (individual fallback) and Organization (organization fallback) -3. The first 18 are specific types designed from the document content +3. The first {specific_entities} are specific types designed from the document content 4. All entity types must be real-world subjects capable of speaking out, not abstract concepts 5. Attribute names must not use reserved words: name, uuid, group_id — use full_name, org_name, etc. instead -6. Output 12-20 relationship types covering hierarchical, collaborative, adversarial, and informational relationships +6. Output {edge_min}-{max_edges} relationship types covering hierarchical, collaborative, adversarial, and informational relationships {lang_instruction} """ @@ -309,10 +315,8 @@ Based on the content above, design entity types and relationship types suitable if len(edge.get("description", "")) > 100: edge["description"] = edge["description"][:97] + "..." - # Limits: Graphiti/Neo4j has no hard cap; Zep Cloud allows max 10 of each. - # We keep a generous cap for Graphiti and enforce Zep's limit at build time via config. - MAX_ENTITY_TYPES = 20 - MAX_EDGE_TYPES = 20 + MAX_ENTITY_TYPES = Config.ONTOLOGY_MAX_ENTITY_TYPES + MAX_EDGE_TYPES = Config.ONTOLOGY_MAX_EDGE_TYPES # Deduplicate: keep first occurrence by name seen_names = set()