Troubleshooting Guide
This guide helps diagnose and resolve common issues with the LLM-based scanno detection system.
Common Issues
1. Ollama Connection Issues
Symptoms:
- Error: "Connection refused" or "Cannot connect to Ollama"
- Timeout errors when calling LLM
Solutions:
# Check if Ollama is running
curl http://localhost:11434/api/version
# Start Ollama service
ollama serve
# On macOS, restart Ollama
brew services restart ollama
# Check Ollama logs
ollama logs
Configuration check:
# Verify Ollama URL in config
config = Application.get_env(:codexis, :scanno_detection)
IO.inspect(config[:ollama_url])
# Test connection
Req.get!("#{config[:ollama_url]}/api/version")
2. Model Not Found
Symptoms:
- Error: "model 'qwen3.0:8b' not found"
- LLM calls fail with model errors
Solutions:
# List available models
ollama list
# Pull required model
ollama pull qwen3.0:8b
ollama pull deepseek-r1:8b
# Verify model is downloaded
ollama show qwen3.0:8b
3. Slow Performance
Symptoms:
- Processing takes too long
- Timeouts during detection
- High CPU/memory usage
Solutions:
# Reduce concurrency
config :codexis, :scanno_detection,
max_concurrency: 2, # Reduce from default
batch_size: 50, # Smaller batches
model: "qwen2.5:3b" # Use smaller model
# Enable caching
config :codexis, :scanno_detection,
cache_results: true,
cache_directory: "priv/scanno_cache"
# Profile performance
{time, result} = :timer.tc(fn ->
ScannoDetector.detect_scannos(content)
end)
IO.puts("Time: #{time/1_000_000} seconds")
4. Memory Issues
Symptoms:
- Out of memory errors
- Process crashes
- System slowdown
Solutions:
# Limit memory usage
config :codexis, :scanno_memory,
max_heap_size: 1_000_000,
fullsweep_after: 10
# Process in smaller chunks
def process_large_file(path) do
path
|> File.stream!([], 5000) # Read in 5KB chunks
|> Stream.chunk_every(10) # Process 10 lines at a time
|> Stream.map(&process_chunk/1)
|> Enum.to_list()
end
# Monitor memory usage
:erlang.memory()
5. Poor Detection Accuracy
Symptoms:
- Many false positives
- Missing obvious errors
- Low confidence scores
Solutions:
# Adjust confidence thresholds
config :codexis, :scanno_detection,
confidence_threshold: 0.8, # Increase threshold
auto_accept_threshold: 0.95 # Be more conservative
# Use better models
config :codexis, :scanno_detection,
default_model: "qwen2.5:14b", # Larger model
math_model: "deepseek-r1:8b"
# Add custom patterns
defmodule CustomPatterns do
def domain_specific_patterns do
%{
~r/\bspecific_error\b/ => "specific_correction",
# Add more patterns
}
end
end
6. LaTeX Processing Errors
Symptoms:
- LaTeX commands not recognized
- Math equations incorrectly processed
- Bibliography errors
Solutions:
# Improve LaTeX extraction
defmodule ImprovedLatexProcessor do
def extract_commands(content) do
# Better regex for LaTeX commands
Regex.scan(~r/\\([a-zA-Z]+\*?)(?:\[[^\]]*\])?(?:\{[^}]*\})*/, content)
end
def extract_math(content) do
# Handle both inline and display math
inline = Regex.scan(~r/\$([^$]+)\$/, content)
display = Regex.scan(~r/\\\[(.*?)\\\]/s, content)
inline ++ display
end
end
# Use specialized prompts for LaTeX
def latex_specific_prompt(content) do
"""
You are checking LaTeX source code for OCR errors.
Focus on:
1. LaTeX command misspellings
2. Bracket mismatches
3. Math symbol errors
Content:
#{content}
"""
end
Debugging Tools
1. Enable Debug Logging
# config/dev.exs
config :logger, level: :debug
config :codexis, :scanno_detection,
verbose_logging: true,
save_intermediate_results: true
# In your code
require Logger
Logger.debug("Processing block: #{inspect(block)}")
Logger.debug("LLM response: #{inspect(response)}")
2. Inspection Tools
defmodule Codexis.Debug do
def inspect_prompt(content) do
prompt = ScannoDetector.build_prompt(content)
IO.puts("Generated prompt:")
IO.puts(prompt)
prompt
end
def test_llm_connection do
case Codexis.LLM.OllamaClient.generate("test", model: "qwen3.0:8b") do
{:ok, response} ->
IO.puts("LLM connection OK")
IO.inspect(response)
{:error, error} ->
IO.puts("LLM connection failed:")
IO.inspect(error)
end
end
def analyze_corrections(corrections) do
%{
total: length(corrections),
by_confidence: Enum.group_by(corrections, & &1["confidence"]),
unique_patterns: corrections
|> Enum.map(& {&1["original"], &1["corrected"]})
|> Enum.uniq()
|> length()
}
end
end
3. Performance Profiling
defmodule Codexis.Profiler do
def profile_detection(content) do
:fprof.apply(&ScannoDetector.detect_scannos/1, [content])
:fprof.profile()
:fprof.analyse(dest: "scanno_profile.txt")
end
def benchmark_models do
models = ["qwen2.5:3b", "qwen3.0:8b", "qwen2.5:14b"]
content = "Sample content with errors"
Enum.each(models, fn model ->
{time, _} = :timer.tc(fn ->
ScannoDetector.detect_scannos(content, model: model)
end)
IO.puts("#{model}: #{time/1_000_000}s")
end)
end
end
Error Messages
Common Error Messages and Solutions
| Error Message | Cause | Solution |
|---|---|---|
{:error, :timeout} |
LLM response too slow | Increase timeout, use smaller model |
{:error, :invalid_json} |
Malformed LLM response | Check prompt format, retry request |
{:error, :model_not_found} |
Model not available | Pull model with ollama pull |
{:error, :connection_refused} |
Ollama not running | Start Ollama service |
{:error, :out_of_memory} |
Too much data in memory | Process in smaller chunks |
Custom Error Handling
defmodule Codexis.ErrorHandler do
def handle_scanno_error({:error, :timeout}) do
Logger.warn("LLM timeout - retrying with smaller chunk")
{:retry, chunk_size: 1000}
end
def handle_scanno_error({:error, :invalid_json}) do
Logger.error("Invalid JSON response - using fallback")
{:fallback, use_pattern_matching: true}
end
def handle_scanno_error({:error, reason}) do
Logger.error("Unexpected error: #{inspect(reason)}")
{:error, reason}
end
end
Health Checks
System Health Check
defmodule Codexis.HealthCheck do
def check_system do
%{
ollama: check_ollama(),
models: check_models(),
memory: check_memory(),
disk: check_disk_space(),
cache: check_cache()
}
end
defp check_ollama do
case Req.get("http://localhost:11434/api/version") do
{:ok, %{status: 200}} -> :ok
_ -> :error
end
end
defp check_models do
required_models = ["qwen3.0:8b", "deepseek-r1:8b"]
available = case System.cmd("ollama", ["list"]) do
{output, 0} -> parse_model_list(output)
_ -> []
end
missing = required_models -- available
if Enum.empty?(missing), do: :ok, else: {:error, missing}
end
defp check_memory do
memory = :erlang.memory(:total) / 1_024_024_024 # GB
if memory < 2.0, do: :warning, else: :ok
end
defp check_disk_space do
cache_dir = Application.get_env(:codexis, :scanno_detection)[:cache_directory]
case System.cmd("df", [cache_dir]) do
{output, 0} ->
# Parse available space
:ok
_ ->
:error
end
end
end
Monitoring Dashboard
defmodule Codexis.Monitor do
use GenServer
def start_link(_) do
GenServer.start_link(__MODULE__, %{}, name: __MODULE__)
end
def get_stats do
GenServer.call(__MODULE__, :get_stats)
end
@impl true
def init(_) do
:timer.send_interval(60_000, :collect_stats)
{:ok, %{stats: %{}}}
end
@impl true
def handle_info(:collect_stats, state) do
stats = %{
detections_per_minute: count_detections(),
average_response_time: calculate_avg_response_time(),
error_rate: calculate_error_rate(),
cache_hit_rate: calculate_cache_hit_rate()
}
{:noreply, %{state | stats: stats}}
end
end
Recovery Procedures
Automatic Recovery
defmodule Codexis.Recovery do
def with_recovery(fun, opts \\ []) do
max_retries = Keyword.get(opts, :max_retries, 3)
try do
fun.()
rescue
error ->
if max_retries > 0 do
Logger.warn("Error occurred, retrying... (#{max_retries} left)")
Process.sleep(1000)
with_recovery(fun, Keyword.put(opts, :max_retries, max_retries - 1))
else
reraise error, __STACKTRACE__
end
end
end
def recover_from_cache_corruption do
cache_dir = Application.get_env(:codexis, :scanno_detection)[:cache_directory]
Logger.warn("Clearing corrupted cache: #{cache_dir}")
File.rm_rf!(cache_dir)
File.mkdir_p!(cache_dir)
end
def recover_from_model_issues(model) do
Logger.warn("Model issues detected, attempting to reload: #{model}")
# Stop using the model temporarily
disable_model(model)
# Re-pull the model
System.cmd("ollama", ["pull", model])
# Re-enable the model
enable_model(model)
end
end
Manual Recovery Steps
-
Clear Cache:
rm -rf priv/scanno_cache/* -
Restart Services:
# Restart Ollama brew services restart ollama # Restart application iex -S mix -
Reset Configuration:
# Reset to defaults Application.put_env(:codexis, :scanno_detection, Codexis.BuildPipeline.Config.default_scanno_config() )
Log Analysis
Log Patterns
defmodule Codexis.LogAnalyzer do
def analyze_logs(log_file) do
log_file
|> File.stream!()
|> Stream.map(&parse_log_line/1)
|> Stream.filter(& &1)
|> Enum.reduce(%{}, &categorize_log/2)
end
defp parse_log_line(line) do
case Regex.run(~r/\[(error|warn|info|debug)\] (.+)/, line) do
[_, level, message] -> %{level: level, message: message}
_ -> nil
end
end
defp categorize_log(log, acc) do
category = determine_category(log.message)
Map.update(acc, category, 1, & &1 + 1)
end
defp determine_category(message) do
cond do
message =~ "timeout" -> :timeout
message =~ "memory" -> :memory
message =~ "connection" -> :connection
message =~ "model" -> :model
true -> :other
end
end
end
Common Log Messages
| Log Message | Meaning | Action |
|---|---|---|
| "LLM timeout after 30000ms" | Request timed out | Increase timeout or use smaller model |
| "Connection refused" | Ollama not available | Start Ollama service |
| "Out of memory" | Memory exhausted | Reduce batch size or concurrency |
| "Invalid JSON response" | Parsing error | Check prompt format |
| "Model not found" | Model not installed | Pull model with ollama |
Support Resources
Getting Help
- Documentation: Check the full documentation at
/docs/llm-scanno - Issue Tracker: Report bugs on GitHub
- Community Forum: Ask questions in discussions
- Debug Mode: Enable with
config :codexis, :debug_mode, true
Diagnostic Script
# Save as diagnostic.exs and run with: mix run diagnostic.exs
defmodule Diagnostic do
def run do
IO.puts("Codexis Scanno Detection Diagnostic")
IO.puts("==================================")
check_environment()
check_configuration()
check_models()
test_detection()
IO.puts("\nDiagnostic complete!")
end
defp check_environment do
IO.puts("\n1. Environment Check:")
IO.puts(" Elixir: #{System.version()}")
IO.puts(" OTP: #{:erlang.system_info(:otp_release)}")
end
defp check_configuration do
IO.puts("\n2. Configuration Check:")
config = Application.get_env(:codexis, :scanno_detection)
IO.inspect(config, label: " Config")
end
defp check_models do
IO.puts("\n3. Model Check:")
case System.cmd("ollama", ["list"]) do
{output, 0} -> IO.puts(" Models: #{output}")
_ -> IO.puts(" ERROR: Cannot list models")
end
end
defp test_detection do
IO.puts("\n4. Detection Test:")
test_content = "This is a tost with an error."
case Codexis.QualityChecker.ScannoDetector.detect_scannos(test_content) do
{:ok, results} ->
IO.puts(" SUCCESS: Detected #{map_size(results)} corrections")
{:error, error} ->
IO.puts(" ERROR: #{inspect(error)}")
end
end
end
Diagnostic.run()
Best Practices
- Start Small: Test with small documents first
- Monitor Resources: Watch CPU and memory usage
- Use Caching: Enable caching for repeated documents
- Choose Models Wisely: Balance accuracy vs. speed
- Handle Errors Gracefully: Implement proper error recovery
- Keep Logs: Enable logging for troubleshooting
- Regular Maintenance: Clean cache, update models periodically