How the LifeTrace Natural Language To‑Do Query Parser Works

The QueryParser class in lifetrace/util/query_parser.py converts free‑form Chinese queries like "搜索昨天在微信上的聊天记录" into structured QueryConditions using a dual‑strategy approach that prioritizes LLM extraction and falls back to deterministic rule‑based parsing.

The freeu‑group/lifetrace repository implements a sophisticated natural language todo query parser that bridges human intent and database filters. Located in lifetrace/util/query_parser.py, this component transforms unstructured Chinese search requests into UTC‑normalized timestamps, resolved process names, and cleaned keyword lists, enabling downstream services such as lifetrace/llm/retrieval_service.py to execute precise vector and SQL searches without requiring users to learn complex query syntax.

Dual‑Strategy Architecture: LLM First, Rules as Fallback

The parser implements a resilient two‑tier system designed to maximize accuracy while maintaining offline capability. When instantiated with an LLM client, it attempts semantic understanding first; otherwise, it immediately engages deterministic extraction logic.

Entry Point and LLM Integration (parse_query)

The parse_query method serves as the orchestration layer. It first checks for the presence of self.llm_client and attempts self.llm_client.parse_query (lines 34‑72). The parser validates the LLM response to ensure at least one of keywords, app_names, or a time range is present. Valid results flow into _build_query_conditions (lines 72‑92), while failures, empty returns, or missing LLM configurations trigger the rule‑based fallback at line 34.

Fallback Rule‑Based Engine (_parse_with_rules)

When LLM extraction fails or is unavailable, _parse_with_rules instantiates an empty QueryConditions object and sequentially invokes three specialized extraction methods. This deterministic path ensures consistent behavior without API dependencies and reduces token costs for common query patterns.

Rule‑Based Extraction Pipeline

The fallback mechanism decomposes natural language todo queries into three structured dimensions: temporal boundaries, application context, and search intent.

Time Range Recognition (_extract_time_range)

This method scans for Chinese temporal keywords stored in self.time_keywords (lines 86‑94), including expressions like 今天, 昨天, and 本周. Relative offsets are converted to UTC boundaries using get_utc_now and to_utc from lifetrace/util/time_utils.py. Explicit dates in YYYY‑MM‑DD format are captured via regex and parsed with datetime.strptime, ensuring all output is UTC‑normalized (lines 94‑97).

Application Name Resolution (_extract_app_names)

Application identification operates through a two‑stage mapping process. First, the method queries the global app_mapper (the AppMapper defined in lifetrace/util/app_utils.py) for known process names (lines 99‑102). Second, it consults the internal alias table self.app_name_mapping (lines 65‑84) and applies regex patterns such as "在 XX 上" or "XX 应用" via _find_app_names_from_patterns. Friendly names are ultimately converted to actual process identifiers through _convert_to_process_names, enabling precise database filtering.

Keyword Intent Detection (_extract_keywords)

The parser identifies search intent by detecting indicator verbs including ["搜索","查找","包含","关于","找到","寻找"]. When present, the method strips temporal expressions and app aliases, then tokenizes the remaining text while filtering stop‑words and functional verbs. This yields a cleaned list of meaningful search terms (lines 55‑78) that drive vector‑search relevance in RAG pipelines.

LLM‑Driven Structured Extraction (_build_query_conditions)

When the LLM returns a JSON payload, _build_query_conditions handles normalization. It extracts temporal boundaries via _extract_time_from_parsed_data (supporting both time_range objects and legacy start_date/end_date fields), converts friendly app names to process names using _convert_to_process_names, and passes keywords through verbatim. The populated QueryConditions dataclass provides a to_dict method (lines 39‑56) that generates clean dictionary representations for immediate SQL or vector‑DB consumption.

Practical Usage Examples

The parser supports both offline rule‑based operation and LLM‑enhanced extraction.

Rule‑Based Parsing Without LLM

from lifetrace.util.query_parser import QueryParser

parser = QueryParser()
cond = parser.parse_query("搜索上周在 Chrome 上打开的网页")
print(cond.to_dict())

# → {'start_date': datetime(...), 'end_date': datetime(...),

#    'app_names': ['chrome.exe'], 'keywords': ['网页']}

LLM‑Enhanced Extraction

class DummyLLM:
    def parse_query(self, q):
        return {
            "time_range": {"start": "2024-04-01 00:00:00", "end": "2024-04-07 23:59:59"},
            "app_names": ["微信"],
            "keywords": ["会议记录"]
        }

parser_llm = QueryParser(llm_client=DummyLLM())
cond_llm = parser_llm.parse_query("帮我找一下微信上这周的会议记录")
print(cond_llm.to_dict())

# → {'start_date': datetime(...), 'end_date': datetime(...),

#    'app_names': ['WeChat.exe', 'Weixin.exe', '微信.exe'],

#    'keywords': ['会议记录']}

Summary

  • Dual‑strategy design: The parser attempts LLM extraction first, then falls back to deterministic rule‑based parsing via _parse_with_rules if the LLM fails or is unavailable.
  • UTC normalization: All temporal expressions are converted to UTC boundaries using get_utc_now and to_utc from lifetrace/util/time_utils.py.
  • App resolution: Friendly Chinese app names map to actual process identifiers via AppMapper in lifetrace/util/app_utils.py and _convert_to_process_names.
  • Intent detection: Keyword extraction requires explicit search indicators (搜索, 查找, etc.) to distinguish search terms from contextual noise.
  • Structured output: Both paths return a QueryConditions dataclass with a to_dict() method for immediate consumption by retrieval_service.py and rag_service.py.

Frequently Asked Questions

What happens if the LLM client returns malformed data?

The parse_query method validates LLM responses to ensure at least one of keywords, app_names, or a time range is present. If validation fails or the LLM returns empty, the parser automatically falls back to _parse_with_rules at line 34, ensuring robust operation even with unreliable LLM outputs.

How does the parser handle ambiguous time expressions like "recently"?

The rule‑based engine relies on predefined Chinese keywords stored in self.time_keywords (lines 86‑94). Ambiguous terms not matching 今天, 昨天, 本周, or explicit date patterns (YYYY‑MM‑DD) may be omitted unless the LLM path successfully interprets them. Explicit dates are captured via regex and parsed with datetime.strptime before UTC conversion via to_utc.

Can the parser recognize English application names?

While the primary implementation targets Chinese queries, the AppMapper in lifetrace/util/app_utils.py maintains process name mappings that may include English identifiers. The regex patterns in _find_app_names_from_patterns focus on Chinese grammar structures ("在 XX 上"), but the underlying mapping system can resolve any friendly name registered in the global app_mapper or self.app_name_mapping tables.

Why are keywords only extracted when search indicators are present?

The _extract_keywords method requires explicit intent signals such as ["搜索","查找","包含","关于","找到","寻找"] to avoid conflating descriptive text with search terms. This prevents casual mentions of applications or dates from being treated as search keywords, ensuring that QueryConditions.keywords contains only terms explicitly marked for content retrieval.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →