bitflicker64 commented on code in PR #372:
URL: https://github.com/apache/hugegraph-ai/pull/372#discussion_r4281595283


##########
hugegraph-llm/docs/extraction-runtime.md:
##########
@@ -0,0 +1,188 @@
+# Reviewed Property-Graph Extraction
+
+The first version adds optional model review and repair to the existing
+`POST /graph/extract` path. Requests without `review_options`, or with it set 
to
+`null`, keep the existing extraction behavior. Sending an object enables 
review;
+`{}` selects the defaults.
+
+The reviewed path uses the existing configured chat model for extraction, 
review,
+and repair. It validates the graph against the supplied schema and returns a
+result for every chunk. It does not write graphs to HugeGraph.
+
+For OpenAI and LiteLLM, our client wrappers omit `max_tokens` from the SDK call
+in all three stages. SDK provider adapters and services may still apply default
+output limits or hard output and context limits. Existing requests without 
review
+and other model uses retain their configured token limit.
+
+## Setup and a runnable example
+
+Use Python 3.10 or 3.11 and run from the repository root:
+
+```bash
+uv sync --python 3.11 --extra llm --extra dev
+```
+
+Configure a supported chat model using the existing
+[LLM configuration](../config.md). The example uses the same
+`get_chat_llm(llm_settings, limit_output=False, raise_on_truncation=True)`
+client factory as the extraction node, so it requires a reachable configured
+model and any credentials needed by that model. An inline schema avoids a
+HugeGraph Server connection.
+
+Run the [Python example](examples/reviewed_property_graph.py):
+
+```bash
+uv run --no-sync python hugegraph-llm/docs/examples/reviewed_property_graph.py
+```
+
+It runs two text chunks concurrently using the complete inline schema in
+[reviewed-extraction.json](examples/reviewed-extraction.json), creates a 
separate
+client for each chunk, and prints all chunk results. Inspect their `status`,
+`issues`, and call counts; a successful process exit alone does not mean every
+chunk was accepted. Live model outputs and review decisions can vary.
+
+To use the HTTP entry, start the existing service:
+
+```bash
+uv run --no-sync python -m hugegraph_llm.demo.rag_demo.app
+```
+
+Then send the same example request from the repository root:
+
+```bash
+curl -X POST http://127.0.0.1:8001/graph/extract \
+  -H 'Content-Type: application/json' \
+  --data-binary @hugegraph-llm/docs/examples/reviewed-extraction.json
+```
+
+On Windows PowerShell, use `curl.exe` and place the command on one line. The
+request contains `texts`, an inline `schema`, and:
+
+```json
+"review_options": {"max_reviews": 2, "max_fixes": 1, "max_workers": 2}
+```
+
+The supplied schema defines person and company vertices with `name` primary 
keys,
+and `works_for` edges from person to company. It does not need to be installed 
in
+HugeGraph. Existing named-schema requests still use `client_config`.
+
+## Processing and budgets
+
+Each chunk follows:
+
+```text
+extract -> validate -> review
+              ^           |
+              |           +-- pass  -> final
+              |           +-- block -> blocked
+              +-- repair <- fix
+```
+
+Validation checks graph structure, labels, properties, schema-provided types 
and
+required fields, vertex identity, and relation endpoints. Invalid entries are
+retained so the model can repair them. Review compares the current graph with 
the
+original text and schema for unsupported facts, wrong properties, relation
+direction, and clear omissions. The existing extraction prompt is reused; 
review
+and repair prompts live in `PromptConfig` alongside it.
+
+Repair returns a complete replacement graph. The engine discards old issues,
+validates the replacement, and reviews it again when budget remains. Model or
+JSON parsing errors fail that chunk instead of being converted into an empty
+successful graph. An actual empty graph can pass if validation and review 
accept
+it.
+
+| Option | Default | Accepted range | Meaning |
+| --- | --- | --- | --- |
+| `max_reviews` | 2 | 0–5 | Maximum review attempts per chunk. |
+| `max_fixes` | 1 | 0–3 | Maximum repair attempts per chunk. |
+| `max_workers` | 4 | 1–8 | Maximum chunks being prepared or executed 
concurrently. |
+
+All options require integers; booleans, fractional numbers, and numeric strings
+are rejected. Unknown keys, such as `max_review`, and out-of-range values 
return
+HTTP 422 before extraction starts. Zero reviews or repairs disables that stage;

Review Comment:
   Important: `max_reviews: 0` does not disable review. It makes acceptance 
impossible. In `engine.py` (lines 76-77), a chunk that passes validation with 
no review budget left returns `candidate` with `review_budget_exhausted`, and 
`ExtractNode._extract_with_review` merges only `final` graphs. So any request 
with `{"max_reviews": 0}` still pays for one extraction call per chunk (plus 
any repairs), and it always returns `status: "failed"` with an empty `result`. 
`test_no_final_chunks_returns_business_failure_with_http_200` and the 
pooled-pipeline test assert exactly this. The Chinese architecture doc gets it 
right (its flowchart sends "no review budget" to `candidate`), but this 
sentence tells English readers the stage is simply skipped. Please either 
reject 0 with `ge=1` on `max_reviews` in `contracts.py`, or reword this 
sentence to say that with zero reviews no chunk can become `final` and the 
merged result is always empty. If you choose `ge=1`, also update the `0` cases 
in `test_co
 ntracts.py`, `test_engine.py`, `test_graph_extract_api.py` and the integration 
tests, and the `0–5` ranges in both docs.



##########
hugegraph-llm/src/hugegraph_llm/models/llms/openai.py:
##########
@@ -67,13 +69,15 @@ def generate(
             completions = self.client.chat.completions.create(
                 model=self.model,
                 temperature=self.temperature,
-                max_tokens=self.max_tokens,
+                **({"max_tokens": self.max_tokens} if self.max_tokens is not 
None else {}),
                 messages=messages,
             )
             if not completions.choices:
                 raise RuntimeError(f"Empty choices in LLM response: 
{str(completions)[:200]}")
             if completions.usage:
                 log.info("Token usage: %s", 
completions.usage.model_dump_json())
+            if self.raise_on_truncation and 
completions.choices[0].finish_reason == "length":
+                raise LLMOutputTruncatedError()
             return completions.choices[0].message.content
         # catch context length / do not retry
         except openai.BadRequestError as e:

Review Comment:
   Minor: on the reviewed path, a provider rejection is reported as a JSON 
parse failure. This handler turns `BadRequestError` into the string `Error: 
...`. That exception is how OpenAI-compatible servers report a context-length 
overflow. `AuthenticationError` just below gets the same treatment. 
`PropertyGraphBundle` passes the string to `_parse_json`. I reproduced this 
with a mocked SDK that raises on the review call: the chunk ends `failed`, 
stage `review`, reason `review_failed: JSONDecodeError`. Review and repair 
prompts embed the text, the full schema and the graph, so they are the calls 
most likely to hit the context limit. Please re-raise both errors when 
`raise_on_truncation` is set (or under a separate flag passed only by the 
reviewed path), so `chunk_results[].reason` names the provider error. Add a 
case for it to `test_output_limits.py`. The `agenerate` handlers can get the 
same change for consistency.



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to