Instructions to use ramankrishna10/npc-reason with libraries, inference providers, notebooks, and local apps. Follow these links to get started.
- Notebooks
- Google Colab
- Kaggle
- Local Apps Settings
- llama.cpp
How to use ramankrishna10/npc-reason with llama.cpp:
Install (macOS, Linux)
curl -LsSf https://llama.app/install.sh | sh # Start a local OpenAI-compatible server with a web UI: llama serve -hf ramankrishna10/npc-reason:Q4_K_M # Run inference directly in the terminal: llama cli -hf ramankrishna10/npc-reason:Q4_K_M
Install from WinGet (Windows)
winget install llama.cpp # Start a local OpenAI-compatible server with a web UI: llama serve -hf ramankrishna10/npc-reason:Q4_K_M # Run inference directly in the terminal: llama cli -hf ramankrishna10/npc-reason:Q4_K_M
Use pre-built binary
# Download pre-built binary from: # https://github.com/ggerganov/llama.cpp/releases # Start a local OpenAI-compatible server with a web UI: ./llama-server -hf ramankrishna10/npc-reason:Q4_K_M # Run inference directly in the terminal: ./llama-cli -hf ramankrishna10/npc-reason:Q4_K_M
Build from source code
git clone https://github.com/ggerganov/llama.cpp.git cd llama.cpp cmake -B build cmake --build build -j --target llama-server llama-cli # Start a local OpenAI-compatible server with a web UI: ./build/bin/llama-server -hf ramankrishna10/npc-reason:Q4_K_M # Run inference directly in the terminal: ./build/bin/llama-cli -hf ramankrishna10/npc-reason:Q4_K_M
Use Docker
docker model run hf.co/ramankrishna10/npc-reason:Q4_K_M
- LM Studio
- Jan
- vLLM
How to use ramankrishna10/npc-reason with vLLM:
Install from pip and serve model
# Install vLLM from pip: pip install vllm # Start the vLLM server: vllm serve "ramankrishna10/npc-reason" # Call the server using curl (OpenAI-compatible API): curl -X POST "http://localhost:8000/v1/chat/completions" \ -H "Content-Type: application/json" \ --data '{ "model": "ramankrishna10/npc-reason", "messages": [ { "role": "user", "content": "What is the capital of France?" } ] }'Use Docker
docker model run hf.co/ramankrishna10/npc-reason:Q4_K_M
- Ollama
How to use ramankrishna10/npc-reason with Ollama:
ollama run hf.co/ramankrishna10/npc-reason:Q4_K_M
- Unsloth Studio
How to use ramankrishna10/npc-reason with Unsloth Studio:
Install Unsloth Studio (macOS, Linux, WSL)
curl -fsSL https://unsloth.ai/install.sh | sh # Run unsloth studio unsloth studio -H 0.0.0.0 -p 8888 # Then open http://localhost:8888 in your browser # Search for ramankrishna10/npc-reason to start chatting
Install Unsloth Studio (Windows)
irm https://unsloth.ai/install.ps1 | iex # Run unsloth studio unsloth studio -H 0.0.0.0 -p 8888 # Then open http://localhost:8888 in your browser # Search for ramankrishna10/npc-reason to start chatting
Using HuggingFace Spaces for Unsloth
# No setup required # Open https://huggingface.co/spaces/unsloth/studio in your browser # Search for ramankrishna10/npc-reason to start chatting
- Atomic Chat new
- Docker Model Runner
How to use ramankrishna10/npc-reason with Docker Model Runner:
docker model run hf.co/ramankrishna10/npc-reason:Q4_K_M
- Lemonade
How to use ramankrishna10/npc-reason with Lemonade:
Pull the model
# Download Lemonade from https://lemonade-server.ai/ lemonade pull ramankrishna10/npc-reason:Q4_K_M
Run and chat with the model
lemonade run user.npc-reason-Q4_K_M
List all available models
lemonade list
| """NPC Reason — mechanical step verifier (THE core artifact). | |
| PURE CODE. No model, no LLM judgment anywhere. This is what makes the | |
| "verifiable-rate" metric un-fakeable, and it is reused verbatim as the RL reward | |
| signal in a later dispatch — so it is frozen (VERIFIER.lock) the moment its tests pass. | |
| DEFINITION (committed; see reports/PREREG.md and VERIFIER.lock): | |
| - A reasoning chain is a sequence of steps ending in a final answer. | |
| - A load-bearing numeric step carries an inline checkable assertion in the canonical | |
| form <<EXPR = RESULT>> where EXPR is an arithmetic/algebraic expression over | |
| numbers and earlier-BOUND variables, and RESULT is the claimed value. | |
| - A step is VERIFIED if a SymPy evaluation of EXPR equals RESULT within tolerance | |
| (exact for integers/rationals; 1e-6 relative for floats). | |
| - A chain is VERIFIABLE iff: | |
| (a) it has >=1 load-bearing <<...>> assertion (no bare asserted numbers drive it), | |
| (b) every such assertion VERIFIES, and | |
| (c) the final answer equals the RESULT of the last load-bearing step | |
| (the chain COMPOSES to its conclusion). | |
| - A chain is CORRECT iff its final answer equals the gold answer. CORRECT and | |
| VERIFIABLE are INDEPENDENT axes. | |
| TOLERANCE POLICY (explicit, frozen): | |
| - Parse EXPR and RESULT with sympy.sympify (after a small, fixed normalization). | |
| - Exact branch: if simplify(EXPR_value - RESULT_value) == 0 -> VERIFIED. | |
| - Float branch: else, if both are finite numbers and | |
| |EXPR_value - RESULT_value| <= 1e-6 * max(1, |RESULT_value|) -> VERIFIED. | |
| - Otherwise NOT verified. | |
| FAIL-CLOSED (conservative by design): | |
| - Unparseable EXPR or RESULT -> NOT verified (reason recorded). | |
| - EXPR references an UNBOUND symbol -> NOT verified (cannot confirm). | |
| - Any exception during evaluation -> NOT verified. | |
| A chain only counts VERIFIABLE if the checker can ACTUALLY confirm every load-bearing step. | |
| VARIABLE BINDING (v1, documented): | |
| - A step may bind a name: `let total = <<3*8 = 24>>` or `total = <<3*8 = 24>>`. | |
| The name binds to the (parsed) RESULT value and is usable by later EXPRs. | |
| - Binding tests internal consistency: each later step is checked against the values | |
| the chain itself previously stated. | |
| - V1 SCOPE: assertions are concrete-valued (EXPR evaluates to a number once prior | |
| bindings are substituted). Algebra with FREE variables / equation-solving such as | |
| `<<x**2 - 4 = 0>>` with x unbound is OUT OF SCOPE for v1 and FAILS CLOSED | |
| (recorded reason: "unbound symbol"). It is noted as a verifier-v2 extension. | |
| """ | |
| from __future__ import annotations | |
| import re | |
| from dataclasses import dataclass, field | |
| from typing import Optional | |
| import sympy | |
| from sympy import Rational, simplify, sympify | |
| # ----------------------------------------------------------------------------- # | |
| # Patterns | |
| # ----------------------------------------------------------------------------- # | |
| # Optional binding name, then << EXPR = RESULT >>. Non-greedy EXPR stops at the | |
| # FIRST '=' inside the brackets. Binding name must start with a letter/underscore, | |
| # so numeric tokens to the left (e.g. "2 + 2 =") are never captured as a name. | |
| ASSERTION = re.compile( | |
| r"(?:(?:let\s+)?([A-Za-z_]\w*)\s*=\s*)?<<\s*(.+?)\s*=\s*(.+?)\s*>>" | |
| ) | |
| # Final-answer extractors, tried in priority order. | |
| _BOXED = re.compile(r"\\boxed\{\s*([^{}]+?)\s*\}") | |
| _GSM = re.compile(r"####\s*([^\n]+)") | |
| _ANSWER_IS = re.compile( | |
| r"(?:final answer|the answer is|answer\s*[:=])\s*\$?\\?\(?\s*" | |
| r"([+-]?[\d.,/eE^*+\-() ]*\d)", | |
| re.IGNORECASE, | |
| ) | |
| # Characters/sequences to normalize before sympify. | |
| _THOUSANDS = re.compile(r"(?<=\d),(?=\d{3}\b)") | |
| _NORM_REPLACE = ( | |
| (r"\times", "*"), | |
| (r"\cdot", "*"), | |
| (r"\div", "/"), | |
| (r"\left", ""), | |
| (r"\right", ""), | |
| ("^", "**"), | |
| ("%", "/100"), | |
| ("$", ""), | |
| ("×", "*"), | |
| ("÷", "/"), | |
| ("−", "-"), # unicode minus | |
| ) | |
| class StepResult: | |
| expr: str | |
| claimed: str | |
| ok: bool | |
| reason: str | |
| binding: Optional[str] = None | |
| class ChainRecord: | |
| n_assertions: int = 0 | |
| n_verified: int = 0 | |
| has_loadbearing_assertions: bool = False | |
| all_assertions_verified: bool = False | |
| final_answer: Optional[str] = None | |
| final_answer_value: Optional[object] = None | |
| composes_to_final: bool = False | |
| verifiable: bool = False | |
| correct: Optional[bool] = None | |
| verified_and_correct: Optional[bool] = None | |
| steps: list = field(default_factory=list) | |
| failures: list = field(default_factory=list) | |
| def as_dict(self) -> dict: | |
| return { | |
| "n_assertions": self.n_assertions, | |
| "n_verified": self.n_verified, | |
| "has_loadbearing_assertions": self.has_loadbearing_assertions, | |
| "all_assertions_verified": self.all_assertions_verified, | |
| "final_answer": self.final_answer, | |
| "composes_to_final": self.composes_to_final, | |
| "verifiable": self.verifiable, | |
| "correct": self.correct, | |
| "verified_and_correct": self.verified_and_correct, | |
| "failures": self.failures, | |
| "steps": [ | |
| {"expr": s.expr, "claimed": s.claimed, "ok": s.ok, | |
| "reason": s.reason, "binding": s.binding} | |
| for s in self.steps | |
| ], | |
| } | |
| # ----------------------------------------------------------------------------- # | |
| # Numeric core | |
| # ----------------------------------------------------------------------------- # | |
| def _normalize(raw: str) -> str: | |
| s = raw.strip() | |
| s = _THOUSANDS.sub("", s) # 1,234 -> 1234 (drop thousands separators) | |
| for a, b in _NORM_REPLACE: | |
| s = s.replace(a, b) | |
| # \frac{a}{b} -> ((a)/(b)) | |
| s = re.sub(r"\\d?frac\{([^{}]+)\}\{([^{}]+)\}", r"((\1)/(\2))", s) | |
| s = s.replace("\\", " ") | |
| return s.strip() | |
| def _to_sympy(raw: str, bindings: dict): | |
| """sympify a normalized token; raises on failure (caller fails closed).""" | |
| expr = sympify(_normalize(raw), locals=bindings, rational=True) | |
| return expr | |
| def _values_match(a, b) -> bool: | |
| """Exact for rationals/integers; 1e-6 relative for floats.""" | |
| diff = simplify(a - b) | |
| if diff == 0: | |
| return True | |
| try: | |
| if diff.free_symbols: | |
| return False | |
| fa, fb = float(a), float(b) | |
| return abs(fa - fb) <= 1e-6 * max(1.0, abs(fb)) | |
| except (TypeError, ValueError): | |
| return False | |
| def verify_assertion(expr: str, claimed: str, bindings: dict) -> StepResult: | |
| """Evaluate one <<EXPR = RESULT>> against current bindings. Fail-closed.""" | |
| try: | |
| e = _to_sympy(expr, bindings) | |
| except Exception as ex: # noqa: BLE001 — fail closed on any parse error | |
| return StepResult(expr, claimed, False, f"unparseable expr: {ex}") | |
| try: | |
| c = _to_sympy(claimed, bindings) | |
| except Exception as ex: # noqa: BLE001 | |
| return StepResult(expr, claimed, False, f"unparseable result: {ex}") | |
| # EXPR must reduce to a concrete value (v1 scope: no free variables). | |
| if getattr(e, "free_symbols", set()): | |
| unbound = ", ".join(sorted(str(s) for s in e.free_symbols)) | |
| return StepResult(expr, claimed, False, f"unbound symbol(s): {unbound}") | |
| try: | |
| ok = _values_match(e, c) | |
| except Exception as ex: # noqa: BLE001 | |
| return StepResult(expr, claimed, False, f"comparison error: {ex}") | |
| reason = "verified" if ok else f"mismatch: {expr} -> {e} != {claimed}" | |
| return StepResult(expr, claimed, ok, reason) | |
| # ----------------------------------------------------------------------------- # | |
| # Final answer | |
| # ----------------------------------------------------------------------------- # | |
| def extract_final_answer(text: str) -> Optional[str]: | |
| """Last \\boxed{}, else last ####, else 'the answer is X'. None if absent.""" | |
| boxed = _BOXED.findall(text) | |
| if boxed: | |
| return boxed[-1].strip() | |
| gsm = _GSM.findall(text) | |
| if gsm: | |
| return gsm[-1].strip() | |
| m = list(_ANSWER_IS.finditer(text)) | |
| if m: | |
| return m[-1].group(1).strip().rstrip(".") | |
| return None | |
| def _safe_value(raw: str, bindings: dict): | |
| try: | |
| v = _to_sympy(raw, bindings) | |
| return None if getattr(v, "free_symbols", set()) else v | |
| except Exception: # noqa: BLE001 | |
| return None | |
| # ----------------------------------------------------------------------------- # | |
| # Chain | |
| # ----------------------------------------------------------------------------- # | |
| def verify_chain(text: str, gold_answer=None) -> dict: | |
| """Mechanically derive every field. No judgment. Returns ChainRecord.as_dict().""" | |
| rec = ChainRecord() | |
| bindings: dict = {} | |
| for m in ASSERTION.finditer(text): | |
| name, expr, claimed = m.group(1), m.group(2), m.group(3) | |
| res = verify_assertion(expr, claimed, bindings) | |
| res.binding = name | |
| rec.steps.append(res) | |
| rec.n_assertions += 1 | |
| if res.ok: | |
| rec.n_verified += 1 | |
| else: | |
| rec.failures.append({"expr": expr, "claimed": claimed, "reason": res.reason}) | |
| # Bind the name to the CLAIMED result value (internal-consistency semantics), | |
| # whenever the result parses to a concrete value — even if the step failed, | |
| # so downstream reasons are about the downstream step, not a cascade. | |
| if name: | |
| v = _safe_value(claimed, bindings) | |
| if v is not None: | |
| bindings[name] = v | |
| rec.has_loadbearing_assertions = rec.n_assertions > 0 | |
| rec.all_assertions_verified = ( | |
| rec.has_loadbearing_assertions and rec.n_verified == rec.n_assertions | |
| ) | |
| # Final answer + composition. | |
| fa = extract_final_answer(text) | |
| rec.final_answer = fa | |
| fa_val = _safe_value(fa, bindings) if fa is not None else None | |
| rec.final_answer_value = fa_val | |
| if rec.has_loadbearing_assertions and fa_val is not None: | |
| last_claimed = rec.steps[-1].claimed | |
| last_val = _safe_value(last_claimed, bindings) | |
| if last_val is not None: | |
| try: | |
| rec.composes_to_final = _values_match(fa_val, last_val) | |
| except Exception: # noqa: BLE001 | |
| rec.composes_to_final = False | |
| if not rec.composes_to_final and rec.has_loadbearing_assertions: | |
| rec.failures.append({"reason": "final answer does not compose from last step"}) | |
| rec.verifiable = ( | |
| rec.has_loadbearing_assertions | |
| and rec.all_assertions_verified | |
| and rec.composes_to_final | |
| ) | |
| # Correctness (independent axis). | |
| if gold_answer is not None: | |
| gold_val = _safe_value(str(gold_answer), {}) | |
| if fa_val is not None and gold_val is not None: | |
| try: | |
| rec.correct = _values_match(fa_val, gold_val) | |
| except Exception: # noqa: BLE001 | |
| rec.correct = False | |
| else: | |
| # Fall back to normalized string compare (handles non-numeric MATH answers). | |
| rec.correct = ( | |
| fa is not None | |
| and _normalize(fa).replace(" ", "") == _normalize(str(gold_answer)).replace(" ", "") | |
| ) | |
| rec.verified_and_correct = bool(rec.verifiable and rec.correct) | |
| return rec.as_dict() | |
| if __name__ == "__main__": | |
| import json | |
| import sys | |
| blob = sys.stdin.read() | |
| print(json.dumps(verify_chain(blob), indent=2, default=str)) | |