Entropic 2.9.4
Local-first agentic inference engine
Loading...
Searching...
No Matches
llama_cpp_sampler.cpp
Go to the documentation of this file.
1// SPDX-License-Identifier: Apache-2.0
21#include "llama_cpp_sampler.h"
23
24#include <llama.h>
25
26#include <cstdint>
27#include <memory>
28#include <unordered_map>
29#include <vector>
30
31static auto logger = entropic::log::get("inference.sampler");
32
33namespace entropic {
34
35namespace {
36
50void add_grammar_sampler(llama_sampler* chain,
51 const llama_vocab* vocab,
52 const std::string& grammar) {
53 if (grammar.empty()) { return; }
54 llama_sampler* g = llama_sampler_init_grammar(
55 vocab, grammar.c_str(), "root");
56 if (g) {
57 llama_sampler_chain_add(chain, g);
58 // gh#95: surface grammar attachment — the issue (and the
59 // tool-staged enforcement gap) had no log to confirm the sampler
60 // actually engaged the constraint.
61 logger->info("Grammar sampler attached ({} bytes)", grammar.size());
62 } else {
63 logger->error("Grammar sampler init FAILED for root rule — output "
64 "will be UNCONSTRAINED. Grammar ({} bytes): {}",
65 grammar.size(), grammar);
66 }
67}
68
79void add_logit_bias_sampler(llama_sampler* chain,
80 const llama_vocab* vocab,
81 const std::unordered_map<int32_t, float>& biases) {
82 if (biases.empty()) { return; }
83 std::vector<llama_logit_bias> entries;
84 entries.reserve(biases.size());
85 for (auto& [tok, val] : biases) {
86 entries.push_back({tok, val});
87 }
88 llama_sampler_chain_add(chain,
89 llama_sampler_init_logit_bias(
90 llama_vocab_n_tokens(vocab),
91 static_cast<int32_t>(entries.size()),
92 entries.data()));
93}
94
105uint32_t resolve_dist_seed(int caller_seed) {
106 return caller_seed < 0
107 ? LLAMA_DEFAULT_SEED
108 : static_cast<uint32_t>(caller_seed);
109}
110
111} // anonymous namespace
112
113// ── LlamaCppSampler ────────────────────────────────────────
114
120LlamaCppSampler::LlamaCppSampler(llama_sampler* chain, llama_context* ctx)
121 : chain_(chain), ctx_(ctx) {}
122
129 if (chain_) {
130 llama_sampler_free(chain_);
131 chain_ = nullptr;
132 }
133}
134
142 if (chain_ == nullptr || ctx_ == nullptr) { return -1; }
143 return llama_sampler_sample(chain_, ctx_, -1);
144}
145
152 if (chain_ != nullptr) {
153 llama_sampler_reset(chain_);
154 }
155}
156
157// ── LlamaCppSamplerFactory ─────────────────────────────────
158
165 llama_context* ctx, const llama_vocab* vocab)
166 : ctx_(ctx), vocab_(vocab) {}
167
179std::unique_ptr<Sampler> LlamaCppSamplerFactory::create(
180 const GenerationParams& params)
181{
182 llama_sampler_chain_params chain_params =
183 llama_sampler_chain_default_params();
184 llama_sampler* chain = llama_sampler_chain_init(chain_params);
185
186 add_grammar_sampler(chain, vocab_, params.grammar);
187 add_logit_bias_sampler(chain, vocab_, params.logit_bias);
188
189 // gh#23 MVP items 2 + 3 (v2.3.14 + v2.3.15): the penalties sampler
190 // now also carries presence_penalty (4th arg) and frequency_penalty
191 // (3rd arg). Gate fires when ANY of repeat / presence / frequency
192 // is non-default, so any single knob is sufficient to activate
193 // the stage.
194 if (params.repeat_penalty != 1.0f
195 || params.presence_penalty > 0.0f
196 || params.frequency_penalty > 0.0f) {
197 llama_sampler_chain_add(chain,
198 llama_sampler_init_penalties(
199 64, params.repeat_penalty,
200 params.frequency_penalty,
201 params.presence_penalty));
202 }
203 if (params.temperature > 0.0f) {
204 llama_sampler_chain_add(chain,
205 llama_sampler_init_temp(params.temperature));
206 }
207 if (params.top_k > 0) {
208 llama_sampler_chain_add(chain,
209 llama_sampler_init_top_k(params.top_k));
210 }
211 if (params.top_p < 1.0f) {
212 llama_sampler_chain_add(chain,
213 llama_sampler_init_top_p(params.top_p, 1));
214 }
215 // Min-P (gh#23 MVP item 1, v2.3.10) — gated so default 0.0f is no-op
216 if (params.min_p > 0.0f) {
217 llama_sampler_chain_add(chain,
218 llama_sampler_init_min_p(params.min_p, 1));
219 }
220
221 llama_sampler_chain_add(chain,
222 llama_sampler_init_dist(resolve_dist_seed(params.seed)));
223
224 return std::make_unique<LlamaCppSampler>(chain, ctx_);
225}
226
227} // namespace entropic
LlamaCppSamplerFactory(llama_context *ctx, const llama_vocab *vocab)
Construct with borrowed context + vocab pointers.
std::unique_ptr< Sampler > create(const GenerationParams &params) override
Build the v2.3.10 sampler chain from GenerationParams.
~LlamaCppSampler() override
Free the underlying llama.cpp sampler chain.
LlamaCppSampler(llama_sampler *chain, llama_context *ctx)
Construct with an already-built llama_sampler chain.
int32_t sample() override
Sample one token from the current logits via the wrapped chain.
void reset() override
Reset llama_sampler internal state.
Concrete llama.cpp Sampler + SamplerFactory (v2.3.10 seam impl).
spdlog initialization and logger access.
ENTROPIC_EXPORT std::shared_ptr< spdlog::logger > get(const std::string &name)
Get or create a named logger.
Definition logging.cpp:211
Activate model on GPU (WARM → ACTIVE).
Generation parameters for a single inference call.
Definition config.h:302
std::string grammar
GBNF grammar string (empty = unconstrained)
Definition config.h:359
int top_k
Top-K sampling.
Definition config.h:305
std::unordered_map< int32_t, float > logit_bias
Per-token logit bias map (gh#23 MVP item 4).
Definition config.h:336
float repeat_penalty
Repetition penalty.
Definition config.h:306
float temperature
Sampling temperature.
Definition config.h:303
float frequency_penalty
Frequency-penalty term in llama.cpp's penalties sampler (gh#23 MVP item 3).
Definition config.h:349
float presence_penalty
Presence-penalty term in llama.cpp's penalties sampler (gh#23 MVP item 2).
Definition config.h:322
float min_p
Min-p nucleus sampling threshold (gh#23 MVP item 1).
Definition config.h:315
float top_p
Nucleus sampling threshold.
Definition config.h:304
int seed
RNG seed for reproducible sampling.
Definition config.h:356