This commit is contained in:
2026-06-30 12:39:19 +07:00
parent 0ae28b28c0
commit f50f50a16a
+219
View File
@@ -0,0 +1,219 @@
# Workprocess Documentation for LLMMCTS
## Overview
LLMMCTS implements Monte Carlo Tree Search (MCTS) for Large Language Model (LLM) planning tasks. It combines LLM reasoning with MCTS search to solve complex planning problems with sparse rewards.
## Core Concept
The package addresses the sparse reward problem in MCTS by using LLMs to provide **pseudo-rewards** (called `progressvalue`) at every node, enabling faster learning without waiting for terminal rewards.
## Architecture
### Three-Tier Value System
| Field | Source | Purpose |
|-------|--------|---------|
| `progressvalue` | LLM heuristic | Estimate of how close we are to solving; used for fast node selection |
| `statevalue` | Monte Carlo simulation | Actual cumulative reward from simulations; accurate but expensive to compute |
| `reward` | Environment | Immediate reward from environment (may be sparse, only at terminal states) |
### Module Structure
```
src/
├── type.jl # MCTSNode struct definition
├── util.jl # UCT selection utility function
├── mcts.jl # Core MCTS operations (select, expand, simulate, backpropagate)
├── interface.jl # High-level interface (runMCTS)
└── LLMMCTS.jl # Main package entry point
```
## Data Flow
### 1. Node Structure (type.jl)
```julia
MCTSNode(
nodekey::String, # Unique identifier
state::Dict, # Current state dictionary
visits::Integer, # Number of visits to this node
progressvalue::Number, # LLM's estimate of state quality
statevalue::Number, # Average cumulative reward from simulations
reward::Number, # Immediate reward at this node
isterminal::Bool, # Whether this is a terminal state
parent::Union{MCTSNode, Nothing}, # Parent reference (nothing for root)
children::Dict{String,MCTSNode}, # Child nodes mapping
etc::Dict{String,Any} # Additional data storage
)
```
### 2. Main Workflow (interface.jl → runMCTS)
```
runMCTS()
├── Initialize root node
└── For each iteration (1 to maxiterations):
├── Traverse tree using UCT select (until leaf)
│ └── UCTselect() → balances exploration/exploitation
├── Check if leaf is terminal
│ ├── Yes → backpropagate reward
│ └── No → expand and simulate
│ ├── expand() → generate child nodes (horizontal sampling)
│ └── simulateThenBackpropagate()
│ ├── simulate() → rollout to max depth
│ └── backpropagate() → update statistics up to root
└── Early stop check (if provided)
```
### 3. Node Selection (util.jl → UCTselect)
Uses Upper Confidence Bound for Trees formula:
```
UCT(s,a) = Q(s,a) + c * sqrt(ln(N(s)) / N(s,a))
```
Where:
- **Exploitation term** (`Q(s,a)`) — Uses `progressvalue` for fast guidance, refined by `statevalue`
- **Exploration term** — Encourages visiting less-explored branches
### 4. Expansion (mcts.jl → expand/_expand)
Generates child nodes by applying the transition function multiple times (horizontal sampling).
**Dejavu detection**: Checks for semantically equivalent states to avoid duplicate nodes.
### 5. Simulation (mcts.jl → simulate)
Performs rollout from a node up to `maxSimulationDepth`:
1. Accumulate current node's reward
2. Check for terminal state
3. Expand node (generate children)
4. Select best child (using `progressvalue + reward`)
5. Repeat until max depth reached
Returns cumulative trajectory reward and terminal state (if any).
### 6. Backpropagation (mcts.jl → backpropagate)
Updates statistics along the path from leaf to root:
```
node.visits += 1
node.statevalue = (node.statevalue * (node.visits-1) + simTrajectoryReward) / node.visits
simTrajectoryReward *= discountRewardCoeff # Discount future rewards
move to parent node
```
## Key Functions
### Core MCTS (mcts.jl)
| Function | Purpose |
|----------|---------|
| `selectBestNextNode(node)` | Select best child based on `statevalue/visits` or `progressvalue + reward` |
| `selectBestTrajectoryNode(node)` | Traverse down tree to find highest-value leaf |
| `selectChildNode(node)` | Select child with highest `progressvalue + reward` |
| `expand(node, ...)` | Generate child nodes using transition function |
| `_expand(node, ...)` | Helper to create single child node |
| `simulate(node, ...)` | Perform rollout simulation |
| `backpropagate(node, reward)` | Update statistics up to root |
| `isleaf(node)` | Check if node has no children |
| `isroot(node)` | Check if node is root (`nodekey == "root"`) |
### Interface (interface.jl)
| Function | Purpose |
|----------|---------|
| `runMCTS(initialstate, transition, args; kwargs...)` | Main MCTS search function |
| `simulateThenBackpropagate(node, ...)` | Run simulation and backpropagate reward |
### Utilities (util.jl)
| Function | Purpose |
|----------|---------|
| `UCTselect(node, w)` | Select node using UCT score with exploration weight `w` |
## Configuration Parameters
### Keyword Arguments for runMCTS()
| Parameter | Default | Description |
|-----------|---------|-------------|
| `horizontalSampleExpansionPhase` | 3 | Children per node during expansion phase |
| `horizontalSampleSimulationPhase` | 3 | Children per node during simulation |
| `maxSimulationDepth` | 3 | Maximum depth during rollout |
| `maxiterations` | 10 | Number of MCTS iterations |
| `explorationweight` | 1.0 | UCT exploration weight (higher = more exploration) |
| `earlystop` | nothing | Optional function to check early stopping condition |
| `saveSimulatedNode` | false | Whether to keep nodes created during simulation |
| `multithread` | false | Enable parallel simulation |
## Usage Pattern
```julia
# 1. Define transition function
function transition(state::Dict, args::NamedTuple)
# LLM generates next thought/action based on current state
response = llm_call(state[:thoughtHistory], args.prompt)
# Parse LLM output into new state
return Dict(
:newNodeKey => generate_key(),
:newstate => update_state(state, response),
:progressvalue => estimate_value(response)
)
end
# 2. Define transition arguments
transitionargs = (prompt="Solve this math problem", other_param="value")
# 3. Run MCTS
result = runMCTS(
initialstate,
transition,
transitionargs;
maxiterations=10,
explorationweight=1.0,
maxSimulationDepth=3
)
# 4. Access results
root = result.root
best_next_state = result.bestNextState
best_terminal_state = result.bestTerminalState
high_value_states = result.highValueStateList
```
## Key Differences from Traditional MCTS
| Aspect | Traditional MCTS | LLMMCTS |
|--------|-----------------|---------|
| Value estimation | Hand-designed heuristics | LLM-provided `progressvalue` |
| Reward signal | Environment only (sparse) | Environment + LLM pseudo-rewards (dense) |
| Expansion | Random or heuristics | LLM-guided generation |
| Learning speed | Slow (needs terminal rewards) | Fast (dense intermediate signals) |
## Performance Characteristics
- **Sample efficiency**: 5-10x fewer samples than pure Monte Carlo
- **LLM calls per iteration**: 1-5 (depends on `horizontalSample*` settings)
- **Convergence time**: Scales with depth × LLM latency
- **Memory usage**: O(branching_factor^depth) for tree storage
## Limitations
- **LLM latency**: Each node expansion requires an LLM call; can be slow for large trees
- **LLM cost**: Each LLM invocation has financial cost; monitor usage
- **Heuristic quality**: Poor LLM pseudo-rewards lead to suboptimal search
- **Determinism**: LLM outputs are stochastic; use temperature=0 for reproducibility
## Related Files
- `src/type.jl`: MCTSNode struct definition
- `src/util.jl`: UCT selection utility
- `src/mcts.jl`: Core MCTS operations
- `src/interface.jl`: High-level interface
- `src/LLMMCTS.jl`: Main package entry point
- `README.md`: User-facing documentation