Language: English | 中文
PCC is an API-only personalization control layer for closed-source LLM APIs. It extracts evidence-backed profile candidates from user messages, applies write-safety rules, stores structured profile state in SQLite, maps profile state into executable coordinates, retrieves only task-relevant controls, and compiles those controls into prompt policy text before an optional LLM call.
- rule, n-gram, and optional fastText profile candidate extraction
- evidence extraction and write-gateway decisions
- SQLite-backed structured profile, evidence, and profile matrix stores
- coordinate mapping and Profile Code generation
- task relevance retrieval with lexical scoring and current-candidate fusion
- prompt policy rendering for closed-source LLM API calls
- optional OpenAI-compatible SDK adapter with Responses API and chat-completions fallback
- deterministic offline evaluation helpers
- standalone terminal chat UI
| Area | Technology |
|---|---|
| Language | Python 3.11+ |
| Packaging | pyproject.toml, setuptools editable installs |
| Data models | Pydantic v2 |
| Config | JSON files under config/, .env via python-dotenv |
| Tokenization | jieba plus project dictionary support |
| Optional classifier | fastText supervised classifier |
| Storage | SQLite local database |
| LLM adapter | OpenAI Python SDK against OpenAI-compatible APIs |
| Optional API dependency | FastAPI and Uvicorn extras are declared; HTTP routes are placeholders |
| Tests | pytest |
.
├── config/ # Local JSON runtime configs; use *.json.example as skeletons
├── data/ # Local runtime databases and vector-store data; ignored
├── fastText/ # Optional supervised classifier workspace
│ ├── data/ # Local train/valid data; use *.txt.example as format skeletons
│ ├── models/ # Local trained models; ignored except placeholders
│ └── scripts/ # Data generation, training, and evaluation scripts
├── src/pcc/ # Python package
│ ├── api/ # Reserved FastAPI integration surface
│ ├── compiler/ # Profile Code generation, conflict handling, prompt rendering
│ ├── config/ # Project-root discovery and JSON config loading
│ ├── coordinates/ # Matrix-to-coordinate mapping and discretization
│ ├── evaluation/ # Deterministic offline evaluation runner
│ ├── extractors/ # Rule, n-gram, fastText, and evidence extractors
│ ├── feedback/ # Feedback collection placeholders
│ ├── gateway/ # Sensitive filtering, conflict checks, write safety policy
│ ├── llm/ # OpenAI-compatible client and prompt assembly
│ ├── models/ # Pydantic domain models
│ ├── retrieval/ # Task analysis and profile relevance retrieval
│ ├── stores/ # SQLite-backed profile, matrix, evidence, and vector stores
│ └── tui/ # Terminal chat UI
├── tests/ # Unit and phase validation tests
├── .env.example # Environment variable skeleton
├── README.md # English project guide
├── README_zh.md # Chinese project guide
└── pyproject.toml # Package metadata, dependencies, extras, and pytest config
Concrete local configuration, local fastText data, and trained models are ignored by Git. Committed .example files intentionally contain only structure, not project-specific rule content or real training data.
| Local file | Skeleton |
|---|---|
.env |
.env.example |
config/app.json |
config/app.json.example |
config/compiler_rules.json |
config/compiler_rules.json.example |
config/coordinate_system.json |
config/coordinate_system.json.example |
config/extractor_rules.json |
config/extractor_rules.json.example |
config/gateway_rules.json |
config/gateway_rules.json.example |
config/light_extractor.json |
config/light_extractor.json.example |
config/profile_codes.json |
config/profile_codes.json.example |
config/relevance_rules.json |
config/relevance_rules.json.example |
fastText/data/train.txt |
fastText/data/train.txt.example |
fastText/data/valid.txt |
fastText/data/valid.txt.example |
fastText/user_dict.txt |
fastText/user_dict.txt.example |
The runtime reads the concrete filenames, not .example files:
cp .env.example .env
for f in config/*.json.example; do cp "$f" "${f%.example}"; done
cp fastText/data/train.txt.example fastText/data/train.txt
cp fastText/data/valid.txt.example fastText/data/valid.txt
cp fastText/user_dict.txt.example fastText/user_dict.txtOPENAI_API_KEY=
OPENAI_BASE_URL=
OPENAI_MODEL=
OPENAI_API_MODE=auto
DATABASE_URL=sqlite:///data/pcc.db
VECTOR_STORE_PATH=./data/vector_store
LOG_LEVEL=INFOOPENAI_API_KEY: required only forPCCPipeline.answer(...).OPENAI_BASE_URL: optional OpenAI-compatible provider base URL; leave blank for official OpenAI defaults.OPENAI_MODEL: required only for real LLM calls.OPENAI_API_MODE:auto,responses, orchat_completions.DATABASE_URL: onlysqlite:///...URLs are supported by the current store layer.VECTOR_STORE_PATH: reserved local vector-store path; currently not used by the SQLite-backed MVP flow.LOG_LEVEL: application log-level setting for callers that choose to read it.
config/app.json:
project.name,project.full_name,project.version: project metadata strings.runtime.language: runtime language label, normallypython.runtime.log_level: log-level string such asDEBUG,INFO,WARNING, orERROR.runtime.timezone: timezone label such asUTC.storage.*: backend labels used for documentation and wiring clarity; current concrete stores are SQLite-backed.
config/profile_codes.json:
version: config version string.codes: object keyed by Profile Code, for exampleSTYLE.CONCISE.HIGH.- Each code needs
descriptionandprompt_instructionstrings. prompt_instructionis emitted into the compiled prompt when the code is active.
config/coordinate_system.json:
version: config version string.axes: object keyed by coordinate axis name, for exampledepthorconcise.- Each axis should define
description,range,low,medium, andhigh. rangeshould be a numeric two-item array, normally[0, 1].
config/compiler_rules.json:
axis_discretization:low,medium, andhighnumeric ranges used by coordinate discretization.max_active_profile_codes: maximum number of codes rendered for one turn.priority_order: ordered conflict-resolution labels.rendering.include_profile_policy: include the static safety policy block.rendering.include_natural_language_controls: include natural-language control instructions.rendering.include_raw_codes: include raw Profile Codes in prompt output.
config/extractor_rules.json:
rules: list of keyword rules.- Each rule needs
label,keywords, andconfidence. labelshould match a key inprofile_codes.jsonwhen the candidate should become a renderable control.keywordsis a list of substrings matched against user text.confidenceshould be a float from0.0to1.0.
config/light_extractor.json:
sources.rules,sources.ngram,sources.fasttext: enable or disable extractor sources.ngram.min_n,ngram.max_n: token n-gram size bounds.ngram.min_score: minimum lexical score for an n-gram candidate.ngram.confidence_floor,ngram.confidence_ceiling: bounds for n-gram candidate confidence.ngram.user_dict_path: optional path to a jieba user dictionary.ngram.extra_terms: object keyed by Profile Code with additional matching terms.fasttext.model_path: trained model path, usuallyfastText/models/profile_classifier.bin.fasttext.user_dict_path: optional dictionary path for segmentation.fasttext.min_confidence: minimum prediction confidence.fasttext.top_k: number of labels requested from fastText.fasttext.label_prefix: usually__label__.fasttext.segment_input: whether to segment text before prediction.
config/gateway_rules.json:
thresholds.min_confidence_long_term: minimum confidence for long-term writes.thresholds.min_confidence_session: minimum confidence for session-only writes.sensitive_categories: category names rejected by the sensitive filter.write_policy.require_evidence: require evidence before writing.write_policy.reject_sensitive_by_default: reject sensitive labels by default.write_policy.current_instruction_overrides_profile: current-turn instructions outrank stored profile state.
config/relevance_rules.json:
default_task: fallback task name.max_active_profile_codes: relevance-layer cap before compiler rendering.min_relevance_score: minimum score for activation.fusion_weights: weights for task score, BM25, TF-IDF, current candidates, and profile strength.current_candidate_source_weights: per-source weights for current-turn candidate fusion.tasks: object keyed by task name.- Each task needs
keywords,axis_weights, andfamily_weights. axis_weightskeys should match coordinate axes.family_weightskeys should match Profile Code families, for exampleSTYLE.CONCISE.
Training and validation files use fastText supervised text format:
__label__PROFILE.CODE user text for this label
__label__PROFILE.CODE __label__OTHER.CODE user text with multiple labels
The user dictionary is one custom segmentation term per line:
custom_term
another_custom_term
python -m pip install -e ".[dev]"
pytestRun the terminal UI:
pcc-tuiThe TUI expects a UTF-8 terminal locale for CJK input and rendering.
from datetime import datetime, timezone
from pcc import PCCPipeline
from pcc.models import UserMessage
pipeline = PCCPipeline()
pipeline.ingest_message(
UserMessage(
user_id="user_001",
message_id="msg_001",
content="请用可视化和分步骤深入讲解 Transformer 底层机制。",
created_at=datetime.now(timezone.utc),
)
)
prompt = pipeline.compile_prompt("user_001", "解释 attention。")
packet = pipeline.compile_active_profile_packet("user_001", "解释 attention。")For a real LLM call:
response = pipeline.answer("user_001", "解释 attention。")Provider behavior:
- Official OpenAI: leave
OPENAI_BASE_URLempty and useOPENAI_API_MODE=auto. - OpenAI-compatible providers: set
OPENAI_BASE_URL;autotries Responses API first and falls back to chat completions if needed.
Install optional dependencies:
python -m pip install -e ".[dev,fasttext]"Generate deterministic local data from config/profile_codes.json:
python fastText/scripts/generate_training_data.pyTrain and evaluate:
python fastText/scripts/train.py
python fastText/scripts/evaluate.pyThe runtime adapter looks for fastText/models/profile_classifier.bin. If the model is missing, extraction falls back to rules and n-grams.
from datetime import datetime, timezone
from pcc import EvaluationCase, EvaluationRunner, OutputConstraints
from pcc.models import UserMessage
result = EvaluationRunner().evaluate_case(
EvaluationCase(
name="concise_attention",
messages=[
UserMessage(
user_id="user_001",
message_id="msg_001",
content="我喜欢简短结论。",
created_at=datetime.now(timezone.utc),
)
],
user_query="请一句话回答 attention。",
expected_active_profile_codes=["STYLE.CONCISE.HIGH"],
output_text="结论:attention 用相关性权重汇聚上下文信息。",
output_constraints=OutputConstraints(
must_contain=["attention"],
must_not_contain=["模型认为"],
max_chars=60,
require_cjk=True,
),
)
)PCC optionally uses fastText for supervised text classification. fastText was introduced by Facebook AI Research and is distributed under the MIT license.
This project is licensed under the MIT License. See LICENSE for the full text.
@software{pcc_profile_coordinate_compiler,
title = {PCC: Profile Coordinate Compiler},
version = {0.1.0},
year = {2026},
note = {API-only personalization control layer for LLM prompts}
}